Skip to content

WireGuard inbound: Fix multi-peer; Fix potential routing issue#5843

Merged
RPRX merged 12 commits intoXTLS:mainfrom
LjhAUMEM:wg-bind
Mar 27, 2026
Merged

WireGuard inbound: Fix multi-peer; Fix potential routing issue#5843
RPRX merged 12 commits intoXTLS:mainfrom
LjhAUMEM:wg-bind

Conversation

@LjhAUMEM
Copy link
Copy Markdown
Contributor

@LjhAUMEM LjhAUMEM commented Mar 25, 2026

@LjhAUMEM
Copy link
Copy Markdown
Contributor Author

ipc 里的 listen_port 也可以去掉,有的话也只是触发一次 BindUpdate 然后传给 bind.Open

https://github.com/WireGuard/wireguard-go/blob/f333402bd9cbe0f3eeb02507bd14e23d7d639280/device/uapi.go#L217-L221

https://github.com/WireGuard/wireguard-go/blob/f333402bd9cbe0f3eeb02507bd14e23d7d639280/device/device.go#L488-L490

还发现一个新的问题,短时间内触发大量 device.logger.Verbosef 日志好像会卡住

@LjhAUMEM
Copy link
Copy Markdown
Contributor Author

异步日志怎么还能丢日志的... 改到 64 暂时解决了,没有再丢了

还是保留了 listen_port

改用 closedCh 来获知 bind close,readQueue 则不关闭,把 recover 去掉了

@RPRX
Copy link
Copy Markdown
Member

RPRX commented Mar 26, 2026

是这个 #5554 (comment) 的锅吗,你对比下看要不要再改改,明天发正式版

顺便既然要改入站的话看一下 #5555 ,主要是能复现和能测试确认修复

@LjhAUMEM
Copy link
Copy Markdown
Contributor Author

嗯,继 5554 之后 wg in 处于不可用状态,不过思路没啥问题,我还把 recover 优化掉了,顺便解决了启动入站的时候冒出一堆 channel closed 日志的问题,不过这个异步日志会在大量并发的时候丢日志让我调试花了点时间

之前这么设计的应该是假定每个 peer 都会持有从 recv func 发来的 readQ,但实现的时候 recv func 数量又不严格和 peer 数量对应,所以就很迷,不过这个设计也只能用在出站,入站随便打来一个 udp 包都会持有 readQ,所以还是保持目前这个方案

5555 只是应用上 sniff 吗,应该就 ctx 变量设置下就行了,让我看看

@LjhAUMEM
Copy link
Copy Markdown
Contributor Author

sniff 我测试是正常的啊,为啥有那个 pr

对于入站的 sniff,是以 session content 的形式储存在 ctx 里,这个入站 content 很明显复制了两遍

ctx = session.ContextWithContent(ctx, &session.Content{
SniffingRequest: session.SniffingRequest{
Enabled: receiverConfig.SniffingSettings.Enabled,
OverrideDestinationForProtocol: receiverConfig.SniffingSettings.DestinationOverride,
ExcludeForDomain: receiverConfig.SniffingSettings.DomainsExcluded,
MetadataOnly: receiverConfig.SniffingSettings.MetadataOnly,
RouteOnly: receiverConfig.SniffingSettings.RouteOnly,
},
})

content := new(session.Content)
if w.sniffingConfig != nil {
content.SniffingRequest.Enabled = w.sniffingConfig.Enabled
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
content.SniffingRequest.ExcludeForDomain = w.sniffingConfig.DomainsExcluded
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
content.SniffingRequest.RouteOnly = w.sniffingConfig.RouteOnly
}

而 wg 在创建新 ctx 时已经把 content 复制过去了,所以 sniff 是有效的,而我实际测试确实是这样,下面是测试配置

if s.info.contentTag != nil {
ctx = session.ContextWithContent(ctx, s.info.contentTag)
}

@LjhAUMEM
Copy link
Copy Markdown
Contributor Author

{
  "log": { "loglevel": "debug" },
  "inbounds": [
    {
      "tag": "socks",
      "listen": "127.0.0.1",
      "port": 1080,
      "protocol": "socks",
      "settings": {
        "auth": "noauth",
        "udp": true
      }
    },
    {
      "tag": "wg-in",
      "listen": "127.0.0.1",
      "port": 1081,
      "protocol": "wireguard",
      "settings": {
        "secretKey": "uJX4Xm3JmWzYpqIZFiKP+JlDXUpD39eqHJ1Bsn5R5nc=",
        "peers": [
          {
            "publicKey": "Eq5K/cMuaVF7NucLpSqzxOQ+/iMFj1ZU2PpeJAscvic="
          }
        ],
        "noKernelTun": true,
        "domainStrategy": "ForceIP"
      },
      "sniffing": {
        "enabled": true,
        "destOverride": ["http", "tls"]
      }
    }
  ],
  "outbounds": [
    {
      "tag": "direct",
      "protocol": "freedom"
    },
    {
      "tag": "block",
      "protocol": "blackhole"
    },
    {
      "tag": "wg-out",
      "protocol": "wireguard",
      "settings": {
        "secretKey": "YKjJrIBGR3QjDvhXSIK4ndxiyDgNOzTJOu8teRxHQGU=",
        "peers": [
          {
            "endpoint": "127.0.0.1:1081",
            "publicKey": "ZaUsMjS5OeCRHLMAtp3rMDBVRYur622DRL71Bx9kjno="
          }
        ],
        "noKernelTun": true,
        "domainStrategy": "ForceIPv4"
      }
    }
  ],
  "routing": {
    "rules": [
      {
        "inboundTag": ["socks"],
        "outboundTag": "wg-out"
      }
      // ,{
      //   "domain": ["ident.me"],
      //   "outboundTag": "block"
      // }
    ]
  }
}

curl https://ident.me --connect-to :255.255.255.255:443 -x socks5://127.0.0.1:1080

可以看到很明显的重定向,把注释去掉可以看到路由也是成功的

@LjhAUMEM
Copy link
Copy Markdown
Contributor Author

等下,--connect-to 少打一个冒号,我再试试

@LjhAUMEM
Copy link
Copy Markdown
Contributor Author

还是没问题,换 255.255.255.254 就好了,255.255.255.255 都出不到 forwardConnection 那里,所以 sniff 是没问题的

curl https://ident.me --connect-to ::255.255.255.254:443 -x socks5://127.0.0.1:1080

@Fangliding
Copy link
Copy Markdown
Member

Fangliding commented Mar 26, 2026

它是好的 就是一些竞争小问题 所以那个issue我没关

@LjhAUMEM
Copy link
Copy Markdown
Contributor Author

看了下 issue,24.11.11 的没问题那搬过来不就好了

不看那个 issue,对于每个 Process 的 ctx 在用的 dispatcher inboundTag contentTag 似乎不会再变化了,来个 sync once 赋值一次应该就可以

@Fangliding
Copy link
Copy Markdown
Member

Fangliding commented Mar 26, 2026

不变的东西让它去赋值也没关系 反正又不是map并发访问会崩溃 主要是content会动 里面有嗅探结果什么的

@LjhAUMEM
Copy link
Copy Markdown
Contributor Author

那也没事,forwardConnection 也用不上嗅探的结果,iirc 每个 func 里的 ctx 都是一份 copy,上游 func 改变了当前 func 和下游 func 不会影响

这条评论比较有用
#4760 (comment)
我对比了下他给的日志,一个有 sniffed domain 一个没有

新 wg 我测试的时候有 sniffed domain,所以可以 close 了,有新问题再说

2026/03/27 10:16:00.164740 [Info] [909028325] app/dispatcher: sniffed domain: ident.me
2026/03/27 10:16:00.164740 from tcp:0.0.0.0:0 accepted tcp:65.108.151.63:443 [wg-in -> block]
2026/03/27 10:16:00.164740 [Info] [909028325] app/dispatcher: taking detour [block] for [tcp:ident.me:443]
2026/03/27 10:16:11.166933 [Debug] peer(Eq5K…cvic) - Receiving keepalive packet

@RPRX #5555 可以直接关了,没有带来任何新的改变

@RPRX
Copy link
Copy Markdown
Member

RPRX commented Mar 27, 2026

我的意思就是确实存在小问题的话,这个 PR 顺便修复一下吧

@LjhAUMEM 还有看一下 mKCP 的 header 啥的能不能再压缩一下(比如 varint),新版顺带 XKCP 算了,分享链接可带 mtu

@RPRX
Copy link
Copy Markdown
Member

RPRX commented Mar 27, 2026

我看了下 mKCP 如果不大改的话优化空间有限,要不还是先完善下分享链接带 mtu、tti 啥的吧

@LjhAUMEM
Copy link
Copy Markdown
Contributor Author

LjhAUMEM commented Mar 27, 2026

要改也是从 c++ 的 kcp 开始,为什么从 mkcp 开始

也就是 mtu 加到 fm 里?没地方放啊,可改 mtu 就 wg 和 kcp,quicParams 也不合适

趁早出客户端就不用纠结分享链接了

@RPRX
Copy link
Copy Markdown
Member

RPRX commented Mar 27, 2026

只是给 mkcp 分享链接加 mtu 和 tti,不是放 fm 里,代码不用改,现在主要的问题是国人 GUI 没跟上,HAPP 啥的倒不担心

XKCP 准备搁置一下了,毕竟 XDNS 这种方式还能在伊朗活多久都不确定,我也不知道为啥伊朗不干脆封掉所有 TXT 查询

@LjhAUMEM WG 入站的小问题你看一下要不要修,暂时不修的话我直接合并这个 PR 发稳定版了

@LjhAUMEM
Copy link
Copy Markdown
Contributor Author

不知道有啥问题主要是,那个 issue 说的 sniff 无效我测试了是有效的,可能之前就修好了吧

@RPRX
Copy link
Copy Markdown
Member

RPRX commented Mar 27, 2026

那个 issue 说的是偶尔失效,可能是 ctx 没 deep clone 然后多并发时同一份 content 被改来改去的,需要多并发,你看看

@LjhAUMEM
Copy link
Copy Markdown
Contributor Author

原来是这个,确实,构建新入站应该用新 content,wg 的特殊性导致从 process 来的并不是入站,到 forwardConnection 才是,就不能也不应该复用 process 来的 session content

@Fangliding
Copy link
Copy Markdown
Member

Fangliding commented Mar 27, 2026

当初留着这个开始是因为这个 forwardconnection 丢失了全部关于源的信息 因为源信息是从process传入的 这修的是当初没注意的 protocol 翻转问题 影响protocol分流 之前会串sniff dest的问题比较大那个早修了

@LjhAUMEM
Copy link
Copy Markdown
Contributor Author

不是 sniff 那为啥 5555 的标题是 sniff

那我先回退一下,protocol 不是看 Dispatch dest 就可以吗,咋会有问题

算了,有问题再其他 pr 修吧

@Fangliding
Copy link
Copy Markdown
Member

现在的东西是每个 process 都根据传来的inbound更新一下 Server.info
这里面的数据包括了源IP 源端口 context 等内容 曾经还包括了 outbound 这里面包括了sniff结果导致请求串sniff 后来改成的独立创建 毕竟它可以用proxy request本身创建
但是源IP端口context这些东西是真的需要 worker 传来的 这些东西目前的办法就是 server 级共享 如果有一个以上的用户会导致后进来的用户覆盖掉这些信息

@LjhAUMEM
Copy link
Copy Markdown
Contributor Author

看了下 sniff 里的 protocol 是会存在 content 上下文里,每个新 Dispatch 持有独立的 content 没啥问题,之前以为说的 tcp, udp

现在 sniff protocol 的问题解决了,forwardconnection 现在丢失掉的应该也只剩 peer 对端 ip,好奇如果两个 peer 在 tun 里的 laddr 是相同的 wg 是怎么处理,不过再说了

@RPRX
Copy link
Copy Markdown
Member

RPRX commented Mar 27, 2026

感觉自己像一个不看代码的 GPT,仅根据你们的聊天来猜测可能的逻辑问题

大概看了一下,似乎改成 clone 一份 ctx 以固定源信息不就行了?

@RPRX
Copy link
Copy Markdown
Member

RPRX commented Mar 27, 2026

@LjhAUMEM 你随意修一下,更新下 PR 描述,然后我顺便把 #4760 关掉吧,说测试这么久了都没人回复应该是不咋重要,等发了新的稳定版后,若 WG 入站还有问题的话让他们开新的 issue 吧

@LjhAUMEM
Copy link
Copy Markdown
Contributor Author

LjhAUMEM commented Mar 27, 2026

感觉自己像一个不看代码的 GPT,仅根据你们的聊天来猜测可能的逻辑问题

大概看了一下,似乎改成 clone 一份 ctx 以固定源信息不就行了?

差不多,那个 content 是指针然后没有 new 就成共用了

tun 入站在 dispatch 前也会 new 一个,其他入站在 addConn 后也会 new 一个 (tcpWorker 的 callback)

@LjhAUMEM 你随意修一下,更新下 PR 描述,然后我顺便把 #4760 关掉吧,说测试这么久了都没人回复应该是不咋重要,等发了新的稳定版后,若 WG 入站还有问题的话让他们开新的 issue 吧

done

@RPRX
Copy link
Copy Markdown
Member

RPRX commented Mar 27, 2026

那就先这样吧

还有我感觉 core 底层传输那里处理 UDP 的逻辑过于复杂了,套来套去的,造成性能堪忧,@LjhAUMEM 有空时优化一下

@LjhAUMEM
Copy link
Copy Markdown
Contributor Author

freedom 还是 raw udp 入站,我有空看看吧,不过之前给 udp hub 接 fm 的时候看到 hub 也分几个 os 用 ReadUDPMsg 暂时是没看出来什么用途

@RPRX
Copy link
Copy Markdown
Member

RPRX commented Mar 27, 2026

感觉 *ray 的底层架构代码都是一坨,都简化下吧

这个 #5843 (comment) 是我纯凭经验猜的,刚看了下 #5555 也有相关改动,AI 还行,总有一天写代码只用 AI,我只 review

@RPRX
Copy link
Copy Markdown
Member

RPRX commented Mar 27, 2026

@LjhAUMEM 现在有空把 noise 的拆出另一个 PR 吗,标题不好写

@LjhAUMEM
Copy link
Copy Markdown
Contributor Author

哦哦,稍等

@RPRX RPRX changed the title Wg bind WireGuard inbound: Fix multi-peer; Fix potential routing issue Mar 27, 2026
@RPRX RPRX merged commit 8aacdbd into XTLS:main Mar 27, 2026
38 of 39 checks passed
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

Successfully merging this pull request may close these issues.

3 participants