Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
acess
V2EX  ›  Linux

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

  •  
  •   acess · Mar 9, 2018 via Android · 8129 views
    This topic created in 2988 days ago, the information mentioned may be changed or developed.
    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 似乎是空的。
    Supplement 1  ·  Mar 10, 2018
    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
    Supplement 2  ·  Mar 12, 2018
    我是一个人么?有没有其他人碰到过这个问题,或者说可以重现这个问题?
    26 replies    2018-03-12 21:34:03 +08:00
    parametrix
        1
    parametrix  
       Mar 9, 2018 via Android
    需要 tproxy 模块
    acess
        2
    acess  
    OP
       Mar 9, 2018 via Android
    @parametrix
    TPROXY 只能在 mangle 表的 PREROUTING 链上使用(其实这台路由也已经用上了),不能对本机生效吧。
    acess
        3
    acess  
    OP
       Mar 9, 2018 via Android
    @parametrix 其实路由下的机器都已经能走 ss 了,就是路由器自己不能走 ss,很奇怪。
    parametrix
        4
    parametrix  
       Mar 9, 2018
    @acess 抱歉没审清楚题目,那么下面这个能工作么?

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

    正确的姿势是:
    dnsmasq 里面把上游 dns 指定为 127.0.0.1:5301,路由器和内网的 dns 就会都通过你的 ss-tunnel 查询了。
    parametrix
        12
    parametrix  
       Mar 9, 2018 via Android
    @acess 不行的话,你先尝试一下把其他自己添加的规则删掉,在一个干净的表上单独尝试这个规则,排除干扰的可能。此外你要不试一下把 ! -o lo 删掉?我还是没明白这个规则怎么改的出 Localhost
    parametrix
        13
    parametrix  
       Mar 9, 2018 via Android
    @acess 对了,WAN 口上默认是有 MASQUERADE 的吧?这可能是 WAN 口成功的原因。
    BOYPT
        14
    BOYPT  
       Mar 9, 2018
    OUTPUT 链是对已经经过路由后的数据包的过程,你在 OUTPUT 链修改后的地址,一样送给上级路由了,你本地是不可能收到的;
    想转发到本地,必须在 NAT 表的 PREROUTING 链里面改,改完后再经过路由,才会转发到本地。
    yiyiwa
        15
    yiyiwa  
       Mar 9, 2018
    我的 openwrt 没有用 ss, 用的 cow, 这个可以自动判断是否需要爬,墙。
    acess
        16
    acess  
    OP
       Mar 9, 2018 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
       Mar 9, 2018 via Android
    @BOYPT 我 tcpdump -i lo 抓包了,OpenWRT 症状如上述,另一台 Debian VPS 则没有问题。
    BOYPT
        18
    BOYPT  
       Mar 9, 2018


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

    DNS 请求这样转发给 ss tunnel 就行
    acess
        20
    acess  
    OP
       Mar 10, 2018 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
       Mar 10, 2018 via Android
    @azh7138m 打错……退而求其次,REDIRECT+ss-tunnel
    acess
        22
    acess  
    OP
       Mar 10, 2018 via Android
    @BOYPT 我其实没看懂你前一个回复的意思……不是本机发出的包走 OUTPUT、转发的包走 REROUTING,“井水不犯河水”么?
    acess
        23
    acess  
    OP
       Mar 10, 2018 via Android
    @BOYPT 又打错…… REROUTING=>PREROUTING
    BOYPT
        24
    BOYPT  
       Mar 10, 2018
    @acess 并不是,你看我发的图;
    PREROUTING 在路由选路前,不管是本地发出还是从外面转发的,进行路由选路前都匹配 PREROUTING (从名字也可以看出这个意思),所以 DNAT 过程都需要在这个链里完成,修改后的地址经过路由选路,才能往想要的地方去。
    pheyx
        25
    pheyx  
       Mar 10, 2018
    @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
       Mar 12, 2018 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 吧。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   5518 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 72ms · UTC 07:42 · PVG 15:42 · LAX 00:42 · JFK 03:42
    ♥ Do have faith in what you're doing.