shadowsocks / shadowsocks-libev

Bug-fix-only libev port of shadowsocks. Future development moved to shadowsocks-rust
https://github.com/shadowsocks/shadowsocks-rust
GNU General Public License v3.0
15.79k stars 5.69k forks source link

The correct UDP iptables rule for ss-redir. #1666

Closed zw963 closed 7 years ago

zw963 commented 7 years ago

I found two version UDP rule for ss-redir, I have no idea which version to choose.

version1: From ss-redir.asciidoc#example

$: ip rule add fwmark 0x01/0x01 table 100
$: ip route add local 0.0.0.0/0 dev lo table 100
$: $ipt -A SHADOWSOCKS -p udp -j TPROXY --on-port 1082 --tproxy-mark 0x01/0x01

version2: From README.md#advanced-usage

root@Wrt:~# iptables -t mangle -N SHADOWSOCKS_MARK

root@Wrt:~# ip route add local default dev lo table 100
root@Wrt:~# ip rule add fwmark 1 lookup 100
root@Wrt:~# iptables -t mangle -A SHADOWSOCKS -p udp --dport 53 -j TPROXY --on-port 12345 --tproxy-mark 0x01/0x01
root@Wrt:~# iptables -t mangle -A SHADOWSOCKS_MARK -p udp --dport 53 -j MARK --set-mark 1
root@Wrt:~# iptables -t mangle -A OUTPUT -j SHADOWSOCKS_MARK

Thanks

zw963 commented 7 years ago

For use with router.

honwen commented 7 years ago

Refer: https://github.com/shadowsocks/luci-app-shadowsocks/tree/master/files/root/usr/bin

zw963 commented 7 years ago

@madeye , I see two guides, one is from README.md#advanced-usage, one is from ss-redir.asciidoc#example, I don't know which better.

zw963 commented 7 years ago

And what difference about following command

# ip rule add fwmark 0x01/0x01 table 100
# ip route add local 0.0.0.0/0 dev lo table 100
# ip rule add fwmark 1 lookup 100
# ip route add local default dev lo table 100

which is the correct choice for a asus router transparent proxy?

zw963 commented 7 years ago

Maybe show my problem is better than just ask why.

https://github.com/zw963/asuswrt-merlin-transparent-proxy/blob/master/route/opt/etc/iptables.sh

this is my iptables.sh rule for my AC5300, UDP rule is added recent days. I am not sure those UDP is worked as execpt, could anyone point out some improper/wrong usage? Or, maybe I missing some rule?

Thanks

zw963 commented 7 years ago

@chenhw2, @madeye , 谁有时间, 麻烦给解释一下, 先谢啦.

madeye commented 7 years ago

Try PREROUTING chain instead of OUTPUT chain.

zw963 commented 7 years ago

Try PREROUTING chain instead of OUTPUT chain.

What does you means?

https://github.com/zw963/asuswrt-merlin-transparent-proxy/blob/master/route/opt/etc/iptables.sh

I am not use OUTPUT chain, tcp and udp all apply with PREROUTING chains

overcache commented 7 years ago

看了你的规则, 谈一些看法, 抛砖引玉吧

# 这行代码为什么要开启?
# $ipt -I OUTPUT 1 -p tcp -j SHADOWSOCKS

这条开启后, 路由器自身也可以通过 ss 代理上网了, 不开启的话只有路由器下的设备能通过代理.

$ipt -A SHADOWSOCKS -p udp --dport 53 -j TPROXY --on-port 1082 --tproxy-mark 0x01/0x01

关于udp, 你就只有这条规则. 但是只对 53端口的 udp 才有效果. 如果你只想转发 DNS 查询到远端服务器, 还不如用 ss-tunnel

zw963 commented 7 years ago

@icymind

这条开启后, 路由器自身也可以通过 ss 代理上网了, 不开启的话只有路由器下的设备能通过代理.

谢, 这个和我理解一致.

关于udp, 你就只有这条规则. 但是只对 53端口的 udp 才有效果. 如果你只想转发 DNS 查询到远端服务器, 还不如用 ss-tunnel 呢

我有用 ss-tunnel, 我这里的 1082 的确就是 ss-tunnel 的端口, ss-redir 是 1080, 而且 ss-redir 没有开启 -u .

