环境:
客户端(windows) 192.168.6.21
服务器(Ubuntu): 192.168.6.23
开启iptables调试内核模块
$ modprobe nf_log_ipv4
$ sysctl net.netfilter.nf_log.2
net.netfilter.nf_log.2 = nf_log_ipv4
添加iptables规则
$ iptables -t raw -A PREROUTING -p icmp -j TRACE
$ iptables -t raw -A OUTPUT -p icmp -j TRACE
测试规则
客户端执行 ping 命令,
$ ping 192.168.6.23 -n 1
这里使用 -n 参数指定发送的包数量为1,方便我们分析日志
此时在服务器上执行查看日志命令, 日志文件为:/var/log/syslog 或者 /var/log/kern.log 或者 /var/log/messages
$ tail -f /var/log/syslog
Jul 20 11:28:40 ubuntu kernel: [ 7606.531051] TRACE: raw:PREROUTING:policy:2 IN=ens37 OUT= MAC=00:0c:29:30:06:44:00:68:eb:c6:60:f2:08:00 SRC=192.168.6.21 DST=192.168.6.23 LEN=60 TOS=0x00 PREC=0x00 TTL=128 ID=33555 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=608
Jul 20 11:28:40 ubuntu kernel: [ 7606.531146] TRACE: nat:PREROUTING:rule:1 IN=ens37 OUT= MAC=00:0c:29:30:06:44:00:68:eb:c6:60:f2:08:00 SRC=192.168.6.21 DST=192.168.6.23 LEN=60 TOS=0x00 PREC=0x00 TTL=128 ID=33555 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=608
Jul 20 11:28:40 ubuntu kernel: [ 7606.531192] TRACE: nat:DOCKER:return:3 IN=ens37 OUT= MAC=00:0c:29:30:06:44:00:68:eb:c6:60:f2:08:00 SRC=192.168.6.21 DST=192.168.6.23 LEN=60 TOS=0x00 PREC=0x00 TTL=128 ID=33555 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=608
Jul 20 11:28:40 ubuntu kernel: [ 7606.531259] TRACE: nat:PREROUTING:policy:2 IN=ens37 OUT= MAC=00:0c:29:30:06:44:00:68:eb:c6:60:f2:08:00 SRC=192.168.6.21 DST=192.168.6.23 LEN=60 TOS=0x00 PREC=0x00 TTL=128 ID=33555 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=608
Jul 20 11:28:40 ubuntu kernel: [ 7606.531316] TRACE: filter:INPUT:policy:1 IN=ens37 OUT= MAC=00:0c:29:30:06:44:00:68:eb:c6:60:f2:08:00 SRC=192.168.6.21 DST=192.168.6.23 LEN=60 TOS=0x00 PREC=0x00 TTL=128 ID=33555 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=608
Jul 20 11:28:40 ubuntu kernel: [ 7606.531373] TRACE: nat:INPUT:policy:1 IN=ens37 OUT= MAC=00:0c:29:30:06:44:00:68:eb:c6:60:f2:08:00 SRC=192.168.6.21 DST=192.168.6.23 LEN=60 TOS=0x00 PREC=0x00 TTL=128 ID=33555 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=608
Jul 20 11:28:40 ubuntu kernel: [ 7606.531424] TRACE: raw:OUTPUT:policy:2 IN= OUT=ens37 SRC=192.168.6.23 DST=192.168.6.21 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=35888 PROTO=ICMP TYPE=0 CODE=0 ID=1 SEQ=608
Jul 20 11:28:40 ubuntu kernel: [ 7606.531488] TRACE: filter:OUTPUT:policy:1 IN= OUT=ens37 SRC=192.168.6.23 DST=192.168.6.21 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=35888 PROTO=ICMP TYPE=0 CODE=0 ID=1 SEQ=608
可以看到除了流量来源 SRC 和目的 DST, 还有一些 ICMP 协议相关的字段,如 TYPE, CODE; 对于 ICMP协议 TYPE 有多类值,其中CODE 根据 TYPE 值的不同而不同。
日志字段
Jul 20 11:28:40 ubuntu kernel: [ 7606.531051] TRACE: raw:PREROUTING:policy:2 IN=ens37 OUT= MAC=00:0c:29:30:06:44:00:68:eb:c6:60:f2:08:00 SRC=192.168.6.21 DST=192.168.6.23 LEN=60 TOS=0x00 PREC=0x00 TTL=128 ID=33555 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=608
raw:PREROUTING:policy:2 这里以”:”分隔四类字段值,分别为 raw 表:PREROUTING 键:policy或 rule : 编号
IN 流量流入网卡名称,当流量 为流出时,此字段为空
OUT 流量流出网卡名称,当流量为流入时,此字段为空
MAC 网卡MAC地址
SRC 流量来源IP
DST 流量目的IP
LEN 数据包大小
TOS 服务类型
ID 流唯一标识, 如日志中请求ID为 33555, 响应ID为 35888
PROTO 数据流协议
TYPE 协议ICMP的类型,见下表
CODE 协议ICMP类型对应的code
上面日志中第2-7条记录为ping 请求(TYPE=8 CODE=0),而最后两条记录为对ping命令的响应(TYPE=0 CODE=0),由于ping 请求经过了nat 表(PREROUTING)和 filter 两个表的不同链,所有打印多条记录。
ICMP类型
TYPE | CODE | DESCRIPTION | QUERY | ERROR |
---|---|---|---|---|
0 | 0 | Echo Reply——回显应答(Ping应答) | x | |
3 | 0 | Network Unreachable——网络不可达 | x | |
3 | 1 | Host Unreachable——主机不可达 | x | |
3 | 2 | Protocol Unreachable——协议不可达 | x | |
3 | 3 | Port Unreachable——端口不可达 | x | |
3 | 4 | Fragmentation needed but no frag. bit set——需要进行分片但设置不分片比特 | x | |
3 | 5 | Source routing failed——源站选路失败 | x | |
3 | 6 | Destination network unknown——目的网络未知 | x | |
3 | 7 | Destination host unknown——目的主机未知 | x | |
3 | 8 | Source host isolated (obsolete)——源主机被隔离(作废不用) | x | |
3 | 9 | Destination network administratively prohibited——目的网络被强制禁止 | x | |
3 | 10 | Destination host administratively prohibited——目的主机被强制禁止 | x | |
3 | 11 | Network unreachable for TOS——由于服务类型TOS,网络不可达 | x | |
3 | 12 | Host unreachable for TOS——由于服务类型TOS,主机不可达 | x | |
3 | 13 | Communication administratively prohibited by filtering——由于过滤,通信被强制禁止 | x | |
3 | 14 | Host precedence violation——主机越权 | x | |
3 | 15 | Precedence cutoff in effect——优先中止生效 | x | |
4 | 0 | Source quench——源端被关闭(基本流控制) | ||
5 | 0 | Redirect for network——对网络重定向 | ||
5 | 1 | Redirect for host——对主机重定向 | ||
5 | 2 | Redirect for TOS and network——对服务类型和网络重定向 | ||
5 | 3 | Redirect for TOS and host——对服务类型和主机重定向 | ||
8 | 0 | Echo request——回显请求(Ping请求) | x | |
9 | 0 | Router advertisement——路由器通告 | ||
10 | 0 | Route solicitation——路由器请求 | ||
11 | 0 | TTL equals 0 during transit——传输期间生存时间为0 | x | |
11 | 1 | TTL equals 0 during reassembly——在数据报组装期间生存时间为0 | x | |
12 | 0 | IP header bad (catchall error)——坏的IP首部(包括各种差错) | x | |
12 | 1 | Required options missing——缺少必需的选项 | x | |
13 | 0 | Timestamp request (obsolete)——时间戳请求(作废不用) | x | |
14 | Timestamp reply (obsolete)——时间戳应答(作废不用) | x | ||
15 | 0 | Information request (obsolete)——信息请求(作废不用) | x | |
16 | 0 | Information reply (obsolete)——信息应答(作废不用) | x | |
17 | 0 | Address mask request——地址掩码请求 | x | |
18 | 0 | Address mask reply——地址掩码应答 | x |
在日志里同时还有 raw表的 PREROUTING 和 OUTPUT 链的相关记录。
现在我们再添加一条禁止ICMP的规则,这里即可以在filter 表中的 INPUT 链中添加,也可以在 OUTPUT 链中添加。
$ iptables -t filter -A OUTPUT -d 192.168.6.21 -j DROP
这里我们添加在了 OUTPUT 链里,所以这里使用的 -d 参数值为 192.168.6.21
现在我们再看一下日志输出
Jul 20 11:09:58 ubuntu kernel: [ 6484.565458] TRACE: raw:PREROUTING:policy:2 IN=ens37 OUT= MAC=00:0c:29:30:06:44:00:68:eb:c6:60:f2:08:00 SRC=192.168.6.21 DST=192.168.6.23 LEN=60 TOS=0x00 PREC=0x00 TTL=128 ID=33554 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=582
Jul 20 11:09:58 ubuntu kernel: [ 6484.565548] TRACE: nat:PREROUTING:rule:1 IN=ens37 OUT= MAC=00:0c:29:30:06:44:00:68:eb:c6:60:f2:08:00 SRC=192.168.6.21 DST=192.168.6.23 LEN=60 TOS=0x00 PREC=0x00 TTL=128 ID=33554 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=582
Jul 20 11:09:58 ubuntu kernel: [ 6484.565592] TRACE: nat:DOCKER:return:3 IN=ens37 OUT= MAC=00:0c:29:30:06:44:00:68:eb:c6:60:f2:08:00 SRC=192.168.6.21 DST=192.168.6.23 LEN=60 TOS=0x00 PREC=0x00 TTL=128 ID=33554 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=582
Jul 20 11:09:58 ubuntu kernel: [ 6484.565631] TRACE: nat:PREROUTING:policy:2 IN=ens37 OUT= MAC=00:0c:29:30:06:44:00:68:eb:c6:60:f2:08:00 SRC=192.168.6.21 DST=192.168.6.23 LEN=60 TOS=0x00 PREC=0x00 TTL=128 ID=33554 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=582
Jul 20 11:09:58 ubuntu kernel: [ 6484.565673] TRACE: filter:INPUT:policy:1 IN=ens37 OUT= MAC=00:0c:29:30:06:44:00:68:eb:c6:60:f2:08:00 SRC=192.168.6.21 DST=192.168.6.23 LEN=60 TOS=0x00 PREC=0x00 TTL=128 ID=33554 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=582
Jul 20 11:09:58 ubuntu kernel: [ 6484.565713] TRACE: nat:INPUT:policy:1 IN=ens37 OUT= MAC=00:0c:29:30:06:44:00:68:eb:c6:60:f2:08:00 SRC=192.168.6.21 DST=192.168.6.23 LEN=60 TOS=0x00 PREC=0x00 TTL=128 ID=33554 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=582
Jul 20 11:09:58 ubuntu kernel: [ 6484.565763] TRACE: raw:OUTPUT:policy:2 IN= OUT=ens37 SRC=192.168.6.23 DST=192.168.6.21 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=14584 PROTO=ICMP TYPE=0 CODE=0 ID=1 SEQ=582
Jul 20 11:09:58 ubuntu kernel: [ 6484.565804] TRACE: filter:OUTPUT:rule:1 IN= OUT=ens37 SRC=192.168.6.23 DST=192.168.6.21 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=14584 PROTO=ICMP TYPE=0 CODE=0 ID=1 SEQ=582
请求ID为 33554,TYPE=8, 而响应ID为 14584,TYPE=0
我们看下最后一条日志,其中filter:OUTPUT:rule:1 表示路径为 filter 表的 OUTPUT 链中的编号为1的规则,这条应该是我们上面添加的规则 ,我们现在确认一下
iptables -t filter -L OUTPUT -nv --line-number
Chain OUTPUT (policy ACCEPT 65 packets, 7466 bytes)
num pkts bytes target prot opt in out source destination
1 3 180 DROP all -- * * 0.0.0.0/0 192.168.6.21
这里是添加在了OUTPUT链中,所以 dst 就是客户端的ip地址,src 就是服务器的地址,这个与我们在 INPUT 链中的正好相反。
清理现场
$ modprobe -r nf_log_ipv4
modprobe: FATAL: Module nf_log_syslog is in use.