V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
acess
V2EX  ›  Linux

iptables 不能重定向本机 DNS 请求到指定端口?

  •  
  •   acess · 2018-03-09 02:07:43 +08:00 via Android · 7448 次点击
    这是一个创建于 2211 天前的主题,其中的信息可能已经有所发展或是发生改变。
    OpenWRT Chaos Calmer
    Linux 3.18.27 mips
    运行 ss-tunnel,监听 0.0.0.0:5301,转发至 8.8.8.8:53
    先尝试添加这个 iptables 规则:
    iptables -t nat -A OUTPUT \! -o lo -p udp --dport 53 -j REDIRECT --to-port 5301
    结果居然不能用,nslookup 提示超时。
    这个时候,tcpdump -i lo 保存 pcap 文件,用 wireshark 打开,发现 DNS 请求包的目的 IP 和端口已经被改为 127.0.0.1:5301,但是 DNS 响应包的源 IP 和端口却还是[本机 WAN 口 IP]:5301(应该被修改为[程序使用的 DNS 服务器 IP]:53 才对吧?),紧跟着的下一个包就是拒绝掉这个 UDP 响应包的 ICMP port unreachable。

    然后删掉这个 iptables 规则,换用这一条:
    iptables -t nat -A OUTPUT \! -o lo -p udp --dport 53 -j DNAT --to-destination [本机 WAN 口 IP]:5301
    这下正常了。tcpdump 抓包,可以看到 DNS 请求包和响应包的目的 IP 端口 /源 IP 端口都被正确修改了。
    但是 WAN 口 IP 不固定啊……况且我的另一台 Debian VPS 上也在用这种 REDIRECT,没发现有这种怪毛病啊。

    iptables -t raw -L 似乎是空的。
    第 1 条附言  ·  2018-03-10 00:04:09 +08:00
    Debian VPS 的 uname -a
    Linux myvps 3.16.0-4-amd64 #1 SMP Debian 3.16.51-3 (2017-12-13) x86_64 GNU/Linux
    第 2 条附言  ·  2018-03-12 21:27:08 +08:00
    我是一个人么?有没有其他人碰到过这个问题,或者说可以重现这个问题?
    26 条回复    2018-03-12 21:34:03 +08:00
    parametrix
        1
    parametrix  
       2018-03-09 02:21:43 +08:00 via Android
    需要 tproxy 模块
    acess
        2
    acess  
    OP
       2018-03-09 02:30:11 +08:00 via Android
    @parametrix
    TPROXY 只能在 mangle 表的 PREROUTING 链上使用(其实这台路由也已经用上了),不能对本机生效吧。
    acess
        3
    acess  
    OP
       2018-03-09 02:36:12 +08:00 via Android
    @parametrix 其实路由下的机器都已经能走 ss 了,就是路由器自己不能走 ss,很奇怪。
    parametrix
        4
    parametrix  
       2018-03-09 03:25:17 +08:00
    @acess 抱歉没审清楚题目,那么下面这个能工作么?

    iptables -t nat -A OUTPUT \! -o lo -p udp --dport 53 -j DNAT --to-destination 127.0.0.1:5301
    parametrix
        5
    parametrix  
       2018-03-09 03:38:14 +08:00
    @acess 还有我没看懂,按说 REDIRECT 应该重定向到 incoming interface,你的第一行命令里已经 ! -o lo,为什么请求包会被定向到 127.0.0.1:5301?
    ThirdFlame
        6
    ThirdFlame  
       2018-03-09 07:24:56 +08:00
    你可以试试 lan 口 IP
    acess
        7
    acess  
    OP
       2018-03-09 11:52:46 +08:00 via Android
    @parametrix
    我在 Debian VPS 上抓包看了,确实是这样。
    @ThirdFlame
    试一下倒是可以,不过这很奇怪啊,难道是我这路由器里有别的什么奇怪的规则在捣鬼?我不信我还能碰到 bug。
    acess
        8
    acess  
    OP
       2018-03-09 11:56:34 +08:00 via Android
    @parametrix
    在 OUTPUT 里加入 REDIRECT 规则后,本机 DNS 请求包的目的 IP:端口被修改,变成 127.0.0.1:[REDIRECT 的目标端口];监听那个端口的是 dnsmasq,它发出的 DNS 响应包的源 IP:端口也被修改,变成[软件请求的 DNS 服务器]:53。
    acess
        9
    acess  
    OP
       2018-03-09 12:04:31 +08:00 via Android
    @ThirdFlame LAN 口 IP 也是一样的,不行……
    acess
        10
    acess  
    OP
       2018-03-09 12:07:08 +08:00 via Android
    @parametrix
    Debian VPS 上用这个 REDIRECT 是没问题的,抓包也能看到来回数据包都被正确修改了。但是这台 OpenWRT 路由器就不正常,抓包可以看到只有请求包被修改了,响应包没有被修改,然后就被 ICMP port unreachable 拒绝。
    mt7620
        11
    mt7620  
       2018-03-09 12:17:29 +08:00
    openwrt 下,路由和内网的默认 DNS 都是路由器上的 dnsmasq 监听的 53 端口。路由器本身并不直接使用运营商分配的 dns 服务器,和内网一样都要通过本机的 dnsmasq 绕一下,你失败的原因就是这个。

    正确的姿势是:
    dnsmasq 里面把上游 dns 指定为 127.0.0.1:5301,路由器和内网的 dns 就会都通过你的 ss-tunnel 查询了。
    parametrix
        12
    parametrix  
       2018-03-09 14:32:31 +08:00 via Android
    @acess 不行的话,你先尝试一下把其他自己添加的规则删掉,在一个干净的表上单独尝试这个规则,排除干扰的可能。此外你要不试一下把 ! -o lo 删掉?我还是没明白这个规则怎么改的出 Localhost
    parametrix
        13
    parametrix  
       2018-03-09 14:36:10 +08:00 via Android
    @acess 对了,WAN 口上默认是有 MASQUERADE 的吧?这可能是 WAN 口成功的原因。
    BOYPT
        14
    BOYPT  
       2018-03-09 14:36:53 +08:00
    OUTPUT 链是对已经经过路由后的数据包的过程,你在 OUTPUT 链修改后的地址,一样送给上级路由了,你本地是不可能收到的;
    想转发到本地,必须在 NAT 表的 PREROUTING 链里面改,改完后再经过路由,才会转发到本地。
    yiyiwa
        15
    yiyiwa  
       2018-03-09 15:56:46 +08:00
    我的 openwrt 没有用 ss, 用的 cow, 这个可以自动判断是否需要爬,墙。
    acess
        16
    acess  
    OP
       2018-03-09 16:35:38 +08:00 via Android
    @mt7620
    我知道 openwrt 用了 dnsmasq,然后内网机器从 DHCP 获取的 DNS 服务器就是它。然后,内网机器的 DNS 请求被这个 dnsmasq 接受、转发,不就是相当于路由器本机上跑的软件发了 DNS 请求了么?
    接下来不就是我碰到的问题了?
    我也装了编译好的 ipk 包(ss-libev 和 luci 插件两个包),然后,好像是通过 ss-rule 生成规则,但对 UDP 来说,ss-rule 只是加了一个 PREROUTING 的 TPROXY,然而内网的机器 DNS 服务器都是路由器上的这个 dnsmasq 啊,所以这个 TPROXY 基本上是废的。
    (ss-rule 还在 nat 表的 OUTPUT 链加了 REDIRECT,不过只对 tcp 生效)
    没记错的话,为了绕过这个问题,我一般是手动在 nat 表的 PREROUTING 链再加一条 REDIRECT 或 DNAT,把内网(不是本机)的 DNS 请求转到 ss-tunnel 上(然后实际上是绕过了这个 dnsmasq)。
    acess
        17
    acess  
    OP
       2018-03-09 16:37:42 +08:00 via Android
    @BOYPT 我 tcpdump -i lo 抓包了,OpenWRT 症状如上述,另一台 Debian VPS 则没有问题。
    BOYPT
        18
    BOYPT  
       2018-03-09 16:45:02 +08:00


    @acess #17 抓包没啥意义,不能显示出 iptables 的工作逻辑。你按着图里的逻辑排查吧。
    azh7138m
        19
    azh7138m  
       2018-03-10 09:28:12 +08:00 via Android
    dnsmasq
    server=/#/127.0.0.1#5301

    DNS 请求这样转发给 ss tunnel 就行
    acess
        20
    acess  
    OP
       2018-03-10 12:55:55 +08:00 via Android
    @mt7620
    其实也不能说路由器上的这个 TPROXY 是废的,因为其他 UDP 包(比如内网机器执行 nslookup qq.com 114.114.114.114 这种)还是会走这个 TPROXY 的。
    但是,路由器上跑的软件自己发出的 UDP 包就不会走这个 TPROXY 了(压根不会过 mangle PREROUTING 链),尤其是路由器上的那个 dnsmasq。

    @azh7138m 这是让 dnsmasq 直接把 ss-tunnel 当上级服务器么?这样也许可以绕过问题,不过我还是好奇为什么会出现这种怪状……
    换句话说,是我一个人碰到这个问题,还是很多人都能重复出来这个问题?
    从另一个方面说,万一我有个需求是让路由器上其他软件发的 UDP 包也走代理呢? TPROXY+ss-redir 看样子是解决不了这个问题了(因为本机发出的包没经过 mangle PREROUTING 链),退而求其次,REDIRECT+ss-local 居然也不行,这就蛋疼了……
    acess
        21
    acess  
    OP
       2018-03-10 12:57:27 +08:00 via Android
    @azh7138m 打错……退而求其次,REDIRECT+ss-tunnel
    acess
        22
    acess  
    OP
       2018-03-10 13:01:17 +08:00 via Android
    @BOYPT 我其实没看懂你前一个回复的意思……不是本机发出的包走 OUTPUT、转发的包走 REROUTING,“井水不犯河水”么?
    acess
        23
    acess  
    OP
       2018-03-10 13:02:08 +08:00 via Android
    @BOYPT 又打错…… REROUTING=>PREROUTING
    BOYPT
        24
    BOYPT  
       2018-03-10 17:01:10 +08:00
    @acess 并不是,你看我发的图;
    PREROUTING 在路由选路前,不管是本地发出还是从外面转发的,进行路由选路前都匹配 PREROUTING (从名字也可以看出这个意思),所以 DNAT 过程都需要在这个链里完成,修改后的地址经过路由选路,才能往想要的地方去。
    pheyx
        25
    pheyx  
       2018-03-10 22:05:19 +08:00
    @BOYPT man iptables:
    ....
    nat:
    This table is consulted when a packet that creates a new connection is encountered. It consists of four built-ins:

    PREROUTING (for altering packets as soon as they come in),
    INPUT (for altering packets destined for local sockets),
    OUTPUT (for altering **locally-generated** packets before routing),
    and POSTROUTING (for altering packets as they are about to go out).
    acess
        26
    acess  
    OP
       2018-03-12 21:34:03 +08:00 via Android
    @parametrix #13
    MASQUERADE 是 zone_wan_postrouting 里的,一个数据包需要走这个路径才能被 MASQUERADE:
    POSTROUTING->delegate_postrouting->zone_wan_postrouting
    但是,在 delegate_postrouting 那里有约束条件-o [WAN 口 iface] -j zone_wan_postrouting。
    因为 DNS 响应包是从 lo 发出的,所以压根就不会走到 zone_wan_postrouting 和后面的 MASQUERADE 吧。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5485 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 08:52 · PVG 16:52 · LAX 01:52 · JFK 04:52
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.