PONOS Advent Calendar 2022の5日目の記事です。
昨日は@Portierさんの「JIRAのステータス変更を自動化」でした。
この記事で取り扱うこと
Netcatを使って、生のHTTP通信を体験してみます。
クライアントとしてリクエストする立場・サーバーとしてレスポンスを返す立場の両方を体験することで、ブラウザやhttpdへの感謝が深まること請け合いです。
この記事で取り扱うNetcatは、様々な用途に応用できるツールです。 1
悪い人が使えば悪用できてしまうため、セキュリティソフトにマルウェア扱いされることもあります。
この記事の内容を検証される際は、利用する環境や実施内容に十分ご注意ください。
Netcat(nc)とは
Netcatは、Unix系OSコマンドラインアプリケーションの一つ。TCPやUDPのパケットを読み書きするバックエンドとして機能するツールで、ネットワークを扱う万能ツールとして知られる。オリジナル版より機能的に優位な派生・互換ツールが開発され、用いられている。
Netcat
ネットワーク越しにcat
するツールです。
コマンドとしてはnc
で登録されていることが多いです。
- 標準入力(STDIN)に書き込んだ内容を通信相手に送る
- 通信相手から受け取った内容を標準出力(STDOUT)に書き出す
他にもサーバーモードやポートスキャン機能など、幅広くなんでもできます。
準備
Unix系のOSであれば、最初から入っていたり公式リポジトリに含まれていたり。
今回はDockerで動かす方法でやっていきます。
Docker DesktopなどのDocker実行環境が入っていればOKです。
$ docker run --rm subfuzion/netcat -h
OpenBSD netcat (Debian patchlevel 1.130)
usage: nc [-46CDdFhklNnrStUuvZz] [-I length] [-i interval] [-O length]
[-P proxy_username] [-p source_port] [-q seconds] [-s source]
[-T toskeyword] [-V rtable] [-w timeout] [-X proxy_protocol]
[-x proxy_address[:port]] [destination] [port]
(略)
クライアントとしてページを取得
nc
を通してHTTPリクエストを送って、ページを取得してみます。
SSL化されていない方が分かりやすいので、みなさんご存知の 阿部 寛のホームページ にアクセスします。
$ docker run --rm -it subfuzion/netcat abehiroshi.la.coocan.jp 80
abehiroshi.la.coocan.jp
のTCP80(HTTP)に接続しています。
するとこちらの入力を待ち受ける状態になるので、HTTPリクエストを送りましょう。
GET / HTTP/1.1
Host: abehiroshi.la.coocan.jp
/
をGETしようとしています。すると……
HTTP/1.1 200 OK
Date: Mon, 05 Dec 2022 06:41:42 GMT
Content-Type: text/html
Content-Length: 538
Connection: keep-alive
Last-Modified: Thu, 27 Feb 2020 07:10:16 GMT
ETag: "21a-59f8969af8600"
Accept-Ranges: bytes
Server: Apache
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<meta name="GENERATOR" content="JustSystems Homepage Builder Version 20.0.6.0 for Windows">
<meta http-equiv="Content-Style-Type" content="text/css">
<title>�������̃z�[���y�[�W</title>
</head>
<frameset cols=18,82>
<frame src="menu.htm" marginheight="0" marginwidth="0" scrolling="auto" name="left">
<frame src="top.htm" marginheight="0" marginwidth="0" scrolling="auto" name="right">
<noframes>
<body></body>
</noframes>
</frameset>
</html>
レスポンスが返ってきます。
HTTPレスポンスと、フレームの親ページですね。
タイトルが文字化けしているのはご愛嬌。(Shift_JISだから)
サーバーとして待ち受け
次はnc
の標準入力・標準出力をシェルに直結して、サーバーとして待ち受けてみます。
$ docker run --rm -it -p 8080:8080 subfuzion/netcat -l 8080
この例だと、8080ポートで待ち受ける状態になります。
届いたリクエストをターミナルに流して、逆に入力した内容はレスポンスとしてクライアントに送られます。
この状態でブラウザから http://localhost:8080/ にアクセスすると、ブラウザはレスポンスを待ち続ける状態になります。
と同時に、ターミナルにはブラウザからのリクエストが流れてきます。
GET / HTTP/1.1
Host: localhost:8080
Connection: keep-alive
sec-ch-ua: "Google Chrome";v="107", "Chromium";v="107", "Not=A?Brand";v="24"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "macOS"
(以下略)
この状態でターミナルからレスポンスを返してあげると、ちゃんとブラウザ側にも表示されます。
HTTP/1.1 200 OK
Server: honeniq
Content-Type: text/html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>netcat http server</title>
</head>
<body>
手入力で返すテストです。
</body>
注目してほしいのは、HTMLだけじゃなくてHTTPレスポンスも同時に返しているところです。
いつもならWebサーバーがやってくれているところを、自分でやっているわけですね。
サーバーとして待ち受け(ファイル使用)
上記の変形として、レスポンス内容を書いたファイルを標準入力に流してあげれば、レスポンスとして定型文を返すことができます。
$ docker run --rm -i -p 8080:8080 subfuzion/netcat -l 8080 < response.txt
< response.txt
で標準入力にテキストファイルを渡しています。
この状態でブラウザから http://localhost:8080/ にアクセスすると、 response.txt
に書かれたHTMLが返ってきます。
response.txt
の中身はこんな感じ。(さっきターミナルから返した内容とほぼ同じ)
HTTP/1.1 200 OK
Server: honeniq
Content-Type: text/html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>netcat http server</title>
</head>
<body>
ファイルで返すテストです。
</body>
まとめ
普段はブラウザやサーバーが隠蔽してくれていますが、実際に試してみると理解が深まりますね!
特に、HTTPといっても普通のテキストをやり取りしているだけなのが面白いところでした。
単純といえば単純だけど、このシンプルさがHTTPの強さなのかもしれない。
明日は @nissy_gp さんです。お楽しみに!
-
ネットワークのスイスアーミーナイフと呼ばれることも。 ↩