Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Hysteria未监听所有地址 #592

Open
wangxiaoerYah opened this issue Mar 24, 2023 · 7 comments
Open

[BUG] Hysteria未监听所有地址 #592

wangxiaoerYah opened this issue Mar 24, 2023 · 7 comments

Comments

@wangxiaoerYah
Copy link

问题详情

我在单网卡上绑定了5个ipv4地址,但是hysteria在使用"listen": ":8443",监听8443端口时并不会使用所有地址,经过测试发现是hysteria的问题,xray或者v2ray它们启动后我可以通过其中任何ip连接vps。

例如:
default via 40.207.168.21 dev enp2s0 proto static 40.207.168.20/28 dev enp2s0 proto kernel scope link src 40.207.168.22
上面的ip都做了修改肯定不是真正ip,仅作解释。
hysteria只能通过其中的40.207.168.22连接。但是40.207.168.23,40.207.168.24,40.207.168.25,这些ip地址是和40.207.168.22在同一张网卡上绑定的。

如果我手动将"listen": ":8443",修改为"listen": "40.207.168.24:8443",我就可以通过40.207.168.24连接,不修改就不行。

目前仅测试了ipv4,不知道ipv6有没有这个问题,毕竟很多vps服务商ipv6地址都是免费给,有的一次给很多个,他们都是一个网段甚至一个网关。

服务端安装信息或者一键脚本信息

hysteria 1.3.4

VPS 信息

服务端配置

"listen": ":8443"

服务端日志

客户端安装信息

hysteria 1.3.4

客户端配置

客户端运行环境(操作系统)

客户端日志

@wangxiaoerYah wangxiaoerYah changed the title Hysteria未监听所有地址 [BUG]Hysteria未监听所有地址 Mar 25, 2023
@wangxiaoerYah wangxiaoerYah changed the title [BUG]Hysteria未监听所有地址 [BUG] Hysteria未监听所有地址 Mar 25, 2023
@wangxiaoerYah
Copy link
Author

我查看了同样使用quic-go的v2ray-5项目,发现他们对于监听地址查找本机存在的ip做了专门的处理
address.go

我想应该是个参考文件。

@wangxiaoerYah
Copy link
Author

如果同一张网卡是有多个同网段的ip地址,那么Linux会默认指定排在最前面的ip作为这个网段的默认ip,也就是
40.207.168.20/28 dev enp2s0 proto kernel scope link src 40.207.168.22

Hysteria 启动时就使用了默认ip作为监听地址?
也就是"listen": ":8443"="listen": "40.207.168.22:8443"

@wangxiaoerYah
Copy link
Author

@tobyxdd @haruue

@haruue
Copy link
Collaborator

haruue commented Mar 26, 2023

这种问题应该是因为一个 bind()* 的 UDP socket , 对它调用 sendto() 无法指定源 IP , 网卡会根据路由表的 prefered src 发出去。

也就是说不是服务端没收到, 而是给客户端发响应包的时候, 使用了另一个源地址, 这种情况下, 客户端不会认为这是个有效响应(并且通常会被 IPv4 NAT 丢弃)。

任何基于 TCP 的协议都不存在这个问题, 因为 TCP 在 accpet() 之后, 源地址和目标地址都被固定了。

我们将会研究其他 h3/quic 应用采用的方案。

@wangxiaoerYah
Copy link
Author

这种问题应该是因为一个 bind()* 的 UDP socket , 对它调用 sendto() 无法指定源 IP , 网卡会根据路由表的 prefered src 发出去。

也就是说不是服务端没收到, 而是给客户端发响应包的时候, 使用了另一个源地址, 这种情况下, 客户端不会认为这是个有效响应(并且通常会被 IPv4 NAT 丢弃)。

任何基于 TCP 的协议都不存在这个问题, 因为 TCP 在 accpet() 之后, 源地址和目标地址都被固定了。

我们将会研究其他 h3/quic 应用采用的方案。

是否可以通过手动调整路由表来修复?

@haruue
Copy link
Collaborator

haruue commented Mar 26, 2023

是否可以通过手动调整路由表来修复?

我认为可以通过 iptables 的 DNAT 功能来修复, 或者说作为绕过这个问题的一种方案。 利用 NAT 的特性, 把对应的 UDP socket 的响应包的源地址改成正确的源地址。

作为例子, 我开了一台虚拟机, 并给它的默认网络接口添加了 10.11.6.250/24 10.11.6.251/24 10.11.6.252/24 10.11.6.253/24 这 4 个地址。

首先我要确认从这台主机发包默认会使用的地址, 这一步可以使用 ip route get 命令, 像下面这样, 也可以把 1.1.1.1 换成任意外部网络的 IP 地址。

# ip route get 1.1.1.1
1.1.1.1 via 10.11.6.1 dev host0 src 10.11.6.250 uid 0 
    cache 

上面输出中出现的 10.11.6.250 即为这个机器向外发包默认使用的地址。

然后, 就可以利用 iptables 的 DNAT 功能, 把发往 10.11.6.251 10.11.6.252 10.11.6.253 的 Hysteria 端口的 UDP 包都 NAT 到 10.11.6.250 。 在这个例子中, 我把 Hysteria 开在 10443 端口上。

iptables -t nat -N hysteria-dnat
iptables -t nat -A hysteria-dnat -p udp -m udp --dport 10443 -j DNAT --to-destination 10.11.6.250
iptables -t nat -A PREROUTING -d 10.11.6.251 -j hysteria-dnat
iptables -t nat -A PREROUTING -d 10.11.6.252 -j hysteria-dnat
iptables -t nat -A PREROUTING -d 10.11.6.253 -j hysteria-dnat

这样操作之后, 外部的 hysteria 客户端通过 10.11.6.251 连接 hysteria 服务端, 也能收到源地址为 10.11.6.251 的回应了。 其他地址亦然。

另外, 测试过程中还发现, hysteria 客户端实际上并不关心回应包的源地址是否和请求时的相同(客户端也是 bind :: 的), 也就是说, 即使不进行上面这样的操作, 也是有可能连上的, 这种情况下外部的流量看起来就是客户端发送 UDP 请求给 10.11.6.251 , 然后收到了从 10.11.6.250 发来的响应。 当然你的运营商 NAT 仍然可能阻止这种流量(尤其是对于 IPv4)。

@f4nff
Copy link

f4nff commented Apr 7, 2023

"server": "[2605:6400:20:1871::2]:123",

如果服务器采用ipv6格式,程序常常闪退,
ipv4倒是没发现.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants