6

Host A:

tar cf -  stuff | dd | nc  -N -l 12987

Host B:

nc a.example.com 12987 | dd | tar tf - 

On host A dd prints its summary after tar completes. Thus it is clear, that tar closes the pipe/file -> EOF.

165040+0 records in 165040+0 records out 84500480 bytes transferred in 25.464802 secs (3318325 bytes/sec)

On both hosts nc happily sits there without exiting. nc(1) :

   -N      shutdown(2) the network socket after EOF on the input.  Some
           servers require this to finish their work.

Thus on host A nc should have seen EOF, closed the damn socket and on host B nc should have seen the TCP connection terminate and should have closed stdout (stdin of dd/tar).

How do I tell nc to close stdout / terminate on host B and terminate on host A.

nc bug?

-D (debug) does nothing. nc can't even tell its version number... sigh

Both hosts are FreeBSD 10.3-RELEASE-p4, IPv4 only.

8

I, too, was puzzled by netcat's behavior, so I dug into the code. Here's the whole story:

nc servers (nc -l) and clients only exit after the mutual connection was closed. That is, if each of the parties sent a FIN packet to the other party.

A server always sends a FIN packet after receiving a FIN packet from the client. (Unless the server already sent a FIN packet.)

A client sends a FIN packet either:

  • after EOF on stdin, when run with argument -N
  • after EOF on stdin, when the server already sent a FIN packet

Option -d always implies EOF on stdin.

Option -N always implies sending FIN after encountering EOF on stdin.

Ways to exit the nc processes after exchanging data:

  1. Georg's answer

    server$ echo hello | nc -l -N 2000
    client$ nc -d localhost 2000
    

    After sending hello, the server encounters EOF on stdin an sends FIN because of -N.

    The client receives the message and, due to -d, sees EOF on stdin and sends FIN, because the server already sent FIN.

    The connection is closed, both the client and the server exit.

  2. Client initiates the close

    server$ echo hello | nc -l 2000
    client$ nc -dN localhost 2000
    

    The server keeps the connection open after EOF on stdin.

    The client sees EOF on stdin and sends FIN, because of -N.

    The server sends FIN after receiving the client's FIN.

    The connection is closed, both the client and the server exit.

1
  • Thank you. But you answer (2.) problematic. If server run (echo hello; sleep 5; echo world;) | nc -l 2000, client will only receive hello and close TCP with FIN, world will not be received. I have tried it on openSUSE 15.1. – Jimm Chen Feb 14 '20 at 13:57
4

nc establishes a bi-directional connection. I.e. it sends stdin from host B to host A as well as the desired one from A to B.

Use -d on host B to ignore stdin. -N on host A is still needed to close the TCP connection on EOF.


In summary

Host A:

tar cf -  stuff | dd | nc  -N -l 12987

Host B:

nc -d a.example.com 12987 | dd | tar tf - 

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.