Troubleshooting Netcat Over UDP – Networking, Debian Jessie

debian-jessienetcatnetworkingudp

While troubleshooting the problem described here, I tried something really basic: I tried setting up a very basic netcat connection over UDP, and I noticed it's not working as I expect.

As with the TCP illustration below, I expected the UDP case to echo the same output on Window 1 as I type it in Window 2; instead, I get no output in Window 1 in the UDP case.

I'm running Debian Jessie on my laptop, and I have Wireshark running with the following capture filter:

udp and not (port 123 or port 5353 or port 1900)

In one terminal window, I began with a TCP test by running the following command:

$ nc -l 6900

In a second terminal window, I ran the following:

$ nc localhost 6900

In Window 2, I typed "one" and pressed Enter, then I typed "two" and pressed Enter, and finally I pressed Ctrl+D to exit.

After pressing Enter on "one", I saw "one" echoed in Window 1. After pressing Enter on "two", I saw "two" echoed in Window 1. When I pressed Ctrl+D, both netcat instances exited and I returned to the prompt.

This demonstrates I could get a TCP connection going without any problem. Next, I tried UDP.

Window 1:

$ nc -l -u 6900

Window 2:

$ nc -u localhost 6900

It's funny. I think I could only type "one", press Enter, then "two", and press Enter, and I automatically returned back to the prompt in Window 2.

On Window 1, I don't see any output.

I retried with -v in Window 1:

$ nc -v -l -u 6900
Listening on [0.0.0.0] (family 0, port 6900)

Funny when I retried with -v in Window 2:

$ nc -v -u localhost 6900
$

It's like netcat never ran; I returned immediately to the prompt.

Update: If I replace localhost with 127.0.0.1, there is progress.

With the "server" listening in Window 1:

$ nc -v -l -u 6900
one
two
three

I was able to get output echoed from Window 2 when typing "one", "two", and "three":

$ nc -u 127.0.0.1 6900
one
two
three
^C

The -v is still puzzling, because it's the same as above.

Best Answer

Using macOS, I come to a different conclusion. The key is IPv6. localhost resolves to both IPv6 and IPv4. However, the following command line will cause nc to listen on IPv4:

nc -l -u 6900

The result:

$ lsof -n -i:6900
COMMAND   PID  USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
nc      63923 fuzzy    3u  IPv4 0xad7f669b928a178b      0t0  UDP *:6900

Now when you use this to “connect”:

nc -u localhost 6900

... it actually connects to IPv6. When you use 127.0.0.1 it will not.

However, it does not connect, because UDP is connectionless. As such, there is no way of knowing whether the remote end of the connection really exists. As such, it cannot detect it should fall back to IPv4. Your messages will be sent, but there is nothing listening for those messages.

When sending, the following can be observed:

$ tcpdump -i lo0 udp port 6900
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo0, link-type NULL (BSD loopback), capture size 262144 bytes
00:46:37.543273 IP6 localhost.54473 > localhost.6900: UDP, length 6

With TCP, it will try to connect on IPv6, determine this isn’t working, and retry with IPv4:

$ tcpdump -i lo0 port 6900
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo0, link-type NULL (BSD loopback), capture size 262144 bytes
00:50:21.495107 IP6 localhost.64306 > localhost.6900: Flags [SEW], seq 1432891337, win 65535, options [mss 16324,nop,wscale 5,nop,nop,TS val 766376063 ecr 0,sackOK,eol], length 0
00:50:21.495136 IP6 localhost.6900 > localhost.64306: Flags [R.], seq 0, ack 1432891338, win 0, length 0
00:50:21.495231 IP localhost.64307 > localhost.6900: Flags [S], seq 307818799, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 766376063 ecr 0,sackOK,eol], length 0
00:50:21.495283 IP localhost.6900 > localhost.64307: Flags [S.], seq 4254625238, ack 307818800, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 766376063 ecr 766376063,sackOK,eol], length 0
00:50:21.495295 IP localhost.64307 > localhost.6900: Flags [.], ack 1, win 12759, options [nop,nop,TS val 766376063 ecr 766376063], length 0
00:50:21.495306 IP localhost.6900 > localhost.64307: Flags [.], ack 1, win 12759, options [nop,nop,TS val 766376063 ecr 766376063], length 0

You can force nc to use IPv4:

nc -4u localhost 6900
Related Question