LoginSignup
1
0

More than 5 years have passed since last update.

nc -v -z すると 2 つ結果を返すのはなぜか?

Posted at

開発時など、突発的に適当なポートの開閉を調べたい時に、 Netcat を使って
nc -v -z host port という風にチェックすることがあると思う。
(Nmap や telnet を使うケースもあると思う)

同僚が OS X 上でこの方法でポートの開閉を調べようとしていたのだが、なぜだか結果が 2 つ出力されていた。
最初は謎だと思っていたのだが、原因が分かったので書いておく。

$ nc -v -z localhost 8000
nc: connectx to localhost port 8000 (tcp) failed: Connection refused
nc: connectx to localhost port 8000 (tcp) failed: Connection refused

最初は OS X 固有の現象かと思ったが
実験したところ同じ設定をすれば OS X 以外でも普通に起きることだとわかった。

なお OS X 上では Homebrew などを使って GNU Netcat を優先している方も居ると思う。
その場合は再現しない。再現したければ /usr/bin/nc と明示すれば良い。

/etc/hosts を見よ

初期状態の OS X の /etc/hosts はこのようになっていた。

/etc/hosts
##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##
127.0.0.1   localhost
255.255.255.255 broadcasthost
::1             localhost

見ての通り、 localhost が IPv4 と IPv6 でそれぞれエントリが書かれている。
そのため 2 箇所ともチェックしているようだ。

解決方法 1: 明示的にどちらかを指定する

localhost と書かずに、 IP そのままで書けば問題ない。

$ nc -v -z 127.0.0.1 8000
nc: connectx to 127.0.0.1 port 8000 (tcp) failed: Connection refused
$ nc -v -z ::1 8000
nc: connectx to ::1 port 8000 (tcp) failed: Connection refused

解決方法 2: オプションで IPv4, IPv6 のどちらかを明示すればよい

$ man nc

して読み進めていくと分かるのだが、 -4-6 のオプションでそれぞれ IPv4, IPv6 を強制できる

$ nc -v -z -4 localhost 8000
nc: connectx to localhost port 8000 (tcp) failed: Connection refused
$ nc -v -z -6 localhost 8000
nc: connectx to localhost port 8000 (tcp) failed: Connection refused

OpenBSD の ncFreeBSD 5.4 以上の nc も同様だ。
どうやら BSD 由来の netcat は全てこのようであるらしい。

GNU Netcat にはこのようなオプションはない。

Nmap の付属コマンドとして広く使われている Ncat にもこのオプションがある。

BSD と GNU と書いてあると混乱しそうだが、最近の有名な Linux ディストリビューションも、
BSD 由来の Netcat が入っていることが多い。
(例えば Ubuntu 14 の Netcat をチェックしたが、 BSD 由来の Netcat だった。)

また、 BusyBox の nc にもこのオプションはない。

解決方法 3: /etc/hosts から片方を削除する

なるほど、たしかに 1 つになる。
しかし、このような破壊的な変更は個人的にはおすすめしない。

解決方法 4: GNU Netcat を使う

上で言及したように GNU Netcat にはそのようなオプションはない。
実は Homebrew を使ってインストールする際に brew install netcat でインストールされるのも GNU Netcat である。
Source: netcat.rb

$ /usr/local/bin/nc -v -z localhost 8000
localhost [127.0.0.1] 8000 (irdmi): Connection refused

この Netcat は安定しているが、最新版のリリース日が 2004 年である。
保守状況がやや気になるので、個人的にはこの解決方法はおすすめしない。

オマケ

Q. もっとたくさん /etc/hosts に書いたらどうなるか?

/etc/hosts
##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##
127.0.0.1   localhost
127.0.0.2   localhost
127.0.0.3   localhost
127.0.0.4   localhost
255.255.255.255 broadcasthost
::1             localhost

A. それぞれに対して試行する

$ /usr/bin/nc -v -z -G 1 localhost 8000
nc: connectx to localhost port 8000 (tcp) failed: Connection refused
nc: connectx to localhost port 8000 (tcp) failed: Connection refused
nc: connectx to localhost port 8000 (tcp) failed: Operation timed out
nc: connectx to localhost port 8000 (tcp) failed: Operation timed out
nc: connectx to localhost port 8000 (tcp) failed: Operation timed out

つまり -4, -6 オプションの話も、あくまで IPv4 と IPv6 と 1 つずつしか書かれていない場合にだけ有効な話だということ。

(なお上の例では、待つのが面倒なので -G オプションでタイムアウトを 1 秒にしている。)

Q. 片方が Open, もう片方が Close だった場合、終了ステータスはどうなる?

$ nc -v -z  localhost 8000 ; echo $?
nc: connectx to localhost port 8000 (tcp) failed: Connection refused
found 0 associations
found 1 connections:
     1: flags=XX<CONNECTED,PREFERRED>
    outif XXX
    src 127.0.0.1 port XXXXX
    dst 127.0.0.1 port 8000
    rank info not available
    TCP aux info available

Connection to localhost port 8000 [tcp/irdmi] succeeded!
0

実験してみたところ 0 を返した。どうやら接続成功と解釈するようだ (?)
片方だけ失敗して片方だけ成功すると、上の例のように失敗した方について詳細が表示される。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0