nc コマンド 使い方メモ

  • 250
    いいね
  • 2
    コメント
この記事は最終更新日から1年以上が経過しています。

はじめに

nc コマンドを使いこなせれば、ネットワークに関するおおよその調査ができると教わったので、使い方をメモしてみます。

そもそものきっかけは、dockerの公式Imageから作ったUbuntuコンテナが、デフォルトだとwgettelnetもインストールできなかったからです。
nc はデフォルトで入っていたので、これを機にまとめることにしました。

おおよそ Wikipedia と man を参考にして書いています。
使用例は http://www.computerhope.com/unix/nc.htm も参考になりそうです。

簡易まとめ表

コマンド 用途
echo -en "GET / HTTP/1.1\n\n" | nc localhost 80 HTTP GET リクエスト
nc -zv localhost 1-65535 ポートスキャニング
(echo 'set KEY1 hoge'; sleep 1s; echo 'key *') | nc localhost 6379 Redisサーバーにアクセス
while : ; do (echo -ne "HTTP/1.0 200 Ok\nContent-Length: $(wc -c < response.txt)\n\n"; cat response.txt) | nc -l -p 8080; done Mockサーバー
nc -l 8080 0<backpipe | nc localhost 80 1>backpip Proxy
/bin/nc.openbsd -x proxy_host:1080 %h %p Socksサーバー経由でSSH接続用(BSD版に限る)

Webサーバーに問い合わせ

GETリクエストを投げる

root@abd32f2b7776:/# echo -en "GET / HTTP/1.1\n\n" | nc www.google.com 80
HTTP/1.1 302 Found
Cache-Control: private
Content-Type: text/html; charset=UTF-8
Location: http://www.google.co.jp/?gfe_rd=cr&ei=pSYgVIaBEMyT8QfJooHADw
Content-Length: 261
Date: Mon, 22 Sep 2014 13:39:49 GMT
Server: GFE/2.0
Alternate-Protocol: 80:quic,p=0.002

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="http://www.google.co.jp/?gfe_rd=cr&amp;ei=pSYgVIaBEMyT8QfJooHADw">here</A>.
</BODY></HTML>

レスポンスコードのみ出力

root@abd32f2b7776:/# echo -en "GET / HTTP/1.1\n\n" | nc www.google.com 80 | head -n 1
HTTP/1.1 302 Found

head コマンドを使っているだけです。

存在しないサーバーを指定した場合

root@abd32f2b7776:/# echo -en "GET / HTTP/1.1\n\n" | nc noexist 80
nc: getaddrinfo: Name or service not known

Listenしてないポートを指定した場合

root@9bd49622dea9:/# echo -en "GET / HTTP/1.1\n\n" | nc web1 8080
root@9bd49622dea9:/# echo $?
1

なにも出力されないので、終了コードを見るしかないようです。

Port Scanning

root@abd32f2b7776:/# nc -vz web1 1-65535 2>&1 | grep succeeded
Connection to web1 22 port [tcp/ssh] succeeded!
Connection to web1 80 port [tcp/http] succeeded!

※追記
ポートスキャニングは、場合によっては攻撃とみなされる可能性があるので、
外部サーバーやAWSなどのIaaSでの使用は気を付けた方が良いそうです。

Redis サーバーにアクセス

root@9bd49622dea9:/# nc redis 6379
set key Hello
+OK
get key
$5
Hello
del key
:1
keys *
*0
quit
+OK

telnet と同じようことができます。

ワンライナー版

root@9bd49622dea9:/# (echo 'set key Hello'; sleep 1s; echo 'get key'; sleep 1s; echo 'del key'; sleep 1s; echo 'keys *'; sleep 1s) | nc  redis 6379
+OK
$5
Hello
:1
*0

こちらも telnet と同じ感じでした。
sleep を挟まないと、レスポンスを得る前に次のコマンドを実行してしまうところも一緒です。
ただし、telnetと違ってリモートアクセスするコマンドではないので、quitはいりません。
 => Ctrl-C で中断できる

Mock サーバーっぽいもの

サーバー側

nc コマンドで、適当なポートをListen状態にしておきます。

root@446c957cfaef:~# while : ; do (echo -ne "HTTP/1.0 200 Ok\nContent-Length: $(wc -c < response.txt)\n\n"; cat response.txt) | nc -l -p 8080; done

一度アクセスを受け付けるとプロセスが終了するので、無限ループで起動し続けています。
-k オプションで何度もアクセスを受け付けられる仕組みがあるのですが、echo部分が一度しかncに渡されないので、2回目以降はレスポンスが得られません。

クライアント側

root@9bd49622dea9:/# nc web1 8080
HTTP/1.0 200 Ok
Content-Length: 14

Response File

response.txt を相応しいものにしておけば、簡単なMockサーバーを用意できそうですね。
もちろん、GETリクエストでも同じレスポンスが得られます。

root@9bd49622dea9:/# echo -en "GET / HTTP/1.1\n\n" | nc  web1 8080
HTTP/1.0 200 Ok
Content-Length: 14

Response File

Proxy

サーバー側

ポート 8080 を、localhost の 80 へプロキシ。

root@446c957cfaef:~# mkfifo backpipe
root@446c957cfaef:~# nc -l 8080 0<backpipe | nc localhost 80 1>backpipe

パイプでくっつけると、8080 にアクセスした相手へレスポンスを返さなくなるので、backpipe なる名前付きパイプを経由させます。
正直、mkfifo コマンドなるものを初めて知ったので、あまり深く理解できていません。
完全にWikiをコピペしてます。すみません。

クライアント側

HTTP リクエストをしてみる。


root@9bd49622dea9:/# (echo -en "GET / HTTP/1.1\n\n"; sleep 1) | nc web1 8080
HTTP/1.1 400 Bad Request
Date: Mon, 22 Sep 2014 17:25:32 GMT
Server: Apache/2.4.7 (Ubuntu)
Content-Length: 299
Connection: close
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
<hr>
<address>Apache/2.4.7 (Ubuntu) Server at 10.1.0.3 Port 80</address>
</body></html>

sleep が必要なのは、Redis にアクセスする時と同じく、レスポンスを取得する前に nc コマンドが終了してしまうからだと思います。

まとめ

長々と書きましたが、ポートスキャニングくらいしか使わなさそうな気がします...。
また、デフォルトだと、SSL や SSH といったセキュアな通信はできない子っぽいので、nc を sshscp 代わりに使うのは止めた方がいいでしょう。

余談ですが、今回の動作検証は、Dockerで作成したUbuntuコンテナで行っています。Redisサーバーもです。
Client役のコンテナから接続できるよう --link を指定して動かしています。便利ですね。

追記

AWSのSecurityGroup設定の確認のため、ncコマンドを使ったので追記します。

受信側EC2上で、nc -l -p 8080 (nc -l 80801) とし、
送信側EC2で、nc -vz 受信側 8080 といった感じで接続を試みます。

穴開けしてあるなら succeeded! になるはずです。

BSD nc だと、-p オプションの意味が違い、-l オプションに待ち受けポートの値を記述します。


  1. AmazonLinux上で、ncが私の知っているncじゃない! と思い調べたら、BSD版のncでした。