你的意思: 这条规则如果用 ss-tunnel, 是无用的吗?

overcache commented 7 years ago

如果你已经设置了 dnsmasq 将 dns 转发到 1082, 那么这条规则就是无用的.

zw963 commented 7 years ago

@icymind , 搞错啦, 我完全搞错啦, 谢谢提示, 难怪别人跟我反馈, 加了 UDP rule 之后, 反而 DNS 不能用了.

但是只对 53端口的 udp 才有效果.

这句话不是很明白.

假设我使用 ss-redir(不用 ss-tunnel 了), 并且开启了 dup relay, 也应用了这些 UDP rule,

我还需要配置 dnsmasq 的默认 DNS 吗? 例如: server=/#/8.8.4.4#53

$ipt -A SHADOWSOCKS -p udp -m set --match-set FREEWEB dst -j RETURN
$ipt -A SHADOWSOCKS -p udp --dport 53 -j TPROXY --on-port 1080 --tproxy-mark 0x01/0x01

我的本意: 如果是白名单(FREEWEB)中的域名, 直接返回, 不是白名单的(国外的)域名, 走 ss-redir (1080 端口)

overcache commented 7 years ago

但是只对 53端口的 udp 才有效果.

我的意思是你的这条规则$ipt -A SHADOWSOCKS -p udp --dport 53 -j TPROXY --on-port 1080 --tproxy-mark 0x01/0x01只匹配 53 端口的 udp (-p udp --dport 53), 对匹配到的包打标记.

如果 udp 能转发成功, 那就不需要了. 但是你确定要所有的 dns 查询都发送给服务器查询吗? 那样的话国内的网站可能会解析到一个比较慢的地址.

如果你想转发 53 端口之外的 UDP, 那就需要.

zw963 commented 7 years ago

@icymind ,

对匹配到的包打标记.

这里打了标记, 怎么用呢? 是不是和下面的两行一起工作?

# ip rule add fwmark 0x01/0x01 table 100
# ip route add local 0.0.0.0/0 dev lo table 100
overcache commented 7 years ago

是的. 按我的理解, 大概意思是:

添加一个 id 是 100 的路由表, 该表的数据默认从 lo 回环设备发送出去

对标记是 0x01/0x01 的数据包, 查询 id 是 100 的路由表, 根据路由表的内容决定他的路径.

至于路由表100里是什么内容, 我就不知道了. 我没看到有任何规则往里面添加内容呢

zw963 commented 7 years ago

@icymind , 标记那个懂了, 谢谢.

不过, 有关 ss-redir 现在已经完全晕了.

下面是手动启动 ss-redir, 开启 udp relay 支持, 和另一个 ss-tunnel.

# ss-redir -u -c /opt/etc/shadowsocks.json -vvv
 2017-09-05 10:57:26 INFO: initializing ciphers... aes-256-cfb
 2017-09-05 10:57:26 INFO: UDP relay enabled
 2017-09-05 10:57:26 INFO: listening at 192.168.50.1:1080
 2017-09-05 10:57:26 INFO: running from root user
# ss-tunnel -c /opt/etc/shadowsocks.json -b 127.0.0.1 -l 1082 -L 8.8.4.4:53 -u
 2017-09-05 11:04:43 INFO: initializing ciphers... aes-256-cfb
 2017-09-05 11:04:43 INFO: UDP relay enabled
 2017-09-05 11:04:43 INFO: listening at 127.0.0.1:1082
 2017-09-05 11:04:43 INFO: running from root user

然后, 在路由器里面, dig -p 1082 www.google.de 返回正确结果 (ss-tunnel) dig -p 1080 www.google.de 就没有结果.(ss-redir)

这是不是不正常啊?

zw963 commented 7 years ago

事实上 , 1080 端口(ss-redir) 日志一点反应都没有, 仿佛没有收到 udp 请求.

admin@RT-AC5300-5E70:/tmp/home/root# dig www.google.de -p 1080

; <<>> DiG 9.10.5 <<>> www.google.de -p 1080
;; global options: +cmd
;; connection timed out; no servers could be reached
zw963 commented 7 years ago

@icymind , 看样子就没有监听 udp 的端口, 請指教.

