25

Why does the following netcat command not time out if the attempt to connect takes longer than 3 seconds (ie: when the port isn't open)? I assumed that the -w flag would be what I needed. OS is OSX 10.9.

nc -v -z -w 3 127.0.0.1 5050

Assuming that worked, I planned to implement like this (unsure if this will work, total bash noob)

nc -v -z -w 3 127.0.0.1 5050 | /dev/null && echo "Online" || echo "Offline"

codeforester
  • 39,467
  • 16
  • 112
  • 140
anditpainsme
  • 601
  • 1
  • 7
  • 14
  • When I try it, I immediately get an error response because the port isn't open. Are you sure it's not open on your host? If it is, then that's why it isn't timing out, because it actually connected. – CDahn Jun 13 '14 at 05:45
  • Weird, it only appears to be happening on a specific port... I was trying to use this to monitor if a specific service is running on my machine from a remote location or network. That service is not currently running, but the netcat doesn't seem to time out, the process just hangs. Any thoughts? – anditpainsme Jun 13 '14 at 05:51
  • Are you running any kind of firewall? What does "iptables -L" show you? – CDahn Jun 13 '14 at 05:55
  • I am using OSX and my firewall is turned off. It explicitly states "All connections are allowed to this computer". There is no native 'iptables' command in OSX. – anditpainsme Jun 13 '14 at 05:58
  • netcat apparently acts different on different platforms (http://www.philandstuff.com/2013/05/17/statsd-netcat.html). I'm on linux. Can you run tcpdump while you run this command to see if the expected behavior is occurring? – CDahn Jun 13 '14 at 06:02
  • Assuming port 5050 isn't open, you should see a SYN packet from localhost, followed by a RST packet from port 5050. – CDahn Jun 13 '14 at 06:12
  • http://pastebin.com/DJV4B04m Will filtering like this contain the info required? Without filtering by port 5050 it's pretty much impossible to interpret the log... Also, just fyi, I have just noticed that the request eventually times out on the remote host, but it's taking over a minute... completely stumped here. – anditpainsme Jun 13 '14 at 06:16
  • You probably want to look at the lo interface (or whatever it's called on OSX). Any traffic to 127.0.0.1 won't show up on en0. – CDahn Jun 13 '14 at 21:08
  • This may be an OSX thing. See this other article: http://stackoverflow.com/questions/18578565/nc-netcat-on-mac-os-x-10-8-4-gets-stuck – CDahn Jun 13 '14 at 21:22
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/55605/discussion-between-cdahn-and-anditpainsme). – CDahn Jun 13 '14 at 21:22

5 Answers5

36

You need to redirect to /dev/null, not pipe to it. Try the following:

nc -v -z -w 3 127.0.0.1 5050 &> /dev/null && echo "Online" || echo "Offline"

On my machine, port 5050 isn't open, and I get the following:

$ nc -v -z -w 3 localhost 5050 &> /dev/null && echo "Online" || echo "Offline"
Offline
CDahn
  • 1,795
  • 12
  • 23
  • 1
    Thanks for that! Out of curiosity why is the & needed when redirecting? – anditpainsme Jun 13 '14 at 05:53
  • 2
    nc dumps out the verbose output to stderr, so if you just want to see the "Online" and "Offline", you need to use &> to tell bash to redirect both stdout and stderr to /dev/null. If you get rid of the -v, you can just say nc -z -w 3 localhost 5050 && echo "Online" || echo "Offline" – CDahn Jun 13 '14 at 05:56
18

Since Mac OS X 10.8.x, nc has used the -G option to set the timeout for initiating a connection. This is separate from the -w option, which sets the timeout for a connection that has been made but has gone idle.

If you are trying to use nc for port scanning, i.e. nc -v -z 10.0.1.1 1-1023, it will spend over a minute trying to connect to each non-responding port unless you add a -G timeout value:

nc -v -z -G 1 10.0.1.1 1-1023

That's one second per port scanned — much more useful.

MacTroy
  • 181
  • 1
  • 2
11

Nc: nc is usually installed already , however on some systems such as Mac OS X, the command hangs on unreachable systems without the -G option. If that does not work use the Workaround.

nc -v -z -w 3 127.0.0.1 22 &> /dev/null && echo "Online" || echo "Offline"

Mac OSX:

nc -z -G 3 127.0.0.1 22  &> /dev/null && echo "Online" || echo "Offline"

Alternative workaround option:

bash -c '(sleep 3; kill $$) & exec nc -z 127.0.0.1 22' &> /dev/null
echo $?
0
bash -c '(sleep 3; kill $$) & exec nc -z 1.2.3.4 22' &> /dev/null
echo $?
143

(examples illustrate connecting to port 22 ssh over a good and bad host example, use the $? to determine if it reached the host with the sleep time of 3 seconds)

Alternatively For Mac Users (mainly) etc, you can use the command in the script like so :

    # -- use NMAP, if not avail. go with nc --
    if command -v nmap | grep -iq nmap ; then
        nmap ${ip} -PN -p ${ssh_port} | grep -iq "open"
        res=$?
    elif command -v nc | grep -iq nc ; then
        # -- run command if fails to complete in 3 secs assume host unreachable --
        ( nc -z ${ip} ${ssh_port} ) & pid=$!
        ( sleep 3 && kill -HUP $pid ) 2>/dev/null & watcher=$!
        if wait $pid 2>/dev/null; then
            pkill -HUP -P $watcher
            wait $watcher
            # -- command finished (we have connection) --
            res=0
        else
            # -- command failed (no connection) --
            res=1
        fi
    else
        echo "Error: You must have NC or NMAP installed"
    fi

    if [[ ${res} -lt 1 ]] ;then
        success=1
        echo "testing  => $ip SUCCESS connection over port ${ssh_port}"
        break;
    else
        echo "testing => $ip FAILED connection over port ${ssh_port}"
    fi
Mike Q
  • 6,716
  • 5
  • 55
  • 62
5

There is an old bug report about this on debian (https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=97583) and still having the same behavior in Debian GNU/Linux 7.7 (wheezy)

I found a "solution" to this: installing the openbsd version of nc:

apt-get install netcat-openbsd
Pokechu22
  • 4,984
  • 9
  • 37
  • 62
Thiago Ruiz
  • 61
  • 1
  • 4
  • 2
    I had this problem with nc on macOS 10.13.4. Installing (gnu) netcat with Homebrew fixed it... – Motsel Apr 28 '18 at 20:51
  • That bug was fixed in 2001, so Debian 3.0 (Woody) and later should not have suffered it. The problem with the question, as noted in the accepted answer, was syntax related (`nc … |/dev/null` won't work because `/dev/null` is not executable, `nc … >/dev/null` works fine). That said, the fix was applied on Debian specifically and upstream netcat still likely has it (current Debian uses netcat 1.10-41.1, the fix was in 1.10-18, the dash refers to the Debian build, using patches to modify the upstream version), so I could understand OS X still having that issue. – Adam Katz Apr 30 '18 at 14:32
1

On Mac OS X (10.14.6) the -w 3 parameter is somehow ignored.

The workaround I found is: timeout 3 nc -vz 10.18.50.134 23

Pier A
  • 151
  • 1
  • 4
  • 3
    `-w` is used to set the timeout after connection. `-G` option is used to set the timeout before connection. This is a better workaround for macOS users: `nc -G 3 xxx.xxx.xxx.xxx 5050` source: https://stackoverflow.com/a/35141831/5972142 – Aditya Purandare Jan 31 '20 at 23:40
  • 1
    timeout as per expectation. I guess will use both 'timeout' and '-G'. The latter is taking a bit more time. However, the conclusion is that '-w' switch does not work at all! – anup Jul 19 '22 at 11:12