Aug*_*bel 3 networking iptables
在 Ubuntu 22.04 上,我设置了以下iptables
规则:
iptables -I OUTPUT -d 192.168.0.0/16 -j LOG --log-prefix "CHECK1 "
iptables -I FORWARD -d 192.168.0.0/16 -j LOG --log-prefix "CHECK2 "
Run Code Online (Sandbox Code Playgroud)
为了验证我的设置是否正确,我192.168.0.0/16
在浏览器中导航到 website.com(位于子网中),并看到一条CHECK1
消息显示在/var/log/kern.log
.
然后,我运行了一个 C 程序,该程序创建了tun
一个 IP 地址为 的接口172.30.0.1
,并从中发出了一个手工制作的 TCP-SYN 数据包。该数据包的源地址为172.30.0.1
,目标地址为192.168.255.8
(website.com 的地址)。它出现在 Wireshark 中。但是,在 中没有相应的日志消息/var/log/kern.log
。
这个数据包发生了什么?
这是iptables-save
:
*filter
:INPUT ACCEPT [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
:DOCKER - [0:0]
:DOCKER-ISOLATION-STAGE-1 - [0:0]
:DOCKER-ISOLATION-STAGE-2 - [0:0]
:DOCKER-USER - [0:0]
-A FORWARD -d 192.168.0.0/16 -j LOG --log-prefix "CHECK2 "
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A OUTPUT -d 192.168.0.0/16 -j LOG --log-prefix "CHECK1 "
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -j RETURN
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -j RETURN
-A DOCKER-USER -j RETURN
COMMIT
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -D 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A DOCKER -i docker0 -j RETURN
COMMIT
Run Code Online (Sandbox Code Playgroud)
这是 C 代码(为了简洁起见,我省略了错误检查):
*filter
:INPUT ACCEPT [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
:DOCKER - [0:0]
:DOCKER-ISOLATION-STAGE-1 - [0:0]
:DOCKER-ISOLATION-STAGE-2 - [0:0]
:DOCKER-USER - [0:0]
-A FORWARD -d 192.168.0.0/16 -j LOG --log-prefix "CHECK2 "
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A OUTPUT -d 192.168.0.0/16 -j LOG --log-prefix "CHECK1 "
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -j RETURN
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -j RETURN
-A DOCKER-USER -j RETURN
COMMIT
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -D 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A DOCKER -i docker0 -j RETURN
COMMIT
Run Code Online (Sandbox Code Playgroud)
使用您的示例代码,我看到了您所描述的相同问题。
\n“小包,你在哪里?” 当数据包似乎神秘消失时,(pwru )是一个很棒的诊断工具,当我运行:
\ndocker run --privileged --rm -t --pid=host \\\n -v /sys/kernel/debug/:/sys/kernel/debug/ \\\n cilium/pwru --filter-port 10001\n
Run Code Online (Sandbox Code Playgroud)\n当您的代码发出数据包时,我看到以下内容:
\n0xffff8cd640b80500 5 [sendpacket] netif_receive_skb\n0xffff8cd640b80500 5 [sendpacket] skb_defer_rx_timestamp\n0xffff8cd640b80500 5 [sendpacket] __netif_receive_skb\n0xffff8cd640b80500 5 [sendpacket] __netif_receive_skb_one_core\n0xffff8cd640b80500 5 [sendpacket] ip_rcv\n0xffff8cd640b80500 5 [sendpacket] ip_rcv_core\n0xffff8cd640b80500 5 [sendpacket] kfree_skb_reason(SKB_DROP_REASON_IP_CSUM)\n0xffff8cd640b80500 5 [sendpacket] skb_release_head_state\n0xffff8cd640b80500 5 [sendpacket] sock_wfree\n0xffff8cd640b80500 5 [sendpacket] skb_release_data\n0xffff8cd640b80500 5 [sendpacket] skb_free_head\n0xffff8cd640b80500 5 [sendpacket] kfree_skbmem\n
Run Code Online (Sandbox Code Playgroud)\n这表明数据包已被丢弃,因为它包含不正确的校验和。
\n如果我们使用wireshark检查数据包捕获,它会告诉我们正确的校验和。解决这些问题可以让我们:
\n static void emitPacket(int tap_fd) {\n \xe2\x94\x82 unsigned char packet[] = {\n \xe2\x94\x82 \xe2\x94\x82 0x45, 0x00, 0x00, 0x3c, 0xd8, 0x6f, 0x40, 0x00, 0x3f, 0x06, 0xf7, 0x7b,\n \xe2\x94\x82 \xe2\x94\x82 172, 30, 0, 1, 192, 168, 255, 8, 0xa2, 0x9a, 0x27, 0x11,\n \xe2\x94\x82 \xe2\x94\x82 0x80, 0x0b, 0x63, 0x79, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0xfa, 0xf0,\n \xe2\x94\x82 \xe2\x94\x82 0x78, 0xc3, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a,\n \xe2\x94\x82 \xe2\x94\x82 0x5b, 0x76, 0x5f, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07};\n \xe2\x94\x82\n \xe2\x94\x82 write(tap_fd, packet, sizeof(packet));\n }\n
Run Code Online (Sandbox Code Playgroud)\n但这在路由逻辑中失败了:
\n0xffff8cd8bca97100 0 [sendpacket] netif_receive_skb\n0xffff8cd8bca97100 0 [sendpacket] skb_defer_rx_timestamp\n0xffff8cd8bca97100 0 [sendpacket] __netif_receive_skb\n0xffff8cd8bca97100 0 [sendpacket] __netif_receive_skb_one_core\n0xffff8cd8bca97100 0 [sendpacket] ip_rcv\n0xffff8cd8bca97100 0 [sendpacket] ip_rcv_core\n0xffff8cd8bca97100 0 [sendpacket] sock_wfree\n0xffff8cd8bca97100 0 [sendpacket] nf_hook_slow\n0xffff8cd8bca97100 0 [sendpacket] nf_checksum\n0xffff8cd8bca97100 0 [sendpacket] nf_ip_checksum\n0xffff8cd8bca97100 0 [sendpacket] __skb_checksum_complete\n0xffff8cd8bca97100 0 [sendpacket] tcp_v4_early_demux\n0xffff8cd8bca97100 0 [sendpacket] ip_route_input_noref\n0xffff8cd8bca97100 0 [sendpacket] ip_route_input_slow\n0xffff8cd8bca97100 0 [sendpacket] fib_validate_source\n0xffff8cd8bca97100 0 [sendpacket] __fib_validate_source\n0xffff8cd8bca97100 0 [sendpacket] ip_handle_martian_source\n0xffff8cd8bca97101 0 [sendpacket] kfree_skb_reason(SKB_DROP_REASON_NOT_SPECIFIED)\n0xffff8cd8bca97100 0 [sendpacket] skb_release_head_state\n0xffff8cd8bca97100 0 [sendpacket] skb_release_data\n0xffff8cd8bca97100 0 [sendpacket] skb_free_head\n0xffff8cd8bca97100 0 [sendpacket] kfree_skbmem\n
Run Code Online (Sandbox Code Playgroud)\n事实上,如果您已log_martians
在系统上启用,您将看到:
Feb 14 12:14:03 madhatter kernel: IPv4: martian source 192.168.255.8 from\n172.30.0.1, on dev tun0\n
Run Code Online (Sandbox Code Playgroud)\n...我们收到该错误是因为有一个数据包进入与该接口具有相同地址的接口,这是一个问题(我们永远无法正确响应它)。
\ntun0
如果我们修改您的代码以 (a) 设置与数据包中不同的地址,并且 (b) 使用/24
网络掩码,以便我们获得到适当网络的自动路由:
static void bringInterfaceUp(void) {\n int sock;\n struct sockaddr_in addr = {.sin_family = AF_INET};\n struct ifreq ifr = {.ifr_name = "tun0"};\n\n inet_aton("172.30.0.10", &addr.sin_addr);\n memcpy(&ifr.ifr_addr, &addr, sizeof(struct sockaddr));\n sock = socket(AF_INET, SOCK_DGRAM, 0);\n must(ioctl(sock, SIOCSIFADDR, &ifr));\n\n /*\n I don\'t know if this is entirely kosher -- it\'s the result of a quick\n glance over the netdevice(7) man page -- but it seems to work.\n */\n inet_aton("255.255.255.0", &addr.sin_addr);\n memcpy(&ifr.ifr_addr, &addr, sizeof(struct sockaddr));\n must(ioctl(sock, SIOCSIFNETMASK, &ifr));\n\n must(ioctl(sock, SIOCGIFFLAGS, &ifr));\n ifr.ifr_flags |= IFF_UP | IFF_RUNNING;\n must(ioctl(sock, SIOCSIFFLAGS, &ifr));\n close(sock);\n}\n
Run Code Online (Sandbox Code Playgroud)\n我们现在看到在 上发出的数据包eth0
:
$ sudo tcpdump -i any -nn port 10001\ntcpdump: data link type LINUX_SLL2\ndropped privs to tcpdump\ntcpdump: verbose output suppressed, use -v[v]... for full protocol decode\nlistening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes\n12:33:26.877514 tun0 In IP 172.30.0.1.41626 > 192.168.255.8.10001: Flags [S], seq 2148230009, win 64240, options [mss 1460,sackOK,TS val 1534484436 ecr 0,nop,wscale 7], length 0\n12:33:26.877536 eth0 Out IP 172.30.0.1.41626 > 192.168.255.8.10001: Flags [S], seq 2148230009, win 64240, options [mss 1460,sackOK,TS val 1534484436 ecr 0,nop,wscale 7], length 0\n
Run Code Online (Sandbox Code Playgroud)\n