Netcat/socat behavior with piping and UDP?

16

5

I guess this is close to linux - Netcat stops listening for UDP traffic - Super User, but I thought I'd better ask anyways

As far as versions of netcat I'm using Ubuntu 11.04 and the default netcat on it, which I'm guessing is the openbsd one:

$ nc
This is nc from the netcat-openbsd package. An alternative nc is available
in the netcat-traditional package.
usage: nc [-46DdhklnrStUuvzC] [-i interval] [-P proxy_username] [-p source_port]
      [-s source_ip_address] [-T ToS] [-w timeout] [-X proxy_protocol]
      [-x proxy_address[:port]] [hostname] [port[s]]

 

This is what I find strange: the first case works as expected - I open a UDP server in one terminal:

$ sudo nc -ul 5000

... and in another terminal I initiate a new UDP client connection - and I type in hello three times, pressing ENTER after each:

$ nc -u 127.0.0.1 5000
hello
hello
hello
^C

... and going back to the server terminal, it has printed hello three times, as expected:

$ sudo nc -ul 5000 
hello
hello
hello
^C

 

So far so good, all works as expected. However, let's say I try now the same by piping input into the client; so establish first a UDP server in one terminal:

$ sudo nc -ul 5000

... and in another, pipe some data into nc as UDP client:

$ echo hello | nc -u 127.0.0.1 5000
hello
hello
^C

... after the client command, the shell sort of freezes as if waiting for input - so there I type hello and ENTER two more times; but the server has registered only the first hello (which was piped via echo). Furthermore, even if you press Ctrl-C, and try to repeat the client echo hello | nc -u 127.0.0.1 5000 command, the server will still remain on having reported just the very first hello:

$ sudo nc -ul 57130 
hello
^C

... and only after stopping the server with Ctrl-C and restarting it again, can one repeat the client echo hello | nc -u 127.0.0.1 5000 command and observe it working.

 

Is this the way nc is supposed to be behaving? I would expect that at least repeated calls to echo hello | nc -u 127.0.0.1 5000 would be registered - without having to restart the server? Or maybe there is a special command-line switch for that kind of behavior?

EDIT: I found this nice PDF presentation: socat – Handling all Kinds of Sockets, which contains the following netcat vs socat notes:

netcat - Limitations
● one-shot only (terminates after socket close)
...
Examples 1: netcat Replacement
...
● UDP client with source port:
nc -­u ­-p 500 1.2.3.4 500
socat ­- udp:1.2.3.4:500,sp=500
● TCP server:
nc ­-l ­-p 8080
socat ­- tcp­-l:8080,reuseaddr
...

... however, I'm pretty much getting the same behavior as above, if I replace the server command with "socat - udp4-listen:5000,reuseaddr" - and the client line with "socat - udp:127.0.0.1:5000"... With the piped input, "echo hello | socat - udp:127.0.0.1:5000", the only difference is that here the command at least exists after the word hello had been sent - however, again, consecutive runs of this command will not cause any reception at the server, until the server is restarted.

sdaau

Posted 2011-09-03T20:14:35.807

Reputation: 3 758

Answers

23

Ok, I think at least I got something with socat - namely, the option fork needs to be appended to the server line:

$ socat - udp4-listen:5000,reuseaddr,fork

... and then, in another terminal, we can call echo piping into socat client line multiple times on command line, as it will exit immediately (well, after half a second :)):

$ echo "hello" | socat - udp-sendto:127.0.0.1:5000
$ echo "hello" | socat - udp-sendto:127.0.0.1:5000
$ echo "hello" | socat - udp-sendto:127.0.0.1:5000

... and going back to the first terminal, we can see that the server has successfully shown all three hellos:

$ socat - udp4-listen:5000,reuseaddr,fork
hello
hello
hello
^C

 

Note that even with a fork-ed socat server, the line echo "hello" | nc -u 127.0.0.1 5000 will still 'lock' as if waiting for user input; however, now after Ctrl-C and re-running the command, i.e.

$ echo "hello" | nc -u 127.0.0.1 5000
^C
$ echo "hello" | nc -u 127.0.0.1 5000
^C
$ echo "hello" | nc -u 127.0.0.1 5000
^C

... the fork-ed socat server will show three hellos without the need to be restarted..

 

Seemingly, this openBSD netcat doesn't have a fork option - but I'm not sure if it has one that is corresponding to it..

Anyways, hope this helps someone,
Cheers!

sdaau

Posted 2011-09-03T20:14:35.807

Reputation: 3 758

4

Your netcat is only reading the output from echo's stdout when you use pipe, it's not "connected" to the keyboard anymore. To get the response you're expecting, you can add your three "hello"'s to a file an run

cat [myfile] | nc -u 127.0.0.1 5000

OldWolf

Posted 2011-09-03T20:14:35.807

Reputation: 2 293

Hi @OldWolf - many thanks for your answer! I tried your suggestion (also in a somewhat more convoluted way, "cat $(echo -e "hello\nhello\nhello\n" > tmpf; echo tmpf) | nc -u 127.0.0.1 5000"), however, while I do see three hellos, what puzzles me is still present: that command too will sort of "lock", as if waiting for typed input from user, and after Ctrl-C and reruning it, the server will not see any data until it is restarted!? That is what I'd like to know better - cheers! – sdaau – 2011-09-03T20:53:16.430

2nc is waiting on an EOF which, in this case, it doesn't get until you send the exit signal to the program. – OldWolf – 2011-09-03T21:12:19.587

Ahh, I see - many thanks for that explanation, @OldWolf! Seemingly socat can work around that with the fork option... Thanks again, cheers! – sdaau – 2011-09-03T21:15:24.770

3

If you do an strace of the listening nc, it will show that netcat is waiting for the connection, and once it gets it, will connect to that host and port, ignoring all others. You need to add '-k' to keep going and '-w 0' to timeout each connection after 0 seconds. Socat is a better choice, I think.

pdragon

Posted 2011-09-03T20:14:35.807

Reputation: 31