feat: support sending ping requests via direct in tun mode

This commit is contained in:
wwqgtxx 2025-08-27 18:00:25 +08:00
parent 84086a6e6c
commit 0ced98da4d
6 changed files with 79 additions and 15 deletions

View File

@ -21,10 +21,10 @@ func bindControl(ifaceIdx int) controlFn {
var innerErr error
err = c.Control(func(fd uintptr) {
switch network {
case "tcp4", "udp4":
innerErr = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_BOUND_IF, ifaceIdx)
case "tcp6", "udp6":
case "tcp6", "udp6", "ip6":
innerErr = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_BOUND_IF, ifaceIdx)
default:
innerErr = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_BOUND_IF, ifaceIdx)
}
})

View File

@ -9,6 +9,7 @@ import (
"os"
"strings"
"sync"
"syscall"
"time"
"github.com/metacubex/mihomo/component/keepalive"
@ -177,6 +178,34 @@ func dialContext(ctx context.Context, network string, destination netip.Addr, po
return dialer.DialContext(ctx, network, address)
}
func ICMPControl(destination netip.Addr) func(network, address string, conn syscall.RawConn) error {
return func(network, address string, conn syscall.RawConn) error {
if DefaultSocketHook != nil {
return DefaultSocketHook(network, address, conn)
}
dialer := &net.Dialer{}
interfaceName := DefaultInterface.Load()
if interfaceName == "" {
if finder := DefaultInterfaceFinder.Load(); finder != nil {
interfaceName = finder.FindInterfaceName(destination)
}
}
if interfaceName != "" {
if err := bindIfaceToDialer(interfaceName, dialer, network, destination); err != nil {
return err
}
}
routingMark := int(DefaultRoutingMark.Load())
if routingMark != 0 {
bindMarkToDialer(routingMark, dialer, network, destination)
}
if dialer.ControlContext != nil {
return dialer.ControlContext(context.TODO(), network, address, conn)
}
return nil
}
}
func serialSingleStackDialContext(ctx context.Context, network string, ips []netip.Addr, port string, opt option) (net.Conn, error) {
return serialDialContext(ctx, network, ips, port, opt)
}

6
go.mod
View File

@ -24,13 +24,13 @@ require (
github.com/metacubex/quic-go v0.54.1-0.20250730114134-a1ae705fe295
github.com/metacubex/randv2 v0.2.0
github.com/metacubex/restls-client-go v0.1.7
github.com/metacubex/sing v0.5.5
github.com/metacubex/sing v0.5.6-0.20250826072929-f69b475e017b
github.com/metacubex/sing-mux v0.3.3-0.20250813083925-d7c9aeaeeaac
github.com/metacubex/sing-quic v0.0.0-20250718154553-1b193bec4cbb
github.com/metacubex/sing-shadowsocks v0.2.12
github.com/metacubex/sing-shadowsocks2 v0.2.6
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2
github.com/metacubex/sing-tun v0.4.7
github.com/metacubex/sing-tun v0.4.8-0.20250827085914-fc5681b9fc9f
github.com/metacubex/sing-vmess v0.2.4-0.20250822020810-4856053566f0
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee
@ -89,7 +89,7 @@ require (
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mdlayher/socket v0.4.1 // indirect
github.com/metacubex/ascon v0.1.0 // indirect
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b // indirect
github.com/metacubex/gvisor v0.0.0-20250826025146-23043f716a2c // indirect
github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 // indirect
github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect
github.com/onsi/ginkgo/v2 v2.9.5 // indirect

12
go.sum
View File

@ -106,8 +106,8 @@ github.com/metacubex/fswatch v0.1.1 h1:jqU7C/v+g0qc2RUFgmAOPoVvfl2BXXUXEumn6oQux
github.com/metacubex/fswatch v0.1.1/go.mod h1:czrTT7Zlbz7vWft8RQu9Qqh+JoX+Nnb+UabuyN1YsgI=
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvOzK9ubNCCkQ+ldc4YSH/rILn53l/xGBFHHI=
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88=
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b h1:RUh4OdVPz/jDrM9MQ2ySuqu2aeBqcA8rtfWUYLZ8RtI=
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b/go.mod h1:8LpS0IJW1VmWzUm3ylb0e2SK5QDm5lO/2qwWLZgRpBU=
github.com/metacubex/gvisor v0.0.0-20250826025146-23043f716a2c h1:N9m7IAKfBuGDieY/JT2wjfdyURgTNpFNOFpqq+RF0i4=
github.com/metacubex/gvisor v0.0.0-20250826025146-23043f716a2c/go.mod h1:8LpS0IJW1VmWzUm3ylb0e2SK5QDm5lO/2qwWLZgRpBU=
github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 h1:1Qpuy+sU3DmyX9HwI+CrBT/oLNJngvBorR2RbajJcqo=
github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793/go.mod h1:RjRNb4G52yAgfR+Oe/kp9G4PJJ97Fnj89eY1BFO3YyA=
github.com/metacubex/quic-go v0.54.1-0.20250730114134-a1ae705fe295 h1:8JVlYuE8uSJAvmyCd4TjvDxs57xjb0WxEoaWafK5+qs=
@ -117,8 +117,8 @@ github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFq
github.com/metacubex/restls-client-go v0.1.7 h1:eCwiXCTQb5WJu9IlgYvDBA1OgrINv58dEe7hcN5H15k=
github.com/metacubex/restls-client-go v0.1.7/go.mod h1:BN/U52vPw7j8VTSh2vleD/MnmVKCov84mS5VcjVHH4g=
github.com/metacubex/sing v0.5.2/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
github.com/metacubex/sing v0.5.5 h1:m5U8iHvRAUxlme3FZlE/LPIGHjU8oMCUzXWGbQQAC1E=
github.com/metacubex/sing v0.5.5/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
github.com/metacubex/sing v0.5.6-0.20250826072929-f69b475e017b h1:ukK1IMo7LJ+VmPWQPIdoslHBv4Tr3E2zE34ilQCH2i4=
github.com/metacubex/sing v0.5.6-0.20250826072929-f69b475e017b/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
github.com/metacubex/sing-mux v0.3.3-0.20250813083925-d7c9aeaeeaac h1:wDH/Jh/yqWbzPktqJP+Y1cUG8hchcrzKzUxJiSpnaQs=
github.com/metacubex/sing-mux v0.3.3-0.20250813083925-d7c9aeaeeaac/go.mod h1:3rt1soewn0O6j89GCLmwAQFsq257u0jf2zQSPhTL3Bw=
github.com/metacubex/sing-quic v0.0.0-20250718154553-1b193bec4cbb h1:U/m3h8lp/j7i8zFgfvScLdZa1/Y8dd74oO7iZaQq80s=
@ -129,8 +129,8 @@ github.com/metacubex/sing-shadowsocks2 v0.2.6 h1:ZR1kYT0f0Vi64iQSS09OdhFfppiNkh7
github.com/metacubex/sing-shadowsocks2 v0.2.6/go.mod h1:vOEbfKC60txi0ca+yUlqEwOGc3Obl6cnSgx9Gf45KjE=
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MYPm7Wme3/OAY2FFzVq9d9GxPHOqu5AQfg/ddhI=
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2/go.mod h1:mbfboaXauKJNIHJYxQRa+NJs4JU9NZfkA+I33dS2+9E=
github.com/metacubex/sing-tun v0.4.7 h1:ZDY/W+1c7PeWWKeKRyUo18fySF/TWjB0i5ui81Ar778=
github.com/metacubex/sing-tun v0.4.7/go.mod h1:xHecZRwBnKWe6zG9amAK9cXf91lF6blgjBqm+VvOrmU=
github.com/metacubex/sing-tun v0.4.8-0.20250827085914-fc5681b9fc9f h1:1MV/pFn2vjnyvH/0u6sJST0kmaoZXgbUytCCfuelhl8=
github.com/metacubex/sing-tun v0.4.8-0.20250827085914-fc5681b9fc9f/go.mod h1:FQ9zXA+kVhdzqgFqeJdi/AUhJgUgw+SUXqrR++GvbnM=
github.com/metacubex/sing-vmess v0.2.4-0.20250822020810-4856053566f0 h1:WZepq4TOZa6WewB8tGAZrrL+bL2R2ivoBzuEgAeolWc=
github.com/metacubex/sing-vmess v0.2.4-0.20250822020810-4856053566f0/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM=
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f h1:Sr/DYKYofKHKc4GF3qkRGNuj6XA6c0eqPgEDN+VAsYU=

View File

@ -0,0 +1,34 @@
package sing_tun
import (
"context"
"time"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/resolver"
"github.com/metacubex/mihomo/log"
tun "github.com/metacubex/sing-tun"
"github.com/metacubex/sing-tun/ping"
M "github.com/metacubex/sing/common/metadata"
N "github.com/metacubex/sing/common/network"
)
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
log.Infoln("[ICMP] %s %s --> %s using fake ping echo", network, source, destination)
return nil, nil
}
log.Infoln("[ICMP] %s %s --> %s using DIRECT", network, source, destination)
directRouteDestination, err := ping.ConnectDestination(context.TODO(), log.SingLogger, dialer.ICMPControl(destination.Addr), destination.Addr, routeContext, timeout)
if err != nil {
log.Warnln("[ICMP] failed to connect to %s", destination)
return nil, err
}
log.Debugln("[ICMP] success connect to %s", destination)
return directRouteDestination, nil
}
return nil, nil
}

View File

@ -11,6 +11,7 @@ import (
"strconv"
"strings"
"sync"
"time"
"github.com/metacubex/mihomo/adapter/inbound"
"github.com/metacubex/mihomo/component/dialer"
@ -174,11 +175,11 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis
if tunMTU == 0 {
tunMTU = 9000
}
var udpTimeout int64
var udpTimeout time.Duration
if options.UDPTimeout != 0 {
udpTimeout = options.UDPTimeout
udpTimeout = time.Second * time.Duration(options.UDPTimeout)
} else {
udpTimeout = int64(sing.UDPTimeout.Seconds())
udpTimeout = sing.UDPTimeout
}
tableIndex := options.IPRoute2TableIndex
if tableIndex == 0 {