admin@RT-AC5300-5E70:/tmp/mnt/sda1/entware/etc# netstat -an |grep 1080
tcp        0      0 192.168.50.1:1080       0.0.0.0:*               LISTEN      
udp        0      0 192.168.50.1:1080       0.0.0.0:* 
overcache commented 7 years ago
  1. 监听了. 只不过 udp 没有 LISTEN 字样罢了.

  2. 另外你监听的是 192.168.50.1:1080, 并没有监听 127.0.0.1, 建议监听 0.0.0.0

  3. 即使你监听了 127.0.0.1, dig -p 1080 www.google.de 也不会有预期的结果. 我的理解是这样(可能是错的):

dig时, 产生一个目标地址是127.0.0.1:1080的UDP包, ss-redir 拿到了这个包, 然后用ss协议封装后发送到了服务器. 服务器打开封包, 发现地址是 127.0.0.1:1080, 然后就发送到了服务器的 1080 端口, 并不会解析. 如果你只想看 ss-redir 日志有没有变化, 那倒是一个可行的办法.

如果你想验证 ss-redir 能不能查询 dns, 应该:

旧文 一篇, 希望能帮助你理解. 没问题就关闭 issues 吧

zw963 commented 7 years ago

@icymind, 那篇文章链接有错. :smile:

zw963 commented 7 years ago

好吧, 我发现我刚刚收藏了你的文章! 哈哈. https://icymind.com/learn-from-gfw/

而且下午我还推荐给 issue #1667 看, 如果是这篇的话, 我已经拜读过了!

zw963 commented 7 years ago

即使你监听了 127.0.0.1, dig -p 1080 www.google.de 也不会有预期的结果. 好像是的, 重启后, 验证了下. (如果没错的话)

参照你那篇文章的例子:

  1. dnsmasq 添加选项:
server=/#/8.8.8.8#53
  1. 添加 rule, 把 8.8.8.8 udp 转发到 1080
iptables -t nat -A OUTPUT -p tcp --dport 53 -d 8.8.8.8 -j REDIRECT --to-port 1080
iptables -t nat -A OUTPUT -p udp --dport 53 -d 8.8.8.8 -j REDIRECT --to-port 1080
  1. dig 失败
    ; <<>> DiG 9.10.5 <<>> @8.8.8.8 www.google.de
    ; (1 server found)
    ;; global options: +cmd
    ;; connection timed out; no servers could be reached
zw963 commented 7 years ago

@icymind, 你在 https://icymind.com/learn-from-gfw/ 中的测试结果, 是在路由器上吗?

真是奇了怪了.

zw963 commented 7 years ago

哎, 不做死了, 我还是 ss-redir + ss-tunnel 凑合着用吧.

真的是 : 不懂原理出了问题简直就像傻逼似的, 根本就没法解决。 ...

@icymind, 最后一个问题, 一切根源的始作俑者是因为这个 issue.

https://github.com/shadowsocks/shadowsocks-libev/issues/1632

当时看 Youtube 速度超级慢, 然后, @madeye 答复说, 可能是 udp relay 的问题,

答复如下:

As mentioned above, it's caused by QUIC and UDP relay. Two possible solutions:

    Disable QUIC in Chrome. (Search the issue tracker for more details)
    Follow the script of OpenWRT (TPROXY kernel module is required) or flash your router to OpenWRT instead.

好吧, 麻烦 @madeye 再回答一下, 当时你说的 udp relay 问题, 是指的 ss-redir 的 udp relay + iptables 问题, 还是说 ss-tunnel 的 udp relay 问题?

是不是我这种 ss-redir + ss-tunnel 的方案就没有你说的问题?

zw963 commented 7 years ago

@icymind, 有空也指教下. 哈

overcache commented 7 years ago

ss-tunnel 只转发 DNS, Youtube 的 QUIC协议不关 ss-tunnel 的事. 关掉 Chrome 的 QUIC 最省事.

不想折腾这些原理的话, 不妨试试 VRouter 😄

baggiogogo commented 7 years ago

确认下是否quic的问题,y2be时检查是否走了udp443,也就是通常所说的直连,没有经过ss。

