- 1 はじめに
- 2 検証環境
- 3 事前準備
- 4 LOGターゲット
- 5 DROP/REJECTターゲット
- 6 RETURNターゲット
- 7 NFLOGターゲット
- 8 REDIRECTターゲット
- 9 MARKターゲット
- 10 TCPMSSターゲット
- 11 NOTRACKターゲット
- Z 参考情報
1 はじめに
ターゲットはルールにマッチしたら実行する処理のことです。LOGターゲットならログへの出力、DROPターゲットならパケット廃棄といった処理を行います。なお、iptablesコマンドの基本的な使い方は、iptablesコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。
2 検証環境
2.1 ネットワーク構成
サーバとクライアントの2台構成です。図中のeth0はNICの名前です。
192.168.122.0/24 client(eth0) -------------------------------------------(eth0) server .153 .128
3 事前準備
firewall-cmdコマンドとiptablesコマンドは一緒に使うことはできないので、firewalldサービスを停止します。なお、firewall-cmdの使い方は、firewall-cmdの使い方 - hana_shinのLinux技術ブログを参照してください。
[root@server ~]# systemctl stop firewalld.service
firewalldサービスの状態を確認します。firewalldサービスが停止したことがわかります。
[root@server ~]# systemctl is-active firewalld.service inactive
4 LOGターゲット
LOGターゲットは、ルールにマッチしたら情報(IPアドレス等)をログに出力するターゲットです。ここでは、ICMPパケットを受信したら、ICMPパケットのIPアドレス等の情報をログに出力するルールを作成してみます。
[root@server ~]# iptables -A INPUT -p icmp -j LOG
作成したルールを確認します。
[root@server ~]# iptables -nvL INPUT Chain INPUT (policy ACCEPT 47 packets, 3272 bytes) pkts bytes target prot opt in out source destination 0 0 LOG icmp -- * * 0.0.0.0/0 0.0.0.0/0 LOG flags 0 level 4
ログを確認するため、journalctlコマンドを実行します。なお、journalctlコマンドの使い方は、journalctlコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。
[root@server ~]# journalctl -f
クライアントで宛先をサーバにしてpingコマンドを1回実行します。なお、pingコマンドの使い方は、pingコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。
[root@client ~]# ping -c 1 192.168.122.128
pingを実行すると、以下のログが出力されることがわかります。
[root@server ~]# journalctl -f 12月 01 21:15:43 server kernel: IN=eth0 OUT= MAC=52:54:00:78:10:73:52:54:00:8c:76:20:08:00 SRC=192.168.122.153 DST=192.168.122.128 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=61606 DF PROTO=ICMP TYPE=8 CODE=0 ID=1456 SEQ=1
5 DROP/REJECTターゲット
5.1 DROPとREJECTの違い
DROPは受信したパケットを破棄するだけです。一方、REJECTは受信パケットを廃棄したら、廃棄した旨をパケット送信元に送信します。
DROPの場合は以下のようになります。クライアントからサーバに送信したICMP echo requestパケットは、サーバで廃棄されます。
192.168.122.0/24 client(eth0) -------------------------------------------(eth0) server .153 .128 ping ----------- ICMP echo request ----------> 廃棄(DROP)
一方、REJECTの場合は以下のようになります。クライアントからサーバに送信したICMP echo requestパケットはサーバで廃棄されます。そして、廃棄した旨をICMP port unreachableパケットでクライアントに送信します。
192.168.122.0/24 client(eth0) -------------------------------------------(eth0) server .153 .128 ping ----------- ICMP echo request ----------> 廃棄(REJECT) <---------- ICMP port unreachable ------
5.2 DROPターゲットの動作確認
ICMPパケットを受信したら廃棄するDROPターゲットのルールを作成します。
[root@server ~]# iptables -A INPUT -p icmp -j DROP
作成したルールを確認します。
[root@server ~]# iptables -nvL INPUT Chain INPUT (policy ACCEPT 37 packets, 2572 bytes) pkts bytes target prot opt in out source destination 0 0 DROP icmp -- * * 0.0.0.0/0 0.0.0.0/0
tcpdumpコマンドを実行します。なお、tcpdumpコマンドの使い方は、tcpdumpの使い方(基本編) - hana_shinのLinux技術ブログを参照してください。
[root@client ~]# tcpdump -i eth0 icmp -nn
クライアントでもう1つターミナルをオープンしてpingコマンドを実行します。-cオプションはpingコマンドを実行する回数です。-wはタイムアウトを指定するオプションです。送信したICMP echo requestパケットに対する応答が1秒以内になければpingコマンドを終了するようにします。
[root@client ~]# ping -c 1 -w 1 192.168.122.128
tcpdumpコマンドの実行結果を確認すると、クライアンからサーバにICMP echoパケットが1つ送信されたことがわかります。
[root@client ~]# tcpdump -i eth0 icmp -nn tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 22:04:03.773560 IP 192.168.122.153 > 192.168.122.128: ICMP echo request, id 1544, seq 1, length 64
ルールを確認すると、ICMPパケットが廃棄されていることがわかります。
[root@server ~]# iptables -nvL INPUT Chain INPUT (policy ACCEPT 99 packets, 6872 bytes) pkts bytes target prot opt in out source destination 1 84 DROP icmp -- * * 0.0.0.0/0 0.0.0.0/0
5.3 REJECTターゲットの動作確認
ICMPパケットを受信したら廃棄します。そして、廃棄した旨を送信元に送信するREJECTターゲットのルールを作成します。
[root@server ~]# iptables -I INPUT -p icmp -j REJECT
作成したルールを確認します。
[root@server ~]# iptables -nvL INPUT Chain INPUT (policy ACCEPT 69 packets, 5588 bytes) pkts bytes target prot opt in out source destination 0 0 REJECT icmp -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable||<
tcpdumpコマンドを実行します。
[root@client ~]# tcpdump -i eth0 -p icmp -nn
クライアントでもう1つターミナルをオープンしてpingコマンドを実行します。
[root@client ~]# ping -c 1 192.168.122.128
tcpdumpの実行結果を確認すると、ICMP port unreachableパケットがICMP echoパケット送信元に送信されていることがわかります。
[root@client ~]# tcpdump -i eth0 -p icmp -nn tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 22:03:10.907403 IP 192.168.122.153 > 192.168.122.128: ICMP echo request, id 1499, seq 1, length 64 22:03:10.909626 IP 192.168.122.128 > 192.168.122.153: ICMP 192.168.122.128 protocol 1 port 17955 unreachable, length 92
ルールを確認すると、ICMPパケットが廃棄されていることがわかります。
[root@server ~]# iptables -nvL INPUT Chain INPUT (policy ACCEPT 88 packets, 6952 bytes) pkts bytes target prot opt in out source destination 1 84 REJECT icmp -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
6 RETURNターゲット
ルールに一致したら、それ以上ルールに一致しているかどうかの処理をしないターゲットです。ルールに一致したら、ルールの呼び出し元に復帰します。
6.1 RETURNターゲットを使用した場合
テスト用のルールを3つ作成します。まず1つ目を作成します。
[root@server ~]# iptables -A INPUT -p icmp -j LOG --log-prefix "--LOG1--"
2つ目のルールを作成します。
[root@server ~]# iptables -A INPUT -p icmp -j RETURN
3つ目のルールを作成します。
[root@server ~]# iptables -A INPUT -p icmp -j LOG --log-prefix "--LOG2--"
作成したルールを確認します。2番目がRETURN ターゲットのルールです。
[root@server ~]# iptables -nvL INPUT --line-numbers Chain INPUT (policy ACCEPT 64 packets, 4480 bytes) num pkts bytes target prot opt in out source destination 1 0 0 LOG icmp -- * * 0.0.0.0/0 0.0.0.0/0 LOG flags 0 level 4 prefix "--LOG1--" 2 0 0 RETURN icmp -- * * 0.0.0.0/0 0.0.0.0/0 3 0 0 LOG icmp -- * * 0.0.0.0/0 0.0.0.0/0 LOG flags 0 level 4 prefix "--LOG2--"
ログを確認するため、journalctlコマンドを実行します。
[root@server ~]# journalctl -f
クライアントでpingコマンドを実行します。宛先はサーバを指定します。
[root@client ~]# ping -c 1 192.168.122.128
ログを確認するとLOG1は表示されていますが、LOG2は表示されていないことがわかります。つまり、1行目のルールを実行したあと、2行目のルールを実行してルールの呼び出し元に復帰していることがわかります。
[root@server ~]# journalctl -f 12月 13 20:21:12 server kernel: --LOG1--IN=eth0 OUT= MAC=52:54:00:78:10:73:52:54:00:8c:76:20:08:00 SRC=192.168.122.153 DST=192.168.122.128 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=27305 DF PROTO=ICMP TYPE=8 CODE=0 ID=1459 SEQ=1
6.2 RETURNターゲットを使用しない場合
テスト用のルールを2つ作成します。まず1つ作成します。
[root@server ~]# iptables -A INPUT -p icmp -j LOG --log-prefix "--LOG1--"
もう1つルールを作成します。
[root@server ~]# iptables -A INPUT -p icmp -j LOG --log-prefix "--LOG2--"
作成したルールを確認します。
[root@server ~]# iptables -nvL INPUT --line-numbers Chain INPUT (policy ACCEPT 13 packets, 972 bytes) num pkts bytes target prot opt in out source destination 1 0 0 LOG icmp -- * * 0.0.0.0/0 0.0.0.0/0 LOG flags 0 level 4 prefix "--LOG1--" 2 0 0 LOG icmp -- * * 0.0.0.0/0 0.0.0.0/0 LOG flags 0 level 4 prefix "--LOG2--"
クライアントでpingコマンドを実行します。宛先はサーバを指定します。
[root@client ~]# ping -c 1 192.168.122.128
ルールを確認すると、RETURNターゲットのルールを指定した時と違って、2つのルールでICMPパケットを処理していることがわかります。
[root@server ~]# iptables -nvL INPUT --line-numbers Chain INPUT (policy ACCEPT 26 packets, 1900 bytes) num pkts bytes target prot opt in out source destination 1 1 84 LOG icmp -- * * 0.0.0.0/0 0.0.0.0/0 LOG flags 0 level 4 prefix "--LOG1--" 2 1 84 LOG icmp -- * * 0.0.0.0/0 0.0.0.0/0 LOG flags 0 level 4 prefix "--LOG2--"
7 NFLOGターゲット
tcpdumpのフックポイントはIP層とドライバの間にありますが、NFLOGターゲットを使うとIP層に位置するチェインにフックポイントを設定することができます。なお、フックポイントとは、パケットをキャプチャする場所のことです。
ここでは、INPUTチェインにtcpdumpのフックポイントを設定してみます。
[root@server ~]# iptables -I INPUT -p tcp --dport 20000 -j NFLOG
作成したルールを確認します。INPUTチェインにNFLOGターゲットが設定されていることがわかります。
[root@server ~]# iptables -nvL INPUT --line-numbers Chain INPUT (policy ACCEPT 5 packets, 380 bytes) num pkts bytes target prot opt in out source destination 1 0 0 NFLOG tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:20000
tcpdumpを実行します。このとき、インタフェースにnflogを指定します。なお、NFLOGを指定した場合、tcpdumpがキャプチャするパケットは、-wオプションを使って、いったんファイルに保存する必要があります。なお、tcpdumコマンドの使い方は、tcpdumpの使い方(基本編) - hana_shinのLinux技術ブログを参照してください。
[root@server ~]# tcpdump -i nflog -w nflog.cap tcpdump: listening on nflog, link-type NFLOG (Linux netfilter log messages), capture size 262144 bytes
サーバでncコマンドを実行します。TCPの20000番ポートでncプロセスがListenするようにします。なお、ncコマンドの使い方は、ncコマンドの使い方(ネットワーク実験の幅が広がるなぁ~) - hana_shinのLinux技術ブログを参照してください。
[root@server ~]# nc -kl 20000
クライアントでncコマンドを実行します。宛先はサーバの20000番ポートを指定します。
[root@client ~]# nc 192.168.122.128 20000
Ctrl+Cを押下して、tcpdumpコマンドを終了します。
[root@server ~]# tcpdump -i nflog -w nflog.cap tcpdump: listening on nflog, link-type NFLOG (Linux netfilter log messages), capture size 262144 bytes ^C2 packets captured 2 packets received by filter 0 packets dropped by kernel
tsharkコマンドの実行結果を確認すると、INPUTチェインで処理するクライアントからサーバへのパケットのみがキャプチャされていることがわかります。サーバからクライアントへのSYN+ACKはINPUTチェインで処理されないので、キャプチャされていません。なお、tsharkコマンドのインストール方法、使い方はtsharkコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。
[root@server ~]# tshark -r nflog.cap -nn Running as user "root" and group "root". This could be dangerous. 1 0 192.168.122.153 -> 192.168.122.128 TCP 164 53888 > 20000 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=3752814 TSecr=0 WS=128 2 0 192.168.122.153 -> 192.168.122.128 TCP 156 53888 > 20000 [ACK] Seq=1 Ack=1 Win=29312 Len=0 TSval=3752815 TSecr=3758610
8 REDIRECTターゲット
宛先ポート番号を変更するターゲットです。ここでは、受信パケットの宛先ポート番号を10000から20000に変更してみます。ポート番号をREDIRECTターゲットで変更することで、クライアントからサーバへの10000番ポート宛てのパケットが20000番ポートで待ち受けているプロセス(nc)にパケットが届きます。
[root@server ~]# iptables -t nat -A PREROUTING -p tcp --dport 10000 -j REDIRECT --to-port 20000
PREROUTINGチェインに設定したREDIRECTターゲットを確認します。このターゲットは宛先ポート番号を10000から20000に変更します。
[root@server ~]# iptables -t nat -nvL PREROUTING --line-numbers Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 REDIRECT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:10000 redir ports 20000
サーバでncコマンドを実行します。
[root@server ~]# nc -kl 20000
lsofコマンドを実行すると、ncプロセスがTCPの20000番ポートでListenしていることがわかります。
なお、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 1702 root 3u IPv6 34357 0t0 TCP *:20000 (LISTEN) nc 1702 root 4u IPv4 34358 0t0 TCP *:20000 (LISTEN)
クライアントでncコマンドを実行します。宛先はサーバの10000番ポートを指定します。
[root@client ~]# nc 192.168.122.128 10000 12345
tcpdumpコマンドの実行結果を確認すると、10000番のポート番号を使ってTCPコネクションを確立していることがわかります。tcpdumpのフックポイントは、IP層とドライバの間にあります。PREROUTINGチェインはIP層にあります。したがって、PREROUTINGチェインで宛先ポート番号を10000から20000に変更する前のポート番号が表示されていることがわかります。
[root@server ~]# tcpdump -i eth0 port 10000 or port 20000 -nn 21:42:49.730489 IP 192.168.122.153.39516 > 192.168.122.128.10000: Flags [S], seq 2432710170, win 29200, options [mss 1460,sackOK,TS val 5123058 ecr 0,nop,wscale 7], length 0 21:42:49.730701 IP 192.168.122.128.10000 > 192.168.122.153.39516: Flags [S.], seq 924901017, ack 2432710171, win 28960, options [mss 1460,sackOK,TS val 5128854 ecr 5123058,nop,wscale 7], length 0 21:42:49.732036 IP 192.168.122.153.39516 > 192.168.122.128.10000: Flags [.], ack 1, win 229, options [nop,nop,TS val 5123061 ecr 5128854], length 0
INPUTチェインで採取したパケットを確認してみます。PREROUTINGチェインで宛先ポート番号を10000番から20000番に変更した後なので、ポート番号が20000番になっていることがわかります。
[root@server ~]# tshark -r nflog.cap -nn Running as user "root" and group "root". This could be dangerous. 1 0 192.168.122.153 -> 192.168.122.128 TCP 164 39516 > 20000 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=5123058 TSecr=0 WS=128 2 0 192.168.122.153 -> 192.168.122.128 TCP 156 39516 > 20000 [ACK] Seq=1 Ack=1 Win=29312 Len=0 TSval=5123061 TSecr=5128854
9 MARKターゲット
パケットに印をつけるターゲットです。ここでは、受信したICMPパケット対して、PREROUTINGチェインでMARKターゲットを実行します。MARKターゲットを実行すると、ICMPパケットに100番の印がつけられます。そして、INPUTチェインでは、100番のパケットに対して、LOGターゲットを実行します。比較のため、INPUTチェインで200番のルールも作成しますが、200番のルールでは、ICMPパケットはLOGターゲットで処理されないことを確認します。
+--------------------------+ | | | INPUT chain | 100番のパケットに対してLOGターゲットを実行します。 | | +--------------------------+ A | | +--------------------------+ | | ICMPパケットに対してMARKターゲットを実行します。 | PREROUTING chain | MARKターゲットを実行すると、ICMPパケットに100番の印が付けられます。 | | +--------------------------+ A | | ICMPパケット
PREROUTINGチェインでICMPパケットに100番の印を付けるルールを作成します。
[root@server ~]# iptables -t mangle -I PREROUTING -p icmp -j MARK --set-mark 100
作成したルールを確認します。
[root@server ~]# iptables -t mangle -nvL PREROUTING --line-numbers Chain PREROUTING (policy ACCEPT 21 packets, 1484 bytes) num pkts bytes target prot opt in out source destination 1 0 0 MARK icmp -- * * 0.0.0.0/0 0.0.0.0/0 MARK set 0x64
100番の印が付いたパケットをLOGターゲットで処理するルールをINPUTチェインに作成します。
[root@server ~]# iptables -I INPUT -m mark --mark 100 -j LOG
200番の印が付いたパケットをLOGターゲットで処理するルールをINPUTチェインに作成します。
[root@server ~]# iptables -I INPUT -m mark --mark 200 -j LOG
作成したルールを確認します。1番目のルールが200番(0xc8)の印が付いたパケットを処理するルール、2番のルールが100番(0x64)の印が付いたパケットを処理するルールです。
[root@server ~]# iptables -nvL INPUT --line-numbers Chain INPUT (policy ACCEPT 5 packets, 364 bytes) num pkts bytes target prot opt in out source destination 1 0 0 LOG all -- * * 0.0.0.0/0 0.0.0.0/0 mark match 0xc8 LOG flags 0 level 4 2 0 0 LOG all -- * * 0.0.0.0/0 0.0.0.0/0 mark match 0x64 LOG flags 0 level 4
クライアントでpingコマンドを実行します。宛先はサーバを指定します。
[root@client ~]# ping -c 1 192.168.122.128
ルールを確認します。1番目のルールではなく、2番目のルールでパケット数が1増加していることがわかります。
[root@server ~]# iptables -nvL INPUT --line-numbers Chain INPUT (policy ACCEPT 35 packets, 2492 bytes) num pkts bytes target prot opt in out source destination 1 0 0 LOG all -- * * 0.0.0.0/0 0.0.0.0/0 mark match 0xc8 LOG flags 0 level 4 2 1 84 LOG all -- * * 0.0.0.0/0 0.0.0.0/0 mark match 0x64 LOG flags 0 level 4
journalctlコマンドを実行します。100番の印が付いたパケットを受信していることがわかります。
[root@server ~]# journalctl -f -snip- Dec 14 20:51:49 server kernel: IN=eth0 OUT= MAC=52:54:00:78:10:73:52:54:00:8c:76:20:08:00 SRC=192.168.122.153 DST=192.168.122.128 LEN=84 TOS=0x00 PREC=0 x00 TTL=64 ID=46647 DF PROTO=ICMP TYPE=8 CODE=0 ID=1485 SEQ=1 MARK=0x64
10 TCPMSSターゲット
TCPヘッダに定義されているMSS(Maximum Segment Size)を変更するためのターゲットです。MSSはMTUからTCP/IPヘッダサイズを引いた値になります。通常、Ethernet環境ではMTUは1500(byte)です。また、TCP/IPの各々のヘッダサイズは20(byte)となるので、MSSは1460(byte)になります。しかし、最近ではTCP TimeStampオプション(12byte)が付くことが一般的なので、MSSは1448(byte)になります。
MSSを1000に変更するターゲットをPOSTROUTINGチェイン設定します。
[root@client ~]# iptables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN SYN -o eth0 -j TCPMSS --set-mss 1000
作成したルールを確認します。POSTROUTINGチェインにTCPMSSターゲットが作成され、MSSが1000に設定されていることがわかります。
[root@client ~]# iptables -t mangle -nvL POSTROUTING --line-numbers Chain POSTROUTING (policy ACCEPT 7 packets, 968 bytes) num pkts bytes target prot opt in out source destination 1 0 0 TCPMSS tcp -- * eth0 0.0.0.0/0 0.0.0.0/0 tcp flags:0x02/0x02 TCPMSS set 1000
サーバとクライアントのTCPコネクション確立時のパケットのやり取りを確認するため、tcpdumpコマンドを実行します。
[root@server ~]# tcpdump -i eth0 port 11111 -nn
サーバでncコマンドを実行します。TCPの11111番ポートでncプロセスがListenするようにします。
[root@server ~]# nc -kl 11111
クライアントでncコマンドを実行します。宛先はサーバの11111番ポートを指定します。
[root@client ~]# nc 192.168.122.128 11111
tcpdumpコマンドの実行結果を確認します。MSSが1000に設定されたSYNパケットが送信されていることがわかります。
[root@server ~]# tcpdump -i eth0 port 11111 -nn tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 21:37:53.952382 IP 192.168.122.153.54832 > 192.168.122.128.11111: Flags [S], seq 1449643484, win 29200, options [mss 1000,sackOK,TS val 6401001 ecr 0,nop,wscale 7], length 0 21:37:53.952545 IP 192.168.122.128.11111 > 192.168.122.153.54832: Flags [S.], seq 3488042956, ack 1449643485, win 28960, options [mss 1460,sackOK,TS val 6405591 ecr 6401001,nop,wscale 7], length 0 21:37:53.953831 IP 192.168.122.153.54832 > 192.168.122.128.11111: Flags [.], ack 1, win 229, options [nop,nop,TS val 6401003 ecr 6405591], length 0
11 NOTRACKターゲット
コネクショントラッキングを実行しないターゲットです。
Z 参考情報
私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