36

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?

jw013
  • 1,718
  • 17
  • 22
MirkoBanchi
  • 2,173
  • 5
  • 35
  • 52
  • 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. – David Schwartz Oct 08 '11 at 12:55
  • 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. – MirkoBanchi Oct 08 '11 at 13:13
  • 1
    Weird. Does it ignore the port specified with `-p`? Or does it use it as the port it listens on? – David Schwartz Oct 08 '11 at 13:19
  • 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:*` – MirkoBanchi Oct 08 '11 at 13:23
  • 4
    The argument confusion stems from the fact that there are multiple slightly incompatible `nc` implementations [(Wikipedia)](https://en.wikipedia.org/wiki/Netcat), including Hobbit's Netcat (`netcat-traditional` in Debian; `-p` required when listening), [OpenBSD Netcat](https://code.google.com/p/openbsd-netcat/) (`netcat-openbsd` in Debian; `-p` optional when listening) and [GNU Netcat](http://netcat.sourceforge.net/) (not in Debian; without `-p`, listen port is random). Use `nc -h` to identify which one you're using. – Søren Løvborg Jul 18 '14 at 16:51

4 Answers4

47

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.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • 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. – MirkoBanchi Oct 08 '11 at 13:18
  • I suppose it's an output of `strace`. Good. Now all is clear. Thank you David. – MirkoBanchi Oct 08 '11 at 17:16
  • 2
    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? – TimCinel Feb 14 '12 at 07:46
  • 18
    Instead, I would recommend using socat. e.g. socat UDP-RECV:[port] STDOUT and socat STDIN UDP-DATAGRAM:[host]:[port] – tudor -Reinstate Monica- May 07 '14 at 03:11
  • 2
    Adding -w 0 seems to work solve the "lock on" problem. – Jannes Apr 04 '16 at 15:24
  • @Jannes, `-w 0` doesn't change anything in `netcat-openbsd 1.105-7ubuntu1`. – Velkan May 15 '17 at 14:41
  • 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. – ch4rl1e97 Nov 13 '19 at 13:33
  • why would netcat bind to a particular client in a state-less protocol.. within a swiss-army-knife networking testing utility is beyond me... – Vega4 Jan 13 '23 at 11:13
  • @Vega4 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". – David Schwartz Jan 13 '23 at 22:47
5

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
Nasser Al-Wohaibi
  • 4,562
  • 2
  • 36
  • 28
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
James Kay
  • 73
  • 7
  • 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! – EugeneRomero Jun 26 '18 at 22:52
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"
Todd Owen
  • 15,650
  • 7
  • 54
  • 52