go-gost / gost

GO Simple Tunnel - a simple tunnel written in golang
https://gost.run
MIT License
4.09k stars 502 forks source link

关于v4/v6单独出口问题 #530

Closed superen7527 closed 2 months ago

superen7527 commented 2 months ago

关于 https://github.com/go-gost/gost/issues/528 问题

我搭建了本机出口的v4 v6 以及 v4v6混合的池 都用虚拟节点负载随机。

后来测试 对于某些双栈域名 比如 cloudflare.com 正常可以v4和v6单独访问,v4优先,命令行 curl -6 cloudflare.com就可以强制指定v6访问,但是我用v6池访问是一直访问失败的no suitable address found


比如

# 强制使用 IPv4
curl -4 'https://icanhazip.com'
# 强制使用 IPv6
curl -6 'https://icanhazip.com'

这些在服务器上都可以返回对应的出口ip

但是

cloudflare.com v4为主 可以v6访问
api64.ipify.org v6优先 可v4

用v6池无法访问cloudflare 同样 v4池 无法访问上面那个v6优先的地址

又搞了一晚上通宵没搞明白。v4+v6混合的池,并不是我想的那样,随机用v4或者v6。而是v4遇到v6优先的双栈服务器,或者v6遇到v4优先的双栈,都访问不了


日志显示

curl -x socks5://127.0.0.1:665 http://ifconfig.me
curl: (97) Can't complete SOCKS5 connection to ifconfig.me. (3)
"listener":"tcp","msg":"dial tcp: address [2604:9cc0:1ce8::10]:0: no suitable address found","service":"v6","time":"2024-07-08T03:28:21.337+08:00"

和使用的127.0.0.1好像没关系 虽然是v4的本机地址,但是用v6ip访问v6入口的域名没问题。 就是想问一下这种情况,是正常的吗?所有池都是这样,还是我用法有问题有遗漏的部分?

ginuerzh commented 2 months ago

对于虚拟节点组的选择,目前没有考虑出口IP与所要访问的目标IP类型一致性。如果目标是ipv4,出口是ipv6或目标是ipv6,出口是ipv4就会访问失败。一种临时性简单的规避方式是采用重试机制(handler.retries):

services:
- name: service-0
  addr: ":8080"
  handler:
    type: auto
    chain: chain-0
    retries: 2
  listener:
    type: tcp
chains:
- name: chain-0
  hops:
  - name: hop-0
    selector:
      strategy: round
    nodes:
    - name: node-0
      addr: :0
      interface: ipv4
      connector:
        type: virtual
      dialer:
        type: virtual
    - name: node-1
      addr: :0
      interface: ipv6
      connector:
        type: virtual
      dialer:
        type: virtual
superen7527 commented 2 months ago

你好 请问一下 不使用虚拟节点 用真实节点还会不会有这种问题?我不太会弄真实节点。 有没有示例?

superen7527 commented 2 months ago

问题在于 目标其实是双栈 我感觉不应该有这个问题,因为我强制用-6 去访问优先v4的双栈域名 是可以访问的,而池选择了v6出口 应该也是只有v6ip 却不能访问目标的v6入口,我不太清楚问题出自哪里。

ginuerzh commented 2 months ago

你的IP是都在一个网口上还是多网口多IP模式? 如果是多网口,可以直接指定网口名:interface: eth0,连接时会自动尝试网口上的所有IP来建立连接。

superen7527 commented 2 months ago

都在 一个网口上,但是我试过指定网口,指定以后只会使用第一个ip,所以我才枚举所有ip然后随机触发的,

superen7527 commented 2 months ago

哦 我明白你的意思了,你是说 如果访问这种双栈失败则会尝试其他ip,如果我网口有v4和v6 就可以正常触发,然后随机和负载还是得用虚拟节点?

ginuerzh commented 2 months ago

如果是多个双栈网口,直接指定网口就可以了,每个网口上会自动尝试所有IP。如果你是单网口就需要用虚拟节点来做负载均衡,可以每个虚拟节点同时指定ipv4和ipv6来模拟多个双栈网口模式,例如有4个IP:ipv4-1,ipv4-2,ipv6-1,ipv6-2

services:
- name: service-0
  addr: ":8080"
  handler:
    type: auto
    chain: chain-0
    retries: 2
  listener:
    type: tcp
chains:
- name: chain-0
  hops:
  - name: hop-0
    selector:
      strategy: round
    nodes:
    - name: node-0
      addr: :0
      interface: ipv4-1,ipv6-1
      connector:
        type: virtual
      dialer:
        type: virtual
    - name: node-1
      addr: :0
      interface: ipv4-2,ipv6-2
      connector:
        type: virtual
      dialer:
        type: virtual

