From 9a124a390f9fad9273ae758dc704b97a62b72ca0 Mon Sep 17 00:00:00 2001 From: NuoFang <137974286+NuoFang6@users.noreply.github.com> Date: Sun, 7 Sep 2025 19:40:30 +0800 Subject: [PATCH] feat: add `disable-icmp-forwarding` option to tun (#2248) When enabled, the TUN listener will use fake ping echo. This can be useful to prevent potential ICMP routing loops in certain network configurations. --- config/config.go | 2 ++ docs/config.yaml | 2 ++ listener/config/tun.go | 4 ++++ listener/inbound/tun.go | 2 ++ listener/sing_tun/dns.go | 3 ++- listener/sing_tun/prepare.go | 2 +- listener/sing_tun/server.go | 5 +++-- 7 files changed, 16 insertions(+), 4 deletions(-) diff --git a/config/config.go b/config/config.go index 77fdd4d6..f6c19a29 100644 --- a/config/config.go +++ b/config/config.go @@ -292,6 +292,7 @@ type RawTun struct { ExcludePackage []string `yaml:"exclude-package" json:"exclude-package,omitempty"` EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint-independent-nat,omitempty"` UDPTimeout int64 `yaml:"udp-timeout" json:"udp-timeout,omitempty"` + DisableICMPForwarding bool `yaml:"disable-icmp-forwarding" json:"disable-icmp-forwarding,omitempty"` FileDescriptor int `yaml:"file-descriptor" json:"file-descriptor"` Inet4RouteAddress []netip.Prefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"` @@ -1552,6 +1553,7 @@ func parseTun(rawTun RawTun, general *General) error { ExcludePackage: rawTun.ExcludePackage, EndpointIndependentNat: rawTun.EndpointIndependentNat, UDPTimeout: rawTun.UDPTimeout, + DisableICMPForwarding: rawTun.DisableICMPForwarding, FileDescriptor: rawTun.FileDescriptor, Inet4RouteAddress: rawTun.Inet4RouteAddress, diff --git a/docs/config.yaml b/docs/config.yaml index 77992164..2f44e24d 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -142,6 +142,7 @@ tun: # gso-max-size: 65536 # 通用分段卸载包的最大大小 auto-redirect: false # 自动配置 iptables 以重定向 TCP 连接。仅支持 Linux。带有 auto-redirect 的 auto-route 现在可以在路由器上按预期工作,无需干预。 # strict-route: true # 将所有连接路由到 tun 来防止泄漏,但你的设备将无法其他设备被访问 + # disable-icmp-forwarding: true # 禁用 ICMP 转发,防止某些情况下的 ICMP 环回问题,ping 将不会显示真实的延迟 route-address-set: # 将指定规则集中的目标 IP CIDR 规则添加到防火墙, 不匹配的流量将绕过路由, 仅支持 Linux,且需要 nftables,`auto-route` 和 `auto-redirect` 已启用。 - ruleset-1 - ruleset-2 @@ -1554,6 +1555,7 @@ listeners: # - com.android.chrome # exclude-package: # 排除被路由的 Android 应用包名 # - com.android.captiveportallogin + # disable-icmp-forwarding: true # 禁用 ICMP 转发,防止某些情况下的 ICMP 环回问题,ping 将不会显示真实的延迟 # 入口配置与 Listener 等价,传入流量将和 socks,mixed 等入口一样按照 mode 所指定的方式进行匹配处理 # shadowsocks,vmess 入口配置(传入流量将和 socks,mixed 等入口一样按照 mode 所指定的方式进行匹配处理) # ss-config: ss://2022-blake3-aes-256-gcm:vlmpIPSyHH6f4S8WVPdRIHIlzmB+GIRfoH3aNJ/t9Gg=@:23456 diff --git a/listener/config/tun.go b/listener/config/tun.go index 0efbc827..0e262329 100644 --- a/listener/config/tun.go +++ b/listener/config/tun.go @@ -48,6 +48,7 @@ type Tun struct { ExcludePackage []string `yaml:"exclude-package" json:"exclude-package,omitempty"` EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint-independent-nat,omitempty"` UDPTimeout int64 `yaml:"udp-timeout" json:"udp-timeout,omitempty"` + DisableICMPForwarding bool `yaml:"disable-icmp-forwarding" json:"disable-icmp-forwarding,omitempty"` FileDescriptor int `yaml:"file-descriptor" json:"file-descriptor"` Inet4RouteAddress []netip.Prefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"` @@ -186,6 +187,9 @@ func (t *Tun) Equal(other Tun) bool { if t.UDPTimeout != other.UDPTimeout { return false } + if t.DisableICMPForwarding != other.DisableICMPForwarding { + return false + } if t.FileDescriptor != other.FileDescriptor { return false } diff --git a/listener/inbound/tun.go b/listener/inbound/tun.go index e6ebb2a1..79004023 100644 --- a/listener/inbound/tun.go +++ b/listener/inbound/tun.go @@ -49,6 +49,7 @@ type TunOption struct { ExcludePackage []string `inbound:"exclude-package,omitempty"` EndpointIndependentNat bool `inbound:"endpoint-independent-nat,omitempty"` UDPTimeout int64 `inbound:"udp-timeout,omitempty"` + DisableICMPForwarding bool `inbound:"disable-icmp-forwarding,omitempty"` FileDescriptor int `inbound:"file-descriptor,omitempty"` Inet4RouteAddress []netip.Prefix `inbound:"inet4-route-address,omitempty"` @@ -122,6 +123,7 @@ func NewTun(options *TunOption) (*Tun, error) { ExcludePackage: options.ExcludePackage, EndpointIndependentNat: options.EndpointIndependentNat, UDPTimeout: options.UDPTimeout, + DisableICMPForwarding: options.DisableICMPForwarding, FileDescriptor: options.FileDescriptor, Inet4RouteAddress: options.Inet4RouteAddress, diff --git a/listener/sing_tun/dns.go b/listener/sing_tun/dns.go index 0b8a3ebe..82a9fdb6 100644 --- a/listener/sing_tun/dns.go +++ b/listener/sing_tun/dns.go @@ -20,7 +20,8 @@ import ( type ListenerHandler struct { *sing.ListenerHandler - DnsAdds []netip.AddrPort + DnsAdds []netip.AddrPort + DisableICMPForwarding bool } func (h *ListenerHandler) ShouldHijackDns(targetAddr netip.AddrPort) bool { diff --git a/listener/sing_tun/prepare.go b/listener/sing_tun/prepare.go index b3e1e0b2..e59947b8 100644 --- a/listener/sing_tun/prepare.go +++ b/listener/sing_tun/prepare.go @@ -17,7 +17,7 @@ import ( func (h *ListenerHandler) PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) { switch network { case N.NetworkICMP: // our fork only send those type to PrepareConnection now - if resolver.IsFakeIP(destination.Addr) { // skip fakeip + if h.DisableICMPForwarding || resolver.IsFakeIP(destination.Addr) { // skip fakeip and if ICMP handling is disabled log.Infoln("[ICMP] %s %s --> %s using fake ping echo", network, source, destination) return nil, nil } diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index 6bee7ffc..ccd12f42 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -267,8 +267,9 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis } handler := &ListenerHandler{ - ListenerHandler: h, - DnsAdds: dnsAdds, + ListenerHandler: h, + DnsAdds: dnsAdds, + DisableICMPForwarding: options.DisableICMPForwarding, } l = &Listener{ closed: false,