diff --git a/adapter/outbound/tailscale.go b/adapter/outbound/tailscale.go index 1c36de99..0e3b9a3f 100644 --- a/adapter/outbound/tailscale.go +++ b/adapter/outbound/tailscale.go @@ -27,6 +27,7 @@ import ( "github.com/metacubex/tailscale/tailcfg" "github.com/metacubex/tailscale/tsnet" D "github.com/miekg/dns" + "github.com/samber/lo" ) type Tailscale struct { @@ -70,13 +71,16 @@ func init() { envknob.SetNoLogsNoSupport() if runtime.GOOS == "android" { // Android SDK 30 no longer permits Go's net.Interfaces to work (Issue 2293) netmon.RegisterInterfaceGetter(func() (nif []netmon.Interface, err error) { + log.Debugln("[Tailscale] InterfaceGetter: start, IsForceAnet: %v", anet.IsForceAnet()) ifaces, err := anet.Interfaces() if err != nil { + log.Warnln("[Tailscale] anet.Interfaces failed: %v", err) return nil, err } for _, iff := range ifaces { addrs, err := anet.InterfaceAddrsByInterface(&iff) if err != nil { + log.Warnln("[Tailscale] anet.InterfaceAddrsByInterface(%v) failed: %v", iff.Name, err) continue } nif = append(nif, netmon.Interface{ @@ -84,6 +88,15 @@ func init() { AltAddrs: addrs, }) } + + log.Debugln("[Tailscale] InterfaceGetter: %v", lo.Map(nif, func(item netmon.Interface, index int) string { + var addrs any + addrs, err := item.Addrs() + if err != nil { + addrs = err + } + return fmt.Sprintf("{Name: %s, Addrs: %v, IsUp: %v, IsLoopback: %v}", item.Name, addrs, item.IsUp(), item.IsLoopback()) + })) return }) } @@ -124,15 +137,30 @@ func NewTailscale(option TailscaleOption) (*Tailscale, error) { } outbound.dialer = option.NewDialer(outbound.DialOptions()) outbound.server = &tsnet.Server{ - Dir: option.StateDir, - Hostname: option.Hostname, - AuthKey: option.AuthKey, - ControlURL: option.ControlURL, - Ephemeral: option.Ephemeral, - SystemDialer: outbound.dialer.DialContext, - SystemPacketListener: tailscalePacketListener{dialer: outbound.dialer}.ListenPacket, - ExtraRootCAs: ca.GetCertPool(), - LookupHook: tailscaleLookupHook, + Dir: option.StateDir, + Hostname: option.Hostname, + AuthKey: option.AuthKey, + ControlURL: option.ControlURL, + Ephemeral: option.Ephemeral, + SystemDialer: func(ctx context.Context, network, address string) (net.Conn, error) { + log.Debugln("[Tailscale](%s) SystemDialer: start dial %s %s", option.Name, network, address) + conn, err := outbound.dialer.DialContext(ctx, network, address) + log.Debugln("[Tailscale](%s) SystemDialer: finish dial %s %s, err: %v", option.Name, network, address, err) + return conn, err + }, + SystemPacketListener: func(ctx context.Context, network, address string) (net.PacketConn, error) { + log.Debugln("[Tailscale](%s) SystemPacketListener: start listen %s %s", option.Name, network, address) + pc, err := outbound.dialer.ListenPacket(ctx, network, address, netip.AddrPort{}) + log.Debugln("[Tailscale](%s) SystemPacketListener: finish listen %s %s, err: %v", option.Name, network, address, err) + return pc, err + }, + ExtraRootCAs: ca.GetCertPool(), + LookupHook: func(ctx context.Context, host string) ([]netip.Addr, error) { + log.Debugln("[Tailscale](%s) LookupHook: start lookup %s", option.Name, host) + ips, err := resolver.LookupIPWithResolver(ctx, host, resolver.ProxyServerHostResolver) + log.Debugln("[Tailscale](%s) LookupHook: finish lookup %s, ips: %v, err: %v", option.Name, host, ips, err) + return ips, err + }, UserLogf: func(format string, args ...any) { log.Infoln("[Tailscale](%s) %s", option.Name, fmt.Sprintf(format, args...)) }, @@ -309,10 +337,6 @@ func tailscaleExitNodeNeedsStatus(option TailscaleOption) bool { return !ok } -func tailscaleLookupHook(ctx context.Context, host string) ([]netip.Addr, error) { - return resolver.LookupIPWithResolver(ctx, host, resolver.ProxyServerHostResolver) -} - func (t *Tailscale) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn, err error) { if err = t.ensureStarted(ctx); err != nil { return nil, err @@ -444,11 +468,3 @@ func (t *Tailscale) Close() error { } return nil } - -type tailscalePacketListener struct { - dialer C.Dialer -} - -func (l tailscalePacketListener) ListenPacket(ctx context.Context, network, address string) (net.PacketConn, error) { - return l.dialer.ListenPacket(ctx, network, address, netip.AddrPort{}) -} diff --git a/component/iface/anet/anet.go b/component/iface/anet/anet.go new file mode 100644 index 00000000..57d7f6f9 --- /dev/null +++ b/component/iface/anet/anet.go @@ -0,0 +1,11 @@ +package anet + +import ( + "os" + "strconv" +) + +func IsForceAnet() bool { + force, _ := strconv.ParseBool(os.Getenv("FORCE_ANET")) + return force +} diff --git a/component/iface/anet/interface_android.go b/component/iface/anet/interface_android.go index af612eae..9d5d0828 100644 --- a/component/iface/anet/interface_android.go +++ b/component/iface/anet/interface_android.go @@ -21,11 +21,13 @@ type ifReq [40]byte // Interfaces returns a list of the system's network interfaces. func Interfaces() ([]net.Interface, error) { - ift, err := net.Interfaces() - if err == nil { - return ift, nil + if !IsForceAnet() { + ift, err := net.Interfaces() + if err == nil { + return ift, nil + } } - ift, err = interfaceTable(0) + ift, err := interfaceTable(0) if err != nil { return nil, &net.OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} } @@ -38,11 +40,13 @@ func Interfaces() ([]net.Interface, error) { // The returned list does not identify the associated interface; use // Interfaces and Interface.Addrs for more detail. func InterfaceAddrs() ([]net.Addr, error) { - ifat, err := net.InterfaceAddrs() - if err == nil { - return ifat, nil + if !IsForceAnet() { + ifat, err := net.InterfaceAddrs() + if err == nil { + return ifat, nil + } } - ifat, err = interfaceAddrTable(nil) + ifat, err := interfaceAddrTable(nil) if err != nil { err = &net.OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} } @@ -55,9 +59,11 @@ func InterfaceAddrs() ([]net.Addr, error) { // sharing the logical data link; for more precision use // InterfaceByName. func InterfaceByIndex(index int) (*net.Interface, error) { - ifi, err := net.InterfaceByIndex(index) - if err == nil { - return ifi, nil + if !IsForceAnet() { + ifi, err := net.InterfaceByIndex(index) + if err == nil { + return ifi, nil + } } if index <= 0 { return nil, &net.OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceIndex} @@ -66,7 +72,7 @@ func InterfaceByIndex(index int) (*net.Interface, error) { if err != nil { return nil, &net.OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} } - ifi, err = interfaceByIndex(ift, index) + ifi, err := interfaceByIndex(ift, index) if err != nil { err = &net.OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} } @@ -75,9 +81,11 @@ func InterfaceByIndex(index int) (*net.Interface, error) { // InterfaceByName returns the interface specified by name. func InterfaceByName(name string) (*net.Interface, error) { - ifi, err := net.InterfaceByName(name) - if err == nil { - return ifi, nil + if !IsForceAnet() { + ifi, err := net.InterfaceByName(name) + if err == nil { + return ifi, nil + } } if name == "" { return nil, &net.OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceName}