hysteria
hysteria copied to clipboard
[BUG] Hysteria未监听所有地址
问题详情
我在单网卡上绑定了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
客户端配置
无
客户端运行环境(操作系统)
无
客户端日志
无
如果同一张网卡是有多个同网段的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"
?
@tobyxdd @haruue
这种问题应该是因为一个 bind()
到 *
的 UDP socket , 对它调用 sendto()
无法指定源 IP , 网卡会根据路由表的 prefered src 发出去。
也就是说不是服务端没收到, 而是给客户端发响应包的时候, 使用了另一个源地址, 这种情况下, 客户端不会认为这是个有效响应(并且通常会被 IPv4 NAT 丢弃)。
任何基于 TCP 的协议都不存在这个问题, 因为 TCP 在 accpet()
之后, 源地址和目标地址都被固定了。
我们将会研究其他 h3/quic 应用采用的方案。
这种问题应该是因为一个
bind()
到*
的 UDP socket , 对它调用sendto()
无法指定源 IP , 网卡会根据路由表的 prefered src 发出去。也就是说不是服务端没收到, 而是给客户端发响应包的时候, 使用了另一个源地址, 这种情况下, 客户端不会认为这是个有效响应(并且通常会被 IPv4 NAT 丢弃)。
任何基于 TCP 的协议都不存在这个问题, 因为 TCP 在
accpet()
之后, 源地址和目标地址都被固定了。我们将会研究其他 h3/quic 应用采用的方案。
是否可以通过手动调整路由表来修复?
是否可以通过手动调整路由表来修复?
我认为可以通过 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)。
"server": "[2605:6400:20:1871::2]:123",
如果服务器采用ipv6格式,程序常常闪退, ipv4倒是没发现.