OS X LoginHook – nc exits prematurely for no apparent reason

Posted on

QUESTION :

I’m trying to use loginhook to download large amounts of data and I’ve been having problems which I’ve nailed down to nc exiting prematurely for no apparent reason. This is a simplified test script:

#!/bin/bash
exec > /tmp/lhook.out.txt 2> /tmp/lhook.err.txt
nc -v server 4444 > /tmp/nc-test
echo "Exit value: $?"

On the server, when I run a simple nc listener like echo "Hello world. | nc -l 4444, the transfer works correctly. But when I want to transfer a larger file, like nc -l 4444 < /path/to/some/large.file, the client transfers only a small part (sometimes 2kiB, sometimes ~250 kiB). The exit value reported is 0.

Oh, and of course – the same script executed in a Terminal.app inside a user session works fine.

Can someone help with debugging, explain what is going on, or provide a solution?

EDIT:
I’ve had dtruss snoop on netcat’s syscalls, and this is what I got:

  157/0x4c6:  write(0x1, "j,35037376377377203304$f211F16350&f04", 0x400)                 = 1024 0
  157/0x4c6:  select(0x5, 0x7FFF53A87B40, 0x0, 0x0, 0x0)                 = 1 0
  157/0x4c6:  read(0x4, "01u374)uf215f6203304200333101b35335172670321327P213317377R04271377377", 0x400)    
         = 1024 0
  157/0x4c6:  write(0x1, "01u374)uf215f6203304200333101b35335172670321327P213317377R04271377377", 0x400)   
         = 1024 0
  157/0x4c6:  select(0x5, 0x7FFF53A87B40, 0x0, 0x0, 0x0)                 = 1 0
  157/0x4c6:  read(0x4, "", 0x400)             = 0 0
  157/0x4c6:  shutdown(0x4, 0x0, 0x0)            = -1 Err#57
  157/0x4c6:  close(0x4)                 = 0 0
  157/0x4c6:  close(0x3)                 = 0 0
  157/0x4c6:  close(0x3)                 = -1 Err#9

I’m guessing that for some reason, the kernel is giving nc EOF instead of waiting for more data.

ANSWER :

What an embarrassing oversight… 🙁

nc quits upon reading EOF from stdin. The client which receives the data runs the LoginHook script in a non-interactive shell, which directs nc‘s stdin descriptor probably to /dev/null. As soon as it reads EOF from it, it quits.

The fix is trivial: supply -d switch to the receiving side. This prevents either version of netcat (BSD or Linux) from reading stdin, and the transfrer completes without issue.

Leave a Reply

Your email address will not be published. Required fields are marked *