apernet / hysteria

Hysteria is a powerful, lightning fast and censorship resistant proxy.
https://v2.hysteria.network/
MIT License
14.03k stars 1.57k forks source link

【Feature Request】服务端支持基于规则的TCP/HTTP转发 #931

Closed bobwng closed 5 months ago

bobwng commented 5 months ago

你的功能请求是否与某个问题有关?

目前很多VPS中不仅仅跑了hysteria服务,还有一些其他基于HTTP/HTTPS的服务。当同时部署hysteria和这些服务,不能共用同一个port作为entrypoint。这样的话,443端口只能被hysteria占用或只能被其他HTTP/HTTPS服务占用。

考虑/尝试过以下做法:

  1. 使用traefik作为前端
    • 基于CDN的说明、#872 的讨论、以及我自己的尝试,没有办法使用traefik作为前端,使用TCP转发的方式将hysteria作为后端。
  2. 使用hysteria作为前端
    • 目前的hysertia的TCP转发基于指定端口,这样还是需要多个端口才能让其他HTTP服务(如traefik)与hystertia同时运行在一台VPS上。
    • 从文档中来看, 伪装模式只能支持指定端口或者指定域名。这样的话,如果有多个域名运行在后端,应当也是不可以的。

描述你希望的解决方案

希望hysteria的服务端能支持基于规则的多协议转发服务,至少先支持基于规则HTTP/TCP转发。

例如,是否可以参考traefik的TCP Router,在hysteria的服务端配置文件中增加以下内容:

tcpForwarding:
  - rule: "HostSNI(`traefik.example.com`)"
    tls:
      passthrough: true
    remote:
      - traefik-1.internal.example.com:8443
      - traefik-2.internal.example.com:8443
  - rule: "HostSNI(`*.sub-domain.example.com`)"
    tls:
      passthrough: true
    remote:
      - node-1.internal.sub-domain.example.com:443
      - node-2.internal.sub-domain.example.com:443

这样,当接收到域名为“traefik.example.com”或者为泛域名“*.sub-domain.example.com”的请求时,将请求内容不做更改(passthrough: true)分别转发到指定的远端服务器例如“traefik-1.internal.example.com:8443”或“node-2.internal.sub-domain.example.com:443”

有没有其他替代方案

额外信息

WoaShieShei commented 5 months ago

hysteria 设置配置使其不监听TCP,然后其他服务监听在同一个端口的TCP上,不知道行不行,只知道DNS好像有这种操作

bobwng commented 5 months ago

hysteria 设置配置使其不监听TCP,然后其他服务监听在同一个端口的TCP上,不知道行不行,只知道DNS好像有这种操作

TCP是4层,算是某种意思上软件方面的底层协议了,应该做不了。DNS是更高层(7层?)的应用。

一定要做的话,应该也是首先由hysteria监听TCP,发现不是自己的数据包后,再进行转发。

WoaShieShei commented 5 months ago

hysteria 设置配置使其不监听TCP,然后其他服务监听在同一个端口的TCP上,不知道行不行,只知道DNS好像有这种操作

TCP是4层,算是某种意思上软件方面的底层协议了,应该做不了。DNS是更高层(7层?)的应用。

一定要做的话,应该也是首先由hysteria监听TCP,发现不是自己的数据包后,再进行转发。

听不懂你的意思,不知道你的需求是不是这种:

[root@fkme ~]# systemctl status hysteria-server | grep Active
   Active: active (running) since Fri 2024-02-02 17:17:26 UTC; 17s ago
[root@fkme ~]# netstat -au | grep https
udp6       0      0 [::]:https              [::]:*
[root@fkme ~]# netstat -at | grep https
tcp        0      0 0.0.0.0:https           0.0.0.0:*               LISTEN
[root@fkme ~]# curl localhost:443
<html>
以下为flask服务器的内容

两种协议分开就行了,浏览器应该不会一步到位走http3的,有一个升级的过程

bobwng commented 5 months ago

两种协议分开就行了,浏览器应该不会一步到位走http3的,有一个升级的过程

看到你的回复才意识到hysteria是基于UDP的协议。。。😭

现在我用以下方案,本地客户端连接服务器已经没有问题了。但是远程机器作为client连过去还是有问题:

当前方案:Traefik作为前端,hysteria作为后端,以容器化方式运行

测试结果

./hysteria-linux-arm64 -c hysteria-client-443.yaml -l DEBUG
2024-02-03T14:34:24+08:00   INFO    client mode
2024-02-03T14:34:24+08:00   INFO    connected to server {"udpEnabled": true, "tx": 2500000, "count": 1}
2024-02-03T14:34:24+08:00   INFO    use this URI to share your server   {"uri": "hysteria2://xxxx@h2.xxxx.com:443/"}
2024-02-03T14:34:24+08:00   DEBUG   checking for updates    {"version": "v2.2.4", "platform": "linux", "arch": "arm64", "channel": "release"}
2024-02-03T14:34:24+08:00   INFO    HTTP proxy server listening {"addr": "127.0.0.1:8088"}
2024-02-03T14:34:24+08:00   INFO    SOCKS5 server listening {"addr": "127.0.0.1:1088"}
2024-02-03T14:34:24+08:00   DEBUG   no update available
./hysteria-linux-amd64 -c hysteria-client-10net-443.yaml -l DEBUG
2024-02-03T14:24:54+08:00   INFO    client mode
2024-02-03T14:24:54+08:00   FATAL   failed to initialize client {"error": "connect error: INTERNAL_ERROR (local): write udp [::]:53500->10.0.0.42:443: sendmsg: invalid argument"}
./hysteria-darwin-arm64 -c hysteria.yaml -l DEBUG
2024-02-03T14:25:15+08:00   INFO    client mode
2024-02-03T14:25:20+08:00   FATAL   failed to initialize client {"error": "connect error: timeout: no recent network activity"}

防火墙情况

VPC

VPC中的防火墙已经配置好相关端口:

image

运行hysteria容器的CentOS 7

sudo iptables -L|grep https

ACCEPT     tcp  --  anywhere             172.18.0.3           tcp dpt:https
ACCEPT     udp  --  anywhere             172.18.0.3           udp dpt:https
ACCEPT     tcp  --  anywhere             172.18.0.8           tcp dpt:pcsync-https
WoaShieShei commented 5 months ago

Same as: https://github.com/apernet/hysteria/issues/810#issuecomment-1807690164 升级你的内核到6.X (kernel-mainline) 不能升就docker环境变量加上QUIC_GO_DISABLE_ECN=true

bobwng commented 5 months ago

Same as: #810 (comment) 升级你的内核到6.X (kernel-mainline) 不能升就docker环境变量加上QUIC_GO_DISABLE_ECN=true

多谢。目前验证下来,在没有环境变量“QUIC_GO_DISABLE_ECN”的情况下,treafik v2作为udp反代也是可以正常工作的。只是目前我通过443端口访问出了问题,还在查找具体原因中。

这个issue应该可以关闭了,目前我碰到的问题很诡异,但是基本可以确定与hysteria无关。

---- 分割线 ----

我的hysteria服务器与mbp之间,有两条网络链路:

当我通过正常的公网的443端口访问时,无法连接hysteria服务器。但是,当我通过tailscale的私有网络访问时,是没有问题的。

这样看起来问题好像很明确了,应该是云提供商那边的Ingress Rule的问题。

于是,我做了以下几件事情:

  1. 在hysteria容器的那台服务器上:
    • 直接CLI启动了一个hysteria实例,监听8443端口
    • 打开了8443/udp的防火墙
  2. 在云提供商的Ingress Rule里面:
    • 放行了8443(跟放行443端口一样,为了避免出错增加了两条rules)
    • image

结果,通过公网,连接上了监听8443端口的hysteria实例! 再次测试“公网+443”端口,仍旧失败!“tailscale + 443”依旧成功 😢

总结一下:

现在的我,一筹莫展。。。😂

bobwng commented 5 months ago
  • 公网 + traefik反代(443端口)

另外找了一台VPS作为client,发现“公网 + traefik反代(443端口)”是没有问题的。原来是我家里网络的问题?! 😂

bobwng commented 5 months ago

破案了,发现家里OpenWRT里面有如下一条iptable rule:

REJECT     udp  --  anywhere             anywhere             udp dpt:https /* OpenClash QUIC REJECT */ ! match-set china_ip_route dst reject-with icmp-port-unreachable