2

I am experimenting with communication over UDP port 6666 (the goal is setting up a listener for netconsole, but that's not really relevant here).

On the listening side, nc -luv 6666. On the sending side, nc -uv LISTENER_IP 6666. I can send and receive, life is good.

Now I leave the listener running, but kill the sender and start another sender. It terminates immediately. A network trace reveals that the receiving server sends an ICMP Port Unreachable. However, the listener still listens:

$ sudo ss -nlup|grep 6666
UNCONN     0      0           :::6666                    :::*                   users:(("nc",pid=3417,fd=3))

I kill the receiver and run a new one. Everything works as before until I kill the sender.

Sender and receiver are physical machines on the same network. The same test between a physical machine and a VM running on it yields the same result.

How can this behaviour be explained?

3

Due to the way that UDP "connections" work, this is expected behaviour. This is discussed in the nc6(1) man page ("UDP"), but is applicable to socat and nc as well:

UDP support in netcat6 works very well in both connect and in listen mode. When using UDP in listen mode netcat6 accepts UDP packets from any source that matches the optional address and/or port specified (if it was specified). However, once the first packet is received, netcat6 will only receive packets from that client in future. This is done by putting the UDP socket into "connected" state (see udp(4) and connect(2)). Packets from other sources are discarded by the kernel and an ICMP unreachable response is sent.

When connecting to a remote host using UDP, nc6 will report that the connection is open regardless of whether a remote server is listening. This is because UDP is a connectionless protocol, and hence no connection establishment is actually required. However, after sending the first packet of data, a server may reply with an ICMP unreachable response causing nc6 to exit with a 'Connection refused' error message.

When you connect from the sender side, a random UDP source port is chosen. The receiver then binds to that particular host:port pair and will not listen to any other connection from then on. To solve this, you need to force the sender to always use the same port. I used socat for this example because it was easier to do:

Listener:

# socat -d -d UDP-LISTEN:6666 stdout
2018/01/29 22:02:02 socat[20969] N listening on UDP AF=2 0.0.0.0:6666
2018/01/29 22:02:07 socat[20969] N accepting UDP connection from AF=2 10.100.0.5:39000
2018/01/29 22:02:07 socat[20969] N using stdout for reading and writing
2018/01/29 22:02:07 socat[20969] N starting data transfer loop with FDs [5,5] and [1,1]
hello
bye
hello1
bye1

Sender:

# socat -d -d stdin UDP:listener-host:6666
2018/01/29 22:01:56 socat[8237] N using stdin for reading and writing
2018/01/29 22:01:56 socat[8237] N opening connection to AF=2 10.100.0.3:6666
2018/01/29 22:01:56 socat[8237] N successfully connected from local address AF=2 10.100.0.5:39000
2018/01/29 22:01:56 socat[8237] N starting data transfer loop with FDs [0,0] and [5,5]
hello
bye
2018/01/29 22:02:10 socat[8237] N socket 1 (fd 0) is at EOF    
2018/01/29 22:02:10 socat[8237] N exiting with status 0

 

# socat -d -d stdin UDP:listener-host:6666
2018/01/29 22:02:13 socat[8238] N using stdin for reading and writing
2018/01/29 22:02:13 socat[8238] N opening connection to AF=2 10.100.0.3:6666
2018/01/29 22:02:13 socat[8238] N successfully connected from local address AF=2 10.100.0.5:57125
2018/01/29 22:02:13 socat[8238] N starting data transfer loop with FDs [0,0] and [5,5]
hello
2018/01/29 22:02:16 socat[8238] E read(5, 0x5619f9b09330, 8192): Connection refused
2018/01/29 22:02:16 socat[8238] N exit(1)

 

# socat -d -d stdin UDP:listener-host:6666,sourceport=39000
2018/01/29 22:05:17 socat[8280] N using stdin for reading and writing
2018/01/29 22:05:17 socat[8280] N opening connection to AF=2 10.100.0.3:6666
2018/01/29 22:05:17 socat[8280] N successfully connected from local address AF=2 10.100.0.5:39000
2018/01/29 22:05:17 socat[8280] N starting data transfer loop with FDs [0,0] and [5,5]
hello1
bye1
2018/01/29 22:05:23 socat[8280] N socket 1 (fd 0) is at EOF
2018/01/29 22:05:24 socat[8280] N exiting with status 0

As you can see, the source port changed on the sender but if I forced it to reuse the same port it worked.

  • Yes, this makes sense and it works. Thanks! Just by the way, netcat (or nc as its friends call it) needs the -p option to set the source port on the sender side, and of course you can use ss or netstat on the listener side to find out what that source port is. – berndbausch Jan 30 '18 at 8:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.