是的话简单解决即可(不用mangle用nat也应该可以,10800为随意未使用的端口): iptables -t mangle -A PREROUTING -p udp -m set --match-set youtube dst -j TPROXY --on-port 10800 --tproxy-mark 0x01/0x01

dnsmasq.d中加入ipset文件youtube.conf ipset=/.googlevideo.com/youtube

zw963 commented 7 years ago

@baggiogogo ,

是的话简单解决即可(不用mangle用nat也应该可以,10800为随意未使用的端口): iptables -t mangle -A PREROUTING -p udp -m set --match-set youtube dst -j TPROXY --on-port 10800 --tproxy-mark 0x01/0x01

这里 10800 是 ss-tunnel 端口还是 ss-redir 端口呢?

zw963 commented 7 years ago

不想折腾这些原理的话, 不妨试试 VRouter 😄

Cool, 我不用 Mac, 不过 Linux 是不是应该更简单了, 连 VirtualBox 都不要了?

zw963 commented 7 years ago

@chenhw2, @madeye , 劳烦, 你们谁在有空的时候, 能讲一下 $ipt -A SHADOWSOCKS -p udp --dport 53 -j TPROXY --on-port 1082 --tproxy-mark 0x01/0x01 从前面的讨论来看, 这行代码是对匹配的包打了一些标记, 这个应该是没有问题的, 但是打了标记, 我们又能干啥? 这行代码的真实用意到底是做什么的?

似乎整个 shadowsocks 缺乏对这个的讨论, 每个人提到这个, 都讳莫如深的感觉, 或者给一些完全看不懂变量名啥意思的代码供参考, 没有头绪啊, 我想要解释, 五句话以内应该能讲清楚吧 ...

@chenhw2 , 请问, 这里面的哪一条 rule, 跟之前打标记的那个 UDP rule 有关?

include_ac_rules() {
    local protocol=$([ "$1" = "mangle" ] && echo udp || echo tcp)
    iptables-restore -n <<-EOF
    *$1
    :SS_SPEC_LAN_DG - [0:0]
    :SS_SPEC_LAN_AC - [0:0]
    :SS_SPEC_WAN_AC - [0:0]
    :SS_SPEC_WAN_FW - [0:0]
    -A SS_SPEC_LAN_DG -m set --match-set ss_spec_dst_sp dst -j RETURN
    -A SS_SPEC_LAN_DG -p $protocol $EXT_ARGS -j SS_SPEC_LAN_AC
    -A SS_SPEC_LAN_AC -m set --match-set ss_spec_src_bp src -j RETURN
    -A SS_SPEC_LAN_AC -m set --match-set ss_spec_src_fw src -j SS_SPEC_WAN_FW
    -A SS_SPEC_LAN_AC -m set --match-set ss_spec_src_ac src -j SS_SPEC_WAN_AC
    -A SS_SPEC_LAN_AC -j ${LAN_TARGET:=SS_SPEC_WAN_AC}
    -A SS_SPEC_WAN_AC -m set --match-set ss_spec_dst_fw dst -j SS_SPEC_WAN_FW
    -A SS_SPEC_WAN_AC -m set --match-set ss_spec_dst_bp dst -j RETURN
    -A SS_SPEC_WAN_AC -j SS_SPEC_WAN_FW
    $(gen_prerouting_rules $protocol)
    COMMIT
EOF
}
odkrys commented 7 years ago

@zw963 To use ss-redir udp relay with ASUS, you have to change 1 rule,

ss-redir.json

{
    "server":"VPS IP",
    "server_port":VPS PORT,
    "local_address":"192.168.1.1",
    "local_port":1080,
    "password":"password",
    "method":"chacha20-ietf-poly1305",
    "timeout":60
}

iptables rule

iptables -t mangle -A SHADOWSOCKS -p udp -m set --match-set gfwlist dst -j TPROXY --on-ip 192.168.1.1 --on-port 1080 --tproxy-mark 0x01/0x01

--on-ip 192.168.1.1 is a point.

zw963 commented 7 years ago

@odkrys, Hi, Your example use a black list (gfwlist), But, I use a white list.

Following is my rule, FREEWEB is whitelist which can access directly from china.