这样node-0和node-1虚拟节点就类似于两个双栈网口。

superen7527 commented 2 months ago

明白了 相当于interface 填网口也是枚举 会启用第一个失败用第个逻辑。

但是有一点我不太明白,明明访问的目标网站拥有双栈入口,比如cloudflare.com v4和v6都有。正常用单v4或者v6ip去访问都是可以访问的,可是用 纯v6出口的gost池 却访问不了。不太明白是为什么。

superen7527 commented 2 months ago

如果是多个双栈网口,直接指定网口就可以了,每个网口上会自动尝试所有IP。如果你是单网口就需要用虚拟节点来做负载均衡,可以每个虚拟节点同时指定ipv4和ipv6来模拟多个双栈网口模式,例如有4个IP:ipv4-1,ipv4-2,ipv6-1,ipv6-2

services:
- name: service-0
  addr: ":8080"
  handler:
    type: auto
    chain: chain-0
    retries: 2
  listener:
    type: tcp
chains:
- name: chain-0
  hops:
  - name: hop-0
    selector:
      strategy: round
    nodes:
    - name: node-0
      addr: :0
      interface: ipv4-1,ipv6-1
      connector:
        type: virtual
      dialer:
        type: virtual
    - name: node-1
      addr: :0
      interface: ipv4-2,ipv6-2
      connector:
        type: virtual
      dialer:
        type: virtual

这样node-0和node-1虚拟节点就类似于两个双栈网口。

这样使用场景还是有点少,有没有另一种用法,就是interface第一个都填v6ip,第二个位置填v4池或者什么虚拟网口

这样可以随机v6失败就去随机v4。如果是写死固定,就需要大量排列组合才能组出随机的情况。

interface: ipv6-1,virtualv4 后面这个不知道能不能填v4的chain或者service?有没有类似于这种用法?

superen7527 commented 2 months ago

我去买了一些外面的池。 测试了一下正常池效果 他们访问出口是ipv6就会访问目标网站的v6口 v4就访问v4入口 就像服务器自己的网络出口一样,

但是gost虚拟出去的,单ip,如果目标双栈入口优先级不一样,不能访问目标对应入口。池是可以的。不知道是gost问题还是虚拟节点问题,感觉这个问题挺严重的。。

像上面gost 用v6出口访问v4优先的双栈网站,

curl -x socks5://127.0.0.1:665 http://ifconfig.me
curl: (97) Can't complete SOCKS5 connection to ifconfig.me. (3)

而用我买的池,可以拿到v6地址。

ginuerzh commented 2 months ago

我不太清楚你具体要达成什么样的目的。 对于单IP访问双栈目标地址,例如

gost -L :1080 -F virtual://:0?interface=1.2.3.4

GOST会以interface指定的IP(1.2.3.4)作为源地址来建立连接。如果你使用curl -x socks5://127.0.0.1:665 http://ifconfig.me,域名是由curl解析,如果解析出来是IPV6,则肯定无法建立连接。

你应该使用curl --socks5-hostname 127.0.0.1:665 http://ifconfig.me,让代理来解析域名,这样代理会根据源IP自动匹配同类型的目标IP地址。

如果你想要在客户端解析IP,让代理自动根据目标IP类型来过滤出匹配的虚拟节点,则需要增加新的负载均衡过滤规则,或者模拟双栈节点。

superen7527 commented 2 months ago

我只是比较奇怪,我用买的池同样的代码,而买的池是可以根据出口ip自动选择的

例如 curl -x socks5://xyz.com:665 http://ifconfig.me 他可以出 v4结果 也可以出v6结果

域名是由curl解析,如果解析出来是IPV6,则肯定无法建立连接。

如果curl解析 出了v6,那么按照这个逻辑,我买的池如果随机到了v4出口,那么应该也是无法访问才对。而且如果是这样 就算池里面有重试机制,那也应该一直出v6结果才对。我有点没理解..

superen7527 commented 2 months ago

我不太清楚你具体要达成什么样的目的。

我的想法或者说目的,就是想: 除非目标不支持双栈,否则我随机到哪个ip就用哪个ip强制访问。如果随机到v6出口ip,遇到双栈就访问他v6入口。如果我gost随机到v4出口,就用v4访问他v4入口。不用额外去添加网口去兼容主动重试,而是目标网站来适应我的出口ip。

