Strange behaviour of netcat with UDP
Asked Answered
E

4

38

I noticed a strange behaviour working with netcat and UDP. I start an instance (instance 1) of netcat that listens on a UDP port:

nc -lu -p 10000

So i launch another instance of netcat (instance 2) and try to send datagrams to my process:

nc -u 127.0.0.1 10000

I see the datagrams. But if i close instance 2 and relaunch again netcat (instance 3):

nc -u 127.0.0.1 10000

i can't see datagrams on instance 1's terminal. Obsiously the operating system assigns a different UDP source port at the instance 3 respect to instance 2 and the problem is there: if i use the same instance'2 source port (example 50000):

 nc -u -p 50000 127.0.0.1 10000

again the instance 1 of netcat receives the datagrams. UDP is a connection less protocol so, why? Is this a standard netcat behaviour?

Eton answered 8/10, 2011 at 12:40 Comment(5)
Your first command is illegal. It doesn't specify the port nc should listen on. And you can't use -l (listen) and -p (specify source port) together. If you're listening, you can't control the source.Tacye
False for version v1.10-38. nc gives an error if you try lo launch it without that option! So nc -lu 10000 won't run.Eton
Weird. Does it ignore the port specified with -p? Or does it use it as the port it listens on?Tacye
It uses that port as "listing" port. And i see that with netstat -an | grep 10000: udp 0 0 0.0.0.0:10000 0.0.0.0:*Eton
The argument confusion stems from the fact that there are multiple slightly incompatible nc implementations (Wikipedia), including Hobbit's Netcat (netcat-traditional in Debian; -p required when listening), OpenBSD Netcat (netcat-openbsd in Debian; -p optional when listening) and GNU Netcat (not in Debian; without -p, listen port is random). Use nc -h to identify which one you're using.Colettecoleus
T
49

When nc is listening to a UDP socket, it 'locks on' to the source port and source IP of the first packet it receives. Check out this trace:

socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP) = 3
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
bind(3, {sa_family=AF_INET, sin_port=htons(10000), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
recvfrom(3, "f\n", 2048, MSG_PEEK, {sa_family=AF_INET, sin_port=htons(52832), sin_addr=inet_addr("127.0.0.1")}, [16]) = 2
connect(3, {sa_family=AF_INET, sin_port=htons(52832), sin_addr=inet_addr("127.0.0.1")}, 16) = 0

Here you can see that it created a UDP socket, set it for address reuse, and bound it to port 10,000. As soon as it received its first datagram (from port 52,832), it issued a connect system call 'connecting' it to the 127.0.0.1:52,832. For UDP, a connect rejects all packets that don't match the IP and port in the connect.

Tacye answered 8/10, 2011 at 12:56 Comment(10)
There are only one process that listen on port 10000. netstat -an | grep 10000 shows it: udp 0 0 0.0.0.0:10000 0.0.0.0:*. There is no Multicast or Broadcast.Eton
I suppose it's an output of strace. Good. Now all is clear. Thank you David.Eton
Bummer, there should be an option to disable this IMO. Then again, how would one specify which host(s) to send datagrams to from the bound "listening" process?Wang
Instead, I would recommend using socat. e.g. socat UDP-RECV:[port] STDOUT and socat STDIN UDP-DATAGRAM:[host]:[port]Baalbeer
Adding -w 0 seems to work solve the "lock on" problem.Hannah
@Jannes, -w 0 doesn't change anything in netcat-openbsd 1.105-7ubuntu1.Stilbestrol
regarding above comments, there are two versions of netcat in common use that take wildly different arguments, e.g. -w0 is rejected on one yet perfectly acceptable by the other.Armoured
why would netcat bind to a particular client in a state-less protocol.. within a swiss-army-knife networking testing utility is beyond me...Northcliffe
@Northcliffe The explicit purpose of this utility is to form a connection. The man page title is, "nc, netcat - arbitrary TCP and UDP connections and listens".Tacye
I had a similar problem. Over Ethernet receiving worked fine, over WiFi not. In packet analyzer I found that the system is soft-rejecting all packets. But socat (thanks @tudor) works, even though the system rejects the packets.Hera
D
6

Use the -k option:

nc -l -u -k 0.0.0.0 10000
  • -k means keep-alive, that netcat keeps listening after each connection
  • -u means UDP
  • -l listening on port 10000
Diastase answered 1/3, 2015 at 11:42 Comment(3)
Ncat: UDP mode does not support the -k or --keep-open options, except with --exec or --sh-exec. QUITTING.Guimond
-k do not helpsTangled
It did work for me. My netcat is OpenBSD one.Reduction
A
3

Having given up on netcat on my OS version this is pretty short and gets the job done:

#!/usr/bin/ruby
# Receive UDP packets bound for a port and output them
require 'socket'
require 'yaml'

unless ARGV.count == 2
  puts "Usage: #{$0} listen_ip port_number"
  exit(1)
end
listen_ip = ARGV[0]
port = ARGV[1].to_i

u1 = UDPSocket.new
u1.bind(listen_ip, port)
while true
  mesg, addr = u1.recvfrom(100000)
  puts mesg
end
Amazonite answered 16/12, 2016 at 16:6 Comment(1)
This script works wonderfully on Ubuntu and does the job listening for UDP traffic and grabbing any new connections sent to it. Thank you very much!Euphemism
L
1

As the accepted answer explains, ncat appears not to support --keep-open with the UDP protocol. However, the error message which it prints hints at a workaround:

Ncat: UDP mode does not support the -k or --keep-open options, except with --exec or --sh-exec. QUITTING.

Simply adding --exec /bin/cat allows --keep-open to be used. Both input and output will be connected to /bin/cat, with the effect of turning it an "echo server" because whatever the client sends will be copied back to it.

To do something more useful with the input, we can use the shell's redirection operators (thus requiring --sh-exec instead of --exec). To see the data on the terminal, this works:

ncat -k -l -u -p 12345 --sh-exec "cat > /proc/$$/fd/1"

Caveat: the above example sends data to the stdout of ncat's parent shell, which could be confusing if combined with additional redirections. To simply append all output to a file is more straightforward:

ncat -k -l -u -p 12345 --sh-exec "cat >> ncat.out"
Lordling answered 4/12, 2018 at 22:31 Comment(1)
Thanks for this. This observation was very useful. The -k and --exec /bin/cat came in handy.Photocell

© 2022 - 2024 — McMap. All rights reserved.