前言
我从大二开始接触linux, 最开始安装的就是基于debian的kali, 之后直接将debian作为主系统日常使用. 包括现在购买的VPS, 又或是wsl都安装的debian, 就如同我对firefox一样, 产生了深厚的感情.
改造
接上篇文章, 历经千幸万苦终于可以在OpenWrt上运行Docker后, tproxy透明代理失效了. 因为OpenWrt系统十分精简, 再加上是我自己编译的版本, 缺少官方的软件源, 所以调试变得异常困难. 最终我不得不放弃, 转向debian. 我熟练地下载官方镜像, 使用rufus写入U盘, 按部就班的完成了系统安装.
那么接下来就需要将它改造成路由器.
网桥
我的主机有4个网口, 我将第一个网口当做WAN, 连接着联通光猫. 那么我需要将剩下三个网口进行桥接, 使它们处于一个网段, 当为LAN口使用.
1 2 3 4 5 6
| # 安装 apt install bridge-utils
# 添加桥接网卡 brctl addbr br0 brctl addif br0 enp0s8 enp0s9
|
你可以选择使用brctl手动添加桥接网卡, 但是重启之后会消失, 所以建议写入网络配置:
1 2 3 4 5 6 7
| # /etc/network/interfaces auto br0 iface br0 inet static address 192.168.12.1 broadcast 192.168.12.255 netmask 255.255.255.0 bridge-ports enp0s8 enp0s9
|
bridge-ports参数替换成具体的网卡, 上面的例子只桥接了两个网卡, 这并不是我实际使用的配置, 仅供参考.
DNS/DHCP
路由器最重要的自然是DHCP/DNS, 而dnsmasq帮我们轻松搞定:
dnsmasq会提供DHCP/DNS服务, DNS默认转发到上游DNS, 暂时不需要修改, 但是DHCP需要修改配置文件指定网段等信息:
1 2 3
| # /etc/dnsmasq.conf interface=br0 dhcp-range=192.168.12.100,192.168.12.250,72h
|
转发
现在将电脑网线插入J1900主机网口, 电脑可以使用DHCP获取到IP, 可惜现在还上不了网. 因为linux默认将目标IP不是本机的流量全部DROP, 首先打开IP转发:
1 2
| # 重启后失效 echo 1 > /proc/sys/net/ipv4/ip_forward
|
光开启转发还是无法上网, 因为内网网段访问外网需要NAT, 所以需要配置iptables:
1
| iptables -t nat -A POSTROUTING -s 192.168.12.0/24 -o enp0s3 -j MASQUERADE
|
enp0s3是WAN口网卡, MASQUERADE将把子网流量自动NAT转换, 现在你可以自由的进行网上冲浪了.
复现
完成上面一切, debian现在与OpenWrt有着同样的功能, 而且还废弃了那些累赘的组件. 我现在准备安装docker-ce, 过程很迅速, 安装完后我开始基于docker-ce搭建自己的SMB服务.
一切都完成了, 我长舒一口气, 我在终端执行
命令卡住了!!! tproxy又罢工了!!! 我突然意识到我错怪了OpenWrt, 这似乎是Docker惹的祸, 于是我又开始了漫长的debug.
调试
网络架构
这张图显示的是linux的网络架构, 包括iptables的链条顺序、路由选择, 下面所有的调试都是基于这张图.
Docker
我知道Docker的网络建立在iptables上, 它一样使用虚拟桥接网卡连接各个容器, 然后在iptables添加规则进行NAT. 可是没理由它会影响到主机的网络, 我一条一条地查看Docker添加的防火墙规则, 唯一异常的点是它将filter表的FORWARD默认策略改成了DROP. 但tproxy压根不会经过FORWARD, 路由规则会让流量进入本地协议栈.
根据架构图可以知道, 如果包进入了filter表的INPUT链, 那么说明流量已经过了路由选择, 即将进入本地协议栈. 如果tproxy正常工作, 修改了包的结构体, 那么此时代理端口与包是相关联的, 所以包会被正常接收.
我开始猜测tproxy没有正常运作, 导致路由失败, 包被FORWARD出去了:
1
| iptables -t filter -I INPUT 1 -p udp -j LOG --log-prefix '** SUSPECT filter INPUT**'
|
我添加了一条iptables规则, 当匹配到包时会打印出日志, 于是我重复了一次DNS查询操作. 日志出现了, 所以我断定它已经走过了路由选择. 我又接着猜测了几种可能:
- tproxy关联包信息失败
- IP_TRANSPARENT属性失效
这两种情况我都没有有效的测试手段, 所以我陷入了困境, 不过我觉得原因大概率是docker-ce加载了某个内核模块. 于是我使用dpkg查看所有安装的包, 只发现了一个aufs.ko, 貌似不是很符合.
当我束手无策时, 我发现了这篇帖子TPROXY compatibility with Docker.
作者遇到了和我一样的问题, 于是它使用strace跟踪dockerd的系统调用, 发现它加载了一个内核模块”br_netfilter”. 我不抱任何希望的执行了”rmmod br_netfilter”, 它恢复了!!! 原来是这个br_netfilter的问题!!!
ebtables
这时我才仔细去观察上面的架构图, 我发现我遗漏了一个问题, 就是网桥的流量会走Link Layer, 所以可能是这部分出了问题. 图中的蓝色表代表的是ebtables, 绿色表代表iptables, ebtables可以理解成链路的iptables.
我想弄清楚流量的具体走向, 所以我在每个点都加上log规则, 数据包的流向将一览无遗:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| # raw iptables -t raw -I PREROUTING 1 -p udp -j LOG --log-prefix '** SUSPECT raw PREROUTING**' iptables -t raw -I OUTPUT 1 -p udp -j LOG --log-prefix '** SUSPECT raw OUTPUT**'
# mangle iptables -t mangle -I PREROUTING 1 -p udp -j LOG --log-prefix '** SUSPECT mangle PREROUTING**' iptables -t mangle -I INPUT 1 -p udp -j LOG --log-prefix '** SUSPECT mangle INPUT**' iptables -t mangle -I FORWARD 1 -p udp -j LOG --log-prefix '** SUSPECT mangle FORWARD**'
# nat iptables -t nat -I PREROUTING 1 -p udp -j LOG --log-prefix '** SUSPECT nat PREROUTING**' iptables -t nat -I INPUT 1 -p udp -j LOG --log-prefix '** SUSPECT nat INPUT**'
# filter iptables -t filter -I INPUT 1 -p udp -j LOG --log-prefix '** SUSPECT filter INPUT**' iptables -t filter -I FORWARD 1 -p udp -j LOG --log-prefix '** SUSPECT filter FORWARD**'
# BROUTING ebtables-legacy -t broute -A BROUTING -p ipv4 --ip-proto udp --log-level 6 --log-ip --log-prefix "TRACE: eb:broute:BROUTING" -j CONTINUE
# nat ebtables-legacy -t nat -A OUTPUT -p ipv4 --ip-proto udp --log-level 6 --log-ip --log-prefix "TRACE: eb:nat:OUTPUT" -j CONTINUE ebtables-legacy -t nat -A PREROUTING -p ipv4 --ip-proto udp --log-level 6 --log-ip --log-prefix "TRACE: eb:nat:PREROUTING" -j CONTINUE ebtables-legacy -t nat -A POSTROUTING -p ipv4 --ip-proto udp --log-level 6 --log-ip --log-prefix "TRACE: eb:nat:POSTROUTING" -j CONTINUE
# filter ebtables-legacy -t filter -A INPUT -p ipv4 --ip-proto udp --log-level 6 --log-ip --log-prefix "TRACE: eb:filter:INPUT" -j CONTINUE ebtables-legacy -t filter -A FORWARD -p ipv4 --ip-proto udp --log-level 6 --log-ip --log-prefix "TRACE: eb:filter:FORWARD" -j CONTINUE ebtables-legacy -t filter -A OUTPUT -p ipv4 --ip-proto udp --log-level 6 --log-ip --log-prefix "TRACE: eb:filter:OUTPUT" -j CONTINUE
|
在未加载br_netfilter的情况下, 我向8.8.8.8查询域名:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| TRACE: eb:broute:BROUTING IN=enp0s8 OUT= MAC source = 08:00:27:6d:c8:0b MAC dest = 08:00:27:9b:fa:c9 proto = 0x0800 IP SRC=192.168.12.192 IP DST=8.8.8.8, IP tos=0x00, IP proto=17 SPT=36289 DPT=53 TRACE: eb:nat:PREROUTING IN=enp0s8 OUT= MAC source = 08:00:27:6d:c8:0b MAC dest = 08:00:27:9b:fa:c9 proto = 0x0800 IP SRC=192.168.12.192 IP DST=8.8.8.8, IP tos=0x00, IP proto=17 SPT=36289 DPT=53 TRACE: eb:filter:INPUT IN=enp0s8 OUT= MAC source = 08:00:27:6d:c8:0b MAC dest = 08:00:27:9b:fa:c9 proto = 0x0800 IP SRC=192.168.12.192 IP DST=8.8.8.8, IP tos=0x00, IP proto=17 SPT=36289 DPT=53 ** SUSPECT raw PREROUTING**IN=br0 OUT= MAC=08:00:27:9b:fa:c9:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=8.8.8.8 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=24626 PROTO=UDP SPT=36289 DPT=53 LEN=46 ** SUSPECT mangle PREROUTING*IN=br0 OUT= MAC=08:00:27:9b:fa:c9:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=8.8.8.8 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=24626 PROTO=UDP SPT=36289 DPT=53 LEN=46 ** SUSPECT nat PREROUTING**IN=br0 OUT= MAC=08:00:27:9b:fa:c9:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=8.8.8.8 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=24626 PROTO=UDP SPT=36289 DPT=53 LEN=46 MARK=0x162 ** SUSPECT mangle INPUT**IN=br0 OUT= MAC=08:00:27:9b:fa:c9:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=8.8.8.8 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=24626 PROTO=UDP SPT=36289 DPT=53 LEN=46 MARK=0x162 ** SUSPECT filter INPUT**IN=br0 OUT= MAC=08:00:27:9b:fa:c9:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=8.8.8.8 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=24626 PROTO=UDP SPT=36289 DPT=53 LEN=46 MARK=0x162 ** SUSPECT nat INPUT**IN=br0 OUT= MAC=08:00:27:9b:fa:c9:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=8.8.8.8 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=24626 PROTO=UDP SPT=36289 DPT=53 LEN=46 MARK=0x162 ** SUSPECT raw OUTPUT**IN= OUT=enp0s3 SRC=10.0.2.15 DST=10.91.0.1 LEN=57 TOS=0x00 PREC=0x00 TTL=64 ID=56764 DF PROTO=UDP SPT=45711 DPT=53 LEN=37 ** SUSPECT raw OUTPUT**IN= OUT=enp0s3 SRC=10.0.2.15 DST=10.91.0.1 LEN=57 TOS=0x00 PREC=0x00 TTL=64 ID=56765 DF PROTO=UDP SPT=59060 DPT=53 LEN=37 ** SUSPECT raw PREROUTING**IN=enp0s3 OUT= MAC=08:00:27:4f:1e:2b:52:54:00:12:35:02:08:00 SRC=10.91.0.1 DST=10.0.2.15 LEN=114 TOS=0x00 PREC=0x00 TTL=64 ID=1722 PROTO=UDP SPT=53 DPT=45711 LEN=94 ** SUSPECT mangle PREROUTING*IN=enp0s3 OUT= MAC=08:00:27:4f:1e:2b:52:54:00:12:35:02:08:00 SRC=10.91.0.1 DST=10.0.2.15 LEN=114 TOS=0x00 PREC=0x00 TTL=64 ID=1722 PROTO=UDP SPT=53 DPT=45711 LEN=94 ** SUSPECT mangle INPUT**IN=enp0s3 OUT= MAC=08:00:27:4f:1e:2b:52:54:00:12:35:02:08:00 SRC=10.91.0.1 DST=10.0.2.15 LEN=114 TOS=0x00 PREC=0x00 TTL=64 ID=1722 PROTO=UDP SPT=53 DPT=45711 LEN=94 ** SUSPECT filter INPUT**IN=enp0s3 OUT= MAC=08:00:27:4f:1e:2b:52:54:00:12:35:02:08:00 SRC=10.91.0.1 DST=10.0.2.15 LEN=114 TOS=0x00 PREC=0x00 TTL=64 ID=1722 PROTO=UDP SPT=53 DPT=45711 LEN=94 ** SUSPECT raw PREROUTING**IN=enp0s3 OUT= MAC=08:00:27:4f:1e:2b:52:54:00:12:35:02:08:00 SRC=10.91.0.1 DST=10.0.2.15 LEN=73 TOS=0x00 PREC=0x00 TTL=64 ID=1723 PROTO=UDP SPT=53 DPT=59060 LEN=53 ** SUSPECT mangle PREROUTING*IN=enp0s3 OUT= MAC=08:00:27:4f:1e:2b:52:54:00:12:35:02:08:00 SRC=10.91.0.1 DST=10.0.2.15 LEN=73 TOS=0x00 PREC=0x00 TTL=64 ID=1723 PROTO=UDP SPT=53 DPT=59060 LEN=53 ** SUSPECT mangle INPUT**IN=enp0s3 OUT= MAC=08:00:27:4f:1e:2b:52:54:00:12:35:02:08:00 SRC=10.91.0.1 DST=10.0.2.15 LEN=73 TOS=0x00 PREC=0x00 TTL=64 ID=1723 PROTO=UDP SPT=53 DPT=59060 LEN=53 ** SUSPECT filter INPUT**IN=enp0s3 OUT= MAC=08:00:27:4f:1e:2b:52:54:00:12:35:02:08:00 SRC=10.91.0.1 DST=10.0.2.15 LEN=73 TOS=0x00 PREC=0x00 TTL=64 ID=1723 PROTO=UDP SPT=53 DPT=59060 LEN=53 ** SUSPECT raw OUTPUT**IN= OUT=br0 SRC=8.8.8.8 DST=192.168.12.192 LEN=98 TOS=0x00 PREC=0x00 TTL=64 ID=40027 DF PROTO=UDP SPT=53 DPT=36289 LEN=78 TRACE: eb:nat:OUTPUT IN= OUT=enp0s8 MAC source = 08:00:27:9b:fa:c9 MAC dest = 08:00:27:6d:c8:0b proto = 0x0800 IP SRC=8.8.8.8 IP DST=192.168.12.192, IP tos=0x00, IP proto=17 SPT=53 DPT=36289 TRACE: eb:filter:OUTPUT IN= OUT=enp0s8 MAC source = 08:00:27:9b:fa:c9 MAC dest = 08:00:27:6d:c8:0b proto = 0x0800 IP SRC=8.8.8.8 IP DST=192.168.12.192, IP tos=0x00, IP proto=17 SPT=53 DPT=36289 TRACE: eb:nat:POSTROUTING IN= OUT=enp0s8 MAC source = 08:00:27:9b:fa:c9 MAC dest = 08:00:27:6d:c8:0b proto = 0x0800 IP SRC=8.8.8.8 IP DST=192.168.12.192, IP tos=0x00, IP proto=17 SPT=53 DPT=36289
|
可以看到包先过了ebtables规则, 然后转入了iptables规则, 也就是包按层级从下到上. 此时的tproxy是正常工作的, 可能你会感到疑惑, 为什么本机向10.91.0.1发送了UDP. 其实是因为我使用了VPN, 所以这是在解析VPN服务器的域名, UDP的转发走的是VPN的TCP通道.
接着我加载了br_netfilter, 观察日志:
1 2 3 4 5 6 7 8 9
| TRACE: eb:broute:BROUTING IN=enp0s8 OUT= MAC source = 08:00:27:6d:c8:0b MAC dest = 08:00:27:9b:fa:c9 proto = 0x0800 IP SRC=192.168.12.192 IP DST=8.8.8.8, IP tos=0x00, IP proto=17 SPT=36003 DPT=53 TRACE: eb:nat:PREROUTING IN=enp0s8 OUT= MAC source = 08:00:27:6d:c8:0b MAC dest = 08:00:27:9b:fa:c9 proto = 0x0800 IP SRC=192.168.12.192 IP DST=8.8.8.8, IP tos=0x00, IP proto=17 SPT=36003 DPT=53 ** SUSPECT raw PREROUTING**IN=br0 OUT= PHYSIN=enp0s8 MAC=08:00:27:9b:fa:c9:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=8.8.8.8 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=35740 PROTO=UDP SPT=36003 DPT=53 LEN=46 ** SUSPECT mangle PREROUTING*IN=br0 OUT= PHYSIN=enp0s8 MAC=08:00:27:9b:fa:c9:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=8.8.8.8 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=35740 PROTO=UDP SPT=36003 DPT=53 LEN=46 ** SUSPECT nat PREROUTING**IN=br0 OUT= PHYSIN=enp0s8 MAC=08:00:27:9b:fa:c9:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=8.8.8.8 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=35740 PROTO=UDP SPT=36003 DPT=53 LEN=46 MARK=0x162 TRACE: eb:filter:INPUT IN=enp0s8 OUT= MAC source = 08:00:27:6d:c8:0b MAC dest = 08:00:27:9b:fa:c9 proto = 0x0800 IP SRC=192.168.12.192 IP DST=8.8.8.8, IP tos=0x00, IP proto=17 SPT=36003 DPT=53 ** SUSPECT mangle INPUT**IN=br0 OUT= PHYSIN=enp0s8 MAC=08:00:27:9b:fa:c9:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=8.8.8.8 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=35740 PROTO=UDP SPT=36003 DPT=53 LEN=46 MARK=0x162 ** SUSPECT filter INPUT**IN=br0 OUT= PHYSIN=enp0s8 MAC=08:00:27:9b:fa:c9:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=8.8.8.8 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=35740 PROTO=UDP SPT=36003 DPT=53 LEN=46 MARK=0x162 ** SUSPECT nat INPUT**IN=br0 OUT= PHYSIN=enp0s8 MAC=08:00:27:9b:fa:c9:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=8.8.8.8 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=35740 PROTO=UDP SPT=36003 DPT=53 LEN=46 MARK=0x162
|
这是什么情况??? 数据包在两个层级之间跳来跳去??? 我开始搜索相关资料, 原来这是br_netfilter提供的透明防火墙功能, 使得三层规则可以作用在二层上. 因为桥接的端口之间发送包是被网桥直接转走的, 不会走到本机的iptables中, 而br_netfilter使得ebtables主动调用iptables规则, 这样所有的包都能接受过滤.
谜底揭开了, 我看到的日志显示包已经到了filter表的INPUT, 可实际上它还没有过IP层路由选择, 它此时在二层ebtables的filter表中, 只不过它主动的调用了iptables. 也就是说这个包没有通过路由进入本地协议栈, 它被丢弃或者转走了. 大概是因为iptables打上的fwmark, 在ebtables中丢失了, 导致进行路由选择时无法命中我们添加的路由规则.
于是我看阅读ebtables的文档, 文档中说道, 在broute表中将流量DROP, 会使得包进入Network Layer处理, 这样就是图中broute有个箭头指到上层的含义.
1
| ebtables-legacy -t broute -A BROUTING -i enp0s8 -p ipv4 --ip-proto udp -j redirect --redirect-target DROP
|
我执行上面的命令后, 再执行查询操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| TRACE: eb:broute:BROUTING IN=enp0s8 OUT= MAC source = 08:00:27:6d:c8:0b MAC dest = 08:00:27:9b:fa:c9 proto = 0x0800 IP SRC=192.168.12.192 IP DST=8.8.8.8, IP tos=0x00, IP proto=17 SPT=47382 DPT=53 ** SUSPECT raw PREROUTING**IN=enp0s8 OUT= MAC=08:00:27:ae:7d:59:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=8.8.8.8 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=25647 PROTO=UDP SPT=47382 DPT=53 LEN=46 ** SUSPECT mangle PREROUTING*IN=enp0s8 OUT= MAC=08:00:27:ae:7d:59:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=8.8.8.8 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=25647 PROTO=UDP SPT=47382 DPT=53 LEN=46 ** SUSPECT nat PREROUTING**IN=enp0s8 OUT= MAC=08:00:27:ae:7d:59:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=8.8.8.8 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=25647 PROTO=UDP SPT=47382 DPT=53 LEN=46 MARK=0x162 ** SUSPECT mangle INPUT**IN=enp0s8 OUT= MAC=08:00:27:ae:7d:59:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=8.8.8.8 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=25647 PROTO=UDP SPT=47382 DPT=53 LEN=46 MARK=0x162 ** SUSPECT filter INPUT**IN=enp0s8 OUT= MAC=08:00:27:ae:7d:59:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=8.8.8.8 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=25647 PROTO=UDP SPT=47382 DPT=53 LEN=46 MARK=0x162 ** SUSPECT nat INPUT**IN=enp0s8 OUT= MAC=08:00:27:ae:7d:59:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=8.8.8.8 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=25647 PROTO=UDP SPT=47382 DPT=53 LEN=46 MARK=0x162 ** SUSPECT raw OUTPUT**IN= OUT=enp0s3 SRC=10.0.2.15 DST=10.91.0.1 LEN=57 TOS=0x00 PREC=0x00 TTL=64 ID=40282 DF PROTO=UDP SPT=54985 DPT=53 LEN=37 ** SUSPECT raw OUTPUT**IN= OUT=enp0s3 SRC=10.0.2.15 DST=10.91.0.1 LEN=57 TOS=0x00 PREC=0x00 TTL=64 ID=40283 DF PROTO=UDP SPT=37997 DPT=53 LEN=37 ** SUSPECT raw PREROUTING**IN=enp0s3 OUT= MAC=08:00:27:4f:1e:2b:52:54:00:12:35:02:08:00 SRC=10.91.0.1 DST=10.0.2.15 LEN=73 TOS=0x00 PREC=0x00 TTL=64 ID=4012 PROTO=UDP SPT=53 DPT=37997 LEN=53 ** SUSPECT mangle PREROUTING*IN=enp0s3 OUT= MAC=08:00:27:4f:1e:2b:52:54:00:12:35:02:08:00 SRC=10.91.0.1 DST=10.0.2.15 LEN=73 TOS=0x00 PREC=0x00 TTL=64 ID=4012 PROTO=UDP SPT=53 DPT=37997 LEN=53 ** SUSPECT mangle INPUT**IN=enp0s3 OUT= MAC=08:00:27:4f:1e:2b:52:54:00:12:35:02:08:00 SRC=10.91.0.1 DST=10.0.2.15 LEN=73 TOS=0x00 PREC=0x00 TTL=64 ID=4012 PROTO=UDP SPT=53 DPT=37997 LEN=53 ** SUSPECT filter INPUT**IN=enp0s3 OUT= MAC=08:00:27:4f:1e:2b:52:54:00:12:35:02:08:00 SRC=10.91.0.1 DST=10.0.2.15 LEN=73 TOS=0x00 PREC=0x00 TTL=64 ID=4012 PROTO=UDP SPT=53 DPT=37997 LEN=53 ** SUSPECT raw PREROUTING**IN=enp0s3 OUT= MAC=08:00:27:4f:1e:2b:52:54:00:12:35:02:08:00 SRC=10.91.0.1 DST=10.0.2.15 LEN=114 TOS=0x00 PREC=0x00 TTL=64 ID=4018 PROTO=UDP SPT=53 DPT=54985 LEN=94 ** SUSPECT mangle PREROUTING*IN=enp0s3 OUT= MAC=08:00:27:4f:1e:2b:52:54:00:12:35:02:08:00 SRC=10.91.0.1 DST=10.0.2.15 LEN=114 TOS=0x00 PREC=0x00 TTL=64 ID=4018 PROTO=UDP SPT=53 DPT=54985 LEN=94 ** SUSPECT mangle INPUT**IN=enp0s3 OUT= MAC=08:00:27:4f:1e:2b:52:54:00:12:35:02:08:00 SRC=10.91.0.1 DST=10.0.2.15 LEN=114 TOS=0x00 PREC=0x00 TTL=64 ID=4018 PROTO=UDP SPT=53 DPT=54985 LEN=94 ** SUSPECT filter INPUT**IN=enp0s3 OUT= MAC=08:00:27:4f:1e:2b:52:54:00:12:35:02:08:00 SRC=10.91.0.1 DST=10.0.2.15 LEN=114 TOS=0x00 PREC=0x00 TTL=64 ID=4018 PROTO=UDP SPT=53 DPT=54985 LEN=94 ** SUSPECT raw OUTPUT**IN= OUT=br0 SRC=8.8.8.8 DST=192.168.12.192 LEN=98 TOS=0x00 PREC=0x00 TTL=64 ID=26403 DF PROTO=UDP SPT=53 DPT=47382 LEN=78 TRACE: eb:nat:OUTPUT IN= OUT=enp0s8 MAC source = 08:00:27:9b:fa:c9 MAC dest = 08:00:27:6d:c8:0b proto = 0x0800 IP SRC=8.8.8.8 IP DST=192.168.12.192, IP tos=0x00, IP proto=17 SPT=53 DPT=47382 TRACE: eb:filter:OUTPUT IN= OUT=enp0s8 MAC source = 08:00:27:9b:fa:c9 MAC dest = 08:00:27:6d:c8:0b proto = 0x0800 IP SRC=8.8.8.8 IP DST=192.168.12.192, IP tos=0x00, IP proto=17 SPT=53 DPT=47382 TRACE: eb:nat:POSTROUTING IN= OUT=enp0s8 MAC source = 08:00:27:9b:fa:c9 MAC dest = 08:00:27:6d:c8:0b proto = 0x0800 IP SRC=8.8.8.8 IP DST=192.168.12.192, IP tos=0x00, IP proto=17 SPT=53 DPT=47382
|
可以看到包的确被重定向到了Network Layer, tproxy也正常工作了.
尾声
正当我以为一切都结束了的时候, 我打开了斗鱼直播, 可浏览器却显示网络异常, 我又上不了网了. 我在终端进行ping测试, IP可以ping通而域名不行, 这样看来是DNS的问题.
1
| dig baidu.com @192.168.12.1
|
命令卡住了, 难道发往本地的包重定向到Network Layer就被拒收了? 我又开始观察ebtables/iptables的日志输出:
1 2 3 4 5 6 7
| TRACE: eb:broute:BROUTING IN=enp0s8 OUT= MAC source = 08:00:27:6d:c8:0b MAC dest = 08:00:27:9b:fa:c9 proto = 0x0800 IP SRC=192.168.12.192 IP DST=192.168.12.1, IP tos=0x00, IP proto=17 SPT=34741 DPT=53 ** SUSPECT raw PREROUTING**IN=enp0s8 OUT= MAC=08:00:27:ae:7d:59:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=192.168.12.1 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=7347 PROTO=UDP SPT=34741 DPT=53 LEN=46 ** SUSPECT mangle PREROUTING*IN=enp0s8 OUT= MAC=08:00:27:ae:7d:59:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=192.168.12.1 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=7347 PROTO=UDP SPT=34741 DPT=53 LEN=46 ** SUSPECT nat PREROUTING**IN=enp0s8 OUT= MAC=08:00:27:ae:7d:59:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=192.168.12.1 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=7347 PROTO=UDP SPT=34741 DPT=53 LEN=46 ** SUSPECT mangle INPUT**IN=enp0s8 OUT= MAC=08:00:27:ae:7d:59:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=192.168.12.1 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=7347 PROTO=UDP SPT=34741 DPT=53 LEN=46 ** SUSPECT filter INPUT**IN=enp0s8 OUT= MAC=08:00:27:ae:7d:59:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=192.168.12.1 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=7347 PROTO=UDP SPT=34741 DPT=53 LEN=46 ** SUSPECT nat INPUT**IN=enp0s8 OUT= MAC=08:00:27:ae:7d:59:08:00:27:6d:c8:0b:08:00 SRC=192.168.12.192 DST=192.168.12.1 LEN=66 TOS=0x00 PREC=0x00 TTL=64 ID=7347 PROTO=UDP SPT=34741 DPT=53 LEN=46
|
数据包已经进入了INPUT, 这次的确是进入了本地协议栈, 但是需要注意数据包的IN网卡已经从桥接网卡bro变成了真实网卡端口enp0s8. 难道是因为这个改变, 而被协议栈拒收? 还是因为dnsmasq没有bind该网卡?
我手动使用nc进行测试:
使用nc监听软路由上3000端口, 然后在电脑上执行:
1
| dig baidu.com @192.168.12.1 -p 3000
|
如果数据能被接收, nc会打印出DNS查询报文, 结果令我诧异, nc打印出了报文内容. 那么看来即使IN interface被修改, 数据包依旧能够被正确接收.
最后我使用strace追踪dnsmasq的系统调用:
执行查询后, 我发现dnsmasq接收到了报文, 只是它似乎获取了网卡名称bro与enp0s8, 应该是它进行了网卡校验, 认为请求不应该由enp0s8流入, 所以没有进行回应.
总结
为了不影响Docker的正常使用, 我没有将所有Link Layer流量进行重定向, 放行了一些常见内网IP网段.
所以我最后的ebtables/iptables配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| #!/bin/sh # tcp iptables -t nat -N CLASH iptables -t nat -A CLASH -d 127.0.0.0/8 -j RETURN iptables -t nat -A CLASH -d 10.0.0.0/8 -j RETURN iptables -t nat -A CLASH -d 169.254.0.0/16 -j RETURN iptables -t nat -A CLASH -d 192.168.0.0/16 -j RETURN iptables -t nat -A CLASH -d 224.0.0.0/4 -j RETURN iptables -t nat -A CLASH -d 240.0.0.0/4 -j RETURN iptables -t nat -A CLASH -d 172.16.0.0/12 -j RETURN iptables -t nat -A CLASH -d 255.255.255.255 -j RETURN iptables -t nat -A CLASH -p tcp -j REDIRECT --to-ports 7892 iptables -t nat -A PREROUTING -p tcp -j CLASH
# udp ip rule add fwmark 0x162 table 0x162 ip route add local 0.0.0.0/0 dev lo table 0x162 iptables -t mangle -N CLASH iptables -t mangle -A CLASH -d 127.0.0.0/8 -j RETURN iptables -t mangle -A CLASH -d 10.0.0.0/8 -j RETURN iptables -t mangle -A CLASH -d 169.254.0.0/16 -j RETURN iptables -t mangle -A CLASH -d 192.168.0.0/16 -j RETURN iptables -t mangle -A CLASH -d 224.0.0.0/4 -j RETURN iptables -t mangle -A CLASH -d 240.0.0.0/4 -j RETURN iptables -t mangle -A CLASH -d 172.16.0.0/12 -j RETURN iptables -t mangle -A CLASH -d 255.255.255.255 -j RETURN iptables -t mangle -A CLASH -p udp -j TPROXY --on-port 7892 --tproxy-mark 0x162 iptables -t mangle -A PREROUTING -p udp -j CLASH
ebtables-legacy -t broute -A BROUTING -p ipv4 --ip-proto udp --ip-destination 127.0.0.0/8 -j ACCEPT ebtables-legacy -t broute -A BROUTING -p ipv4 --ip-proto udp --ip-destination 10.0.0.0/8 -j ACCEPT ebtables-legacy -t broute -A BROUTING -p ipv4 --ip-proto udp --ip-destination 169.254.0.0/16 -j ACCEPT ebtables-legacy -t broute -A BROUTING -p ipv4 --ip-proto udp --ip-destination 192.168.0.0/16 -j ACCEPT ebtables-legacy -t broute -A BROUTING -p ipv4 --ip-proto udp --ip-destination 224.0.0.0/4 -j ACCEPT ebtables-legacy -t broute -A BROUTING -p ipv4 --ip-proto udp --ip-destination 240.0.0.0/4 -j ACCEPT ebtables-legacy -t broute -A BROUTING -p ipv4 --ip-proto udp --ip-destination 172.16.0.0/12 -j ACCEPT ebtables-legacy -t broute -A BROUTING -p ipv4 --ip-proto udp --ip-destination 255.255.255.255 -j ACCEPT ebtables-legacy -t broute -A BROUTING -p ipv4 --ip-proto udp -j redirect --redirect-target DROP
|
有一点需要注意, ebtables规则不需要”-i name”指定网卡名称, 因为理论上docker容器与个人电脑(连接软路由LAN口)处于同一网络层面. 不管是LAN口网桥还是docker网桥, 都需要适配该规则, 否则UDP透明代理将失败.