就像这个购买的池一样,他用curl解析也可以随时给我v4/v6的出口ip。而gost绑定的单出口ip,却不能访问对应入口的双栈。我如果为了可以访问去添加interface做备用那是没问题,但是就意味着我想访问这个目标网站,那这个ip永远都用不到了。

superen7527 commented 2 months ago

不过很感谢作者耐心回复,我确实更了解gost和curl,倒是一直打扰有些不好意思。

superen7527 commented 2 months ago

找到了个完整的输出。v4v6混杂的

root@superen:~# 
root@superen:~# curl -x socks5://127.0.0.1:665 http://ifconfig.me
2604:9cc0:1ce6:3f40::root@superen:~# curl -x socks5://127.0.0.1:665 http://ifconfig.me
2604:9cc0:1ce6:6940::root@superen:~# 
root@superen:~# curl -x socks5://127.0.0.1:665 http://ifconfig.me
curl: (97) Can't complete SOCKS5 connection to ifconfig.me. (3)
root@superen:~# curl -x socks5://127.0.0.1:665 http://ifconfig.me
curl: (97) Can't complete SOCKS5 connection to ifconfig.me. (3)
root@superen:~# curl -x socks5://127.0.0.1:665 http://ifconfig.me
curl: (97) Can't complete SOCKS5 connection to ifconfig.me. (3)
root@superen:~# 

失败的日志


{"handler":"socks5","kind":"handler","level":"info","listener":"tcp","local":"127.0.0.1:665","msg":"127.0.0.1:37344 <> 127.0.0.1:665","remote":"127.0.0.1:37344","service":"mixall","time":"2024-07-17T20:32:56.021+08:00"}
{"handler":"auto","kind":"handler","level":"error","listener":"tcp","msg":"route(retry=0) dial tcp: address 62.204.54.150:0: no suitable address found","service":"mixall","time":"2024-07-17T20:32:56.027+08:00"}
{"duration":6507898,"handler":"socks5","kind":"handler","level":"info","listener":"tcp","local":"127.0.0.1:665","msg":"127.0.0.1:37344 >< 127.0.0.1:665","remote":"127.0.0.1:37344","service":"mixall","time":"2024-07-17T20:32:56.027+08:00"}
{"handler":"auto","kind":"service","level":"error","listener":"tcp","msg":"dial tcp: address 62.204.54.150:0: no suitable address found","service":"mixall","time":"2024-07-17T20:32:56.027+08:00"}

成功的日志


{"handler":"socks5","kind":"handler","level":"info","listener":"tcp","local":"127.0.0.1:665","msg":"127.0.0.1:38176 <> 127.0.0.1:665","remote":"127.0.0.1:38176","service":"mixall","time":"2024-07-17T20:35:16.737+08:00"}
{"cmd":"connect","dst":"[2600:1901:0:b2bd::]:80/tcp","handler":"socks5","kind":"handler","level":"info","listener":"tcp","local":"127.0.0.1:665","msg":"127.0.0.1:38176 <-> [2600:1901:0:b2bd::]:80","remote":"127.0.0.1:38176","service":"mixall","time":"2024-07-17T20:35:16.745+08:00"}
{"cmd":"connect","dst":"[2600:1901:0:b2bd::]:80/tcp","duration":49051228,"handler":"socks5","kind":"handler","level":"info","listener":"tcp","local":"127.0.0.1:665","msg":"127.0.0.1:38176 >-< [2600:1901:0:b2bd::]:80","remote":"127.0.0.1:38176","service":"mixall","time":"2024-07-17T20:35:16.794+08:00"}
{"duration":56614792,"handler":"socks5","kind":"handler","level":"info","listener":"tcp","local":"127.0.0.1:665","msg":"127.0.0.1:38176 >< 127.0.0.1:665","remote":"127.0.0.1:38176","service":"mixall","time":"2024-07-17T20:35:16.794+08:00"}
superen7527 commented 2 months ago

我就是想 混合的时候,可以自动选择出口,不然排列组合一下ip组合文件太大了。10个v4 1000个v6,组合就是10000个列表,虽然好像对程序来说不大,但是这样匹配写总感觉怪怪的。作者好像当作一个正常现象,可能是我见识不够,就不提需求兼容了。就关闭吧。作为我自己的疑惑贴

superen7527 commented 1 month ago

@ginuerzh

你好,我想付费请你帮忙修复一下这个问题,github交流不太方便,没有找到邮件地址,只有一个微信赞赏码,方便的话,我通过微信赞赏码留下微信号,您可以加一下吗?我研究一个月没有效果。如有打扰再次抱歉。