diff --git a/android_tz.go b/android_tz.go new file mode 100644 index 00000000..82fc38e3 --- /dev/null +++ b/android_tz.go @@ -0,0 +1,21 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// kanged from https://github.com/golang/mobile/blob/c713f31d574bb632a93f169b2cc99c9e753fef0e/app/android.go#L89 + +package main + +// #include +import "C" +import "time" + +func init() { + var currentT C.time_t + var currentTM C.struct_tm + C.time(¤tT) + C.localtime_r(¤tT, ¤tTM) + tzOffset := int(currentTM.tm_gmtoff) + tz := C.GoString(currentTM.tm_zone) + time.Local = time.FixedZone(tz, tzOffset) +} diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 070d98b8..12e7c960 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -7,12 +7,14 @@ import ( "net" "net/netip" "os" + "strconv" "strings" "sync" "time" "github.com/metacubex/mihomo/component/resolver" "github.com/metacubex/mihomo/constant/features" + "github.com/metacubex/mihomo/log" ) const ( @@ -24,6 +26,7 @@ type dialFunc func(ctx context.Context, network string, ips []netip.Addr, port s var ( dialMux sync.Mutex + IP4PEnable bool actualSingleStackDialContext = serialSingleStackDialContext actualDualStackDialContext = serialDualStackDialContext tcpConcurrent = false @@ -128,7 +131,13 @@ func dialContext(ctx context.Context, network string, destination netip.Addr, po return dialContextHooked(ctx, network, destination, port) } - address := net.JoinHostPort(destination.String(), port) + var address string + if IP4PEnable { + NewDestination, NewPort := lookupIP4P(destination.String(), port) + address = net.JoinHostPort(NewDestination, NewPort) + } else { + address = net.JoinHostPort(destination.String(), port) + } netDialer := opt.netDialer switch netDialer.(type) { @@ -383,3 +392,21 @@ func NewDialer(options ...Option) Dialer { opt := applyOptions(options...) return Dialer{Opt: *opt} } + +func GetIP4PEnable(enableIP4PConvert bool) { + IP4PEnable = enableIP4PConvert +} + +// kanged from https://github.com/heiher/frp/blob/ip4p/client/ip4p.go + +func lookupIP4P(addr string, port string) (string, string) { + ip := net.ParseIP(addr) + if ip[0] == 0x20 && ip[1] == 0x01 && + ip[2] == 0x00 && ip[3] == 0x00 { + addr = net.IPv4(ip[12], ip[13], ip[14], ip[15]).String() + port = strconv.Itoa(int(ip[10])<<8 + int(ip[11])) + log.Debugln("Convert IP4P address %s to %s", ip, net.JoinHostPort(addr, port)) + return addr, port + } + return addr, port +} diff --git a/config/config.go b/config/config.go index d4b9ad89..8fec0bab 100644 --- a/config/config.go +++ b/config/config.go @@ -169,6 +169,7 @@ type Experimental struct { Fingerprints []string `yaml:"fingerprints"` QUICGoDisableGSO bool `yaml:"quic-go-disable-gso"` QUICGoDisableECN bool `yaml:"quic-go-disable-ecn"` + IP4PEnable bool `yaml:"dialer-ip4p-convert"` } // Config is mihomo config manager diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 14e826d7..c23eb9f3 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -197,6 +197,7 @@ func updateExperimental(c *config.Config) { if c.Experimental.QUICGoDisableECN { _ = os.Setenv("QUIC_GO_DISABLE_ECN", strconv.FormatBool(true)) } + dialer.GetIP4PEnable(c.Experimental.IP4PEnable) } func updateNTP(c *config.NTP) { diff --git a/main.go b/main.go index 4b2dff9c..748fa2e3 100644 --- a/main.go +++ b/main.go @@ -4,7 +4,6 @@ import ( "flag" "fmt" "os" - "os/exec" "os/signal" "path/filepath" "runtime" @@ -49,10 +48,6 @@ func init() { } func main() { - if runtime.GOOS == "android" { - SetAndroidTZ() - } - _, _ = maxprocs.Set(maxprocs.Logger(func(string, ...any) {})) if version { fmt.Printf("Mihomo Meta %s %s %s with %s %s\n", @@ -181,15 +176,3 @@ func updateGeoDatabases() { executor.ApplyConfig(cfg, false) }() } - -func SetAndroidTZ() { - out, err := exec.Command("getprop", "persist.sys.timezone").Output() - if err != nil { - return - } - z, err := time.LoadLocation(strings.TrimSpace(string(out))) - if err != nil { - return - } - time.Local = z -}