auto_detect_interface 将 loopback UDP 出站绑定到默认网卡
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 38.2k
- Forks
- 4.6k
- Avg merge
- 19d 15h
- Merged PRs (30d)
- 1
Description
操作系统
Linux
系统版本
Ubuntu 24.04.4 LTS Linux 6.8.0-101-generic x86_64
安装类型
sing-box 原始命令行程序
如果您使用图形客户端程序,请提供该程序版本。
No response
版本
sing-box version 1.14.0-beta.15
Environment: go1.26.6 linux/amd64
Tags:
with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_ocm,with_clo
udflared,with_naive_outbound,with_usbip,with_openvpn,with_openconnect,badlinkname,tfogo_checklinkname0,with_musl
Revision: e98ae31a7d9a558d1b2dd982c9f1f9c4b8bbff87
CGO: enabled
描述
在 Linux 上启用 route.auto_detect_interface=true 后,
Shadowsocks relay 将 UDP 数据转发到本机 127.0.0.1 destination 时,
UDP 包会被绑定到默认物理网卡,而不是通过 lo 发送到本机 loopback socket。
环境中的链路:
Shadowsocks relay inbound
-> destination 127.0.0.1:38080
-> 本地 Shadowsocks inbound
-> 实际 UDP 目标
sing-box 日志显示 relay 已经将数据路由到
127.0.0.1:38080,但是本地 Shadowsocks inbound 收不到 UDP 包。
tcpdump 显示数据包实际从 eth0 发出:
eth0 Out:
10.42.2.41:<ephemeral> -> 127.0.0.1:38080 UDP
而在 lo 上抓不到对应的数据包。
这会导致本地二级 Shadowsocks relay 无法收到 UDP,
上层 DNS 查询持续超时并产生大量重试。
为 loopback destination 增加一个 bind_interface=lo 的 direct outbound,
并为 127.0.0.0/8 和 ::1/128 增加路由规则后,问题消失。
重现方式
以下是已经在同一台 Linux 主机上验证过的最小化复现方式。
不依赖远程服务器、不依赖 TUN、不依赖图形客户端。
测试使用两个临时 sing-box 进程。
1. Relay 配置
注意:该配置没有 route.rules,也没有 route.final。
{
"log": {
"level": "debug",
"timestamp": true
},
"inbounds": [
{
"type": "shadowsocks",
"tag": "relay-in",
"listen": "::",
"listen_port": 55517,
"method": "2022-blake3-aes-128-gcm",
"password": "ArTR9gokhcj3C95CVIPNDw==",
"destinations": [
{
"name": "local",
"server": "127.0.0.1",
"server_port": 5380,
"password": "YF+PqRw6PDNPlqHPfztgKg=="
}
]
},
{
"type": "shadowsocks",
"tag": "down-in",
"listen": "127.0.0.1",
"listen_port": 5380,
"method": "2022-blake3-aes-128-gcm",
"password": "YF+PqRw6PDNPlqHPfztgKg=="
}
],
"outbounds": [
{
"type": "direct",
"tag": "direct"
}
],
"route": {
"auto_detect_interface": true
}
}
2. Client 配置
{
"log": {
"level": "debug",
"timestamp": true
},
"inbounds": [
{
"type": "direct",
"tag": "udp-in",
"listen": "127.0.0.1",
"listen_port": 55553,
"network": "udp",
"override_address": "1.1.1.1",
"override_port": 53
}
],
"outbounds": [
{
"type": "shadowsocks",
"tag": "ss-out",
"server": "127.0.0.1",
"server_port": 55517,
"method": "2022-blake3-aes-128-gcm",
"password": "ArTR9gokhcj3C95CVIPNDw==:YF+PqRw6PDNPlqHPfztgKg=="
}
],
"route": {
"rules": [
{
"inbound": [
"udp-in"
],
"outbound": "ss-out"
}
]
}
}
3. 启动
分别启动两个 sing-box 进程:
sing-box run -c relay.json
sing-box run -c client.json
4. 发送 UDP 数据包
printf 'repro-payload' | nc -u -w 1 127.0.0.1 55553
5. 观察结果
Relay 日志显示:
inbound/shadowsocks[relay-in]:
[local] inbound packet connection to 127.0.0.1:5380
outbound/direct[direct]:
outbound packet connection
但是 downstream 的 down-in 没有收到对应的:
inbound/shadowsocks[down-in]:
inbound packet connection
Client 日志显示:
inbound/direct[udp-in]:
inbound packet connection to 1.1.1.1:53
outbound/shadowsocks[ss-out]:
outbound packet connection to 1.1.1.1:53
但 UDP 数据无法继续到达本机的 downstream Shadowsocks inbound。
6. 生产环境抓包结果
在实际生产配置中,抓包结果为:
eth0 Out IP 10.42.2.41.46742 > 127.0.0.1.38080:
UDP, length 886
在 lo 上抓包:
tcpdump -ni lo 'udp port 38080'
0 packets captured
7. Workaround
增加 loopback 专用 outbound:
{
"type": "direct",
"tag": "direct-loopback",
"bind_interface": "lo"
}
并在通用规则前增加:
{
"ip_cidr": [
"127.0.0.0/8",
"::1/128"
],
"outbound": "direct-loopback"
}
增加后,数据包恢复为:
lo:
127.0.0.1:<ephemeral> -> 127.0.0.1:38080 UDP
127.0.0.1:38080 -> 127.0.0.1:<ephemeral> UDP
downstream Shadowsocks inbound 可以正常收到 UDP。
日志
# 复现时 Relay 日志
+0800 2026-08-16 00:36:58 INFO [4107452948 0ms] inbound/shadowsocks[relay-in]: [local] inbound packet connection from
127.0.0.1:59368
+0800 2026-08-16 00:36:58 INFO [4107452948 0ms] inbound/shadowsocks[relay-in]: [local] inbound packet connection to
127.0.0.1:5380
+0800 2026-08-16 00:36:58 INFO [4107452948 0ms] outbound/direct[direct]: outbound packet connection
# 复现时 Client 日志
+0800 2026-08-16 00:36:58 INFO [824732556 0ms] inbound/direct[udp-in]: inbound packet connection from 127.0.0.1:59368
+0800 2026-08-16 00:36:58 INFO [824732556 0ms] inbound/direct[udp-in]: inbound packet connection to 1.1.1.1:53
+0800 2026-08-16 00:36:58 DEBUG [824732556 0ms] router: match[0] inbound=udp-in => route(ss-out)
+0800 2026-08-16 00:36:58 INFO [824732556 0ms] outbound/shadowsocks[ss-out]: outbound packet connection to 1.1.1.1:53
# 复现时 downstream 日志
没有出现 inbound/shadowsocks[down-in] 的 UDP 接收记录。
# 生产环境错误路径抓包
eth0 Out IP 10.42.2.41.46742 > 127.0.0.1.38080:
UDP, length 886
# 修复后的抓包
lo IP 127.0.0.1.47152 > 127.0.0.1.38080:
UDP, length 607
lo IP 127.0.0.1.38080 > 127.0.0.1.47152:
UDP, length 875
支持我们
- 我已经 赞助
完整性要求
- 我保证阅读了文档,了解所有我编写的配置文件项的含义,而不是大量堆砌看似有用的选项或默认值。
- 我保证提供了可以在本地重现该问题的服务器、客户端配置文件与流程,而不是一个脱敏的复杂客户端配置文件。
- 我保证提供了可用于重现我报告的错误的最简配置,而不是依赖远程服务器、TUN、图形界面客户端或者其他闭源软件。
- 我保证提供了完整的配置文件与日志,而不是出于对自身智力的自信而仅提供了部分认为有用的部分。
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with route.auto_detect_interface and the direct outbound's bind_interface behavior on Linux, using the two-process relay configuration and the provided nc command to reproduce the UDP path. Compare the failing default route with the direct-loopback workaround; done means 127.0.0.0/8 and ::1/128 UDP destinations reach the local downstream inbound without manual routing rules.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, linux
- Domain
- networking
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100