技术解析

IPTABLES UDP 端口转发疑惑
0
2021-06-12 00:54:42
idczone

在 centos7 拉取 github 源码编译经常连不上,找了许多资料发现透明代理比较合适。

一番折腾 TCP 终于正常转发,UDP 如果配置 PREROUTING 就没任何转发效果,配置成 OUTPUT 可以转发不过报文不对:

;; reply from unexpected source: 192.168.0.101#1080, expected 119.29.29.29#53

求大佬帮忙

#!/usr/bin/env bash

start() {
    stop

    iptables -t nat -A OUTPUT -p tcp -m mark --mark 0x255 -j ACCEPT
    iptables -t nat -A OUTPUT -p udp -m mark --mark 0x255 -j ACCEPT

    # tcp
    iptables -t nat -A OUTPUT -p tcp -j REDIRECT --to-ports 1080

    # udp
    # ip rule add fwmark 0x2333/0x2333 pref 100 table 100
    # ip route add local default dev lo table 100
    # iptables -t mangle -A PREROUTING -p udp --dport 53 -j TPROXY --tproxy-mark 0x2333/0x2333 --on-ip 127.0.0.1 --on-port 1080
    # --dport 53

    # iptables -t nat -A PREROUTING -p udp --dport 53 -j DNAT --to 192.168.6.10

    iptables -t nat -A OUTPUT -p udp --dport 53 -j REDIRECT --to-ports 1080
}

stop() {
    iptables -t nat -F
    iptables -t mangle -F
    iptables -F
    iptables -X
    ip rule delete fwmark 0x2333/0x2333 pref 100 tab大带宽服务器le 100 &>/dev/null
    ip route delete local default dev lo table 100 &>/dev/null
}

if [[ $1 == "start" ]]; then
    start
elif [[ $1 == "stop" ]]; then
    stop
fi

iptables dnat 转发 udp 好像会丢失转发前的地址和端口
shadowsocks-libev 项目上有提供使用内核的 tproxy 来转发 udp 的方法

把 DNAT 都换成 REDIRECT 吧,至少 REDIRECT 到本机后接收到包的进程可以获取 SO_ORIGINAL_DST 来帮你转发

谢谢抽空解答 ^_^
ss 提供的 tproxy udp 解决方案似乎只能用于“路由器”或将 Linux 作为路由器使用,不适用于透明代理当前 Linux 对外发包,ss 代码倒没问题,就是防火墙没配对。
REDIRECT 可以成功重定向到本机端口,代理程序也可以收到数据包,但是回复后防火墙似乎没正确转换。
比如我查询:dig www.baidu.com ,会得到以下错误报告:预期收到来自 119.29.29.29:53 的 udp 答复,但收到了 192.168.0.101:1080 的
```
;; reply from unexpected source: 192.168.0.101expected 119.29.29.29/>```
```
{
stop
iptables -t nat -A OUTPUT -p tcp -m mark --mark 0x255 -j ACCEPT
iptables -t mangle -A OUTPUT -p udp -m mark --mark 0x255 -j ACCEPT
tcp
iptables -t nat -A OUTPUT -p tcp -j REDIRECT --to-ports 1080
udp
ip rule add fwmark 1 lookup 100
ip route add local default dev lo table 100
iptables -t mangle -A OUTPUT -p udp --dport 53 -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -p udp --dport 53 -j TPROXY --on-ip 127.0.0.1 --on-port 1080 --tproxy-mark 0x01/0x01
iptables -t nat -L -nvx
iptables -t mangle -L -nvx
}
stop() {
iptables -t nat -F
iptables -t mangle -F
iptables -F
iptables -X
ip rule delete fwmark 1 lookup 100 &>/dev/null
ip route delete local default dev lo table 100 &>/dev/null
}
if [[ $1 == "start" ]]; then
start
elif [[ $1 == "stop" ]]; then
stop
fi
```

有些眉目了:
当转发到本地代理程序之后,需要在程序中通过 recvmsg 接受 udp 数据,并传入结构体 msghdr 以填充具体信息。
然后再从 msghdr 中查找原始目的地信息,如 119.29.29.29 。
当要回复 udp 给客户端时,新建 socket 并 bind 到原始目的地( 119.29.29.29 ),然后再 send 给客户端。
据测试 macOS pf udp 转发不需要这样处理,直接 send 给 client 就好了。

配置 http_proxy 和 https_proxy 就可以了吧

数据地带为您的网站提供全球顶级IDC资源
在线咨询
专属客服