- 0 はじめに
- 1 ncコマンドとは
- 2 検証環境
- 3 インストール方法
- 4 オプション一覧
- 5 事前準備
- 6 IPv4オプションの使い方
- 7 IPv6オプションの使い方
- 8 UNIXドメイオプションの使い方
- 9 ファイルの送信方法
- 10 サーバ側でコマンドを実行する方法(-e)
- 11 改行コードを変更する方法(-C)
- 12 TCPコネクションの同時接続数を指定する方法(-m)
- 13 proxyオプションの使い方
- 14 TCPコネクション確立、解放時のシーケンス
- Z 参考情報
0 はじめに
元記事を「はてな記法」に変更するた、あらたに記事を作成しました。内容に変更はありません。
1 ncコマンドとは
TCPやUDPのエコーサーバを起動することができます。
私の場合、サーバ、クライアントの2台構成で、TCPのコネクション確立/開放やTCPの状態遷移等を確認するための実験に使っています。
2 検証環境
2.1 ネットワーク構成
サーバとクライアントの2台構成です。図中のeth0はNICの名前です。
192.168.2.0/24 client(eth0) -------------------------------------(eth0) server .115 .120
3 インストール方法
サーバとクライアントで下記コマンドを実行します。
netcatパッケージはepelリポジトリにあるので、まず、epel-releaseパッケージをインストールします。
[root@server ~]# yum -y install epel-release
次に、netcatパッケージをインストールします。
[root@server ~]# yum -y install netcat
ncコマンドの版数を確認します。版数は次のとおりです。
[root@server ~]# nc -v Ncat: Version 7.70 ( https://nmap.org/ncat ) Ncat: You must specify a host to connect to. QUITTING.
なお、ncコマンドは、以下のように最終的にncatコマンドへのシンボリックリンクとなっています。どちらを使っても同じですが、本記事ではncを使います。
[root@server ~]# ls -l /usr/bin/nc lrwxrwxrwx. 1 root root 22 10月 17 09:08 /usr/bin/nc -> /etc/alternatives/nmap [root@server ~]# ls -l /etc/alternatives/nmap lrwxrwxrwx. 1 root root 13 10月 17 09:08 /etc/alternatives/nmap -> /usr/bin/ncat
4 オプション一覧
オプションは以下のとおりです。なお、ncatのmanページを参照することで、全てのオプションを参照することができます。
[root@server ~]# nc -h Ncat 7.70 ( https://nmap.org/ncat ) Usage: ncat [options] [hostname] [port] Options taking a time assume seconds. Append 'ms' for milliseconds, 's' for seconds, 'm' for minutes, or 'h' for hours (e.g. 500ms). -4 Use IPv4 only -6 Use IPv6 only -U, --unixsock Use Unix domain sockets only -C, --crlf Use CRLF for EOL sequence -c, --sh-exec <command> Executes the given command via /bin/sh -e, --exec <command> Executes the given command --lua-exec <filename> Executes the given Lua script -g hop1[,hop2,...] Loose source routing hop points (8 max) -G <n> Loose source routing hop pointer (4, 8, 12, ...) -m, --max-conns <n> Maximum <n> simultaneous connections -h, --help Display this help screen -d, --delay <time> Wait between read/writes -o, --output <filename> Dump session data to a file -x, --hex-dump <filename> Dump session data as hex to a file -i, --idle-timeout <time> Idle read/write timeout -p, --source-port port Specify source port to use -s, --source addr Specify source address to use (doesn't affect -l) -l, --listen Bind and listen for incoming connections -k, --keep-open Accept multiple connections in listen mode -n, --nodns Do not resolve hostnames via DNS -t, --telnet Answer Telnet negotiations -u, --udp Use UDP instead of default TCP --sctp Use SCTP instead of default TCP -v, --verbose Set verbosity level (can be used several times) -w, --wait <time> Connect timeout -z Zero-I/O mode, report connection status only --append-output Append rather than clobber specified output files --send-only Only send data, ignoring received; quit on EOF --recv-only Only receive data, never send anything --allow Allow only given hosts to connect to Ncat --allowfile A file of hosts allowed to connect to Ncat --deny Deny given hosts from connecting to Ncat --denyfile A file of hosts denied from connecting to Ncat --broker Enable Ncat's connection brokering mode --chat Start a simple Ncat chat server --proxy <addr[:port]> Specify address of host to proxy through --proxy-type <type> Specify proxy type ("http" or "socks4" or "socks5") --proxy-auth <auth> Authenticate with HTTP or SOCKS proxy server --ssl Connect or listen with SSL --ssl-cert Specify SSL certificate file (PEM) for listening --ssl-key Specify SSL private key (PEM) for listening --ssl-verify Verify trust and domain name of certificates --ssl-trustfile PEM file containing trusted SSL certificates --ssl-ciphers Cipherlist containing SSL ciphers to use --ssl-alpn ALPN protocol list to use. --version Display Ncat's version information and exit See the ncat(1) manpage for full options, descriptions and usage examples
5 事前準備
テストに使うためのポート番号(TCP/UDPの11111番ポート)を解放します。ポートの開放は以下のように実行します。なお、firewall-cmdコマンドの使い方は、firewall-cmdの使い方 - hana_shinのLinux技術ブログを参照してください。
[root@server ~]# firewall-cmd --add-port=11111/tcp success
UDPのポート番号開放は次のように実行します。
[root@server ~]# firewall-cmd --add-port=11111/udp success
開放したポート番号を確認します。
[root@server ~]# firewall-cmd --list-ports 11111/tcp 11111/udp
6 IPv4オプションの使い方
6.1 TCPソケットの使い方
サーバ側でncコマンドを実行します。ncプロセスが、11111番ポートでListenするようにします。-kは複数クライアントとTCPコネクションを同時に確立するためのオプションです。
[root@server ~]# nc -kl 11111
もう1つターミナルを開きます。そして、lsofコマンドを実行します。ncプロセスがLISTEN状態であることがわかります。LISTEN状態は、TCPの状態のうちの1つです。
なお、lsofコマンドの使い方は、lsofコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。
[root@server ~]# lsof -c nc -a -i -a -nP COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME nc 1439 root 3u IPv6 20378 0t0 TCP *:11111 (LISTEN) nc 1439 root 4u IPv4 20379 0t0 TCP *:11111 (LISTEN)
次に、クライアントでncコマンドを実行します。
[root@client ~]# nc 192.168.3.120 11111
クライアントでncコマンドを実行すると、以下のように3 Way Handshakeが実行され、TCPコネクションが確立されます。
192.168.2.0/24 client server | .115 .120 | | | | |<-- nc -kl 11111 | | nc server 11111 -->|--------------- SYN -------------->| |<-------------- SYN+ACK -----------| |--------------- ACK -------------->| | |
次に、サーバ側でlsofコマンドを実行します。クライアントとTCPコネクションが確立されたことがわかります(★)。
[root@server ~]# lsof -c nc -i -a -nP COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME nc 37007 root 4u IPv4 88205 0t0 TCP *:11111 (LISTEN) nc 37007 root 5u IPv4 88206 0t0 TCP 192.168.2.120:11111->192.168.2.115:34082 (ESTABLISHED) ★
クライアントからサーバにデータ(12345)を送信してみます。
[root@client ~]# nc 192.168.2.120 11111 12345
サーバで受信したデータを確認します。クライアントが送信した文字列を受信したことがわかります。
[root@server ~]# nc -kl 11111 12345
6.2 UDPソケットの使い方
クライアントからのUDPパケットを11111番ポートで待ちます。
[root@server ~]# nc -ul 11111
サーバでlsofコマンドを実行します。UDPの11111番ポートで受信待ちであることがわかります。
[root@server ~]# lsof -c nc -i -a -nP COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME nc 2051 root 3u IPv6 28056 0t0 UDP *:11111 nc 2051 root 4u IPv4 28057 0t0 UDP *:11111
クライアントからサーバにデータ(12345)を送信します。
[root@client ~]# nc -u 192.168.2.120 11111 12345
サーバで受信したデータを確認します。クライアントが送信した文字列を受信したことがわかります。
[root@server ~]# nc -ul 11111 12345
6.3 送信元ポート番号を指定する方法(-p)
-pオプションは、送信元ポート番号を指定するオプションです。オプションの動作確認するため、まず、サーバ側は、TCPの11111番ポートでListenします。
[root@server ~]# nc -kl 11111
もう1つターミナルをひらいて、tcpdumpを実行します。なお、tcpdumpの使い方は、tcpdumpの使い方(基本編) - hana_shinのLinux技術ブログを参照してください。
[root@server ~]# tcpdump -i eth0 port 11111 -nn
次に、クライアントからサーバにデータを送信します。このとき、-pオプションを使って送信元ポート番号を22222に指定します。
[root@client ~]# nc 192.168.2.120 11111 -p 22222
tcpdumpの実行結果を確認すると、送信元ポート番号が22222であることがわかります。
[root@server ~]# tcpdump -i eth0 port 11111 -nn dropped privs to tcpdump tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 20:44:16.447290 IP 192.168.2.115.22222 > 192.168.2.120.11111: Flags [S], seq 4037070127, win 29200, options [mss 1460,sackOK,TS val 1665434420 ecr 0,nop,wscale 7], length 0 20:44:16.447512 IP 192.168.2.120.11111 > 192.168.2.115.22222: Flags [S.], seq 106715132, ack 4037070128, win 28960, options [mss 1460,sackOK,TS val 715173567 ecr 1665434420,nop,wscale 7], length 0 20:44:16.448036 IP 192.168.2.115.22222 > 192.168.2.120.11111: Flags [.], ack 1, win 229, options [nop,nop,TS val 1665434420 ecr 715173567], length 0
7 IPv6オプションの使い方
ここでは、IPv6環境でのncコマンドの使い方を説明します。サーバ、クライアントのIPv6アドレスは以下のとおりです。ともに、リンクローカルアドレスです。
client(eth0) --------------------------------------(eth0) server fe80::34cf:b07d:d3f3:c23c/64 fe80::8de4:812d:1d98:43e2/64
7.1 TCPソケットの使い方
サーバ側でncコマンドを実行します。ncプロセスが、11111番ポートでListenするようにします。-kは複数クライアントとTCPコネクションを同時に確立するためのオプションです。
[root@server ~]# nc -6 -kl 11111
もう1つターミナルを開きます。そして、lsofコマンドを実行します。ncプロセスがLISTEN状態であることがわかります。
[root@server ~]# lsof -c nc -i -a -nP COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME nc 2055 root 3u IPv6 26570 0t0 TCP *:11111 (LISTEN)
クライアント側では、宛先を次のように指定します。<サーバのIPv6アドレス>%<インタフェース名>
[root@client ~]# nc -6 fe80::34cf:b07d:d3f3:c23c%eth0 11111
次に、クライアントで"12345"と入力します。
[root@client ~]# nc -6 fe80::34cf:b07d:d3f3:c23c%eth0 11111 12345
サーバで受信したデータを確認します。
クライアントが送信した文字列を受信したことがわかります。
[root@server ~]# nc -6 -kl 11111 12345
lsofコマンドを実行します。サーバとクライアント間でTCPコネクションが確立されていることがわかります。
[root@server ~]# lsof -c nc -a -i6 -nP COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME nc 2683 root 3u IPv6 52637 0t0 TCP *:11111 (LISTEN) nc 2683 root 4u IPv6 52638 0t0 TCP [fe80::34cf:b07d:d3f3:c23c]:11111->[fe80::8de4:812d:1d98:43e2]:35382 (ESTABLISHED)
8 UNIXドメイオプションの使い方
ターミナルを2つオープンします。それぞれ、ターミナル1、ターミナル2と呼びます。
[root@server ~]# nc -U -l /tmp/sock -vv Ncat: Version 7.70 ( https://nmap.org/ncat ) Ncat: Listening on /tmp/sock
ターミナル2で12345と入力する。
[root@server ~]# nc -U /tmp/sock 12345
ターミナル1で受信した文字列を確認します。ターミナル2で送信した文字列がターミナル1で受信できたことがわかります。
[root@server ~]# nc -U -l /tmp/sock -vv Ncat: Version 7.70 ( https://nmap.org/ncat ) Ncat: Listening on /tmp/sock Ncat: Connection from a client on Unix domain socket. Ncat: Connection from . 12345
あと始末をします。作成したUNIXドメインソケットを削除します。
[root@server ~]# rm /tmp/sock rm: ソケット '/tmp/sock' を削除しますか? y
9 ファイルの送信方法
9.1 基本的な使い方
クライアントからのファイル受信を待ちます。
[root@server ~]# nc -kl 11111 > sv.dat
サーバに送信するファイル(1M)を作成します。なお、fallocateコマンドの使い方は、ファイルの作り方 - hana_shinのLinux技術ブログを参照してください。
[root@client ~]# fallocate -l 1M cl.dat
作成したファイルのファイルサイズを確認します。
[root@client ~]# ls -l cl.dat -rw-r--r--. 1 root root 1048576 12月 20 21:50 cl.dat
作成したファイルのチェックサムを確認します。
[root@client ~]# md5sum cl.dat b6d81b360a5672d80c27430f39153e2c cl.dat
クライアントからサーバにファイルを送信します。
[root@client ~]# nc 192.168.2.100 11111 < cl.dat
Ctrl +c押下して、サーバ側のncプロセスを終了します。
[root@server ~]# nc -kl 11111 > sv.dat ^C [root@server ~]#
ファイルサイズを確認します。クライアントで作成したファイルサイズと同じであることがわかります。
[root@server ~]# ls -l sv.dat -rw-r--r--. 1 root root 1048576 12月 20 21:53 sv.dat
次にチェックサム値を確認します。クライアントで作成したファイルのチェックサムと同じであることがわかります。
[root@server ~]# md5sum sv.dat b6d81b360a5672d80c27430f39153e2c sv.dat
9.2 パケットの送信間隔を指定する方法(-d)
-dオプションは、パケットの送信間隔を指定するオプションです。送信間隔は1ミリ秒単位で指定できます。
まず、送信用のファイルを作成します。
[root@client ~]# fallocate -l 1M test.dat
作成したファイルを確認します。
[root@client ~]# ls -l test.dat -rw-r--r--. 1 root root 1048576 12月 18 22:00 test.dat
サーバ側はTCPの11111番ポートでパケットを受信するようにします。
[root@server ~]# nc -kl 11111 > file.dat
パケットの送信間隔を確認するため、tcpdumpを実行します。
[root@server ~]# tcpdump -i any port 11111 -nn
クライアントからサーバに1秒間隔でパケットを送信します。
[root@client ~]# nc -d 1 192.168.2.120 11111 < test.dat
tcpdumpの実行結果を確認します。クライアントからパケットを1秒間隔で受信していることがわかります。なお、tcpdumpの最初の3行は無視してください。最初の3行はTCP 3way handshakeです。ここでやりとりするパケットの送信間隔はあらかじめ決まっているので、アプリが変更することはできません。
[root@server ~]# tcpdump -i any port 11111 -nn dropped privs to tcpdump tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on any, link-type LINUX_SLL (Linux cooked v1), capture size 262144 bytes 22:18:31.329840 IP 192.168.2.115.53754 > 192.168.2.120.11111: Flags [S], seq 728896519, win 29200, options [mss 1460,sackOK,TS val 2473293355 ecr 0,nop,wscale 7], length 0 22:18:31.329963 IP 192.168.2.120.11111 > 192.168.2.115.53754: Flags [S.], seq 2181520658, ack 728896520, win 28960, options [mss 1460,sackOK,TS val 656406415 ecr 2473293355,nop,wscale 7], length 0 22:18:31.330527 IP 192.168.2.115.53754 > 192.168.2.120.11111: Flags [.], ack 1, win 229, options [nop,nop,TS val 2473293356 ecr 656406415], length 0 22:18:32.339211 IP 192.168.2.115.53754 > 192.168.2.120.11111: Flags [P.], seq 1:8193, ack 1, win 229, options [nop,nop,TS val 2473294363 ecr 656406415], length 8192 22:18:32.339329 IP 192.168.2.120.11111 > 192.168.2.115.53754: Flags [.], ack 8193, win 355, options [nop,nop,TS val 656407424 ecr 2473294363], length 0 22:18:33.353334 IP 192.168.2.115.53754 > 192.168.2.120.11111: Flags [P.], seq 8193:16385, ack 1, win 229, options [nop,nop,TS val 2473295377 ecr 656407424], length 8192 22:18:33.353407 IP 192.168.2.120.11111 > 192.168.2.115.53754: Flags [.], ack 16385, win 483, options [nop,nop,TS val 656408438 ecr 2473295377], length 0 22:18:34.367750 IP 192.168.2.115.53754 > 192.168.2.120.11111: Flags [P.], seq 16385:24577, ack 1, win 229, options [nop,nop,TS val 2473296392 ecr 656408438], length 8192 22:18:34.367823 IP 192.168.2.120.11111 > 192.168.2.115.53754: Flags [.], ack 24577, win 611, options [nop,nop,TS val 656409453 ecr 2473296392], length 0 -snip-
10 サーバ側でコマンドを実行する方法(-e)
サーバ側で以下のようにコマンドを実行します。
[root@server ~]# nc -kl 11111 -e /usr/bin/bash
クライアントでhostnameコマンドを実行すると、サーバのホスト名が表示されることがわかります。
[root@client ~]# nc 192.168.2.100 11111 hostname server
11 改行コードを変更する方法(-C)
送信パケットの改行コードを変更する方法について説明します。デフォルトでは、改行コードは0x0aですが、オプションを指定すると0x0d 0x0aになります。
11.1 デフォルト時の改行コード確認
TCPの11111番ポートでTCPコネクション確立を待ちます。
[root@server ~]# nc -kl 11111
tcpdumpを実行します。このとき-xオプションを指定します。-xオプションは、パケットの中身をASCII表示するためのものです。
[root@server ~]# tcpdump -p -i eth0 dst port 11111 -x
サーバにTCPコネクションを確立します。
[root@client ~]# nc 192.168.2.100 11111
TCPコネクションが確立したら、5を入力します。
[root@client ~]# nc 192.168.2.100 11111 5
tcpdumpの実行結果を確認します。5のあと(5はASCIIコードで0x35です)、0x0aが表示されているのがわかります。
[root@server ~]# tcpdump -p -i eth0 dst port 11111 -x tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 22:34:31.871198 IP 192.168.2.105.60638 > server.vce: Flags [P.], seq 1048326853:1048326855, ack 2651245960, win 229, options [nop,nop,TS val 22499620 ecr 22621151], length 2 0x0000: 4500 0036 1a4d 4000 4006 9a57 c0a8 0269 0x0010: c0a8 0264 ecde 2b67 3e7c 32c5 9e06 cd88 0x0020: 8018 00e5 45dc 0000 0101 080a 0157 5124 0x0030: 0159 2bdf 350a
11.2 オプション指定時の改行コード確認
改行コードを0x0d 0x0aに変更するため、-Cオプションを指定してncコマンドを実行します。そして、例として5を入力します。
[root@client ~]# nc -C 192.168.2.100 11111 5
tcpdumpの実行結果を確認します。5のあと(5はASCIIコードで0x35です)、0d 0aが表示されているのがわかります。
[root@server ~]# tcpdump -p -i eth0 dst port 11111 -x 22:45:01.473096 IP 192.168.2.105.60642 > server.vce: Flags [P.], seq 0:3, ack 1, win 229, options [nop,nop,TS val 23129222 ecr 23255866], length 3 0x0000: 4500 0037 4ea5 4000 4006 65fe c0a8 0269 0x0010: c0a8 0264 ece2 2b67 25fc 9953 f756 8f81 0x0020: 8018 00e5 87ac 0000 0101 080a 0160 ec86 0x0030: 0162 db3a 350d 0a
12 TCPコネクションの同時接続数を指定する方法(-m)
12.1 TCPコネクションを1つに制限する方法
ncサーバが同時に接続できるクライアント数を1に制限してみます。
[root@server ~]# nc -m 1 -kl 11111
クライアンでncコマンドを実行します。
[root@client ~]# nc 192.168.2.100 11111& [1] 2770 [root@client ~]# nc 192.168.2.100 11111& [2] 2771 [1]+ 停止 nc 192.168.2.100 11111
もう1つ、サーバ側でターミナルをオープンします。TCPコネクションを確認すると、1つしか確立できていないことがわかります。なお、lsofコマンドは、lsofコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。
[root@server ~]# lsof -i4:11111 -n -a -P COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME nc 2774 root 4u IPv4 43277 0t0 TCP *:11111 (LISTEN) nc 2774 root 5u IPv4 43278 0t0 TCP 192.168.2.100:11111->192.168.2.105:42318 (ESTABLISHED)
12.2 TCPコネクションを2つに制限する方法
ncサーバが同時に接続できるクライアント数を2に制限してみます。
[root@server ~]# nc -m 2 -kl 11111
クライアンでncコマンドを実行します。
[root@client ~]# nc 192.168.2.100 11111& [1] 2905 [root@client ~]# nc 192.168.2.100 11111& [2] 2906 [root@client ~]# nc 192.168.2.100 11111& [3] 2907
もう1つ、サーバ側でターミナルをオープンします。TCPコネクションを確認すると、2つしか確立できていないことがわかります。
[root@server ~]# lsof -i4:11111 -n -a -P COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME nc 2966 root 4u IPv4 44697 0t0 TCP *:11111 (LISTEN) nc 2966 root 5u IPv4 44747 0t0 TCP 192.168.2.100:11111->192.168.2.105:42336 (ESTABLISHED) nc 2966 root 6u IPv4 44748 0t0 TCP 192.168.2.100:11111->192.168.2.105:42338 (ESTABLISHED)
13 proxyオプションの使い方
ncコマンドを実行します。このとき、ncプロセスは、8080番ポートでListenするようにします。
[root@server ~]# nc -l 8080 --proxy-type http
lsofコマンドを実行します。ncプロセスがTCPの8080番ポートでListenしていることがわかります。
[root@server ~]# lsof -c nc -i -a -nP COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME nc 2038 root 3u IPv6 26836 0t0 TCP *:8080 (LISTEN) nc 2038 root 4u IPv4 26837 0t0 TCP *:8080 (LISTEN)
TCPの8080番ポートへのアクセスを許可します。
[root@server ~]# firewall-cmd --add-port=8080/tcp success
次にクライアントでcurlコマンドを実行します。curlコマンドのアクセス先は、東京都のHPにしてみます。応答が、HTTP/1.0 200 OKとなっているので、正しくアクセスできていることがわかります。なお、curlコマンドの使い方は、curlコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。
[root@client ~]# curl -I -x http://192.168.2.100:8080 https://www.metro.tokyo.lg.jp/ HTTP/1.0 200 OK HTTP/1.1 200 OK Last-Modified: Mon, 27 Dec 2021 08:03:47 GMT ETag: "480f669-61de-5d41c24e95ec0" Accept-Ranges: bytes Content-Length: 25054 X-XSS-Protection: 1;mode=block X-Content-Type-Options: nosniff Content-Type: text/html X-Frame-Options: SAMEORIGIN Date: Mon, 27 Dec 2021 10:56:07 GMT Connection: keep-alive
14 TCPコネクション確立、解放時のシーケンス
Z 参考情報
私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