22

I'm trying to send commands to a tcp port using netcat and pipe response
when I run netcat and type my command it prints response correctly but when I pass command from a pipe it sends the command correctly but doesn't print response

So, this works correctly:

netcat  localhost 9009

while this just sends command but doesn't print response:

echo 'my_command' | netcat  localhost 9009

why?
How can I make netcat to print response text ?

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
Ariyan
  • 2,106
  • this is probably happening to you – Jeff Schaller Jun 13 '16 at 02:10
  • @JeffSchaller: no! unfortunately using those commands doesn't help! this time it blocks forever! – Ariyan Jun 13 '16 at 02:26
  • Which netcat are you using? Unfortunately there's a dozen different variations of the netcat tool, and they don't all behave the same. Also, what is on the remote end? – phemmer Jun 13 '16 at 02:33
  • @Patrick: my netcat is OpenBSD netcat (Debian patchlevel 1.105-7ubuntu1) version; and at the remote end is telegram-cli on the same machine. – Ariyan Jun 13 '16 at 02:46
  • I think I found a man page for that netcat, but I don't see any flags which would control what I suspect is happening. I suspect that once netcat receives the EOF on STDIN, that it immediately shuts down both sides of the socket instead of doing a half-close and waiting for the remote side to close its end. If socat is an option, I would highly recommend it instead. There's only one socat, so you don't have the portability issues with there being a dozen different flavors of it, it behaves a lot more sanely, and is highly configurable. – phemmer Jun 13 '16 at 03:34
  • @Patrick: thanks; I tried socat and same thing happens with it !!! interesting point is that both netcat & socat in using piped input exit immediately while in interactive mode it takes a time to get response; second, some telegram-cli commands work correctly (e.g. help); actually it seems commands that need to communicate over network has this problem! – Ariyan Jun 13 '16 at 03:50
  • Try adjusting the -t option of socat. If that doesn't solve it, I'd look at an strace or a packet capture then. It's likely that the issue is the remote (telegram-cli) end, and it shutting down the connection as soon as it receives the EOF reading from the client, even if it has pending responses to write. – phemmer Jun 13 '16 at 04:57
  • @Patrick: changing -t had no effect! – Ariyan Jun 14 '16 at 01:11
  • The difference is that the first variant is waiting for more input on stdin, while the second variant terminates stdin as soon as echo has finished. I guess netcat terminates once it sees EOF on stdin. – U. Windl Feb 03 '22 at 22:55

5 Answers5

10

Use this:

cat <(echo command) - | nc host port

The problem is that nc will close the connection immediately after stdin is closed, which is very quick for a simple my_command string, and thus never gets the chance to receive a response. (If you pipe a very large file you will see that it might get a response before it's done sending the file).

Enter cat with - as second argument: It makes cat listen on stdin for more content to pipe through after it has sent the contents of the first argument. The first argument is just getting the echo command through cat – it could also be a file with your commands a la cat < file - | ....

Alternatively do this:

(echo command; while true; do sleep 0.01; echo -n "#"; done) | nc host port

This sends unlimited # characters on the 2nd line of the input. Using # works for a bash like remote that would ignore this as a comment. I chose a small wait time of 10 milliseconds here, so it reacts faster on connection end. YMMV.

The downside of that can be that cat or the while loop and nc keep running until you hit ^C or ^D on the shell. It really depends on the remote end.

Adding a timeout using -w 1 (OSX netcat) or -i 1 (nmap's ncat) makes it close the connection and nc after 1 second, but cat will keep running until you enter some character and the pipe breaks (I think).

However, it works if the remote side will automatically close the connection after receiving and handling the command - this will also end the nc client and the process piping into it.

This answer is based on this this answer to an identical superuser question.

9

As @Patrick said, this problem is usually due to netcat exiting before the response has been given. You remedy that by adding -q 2 to the command line, i.e., tell netcat to hang around 2 seconds after detecting EOF on standard input. Obviously you can make it wait some other number of seconds as well.

  • Thanks; -q 2 worked but is it trust-able? it is making web request I can't be sure 2s is always enough! can I ? – Ariyan Jun 14 '16 at 01:13
  • 1
    Use a larger number to make it wait longer, or some negative number to make it wait indefinitely. There's also the -w option to play with. This is all in the man nc page of course. – Ralph Rönnquist Jun 14 '16 at 06:15
  • 9
    it says invalid option -- 'q' – phil294 Sep 12 '18 at 19:21
  • 1
    I think a good follow-up question is: why is nc exiting immediately instead of waiting for a response? If the connection is still open, there should be an option to make nc wait for it to close, not just for stdin to end – theferrit32 Sep 30 '19 at 22:51
  • 1
    On Ubuntu 18.04, I used --no-shutdown and it works. – Ani Jul 28 '21 at 07:08
2

Different openbsd-netcat versions are quirky, needing different combinations of -w <seconds>, -q <seconds>, -N and even need different arguments depending on what is running on the other end of the connection. Using timeout options with certain versions or servers cause delays, and not using them might result in an extremely long (infinite?) delay. And I would expect different quirks with gnu netcat, but don't know if they are different between versions of it.

For example version 1.130_3 from archlinux takes extremely long (forever?) when I do this:

$ echo response | nc -l 9999 &
[1] 15190

$ time echo request | nc localhost 9999
request
response

(wait forever possibly)

But it works with -N added to either the server or the client.

Peter
  • 1,247
1

I know this is a bit old but no other answer worked for me and this did:

echo 'test' | netcat -N $server $port

Notice the -N:

shutdown the network socket after EOF on the input. Some servers require this to finish their work.

Worked for me on both Windows and Linux.

Note: This is a copy paste of the answer I posted for a duplicate question.

I'm thinking this could be useful. Mods feel free to edit / delete if this is against policy or something.

0

I am using the ncat from nmap.

Ncat: Version 7.80 ( https://nmap.org/ncat )

The --no-shutdown option solves this issue:

echo 'test' | netcat --no-shutdown $server $port