ipset -N FREEWEB iphash
iptables -t mangle  -A SHADOWSOCKS -p udp -m set --match-set FREEWEB dst -j RETURN
iptables -t mangle -A SHADOWSOCKS -p udp --dport 53 -j TPROXY --on-port 1082 --tproxy-mark 0x01/0x01

What I expect is: if DNS match FREEWEB, use default DNS, othersize, redirect DNS to 1082(ss-tunnel) But, I don't know above rule if work as expect.

Thanks

----------- Update -------- if change your's rule to white list, how to do that?

odkrys commented 7 years ago

I have no idea about whitelist. I just use countable sites on list. When you test the rules, you must add --on-ip 192.168.1.1 in rule.

let's check, https://ly798.github.io/2016/01/02/%E5%B0%8F%E7%B1%B3mini-%E7%A7%91%E5%AD%A6%E4%B8%8A%E7%BD%91/

baggiogogo commented 7 years ago

@zw963 不是任何使用中的端口,任何随意无用的端口即可,当YouTube走quic时,走得通它会走,走不通会回到tcp去,这样就不用费力处理udp部分了,另外是方便kcptun之类的加速,如果走了quic,就享受不到了,app之类的不能关闭quic的也可以正常使用。

另外一定要用udp转发的话,分情况的,游戏这些的话你上面这些iptables就可以了,涉及到dns还要处理OUTPUT链。

honwen commented 7 years ago

这样或许直观一点 UDP在 表: Mangle 中处理

具体 TPROXY 的用法可以参考 http://itoedr.blog.163.com/blog/static/1202842972013631258540/

2017-09-06 15-12-50

zw963 commented 7 years ago

不是任何使用中的端口,任何随意无用的端口即可

@baggiogogo , 晕哦, 难道我又完全错了.

iptables -t mangle -A PREROUTING -p udp -m set --match-set youtube dst -j TPROXY --on-port 10800 --tproxy-mark 0x01/0x01

这条 rule 的 --on-port 竟然指定到一个完全没有被监听的端口, 是这样的意思吗? 我一直以为这个端口必须是 ss-redir 监听的那个端口.

好吧, 如果上面 --on-port 10800 理解没错的话, 请问, 这条语句到底在做什么事情?

zw963 commented 7 years ago

@chenhw2 , 请教几个在我的理解范围内的问题:

还望解答. 谢谢.

honwen commented 7 years ago

@zw963 这两个是我自己另外的处理,与SS无关,可以忽略

zw963 commented 7 years ago

@chenhw2 , 为了节省你宝贵的时间, 我创建了一个我的脚本的新的分支, 并加了很多注释, 麻烦你看一下, 直接就问题来解决问题.

https://github.com/zw963/asuswrt-merlin-transparent-proxy/blob/udp_relay/route/opt/etc/iptables.sh#L79-L115

honwen commented 7 years ago

@zw963 没有梅林设备,只搞过LEDE/OpenWRT

zw963 commented 7 years ago

@chenhw2 , 我只是想找到只使用 ss-redir 实现透明代理的路子, 这点 merlin 和 openwrt 是相同的吧?

你可以指导下我那个脚本该如何编写吗?

zw963 commented 7 years ago

@zw963 这两个是我自己另外的处理,与SS无关,可以忽略

你截的那个图里面, 有那个和 ss-redir 做透明代理(udp relay)有关呢?

你可以告诉我哪一行, 或者再截个部分图, 或者你可以直接指导下 我那个 iptables.sh 文件该如何编写这块的 rule 呢?

honwen commented 7 years ago

@zw963 带SS字样(不区分大小写)的都是和ss-redir 做透明代理(udp relay)有关

zw963 commented 7 years ago

@chenhw2 , 好吧, 能看出一点儿眉目的, 貌似只有下面两条, 有些疑问

baggiogogo commented 7 years ago

@zw963 您搞混了,关键不知您到底想解决的是什么问题,是quic的问题,还是一定要做udp转发。

解决quic有三个办法,1关闭浏览器quic(这样对于app就无解了),2使quic走不通重新回到SS tcp去(任何简单的iptables只要能达到这个效果,那都可以),3做udp转发(这样会涉及到dns问题,除非dns做tcp查询),复杂程度依次递增1<2<3

