Linux netcat listener (nc -l) hung

0

On my Raspberry Pi 3 Terminal (Linux) I typed the following and hit Enter:

printf 'HTTP/1.1 302 Moved\r\nLocation: https://www.eff.org/' | nc -l 2345

The Raspberry Pi 3 is part of my home network with a fixed address of 192.168.0.8. Then, on my mac I typed the following into my browser (Chrome) and hit Enter:

192.168.0.8:2345

I can see the browser's GET request on my Linux Terminal (Raspberry Pi), but the nc listener gets stuck and does not send the reply (the HTTP 302 redirect message) to the browser.

Only when I stop the nc program by hitting Ctrl+C, the browser receives the reply message and displays the https://www.eff.org website.

Has anyone an idea why the nc listener gets stuck instead of sending the reply and close the connection?

Thomas Grusz

Posted 2017-12-04T05:17:54.237

Reputation: 3

(1) How do you know that the nc process is “stuck”?  Have you done an strace or sniffed the network?  (2) But first, try adding another \r\n to the end of the printf text string. – G-Man Says 'Reinstate Monica' – 2017-12-04T05:30:25.063

Answers

0

I replicated your problem. When I connect with another nc instead of a browser, I see the reply is being sent immediately. I think your browser also receives the reply but since nc doesn't terminate the connection, the browser doesn't know it's all and it's OK to proceed with redirection.

(Note: during my tests I needed the final \r\n in the reply from nc to successfully redirect my browser, therefore all my examples use this fix.)


Edit: simple fix

Here I have found the following:

HTTP requests and HTTP responses use a generic message format of RFC 822 for transferring the required data. This generic message format consists of the following four items.

  • [...]
  • [...]
  • An empty line (i.e., a line with nothing preceding the CRLF) indicating the end of the header fields
  • [...]

So your reply should be:

printf 'HTTP/1.1 302 Moved\r\nLocation: https://www.eff.org/\r\n\r\n' | ...

After receiving this, your browser should continue with redirection, terminating the connection to nc on its own behalf. In early December 2017 it works with Opera and Vivaldi; it doesn't work with Firefox, Chrome or Safari, for which you may need another fix (see below).



Original, now inferior answer (it may still be useful for non-HTTP communication with nc)

According to this answer on Server Fault you need to use -c, -q or similar option, depending on nc implementation.

In my Debian I have the -q capable version installed. Then

printf 'HTTP/1.1 302 Moved\r\nLocation: https://www.eff.org/\r\n' | nc -q 0 -l -p 2345

works fine (note I also need -p to specify port). The explanation is:

-q seconds
after EOF on stdin, wait the specified number of seconds and then quit. If seconds is negative, wait forever (default).


If your nc has no proper option then the workaround may be to detect communication from a client and kill the entire command line. An example that works in my Debian, bash:

printf 'HTTP/1.1 302 Moved\r\nLocation: https://www.eff.org/\r\n' | nc -l -p 2345 | { read foo; sleep 1; kill 0; }

When running a pipe, bash places every process in a single process group; kill 0 sends signals to its entire process group. This way nc is killed about 1 second after any request is received that triggers read.

Kamil Maciorowski

Posted 2017-12-04T05:17:54.237

Reputation: 38 429

Thanks!

I tried the simple fix by adding \r\n\r\n at the end of the string as you suggested. This only works on the Opera browser (latest version). However with Firefox, Chrome or Safari (all latest versions) the process still gets stuck.

But when I add the -q 0 option to the nc command, then it works in all browsers. – Thomas Grusz – 2017-12-05T08:22:06.183

@ThomasGrusz Thank you. I tested with Vivaldi and added a browser compatibility note to my answer -- for future users. – Kamil Maciorowski – 2017-12-05T09:15:15.113