使用 pwru 追踪 linux kernel 网络包
- 官方仓库: github.com/cilium/pwru
1. 编译构建
git clone git@github.com:cilium/pwru.git
cd pwru
# 原生编译
make
# 或构建 docker 镜像
docker build -t pwru .
#docker build - < Dockerfile
2. 应用示例
sudo iptables -t filter -I OUTPUT 1 -m tcp --proto tcp --dst 1.1.1.1/32 -j DROP
curl 1.1.1.1
docker run --rm --privileged pwru --filter-dst-ip=1.1.1.1 --filter-dst-port=80 --filter-proto=tcp --output-tuple
[2022-01-26 05:14:27] SKB PROCESS FUNC TIMESTAMP
[2022-01-26 05:14:35] 0xffff89fb5768f0e0 [curl] ip_local_out 161391938235954 192.168.110.130:33248->1.1.1.1:80(tcp) # 因为是从本地发出数据到公网
[2022-01-26 05:14:35] 0xffff89fb5768f0e0 [curl] __ip_local_out 161391938266384 192.168.110.130:33248->1.1.1.1:80(tcp)
[2022-01-26 05:14:35] 0xffff89fb5768f0e0 [curl] nf_hook_slow 161391938281657 192.168.110.130:33248->1.1.1.1:80(tcp) # 调用IPtables中的Chains判别数据包
[2022-01-26 05:14:35] 0xffff89fb5768f0e0 [curl] kfree_skb 161391938297492 192.168.110.130:33248->1.1.1.1:80(tcp) # 回收skb 拒绝 consume_skb 表示 skb是正常释放。 kfree_skb 表示因为某种错误报文被丢弃。
[2022-01-26 05:14:35] 0xffff89fb5768f0e0 [curl] skb_release_head_state 161391938311827 192.168.110.130:33248->1.1.1.1:80(tcp)
[2022-01-26 05:14:35] 0xffff89fb5768f0e0 [curl] tcp_wfree 161391938345431 192.168.110.130:33248->1.1.1.1:80(tcp) # 针对TCP回收
[2022-01-26 05:14:35] 0xffff89fb5768f0e0 [curl] skb_release_data 161391938359294 192.168.110.130:33248->1.1.1.1:80(tcp)
[2022-01-26 05:14:35] 0xffff89fb5768f0e0 [curl] kfree_skbmem 161391938374122 192.168.110.130:33248->1.1.1.1:80(tcp)
# 重试
[2022-01-26 05:14:36] 0xffff89fb5768f0e0 [EMT-1] __skb_clone 161392965281794 192.168.110.130:33248->1.1.1.1:80(tcp) # 单单克隆下sk_buff结构体,对sk_buff结构的数据区、分片结构体skb_shared_info、分片结构体数据区等结果进行共享。
[2022-01-26 05:14:36] 0xffff89fb5768f0e0 [EMT-1] __copy_skb_header 161392965336975 192.168.110.130:33248->1.1.1.1:80(tcp) # 复用之前的构造好的数据结构
[2022-01-26 05:14:36] 0xffff89fb5768f0e0 [EMT-1] ip_local_out 161392965394428 192.168.110.130:33248->1.1.1.1:80(tcp)
[2022-01-26 05:14:36] 0xffff89fb5768f0e0 [EMT-1] __ip_local_out 161392965423078 192.168.110.130:33248->1.1.1.1:80(tcp)
[2022-01-26 05:14:36] 0xffff89fb5768f0e0 [EMT-1] nf_hook_slow 161392965464020 192.168.110.130:33248->1.1.1.1:80(tcp)
[2022-01-26 05:14:36] 0xffff89fb5768f0e0 [EMT-1] kfree_skb 161392965480966 192.168.110.130:33248->1.1.1.1:80(tcp)
[2022-01-26 05:14:36] 0xffff89fb5768f0e0 [EMT-1] skb_release_head_state 161392965535446 192.168.110.130:33248->1.1.1.1:80(tcp)
[2022-01-26 05:14:36] 0xffff89fb5768f0e0 [EMT-1] tcp_wfree 161392965577236 192.168.110.130:33248->1.1.1.1:80(tcp)
[2022-01-26 05:14:36] 0xffff89fb5768f0e0 [EMT-1] skb_release_data 161392965590979 192.168.110.130:33248->1.1.1.1:80(tcp)
[2022-01-26 05:14:36] 0xffff89fb5768f0e0 [EMT-1] kfree_skbmem 161392965605683 192.168.110.130:33248->1.1.1.1:80(tcp)
# 清理现场(删 OUTPUT 链第一条规则)
iptables -D OUTPUT 1
3. iptables 相关指令
iptables是linux系统自带的防火墙,功能强大,学习起来需要一段时间,下面是一些习iptables的时候的记录。如果iptables不熟悉的话可以用apf,是一款基于iptables的防火墙,挺好用的。请参考:linux apf 防火墙 安装 配置
- 3.1 添加 filter 表
# 开放21端口(出口一般都是开放的 iptables -P OUTPUT ACCEPT,所以出口就没必要在去开放端口了)
iptables -A INPUT -p tcp -m tcp --dport 21 -j ACCEPT
- 3.2 添加 nat 表
# 将源地址是 192.168.10.0/24 的数据包进行地址伪装
# -A默认是插入到尾部的,可以-I来插入到指定位置
iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -j MASQUERADE
iptables -I INPUT 3 -p tcp -m tcp --dport 20 -j ACCEPT
iptables -L -n --line-number
Chain INPUT (policy DROP)
num target prot opt source destination
1 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
2 DROP icmp -- 0.0.0.0/0 0.0.0.0/0 icmp type 8
3 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:20 # -I 指定位置插的
4 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:22
5 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
6 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
7 DROP all -- 0.0.0.0/0 0.0.0.0/0 state INVALID,NEW
8 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:21 # -A 默认插到最后
Chain FORWARD (policy ACCEPT)
num target prot opt source destination
Chain OUTPUT (policy ACCEPT)
num target prot opt source destination
- 3.3 查看 filter 表
# --line-number可以显示规则序号,在删除的时候比较方便
# 如果不加-t的话,默认就是filter表,查看,添加,删除都是的
iptables -L -n --line-number | grep 21
5 ACCEPT tcp -- 192.168.1.0/24 0.0.0.0/0 tcp dpt:21
- 3.4 查看 nat 表
iptables -t nat -vnL POSTROUTING --line-number
Chain POSTROUTING (policy ACCEPT 38 packets, 2297 bytes)
num pkts bytes target prot opt in out source destination
1 0 0 MASQUERADE all -- * * 192.168.10.0/24 0.0.0.0/0
- 3.5 修改规则
# 将规则3改成DROP
iptables -R INPUT 3 -j DROP
- 3.6 删除规则
# 删除 INPUT 的第3条规则
iptables -D INPUT 3
# 删除 nat 表中 POSTROUTING 的第一条规则
iptables -t nat -D POSTROUTING 1
# 清空 filter 表 INPUT 所有规则
iptables -F INPUT
# 清空所有规则
iptables -F
# 清空 nat 表 POSTROUTING 所有规则
iptables -t nat -F POSTROUTING
- 3.6 设置默认规则
# 设置filter表INPUT默认规则是 DROP
iptables -P INPUT DROP
如上增删改后都需使用 /etc/init.d/iptables save
导出外部保存起来,上面只是一些最基本的操作,要想灵活运用,还要一定时间的实际操作。
4. 原理资料
- 4.1 推荐朱双印的 iptables 原理解读:www.zsythink.net/archives/1199
核心搞明白这张图:
5 FAQ
TODO