如果一定要做udp转发,那思路和ss-redir透明转发tcp是一样的,假设采用tcp查询dns,只处理PREROUTING肯定是不够的,还要处理OUTPUT。 至少要加上以下(中间应该也需要加内网地址防止回环,仅供参考), iptables -t mangle -N SHADOWSOCKS_MARK iptables -t mangle -A SHADOWSOCKS_MARK -d 8.8.8.8 -p udp --dport 53 -j MARK --set-mark 1 iptables -t mangle -A OUTPUT -p udp -j SHADOWSOCKS_MARK

以上都是在不开ss-tunnel只用ss-redir的情况下,另外如果做udp转发,ss-redir肯定要加-u的,不加它只处理tcp,相应ss-server也必须加-u。

zw963 commented 7 years ago

@icymind , 为什么我参照你的下面配置, 在路由器上从来不工作 ...

先配置dnsmasq用4个8查询Evil-Domain: 把127.0.0.1#1080改为8.8.8.8#53
然后再用iptables把发往8.8.8.8的数据包转发给ss-redir:
iptables -t nat -A OUTPUT -p udp --dport 53 -d 8.8.8.8 -j REDIRECT --to-port 1080
然而通过观察,虽然ss-server收到了udp数据,但是udp的目标地址仍然是127.0.0.1#1080。这个方法并不奏效。
添加一条规则,试试如果使用TCP查询DNS,ss-server能不能进行正常的DNS解析:
iptables -t nat -A OUTPUT -p tcp --dport 53 -d 8.8.8.8 -j REDIRECT --to-port 1080
再次通过nslookup发起查询,结果观察到ss-server收到数据后成功向8.8.8.8发送请求,并将响应发回了ss-redir。
zw963 commented 7 years ago

@baggiogogo

您搞混了,

是的, 完全搞乱了.

关键不知您到底想解决的是什么问题,是quic的问题,还是一定要做udp转发。

https://github.com/zw963/asuswrt-merlin-transparent-proxy/blob/udp_relay/route/opt/etc/iptables.sh#L79-L110

这里有描述我的精确问题. 谢谢, 看了你的答复, 看样子我少了 SHADOWSOCKS_MARK 之类的代码??

zw963 commented 7 years ago

@baggiogogo, 能否直接针对那个 iptables.sh, 指点一二?

zw963 commented 7 years ago

@baggiogogo , 且不论我是否理解具体含义 我根据你最近的回复, 我改写了 udp rule,

你看下, 给点指导意见, 例如哪些地方写的部队, 或者根本没有必要. 我的目的暂时先定为一个, 让 ss-redir 可以支持 DNS 查询.

ip rule add fwmark 0x01/0x01 table 100
ip route add local 0.0.0.0/0 dev lo table 100

ipt="$iptables -t mangle"

$ipt -N SHADOWSOCKS
$ipt -N SHADOWSOCKS_MARK

# 本地回环 ip 集合.
for i in $localips; do
    $ipt -A SHADOWSOCKS -d "$i" -j RETURN
done

$ipt -A SHADOWSOCKS -p udp -m set --match-set FREEWEB dst -j RETURN
$ipt -A SHADOWSOCKS -p udp --dport 53 -j TPROXY --on-port 1080 --tproxy-mark 0x01/0x01

$ipt -A SHADOWSOCKS_MARK -d 8.8.8.8 -p udp --dport 53 -j MARK --set-mark 1

# 应用规则, 注释这行代码, 重启后会让 UDP rules 失效.
$ipt -I PREROUTING 1 -p udp -j SHADOWSOCKS
$ipt -A OUTPUT -p udp -j SHADOWSOCKS_MARK
baggiogogo commented 7 years ago

抱歉,不是太懂脚本,但看大意是差不多了,您能否实际尝试一下能否正常工作,如还是不行晚点我用树莓派试验。

很好理解的,PREROUTING是针对局域网进入路由的请求(比如DNS),如果以这个路由作为一个dns服务器,那局域网的请求进入以后,路由自身还要出去真正的dns服务器查询随后反馈,路由器这个请求就需要用OUTPUT。

麻烦就麻烦在tproxy用法上,确实有点云里雾里的,处理tcp链的nat就很容易理解。