diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index f979b446..afed410f 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -158,9 +158,9 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { } tlsConfig := &tls.Config{ - NextProtos: option.ALPN, - MinVersion: tls.VersionTLS12, - //InsecureSkipVerify: tOption.SkipCertVerify, + NextProtos: option.ALPN, + MinVersion: tls.VersionTLS12, + InsecureSkipVerify: tOption.SkipCertVerify, ServerName: tOption.ServerName, } diff --git a/component/mmdb/mmdb.go b/component/mmdb/mmdb.go new file mode 100644 index 00000000..e120055d --- /dev/null +++ b/component/mmdb/mmdb.go @@ -0,0 +1,45 @@ +package mmdb + +import ( + "sync" + + C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/log" + + "github.com/oschwald/geoip2-golang" +) + +var ( + mmdb *geoip2.Reader + once sync.Once +) + +func LoadFromBytes(buffer []byte) { + once.Do(func() { + var err error + mmdb, err = geoip2.FromBytes(buffer) + if err != nil { + log.Fatalln("Can't load mmdb: %s", err.Error()) + } + }) +} + +func Verify() bool { + instance, err := geoip2.Open(C.Path.MMDB()) + if err == nil { + instance.Close() + } + return err == nil +} + +func Instance() *geoip2.Reader { + once.Do(func() { + var err error + mmdb, err = geoip2.Open(C.Path.MMDB()) + if err != nil { + log.Fatalln("Can't load mmdb: %s", err.Error()) + } + }) + + return mmdb +} diff --git a/config/initial.go b/config/initial.go index 79ae1878..9d8288ba 100644 --- a/config/initial.go +++ b/config/initial.go @@ -6,18 +6,19 @@ import ( "net/http" "os" + "github.com/Dreamacro/clash/component/mmdb" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" ) -func downloadGeoIP(path string) (err error) { - resp, err := http.Get("https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geoip.dat") +func downloadMMDB(path string) (err error) { + resp, err := http.Get("https://cdn.jsdelivr.net/gh/Loyalsoldier/geoip@release/Country.mmdb") if err != nil { return } defer resp.Body.Close() - f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0644) + f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0o644) if err != nil { return err } @@ -27,6 +28,45 @@ func downloadGeoIP(path string) (err error) { return err } +func initMMDB() error { + if _, err := os.Stat(C.Path.MMDB()); os.IsNotExist(err) { + log.Infoln("Can't find MMDB, start download") + if err := downloadMMDB(C.Path.MMDB()); err != nil { + return fmt.Errorf("can't download MMDB: %s", err.Error()) + } + } + + if !mmdb.Verify() { + log.Warnln("MMDB invalid, remove and download") + if err := os.Remove(C.Path.MMDB()); err != nil { + return fmt.Errorf("can't remove invalid MMDB: %s", err.Error()) + } + + if err := downloadMMDB(C.Path.MMDB()); err != nil { + return fmt.Errorf("can't download MMDB: %s", err.Error()) + } + } + + return nil +} + +//func downloadGeoIP(path string) (err error) { +// resp, err := http.Get("https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geoip.dat") +// if err != nil { +// return +// } +// defer resp.Body.Close() +// +// f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0644) +// if err != nil { +// return err +// } +// defer f.Close() +// _, err = io.Copy(f, resp.Body) +// +// return err +//} + func downloadGeoSite(path string) (err error) { resp, err := http.Get("https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat") if err != nil { @@ -34,7 +74,7 @@ func downloadGeoSite(path string) (err error) { } defer resp.Body.Close() - f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0644) + f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0o644) if err != nil { return err } @@ -44,17 +84,18 @@ func downloadGeoSite(path string) (err error) { return err } -func initGeoIP() error { - if _, err := os.Stat(C.Path.GeoIP()); os.IsNotExist(err) { - log.Infoln("Can't find GeoIP.dat, start download") - if err := downloadGeoIP(C.Path.GeoIP()); err != nil { - return fmt.Errorf("can't download GeoIP.dat: %s", err.Error()) - } - log.Infoln("Download GeoIP.dat finish") - } - - return nil -} +// +//func initGeoIP() error { +// if _, err := os.Stat(C.Path.GeoIP()); os.IsNotExist(err) { +// log.Infoln("Can't find GeoIP.dat, start download") +// if err := downloadGeoIP(C.Path.GeoIP()); err != nil { +// return fmt.Errorf("can't download GeoIP.dat: %s", err.Error()) +// } +// log.Infoln("Download GeoIP.dat finish") +// } +// +// return nil +//} func initGeoSite() error { if _, err := os.Stat(C.Path.GeoSite()); os.IsNotExist(err) { @@ -72,7 +113,7 @@ func initGeoSite() error { func Init(dir string) error { // initial homedir if _, err := os.Stat(dir); os.IsNotExist(err) { - if err := os.MkdirAll(dir, 0777); err != nil { + if err := os.MkdirAll(dir, 0o777); err != nil { return fmt.Errorf("can't create config directory %s: %s", dir, err.Error()) } } @@ -80,7 +121,7 @@ func Init(dir string) error { // initial config.yaml if _, err := os.Stat(C.Path.Config()); os.IsNotExist(err) { log.Infoln("Can't find config, create a initial config file") - f, err := os.OpenFile(C.Path.Config(), os.O_CREATE|os.O_WRONLY, 0644) + f, err := os.OpenFile(C.Path.Config(), os.O_CREATE|os.O_WRONLY, 0o644) if err != nil { return fmt.Errorf("can't create file %s: %s", C.Path.Config(), err.Error()) } @@ -88,9 +129,14 @@ func Init(dir string) error { f.Close() } - // initial GeoIP - if err := initGeoIP(); err != nil { - return fmt.Errorf("can't initial GeoIP: %w", err) + //// initial GeoIP + //if err := initGeoIP(); err != nil { + // return fmt.Errorf("can't initial GeoIP: %w", err) + //} + + // initial mmdb + if err := initMMDB(); err != nil { + return fmt.Errorf("can't initial MMDB: %w", err) } // initial GeoSite diff --git a/constant/rule.go b/constant/rule.go index f36a3b51..aaa7e26d 100644 --- a/constant/rule.go +++ b/constant/rule.go @@ -1,5 +1,7 @@ package constant +import "net" + // Rule Type const ( Domain RuleType = iota @@ -54,3 +56,5 @@ type Rule interface { ShouldResolveIP() bool RuleExtra() *RuleExtra } + +var TunBroadcastAddr = net.IPv4(198, 18, 255, 255) diff --git a/dns/filters.go b/dns/filters.go index c7c56f8a..5939020e 100644 --- a/dns/filters.go +++ b/dns/filters.go @@ -2,16 +2,13 @@ package dns import ( "net" + "strings" + "github.com/Dreamacro/clash/component/mmdb" "github.com/Dreamacro/clash/component/trie" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/rule/geodata" - "github.com/Dreamacro/clash/rule/geodata/router" - _ "github.com/Dreamacro/clash/rule/geodata/standard" + C "github.com/Dreamacro/clash/constant" ) -var multiGeoIPMatcher *router.MultiGeoIPMatcher - type fallbackIPFilter interface { Match(net.IP) bool } @@ -21,49 +18,8 @@ type geoipFilter struct { } func (gf *geoipFilter) Match(ip net.IP) bool { - if multiGeoIPMatcher == nil { - countryCode := gf.code - countryCodePrivate := "private" - geoLoader, err := geodata.GetGeoDataLoader("standard") - if err != nil { - log.Errorln("[GeoIPFilter] GetGeoDataLoader error: %s", err.Error()) - return false - } - - recordsCN, err := geoLoader.LoadGeoIP(countryCode) - if err != nil { - log.Errorln("[GeoIPFilter] LoadGeoIP error: %s", err.Error()) - return false - } - - recordsPrivate, err := geoLoader.LoadGeoIP(countryCodePrivate) - if err != nil { - log.Errorln("[GeoIPFilter] LoadGeoIP error: %s", err.Error()) - return false - } - - geoips := []*router.GeoIP{ - { - CountryCode: countryCode, - Cidr: recordsCN, - ReverseMatch: false, - }, - { - CountryCode: countryCodePrivate, - Cidr: recordsPrivate, - ReverseMatch: false, - }, - } - - multiGeoIPMatcher, err = router.NewMultiGeoIPMatcher(geoips) - - if err != nil { - log.Errorln("[GeoIPFilter] NewMultiGeoIPMatcher error: %s", err.Error()) - return false - } - } - - return !multiGeoIPMatcher.ApplyIp(ip) + record, _ := mmdb.Instance().Country(ip) + return !strings.EqualFold(record.Country.IsoCode, gf.code) && !ip.IsPrivate() && !ip.Equal(C.TunBroadcastAddr) } type ipnetFilter struct { diff --git a/go.mod b/go.mod index 596ab397..65945cf8 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac github.com/kr328/tun2socket v0.0.0-20210412191540-3d56c47e2d99 github.com/miekg/dns v1.1.43 + github.com/oschwald/geoip2-golang v1.5.0 github.com/sirupsen/logrus v1.8.1 github.com/stretchr/testify v1.7.0 github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499 @@ -28,6 +29,7 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/google/btree v1.0.1 // indirect + github.com/oschwald/maxminddb-golang v1.8.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect golang.org/x/text v0.3.6 // indirect diff --git a/go.sum b/go.sum index df833f0d..09d1e7b5 100644 --- a/go.sum +++ b/go.sum @@ -463,6 +463,10 @@ github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.m github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= +github.com/oschwald/geoip2-golang v1.5.0 h1:igg2yQIrrcRccB1ytFXqBfOHCjXWIoMv85lVJ1ONZzw= +github.com/oschwald/geoip2-golang v1.5.0/go.mod h1:xdvYt5xQzB8ORWFqPnqMwZpCpgNagttWdoZLlJQzg7s= +github.com/oschwald/maxminddb-golang v1.8.0 h1:Uh/DSnGoxsyp/KYbY1AuP0tYEwfs0sCph9p/UMXK/Hk= +github.com/oschwald/maxminddb-golang v1.8.0/go.mod h1:RXZtst0N6+FY/3qCNmZMBApR19cdQj43/NM9VkrNAis= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= @@ -750,6 +754,7 @@ golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/listener/tun/dev/dev_darwin.go b/listener/tun/dev/dev_darwin.go index cb1b3296..e127d96c 100644 --- a/listener/tun/dev/dev_darwin.go +++ b/listener/tun/dev/dev_darwin.go @@ -20,41 +20,36 @@ import ( "github.com/Dreamacro/clash/common/pool" ) -const utunControlName = "com.apple.net.utun_control" -const _IOC_OUT = 0x40000000 -const _IOC_IN = 0x80000000 -const _IOC_INOUT = _IOC_IN | _IOC_OUT +const ( + utunControlName = "com.apple.net.utun_control" + iocOut = 0x40000000 + iocIn = 0x80000000 + iocInout = iocIn | iocOut +) // _CTLIOCGINFO value derived from /usr/include/sys/{kern_control,ioccom}.h // https://github.com/apple/darwin-xnu/blob/master/bsd/sys/ioccom.h // #define CTLIOCGINFO _IOWR('N', 3, struct ctl_info) /* get id from name */ = 0xc0644e03 -const _CTLIOCGINFO = _IOC_INOUT | ((100 & 0x1fff) << 16) | uint32(byte('N'))<<8 | 3 - -// #define SIOCAIFADDR_IN6 _IOW('i', 26, struct in6_aliasreq) = 0x8080691a -//const _SIOCAIFADDR_IN6 = _IOC_IN | ((128 & 0x1fff) << 16) | uint32(byte('i'))<<8 | 26 +const _CTLIOCGINFO = iocInout | ((100 & 0x1fff) << 16) | uint32(byte('N'))<<8 | 3 // #define SIOCPROTOATTACH_IN6 _IOWR('i', 110, struct in6_aliasreq_64) -const _SIOCPROTOATTACH_IN6 = _IOC_INOUT | ((128 & 0x1fff) << 16) | uint32(byte('i'))<<8 | 110 +const siocprotoattachIn6 = iocInout | ((128 & 0x1fff) << 16) | uint32(byte('i'))<<8 | 110 -// #define SIOCLL_START _IOWR('i', 130, struct in6_aliasreq) -const _SIOCLL_START = _IOC_INOUT | ((128 & 0x1fff) << 16) | uint32(byte('i'))<<8 | 130 - -// https://github.com/apple/darwin-xnu/blob/a449c6a3b8014d9406c2ddbdc81795da24aa7443/bsd/netinet6/nd6.h#L469 -const ND6_INFINITE_LIFETIME = 0xffffffff +// #define SIOCLL_START _IOWR('i', 130, struct in6Aliasreq) +const siocllStart = iocInout | ((128 & 0x1fff) << 16) | uint32(byte('i'))<<8 | 130 // Following the wireguard-go solution: // These unix.SYS_* constants were removed from golang.org/x/sys/unix // so copy them here for now. // See https://github.com/golang/go/issues/41868 const ( - sys_IOCTL = 54 - sys_CONNECT = 98 - sys_GETSOCKOPT = 118 + sysIoctl = 54 + sysConnect = 98 + sysGetsockopt = 118 ) type tunDarwin struct { - //url string name string tunAddress string autoRoute bool @@ -75,6 +70,37 @@ type sockaddrCtl struct { scReserved [5]uint32 } +type ctlInfo struct { + ctlID uint32 + ctlName [96]byte +} + +// https://github.com/apple/darwin-xnu/blob/a449c6a3b8014d9406c2ddbdc81795da24aa7443/bsd/sys/sockio.h#L107 +// https://github.com/apple/darwin-xnu/blob/a449c6a3b8014d9406c2ddbdc81795da24aa7443/bsd/net/if.h#L570-L575 +// https://man.openbsd.org/netintro.4#SIOCAIFADDR +type aliasreq struct { + ifraName [unix.IFNAMSIZ]byte + ifraAddr unix.RawSockaddrInet4 + ifraDstaddr unix.RawSockaddrInet4 + ifraMask unix.RawSockaddrInet4 +} + +// SIOCAIFADDR_IN6 +// https://github.com/apple/darwin-xnu/blob/a449c6a3b8014d9406c2ddbdc81795da24aa7443/bsd/netinet6/in6_var.h#L114-L119 +// https://opensource.apple.com/source/network_cmds/network_cmds-543.260.3/ +type in6Addrlifetime struct{} + +// https://github.com/apple/darwin-xnu/blob/a449c6a3b8014d9406c2ddbdc81795da24aa7443/bsd/netinet6/in6_var.h#L336-L343 +// https://github.com/apple/darwin-xnu/blob/a449c6a3b8014d9406c2ddbdc81795da24aa7443/bsd/netinet6/in6.h#L174-L181 +type in6Aliasreq struct { + ifraName [unix.IFNAMSIZ]byte + ifraAddr unix.RawSockaddrInet6 + ifraDstaddr unix.RawSockaddrInet6 + ifraPrefixmask unix.RawSockaddrInet6 + ifraFlags int32 + ifraLifetime in6Addrlifetime +} + // https://github.com/apple/darwin-xnu/blob/a449c6a3b8014d9406c2ddbdc81795da24aa7443/bsd/net/if.h#L402-L563 //type ifreqAddr struct { @@ -87,7 +113,6 @@ var sockaddrCtlSize uintptr = 32 // OpenTunDevice return a TunDevice according a URL func OpenTunDevice(tunAddress string, autoRoute bool) (TunDevice, error) { - name := "utun" // TODO: configure the MTU mtu := 9000 @@ -101,23 +126,19 @@ func OpenTunDevice(tunAddress string, autoRoute bool) (TunDevice, error) { } fd, err := unix.Socket(unix.AF_SYSTEM, unix.SOCK_DGRAM, 2) - if err != nil { return nil, err } - var ctlInfo = &struct { - ctlID uint32 - ctlName [96]byte - }{} + ctlInfo1 := &ctlInfo{} - copy(ctlInfo.ctlName[:], []byte(utunControlName)) + copy(ctlInfo1.ctlName[:], []byte(utunControlName)) _, _, errno := unix.Syscall( - sys_IOCTL, + sysIoctl, uintptr(fd), uintptr(_CTLIOCGINFO), - uintptr(unsafe.Pointer(ctlInfo)), + uintptr(unsafe.Pointer(ctlInfo1)), ) if errno != 0 { @@ -128,14 +149,14 @@ func OpenTunDevice(tunAddress string, autoRoute bool) (TunDevice, error) { scLen: uint8(sockaddrCtlSize), scFamily: unix.AF_SYSTEM, ssSysaddr: 2, - scID: ctlInfo.ctlID, + scID: ctlInfo1.ctlID, scUnit: uint32(ifIndex) + 1, } scPointer := unsafe.Pointer(&sc) _, _, errno = unix.RawSyscall( - sys_CONNECT, + sysConnect, uintptr(fd), uintptr(scPointer), uintptr(sockaddrCtlSize), @@ -151,7 +172,6 @@ func OpenTunDevice(tunAddress string, autoRoute bool) (TunDevice, error) { } tun, err := CreateTUNFromFile(os.NewFile(uintptr(fd), ""), mtu, tunAddress, autoRoute) - if err != nil { return nil, err } @@ -271,7 +291,6 @@ func (t *tunDarwin) Close() error { } func (t *tunDarwin) getInterfaceMtu() (int, error) { - // open datagram socket fd, err := unix.Socket( @@ -279,7 +298,6 @@ func (t *tunDarwin) getInterfaceMtu() (int, error) { unix.SOCK_DGRAM, 0, ) - if err != nil { return 0, err } @@ -291,7 +309,7 @@ func (t *tunDarwin) getInterfaceMtu() (int, error) { var ifr [64]byte copy(ifr[:], t.name) _, _, errno := unix.Syscall( - sys_IOCTL, + sysIoctl, uintptr(fd), uintptr(unix.SIOCGIFMTU), uintptr(unsafe.Pointer(&ifr[0])), @@ -312,7 +330,7 @@ func (t *tunDarwin) getName() (string, error) { var errno syscall.Errno t.operateOnFd(func(fd uintptr) { _, _, errno = unix.Syscall6( - sys_GETSOCKOPT, + sysGetsockopt, fd, 2, /* #define SYSPROTO_CONTROL 2 */ 2, /* #define UTUN_OPT_IFNAME 2 */ @@ -335,7 +353,6 @@ func (t *tunDarwin) setMTU(n int) error { unix.SOCK_DGRAM, 0, ) - if err != nil { return err } @@ -348,7 +365,7 @@ func (t *tunDarwin) setMTU(n int) error { copy(ifr[:], t.name) *(*uint32)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = uint32(n) _, _, errno := unix.Syscall( - sys_IOCTL, + sysIoctl, uintptr(fd), uintptr(unix.SIOCSIFMTU), uintptr(unsafe.Pointer(&ifr[0])), @@ -389,32 +406,22 @@ func (t *tunDarwin) setTunAddress(addr net.IP) error { } defer syscall.Close(fd4) - // https://github.com/apple/darwin-xnu/blob/a449c6a3b8014d9406c2ddbdc81795da24aa7443/bsd/sys/sockio.h#L107 - // https://github.com/apple/darwin-xnu/blob/a449c6a3b8014d9406c2ddbdc81795da24aa7443/bsd/net/if.h#L570-L575 - // https://man.openbsd.org/netintro.4#SIOCAIFADDR - type aliasreq struct { - ifra_name [unix.IFNAMSIZ]byte - ifra_addr unix.RawSockaddrInet4 - ifra_dstaddr unix.RawSockaddrInet4 - ifra_mask unix.RawSockaddrInet4 - } - var ip4 [4]byte copy(ip4[:], addr.To4()) ip4mask := [4]byte{255, 255, 0, 0} ifra4 := aliasreq{ - ifra_name: ifr, - ifra_addr: unix.RawSockaddrInet4{ + ifraName: ifr, + ifraAddr: unix.RawSockaddrInet4{ Len: unix.SizeofSockaddrInet4, Family: unix.AF_INET, Addr: ip4, }, - ifra_dstaddr: unix.RawSockaddrInet4{ + ifraDstaddr: unix.RawSockaddrInet4{ Len: unix.SizeofSockaddrInet4, Family: unix.AF_INET, Addr: ip4, }, - ifra_mask: unix.RawSockaddrInet4{ + ifraMask: unix.RawSockaddrInet4{ Len: unix.SizeofSockaddrInet4, Family: unix.AF_INET, Addr: ip4mask, @@ -422,7 +429,7 @@ func (t *tunDarwin) setTunAddress(addr net.IP) error { } if _, _, errno := unix.Syscall( - sys_IOCTL, + sysIoctl, uintptr(fd4), uintptr(unix.SIOCAIFADDR), uintptr(unsafe.Pointer(&ifra4)), @@ -447,42 +454,24 @@ func (t *tunDarwin) attachLinkLocal() error { return err } defer syscall.Close(fd6) - // SIOCAIFADDR_IN6 - // https://github.com/apple/darwin-xnu/blob/a449c6a3b8014d9406c2ddbdc81795da24aa7443/bsd/netinet6/in6_var.h#L114-L119 - // https://opensource.apple.com/source/network_cmds/network_cmds-543.260.3/ - type in6_addrlifetime struct { - //ia6t_expire uint64 - //ia6t_preferred uint64 - //ia6t_vltime uint32 - //ia6t_pltime uint32 - } - // https://github.com/apple/darwin-xnu/blob/a449c6a3b8014d9406c2ddbdc81795da24aa7443/bsd/netinet6/in6_var.h#L336-L343 - // https://github.com/apple/darwin-xnu/blob/a449c6a3b8014d9406c2ddbdc81795da24aa7443/bsd/netinet6/in6.h#L174-L181 - type in6_aliasreq struct { - ifra_name [unix.IFNAMSIZ]byte - ifra_addr unix.RawSockaddrInet6 - ifra_dstaddr unix.RawSockaddrInet6 - ifra_prefixmask unix.RawSockaddrInet6 - ifra_flags int32 - ifra_lifetime in6_addrlifetime - } + // Attach link-local address - ifra6 := in6_aliasreq{ - ifra_name: ifr, + ifra6 := in6Aliasreq{ + ifraName: ifr, } if _, _, errno := unix.Syscall( - sys_IOCTL, + sysIoctl, uintptr(fd6), - uintptr(_SIOCPROTOATTACH_IN6), + uintptr(siocprotoattachIn6), uintptr(unsafe.Pointer(&ifra6)), ); errno != 0 { return fmt.Errorf("failed to attach link-local address on %s: SIOCPROTOATTACH_IN6 %v", t.name, errno) } if _, _, errno := unix.Syscall( - sys_IOCTL, + sysIoctl, uintptr(fd6), - uintptr(_SIOCLL_START), + uintptr(siocllStart), uintptr(unsafe.Pointer(&ifra6)), ); errno != 0 { return fmt.Errorf("failed to set ipv6 address on %s: SIOCLL_START %v", t.name, errno) diff --git a/listener/tun/ipstack/commons/dns.go b/listener/tun/ipstack/commons/dns.go new file mode 100644 index 00000000..4c4ca29b --- /dev/null +++ b/listener/tun/ipstack/commons/dns.go @@ -0,0 +1,30 @@ +package commons + +import ( + "github.com/Dreamacro/clash/component/resolver" + D "github.com/miekg/dns" +) + +func RelayDnsPacket(payload []byte) ([]byte, error) { + msg := &D.Msg{} + if err := msg.Unpack(payload); err != nil { + return nil, err + } + + r, err := resolver.ServeMsg(msg) + if err != nil { + return nil, err + } + + for _, ans := range r.Answer { + header := ans.Header() + + if header.Class == D.ClassINET && (header.Rrtype == D.TypeA || header.Rrtype == D.TypeAAAA) { + header.Ttl = 1 + } + } + + r.SetRcode(msg, r.Rcode) + r.Compress = true + return r.Pack() +} diff --git a/listener/tun/ipstack/gvisor/tun.go b/listener/tun/ipstack/gvisor/tun.go index d53f55b9..385d2388 100644 --- a/listener/tun/ipstack/gvisor/tun.go +++ b/listener/tun/ipstack/gvisor/tun.go @@ -48,7 +48,6 @@ type gvisorAdapter struct { // GvisorAdapter create GvisorAdapter func NewAdapter(device dev.TunDevice, conf config.Tun, tunAddress string, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) (ipstack.TunAdapter, error) { - ipstack := stack.New(stack.Options{ NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol}, TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol, udp.NewProtocol}, @@ -180,7 +179,6 @@ func (t *gvisorAdapter) AsLinkEndpoint() (result stack.LinkEndpoint, err error) } mtu, err := t.device.MTU() - if err != nil { return nil, errors.New("unable to get device mtu") } @@ -195,6 +193,7 @@ func (t *gvisorAdapter) AsLinkEndpoint() (result stack.LinkEndpoint, err error) n, err := t.device.Read(packet) if err != nil && !t.device.IsClose() { log.Errorln("can not read from tun: %v", err) + continue } var p tcpip.NetworkProtocolNumber switch header.IPVersion(packet) { diff --git a/listener/tun/ipstack/gvisor/tundns.go b/listener/tun/ipstack/gvisor/tundns.go index 9b007a59..1bb9e766 100644 --- a/listener/tun/ipstack/gvisor/tundns.go +++ b/listener/tun/ipstack/gvisor/tundns.go @@ -73,7 +73,6 @@ func (e *dnsEndpoint) Close() { } func (e *dnsEndpoint) Wait() { - } func (e *dnsEndpoint) HandleError(transErr stack.TransportError, pkt *stack.PacketBuffer) { @@ -102,13 +101,16 @@ func (w *dnsResponseWriter) WriteMsg(msg *D.Msg) error { _, err = w.Write(b) return err } + func (w *dnsResponseWriter) TsigStatus() error { // Unsupported return nil } + func (w *dnsResponseWriter) TsigTimersOnly(bool) { // Unsupported } + func (w *dnsResponseWriter) Hijack() { // Unsupported } @@ -128,7 +130,6 @@ func (w *dnsResponseWriter) Close() error { // CreateDNSServer create a dns server on given netstack func CreateDNSServer(s *stack.Stack, resolver *dns.Resolver, mapper *dns.ResolverEnhancer, ip net.IP, port int, nicID tcpip.NICID) (*DNSServer, error) { - var v4 bool var err error diff --git a/listener/tun/ipstack/gvisor/utils.go b/listener/tun/ipstack/gvisor/utils.go index 31213894..44063f0b 100644 --- a/listener/tun/ipstack/gvisor/utils.go +++ b/listener/tun/ipstack/gvisor/utils.go @@ -53,7 +53,6 @@ func (c *fakeConn) Close() error { } func (c *fakeConn) Drop() { - } func (c *fakeConn) FakeIP() bool { diff --git a/listener/tun/ipstack/system/dns.go b/listener/tun/ipstack/system/dns.go index 21a22393..6bbd4980 100644 --- a/listener/tun/ipstack/system/dns.go +++ b/listener/tun/ipstack/system/dns.go @@ -6,10 +6,7 @@ import ( "net" "time" - "github.com/Dreamacro/clash/component/resolver" - - D "github.com/miekg/dns" - + D "github.com/Dreamacro/clash/listener/tun/ipstack/commons" "github.com/kr328/tun2socket/binding" "github.com/kr328/tun2socket/redirect" ) @@ -26,8 +23,7 @@ func shouldHijackDns(dnsAddr binding.Address, targetAddr binding.Address) bool { func hijackUDPDns(pkt []byte, ep *binding.Endpoint, sender redirect.UDPSender) { go func() { - answer, err := relayDnsPacket(pkt) - + answer, err := D.RelayDnsPacket(pkt) if err != nil { return } @@ -41,7 +37,9 @@ func hijackUDPDns(pkt []byte, ep *binding.Endpoint, sender redirect.UDPSender) { func hijackTCPDns(conn net.Conn) { go func() { - defer conn.Close() + defer func(conn net.Conn) { + _ = conn.Close() + }(conn) for { if err := conn.SetReadDeadline(time.Now().Add(defaultDnsReadTimeout)); err != nil { @@ -60,7 +58,7 @@ func hijackTCPDns(conn net.Conn) { return } - rb, err := relayDnsPacket(data) + rb, err := D.RelayDnsPacket(data) if err != nil { continue } @@ -75,27 +73,3 @@ func hijackTCPDns(conn net.Conn) { } }() } - -func relayDnsPacket(payload []byte) ([]byte, error) { - msg := &D.Msg{} - if err := msg.Unpack(payload); err != nil { - return nil, err - } - - r, err := resolver.ServeMsg(msg) - if err != nil { - return nil, err - } - - for _, ans := range r.Answer { - header := ans.Header() - - if header.Class == D.ClassINET && (header.Rrtype == D.TypeA || header.Rrtype == D.TypeAAAA) { - header.Ttl = 1 - } - } - - r.SetRcode(msg, r.Rcode) - r.Compress = true - return r.Pack() -} diff --git a/listener/tun/ipstack/system/tcp.go b/listener/tun/ipstack/system/tcp.go index 07b99eac..f52f7268 100644 --- a/listener/tun/ipstack/system/tcp.go +++ b/listener/tun/ipstack/system/tcp.go @@ -16,12 +16,18 @@ func handleTCP(conn net.Conn, endpoint *binding.Endpoint, tcpIn chan<- C.ConnCon Port: int(endpoint.Source.Port), Zone: "", } + dst := &net.TCPAddr{ IP: endpoint.Target.IP, Port: int(endpoint.Target.Port), Zone: "", } + addrType := C.AtypIPv4 + if dst.IP.To4() == nil { + addrType = C.AtypIPv6 + } + metadata := &C.Metadata{ NetWork: C.TCP, Type: C.TUN, @@ -29,9 +35,12 @@ func handleTCP(conn net.Conn, endpoint *binding.Endpoint, tcpIn chan<- C.ConnCon DstIP: dst.IP, SrcPort: strconv.Itoa(src.Port), DstPort: strconv.Itoa(dst.Port), - AddrType: C.AtypIPv4, + AddrType: addrType, Host: "", } + //if c, ok := conn.(*net.TCPConn); ok { + // c.SetKeepAlive(true) + //} tcpIn <- context.NewConnContext(conn, metadata) } diff --git a/listener/tun/ipstack/system/tun.go b/listener/tun/ipstack/system/tun.go index 354d9ed1..fbfb8cb1 100644 --- a/listener/tun/ipstack/system/tun.go +++ b/listener/tun/ipstack/system/tun.go @@ -26,7 +26,6 @@ type systemAdapter struct { } func NewAdapter(device dev.TunDevice, conf config.Tun, mtu int, gateway, mirror string, onStop func(), tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) (ipstack.TunAdapter, error) { - adapter := &systemAdapter{ device: device, stackName: conf.Stack, @@ -37,8 +36,6 @@ func NewAdapter(device dev.TunDevice, conf config.Tun, mtu int, gateway, mirror adapter.lock.Lock() defer adapter.lock.Unlock() - //adapter.stopLocked() - dnsHost, dnsPort, err := net.SplitHostPort(conf.DNSListen) if err != nil { return nil, err @@ -63,10 +60,7 @@ func NewAdapter(device dev.TunDevice, conf config.Tun, mtu int, gateway, mirror t.SetTCPHandler(func(conn net.Conn, endpoint *binding.Endpoint) { if shouldHijackDns(dnsAddr, endpoint.Target) { hijackTCPDns(conn) - - if log.Level() == log.DEBUG { - log.Debugln("[TUN] hijack dns tcp: %s:%d", endpoint.Target.IP.String(), endpoint.Target.Port) - } + log.Debugln("[TUN] hijack dns tcp: %s:%d", endpoint.Target.IP.String(), endpoint.Target.Port) return } @@ -75,10 +69,7 @@ func NewAdapter(device dev.TunDevice, conf config.Tun, mtu int, gateway, mirror t.SetUDPHandler(func(payload []byte, endpoint *binding.Endpoint, sender redirect.UDPSender) { if shouldHijackDns(dnsAddr, endpoint.Target) { hijackUDPDns(payload, endpoint, sender) - - if log.Level() == log.DEBUG { - log.Debugln("[TUN] hijack dns udp: %s:%d", endpoint.Target.IP.String(), endpoint.Target.Port) - } + log.Debugln("[TUN] hijack dns udp: %s:%d", endpoint.Target.IP.String(), endpoint.Target.Port) return } diff --git a/rule/geodata/memconservative/cache.go b/rule/geodata/memconservative/cache.go index 3a1ac7e6..d66438b4 100644 --- a/rule/geodata/memconservative/cache.go +++ b/rule/geodata/memconservative/cache.go @@ -2,7 +2,7 @@ package memconservative import ( "fmt" - "io/ioutil" + "os" "strings" C "github.com/Dreamacro/clash/constant" @@ -54,7 +54,7 @@ func (g GeoIPCache) Unmarshal(filename, code string) (*router.GeoIP, error) { case errFailedToReadBytes, errFailedToReadExpectedLenBytes, errInvalidGeodataFile, errInvalidGeodataVarintLength: log.Warnln("failed to decode geoip file: %s%s", filename, ", fallback to the original ReadFile method") - geoipBytes, err = ioutil.ReadFile(asset) + geoipBytes, err = os.ReadFile(asset) if err != nil { return nil, err } @@ -119,7 +119,7 @@ func (g GeoSiteCache) Unmarshal(filename, code string) (*router.GeoSite, error) case errFailedToReadBytes, errFailedToReadExpectedLenBytes, errInvalidGeodataFile, errInvalidGeodataVarintLength: log.Warnln("failed to decode geoip file: %s%s", filename, ", fallback to the original ReadFile method") - geositeBytes, err = ioutil.ReadFile(asset) + geositeBytes, err = os.ReadFile(asset) if err != nil { return nil, err } diff --git a/rule/geodata/router/condition.go b/rule/geodata/router/condition.go index cfe7cf42..26be8237 100644 --- a/rule/geodata/router/condition.go +++ b/rule/geodata/router/condition.go @@ -2,7 +2,6 @@ package router import ( "fmt" - "net" "strings" "github.com/Dreamacro/clash/rule/geodata/strmatcher" @@ -69,44 +68,3 @@ func NewDomainMatcher(domains []*Domain) (*DomainMatcher, error) { func (m *DomainMatcher) ApplyDomain(domain string) bool { return len(m.matchers.Match(strings.ToLower(domain))) > 0 } - -type MultiGeoIPMatcher struct { - matchers []*GeoIPMatcher -} - -func NewMultiGeoIPMatcher(geoips []*GeoIP) (*MultiGeoIPMatcher, error) { - var matchers []*GeoIPMatcher - for _, geoip := range geoips { - matcher, err := globalGeoIPContainer.Add(geoip) - if err != nil { - return nil, err - } - matchers = append(matchers, matcher) - } - - matcher := &MultiGeoIPMatcher{ - matchers: matchers, - } - - return matcher, nil -} - -func (m *MultiGeoIPMatcher) ApplyIp(ip net.IP) bool { - - for _, matcher := range m.matchers { - if matcher.Match(ip) { - return true - } - } - - return false -} - -func NewGeoIPMatcher(geoip *GeoIP) (*GeoIPMatcher, error) { - matcher, err := globalGeoIPContainer.Add(geoip) - if err != nil { - return nil, err - } - - return matcher, nil -} diff --git a/rule/geodata/router/condition_geoip.go b/rule/geodata/router/condition_geoip.go deleted file mode 100644 index 5a4bb5ca..00000000 --- a/rule/geodata/router/condition_geoip.go +++ /dev/null @@ -1,243 +0,0 @@ -package router - -import ( - "encoding/binary" - "fmt" - "net" - "sort" -) - -// CIDRList is an alias of []*CIDR to provide sort.Interface. -type CIDRList []*CIDR - -// Len implements sort.Interface. -func (l *CIDRList) Len() int { - return len(*l) -} - -// Less implements sort.Interface. -func (l *CIDRList) Less(i int, j int) bool { - ci := (*l)[i] - cj := (*l)[j] - - if len(ci.Ip) < len(cj.Ip) { - return true - } - - if len(ci.Ip) > len(cj.Ip) { - return false - } - - for k := 0; k < len(ci.Ip); k++ { - if ci.Ip[k] < cj.Ip[k] { - return true - } - - if ci.Ip[k] > cj.Ip[k] { - return false - } - } - - return ci.Prefix < cj.Prefix -} - -// Swap implements sort.Interface. -func (l *CIDRList) Swap(i int, j int) { - (*l)[i], (*l)[j] = (*l)[j], (*l)[i] -} - -type ipv6 struct { - a uint64 - b uint64 -} - -type GeoIPMatcher struct { - countryCode string - reverseMatch bool - ip4 []uint32 - prefix4 []uint8 - ip6 []ipv6 - prefix6 []uint8 -} - -func normalize4(ip uint32, prefix uint8) uint32 { - return (ip >> (32 - prefix)) << (32 - prefix) -} - -func normalize6(ip ipv6, prefix uint8) ipv6 { - if prefix <= 64 { - ip.a = (ip.a >> (64 - prefix)) << (64 - prefix) - ip.b = 0 - } else { - ip.b = (ip.b >> (128 - prefix)) << (128 - prefix) - } - return ip -} - -func (m *GeoIPMatcher) Init(cidrs []*CIDR) error { - ip4Count := 0 - ip6Count := 0 - - for _, cidr := range cidrs { - ip := cidr.Ip - switch len(ip) { - case 4: - ip4Count++ - case 16: - ip6Count++ - default: - return fmt.Errorf("unexpect ip length: %d", len(ip)) - } - } - - cidrList := CIDRList(cidrs) - sort.Sort(&cidrList) - - m.ip4 = make([]uint32, 0, ip4Count) - m.prefix4 = make([]uint8, 0, ip4Count) - m.ip6 = make([]ipv6, 0, ip6Count) - m.prefix6 = make([]uint8, 0, ip6Count) - - for _, cidr := range cidrs { - ip := cidr.Ip - prefix := uint8(cidr.Prefix) - switch len(ip) { - case 4: - m.ip4 = append(m.ip4, normalize4(binary.BigEndian.Uint32(ip), prefix)) - m.prefix4 = append(m.prefix4, prefix) - case 16: - ip6 := ipv6{ - a: binary.BigEndian.Uint64(ip[0:8]), - b: binary.BigEndian.Uint64(ip[8:16]), - } - ip6 = normalize6(ip6, prefix) - - m.ip6 = append(m.ip6, ip6) - m.prefix6 = append(m.prefix6, prefix) - } - } - - return nil -} - -func (m *GeoIPMatcher) SetReverseMatch(isReverseMatch bool) { - m.reverseMatch = isReverseMatch -} - -func (m *GeoIPMatcher) match4(ip uint32) bool { - if len(m.ip4) == 0 { - return false - } - - if ip < m.ip4[0] { - return false - } - - size := uint32(len(m.ip4)) - l := uint32(0) - r := size - for l < r { - x := ((l + r) >> 1) - if ip < m.ip4[x] { - r = x - continue - } - - nip := normalize4(ip, m.prefix4[x]) - if nip == m.ip4[x] { - return true - } - - l = x + 1 - } - - return l > 0 && normalize4(ip, m.prefix4[l-1]) == m.ip4[l-1] -} - -func less6(a ipv6, b ipv6) bool { - return a.a < b.a || (a.a == b.a && a.b < b.b) -} - -func (m *GeoIPMatcher) match6(ip ipv6) bool { - if len(m.ip6) == 0 { - return false - } - - if less6(ip, m.ip6[0]) { - return false - } - - size := uint32(len(m.ip6)) - l := uint32(0) - r := size - for l < r { - x := (l + r) / 2 - if less6(ip, m.ip6[x]) { - r = x - continue - } - - if normalize6(ip, m.prefix6[x]) == m.ip6[x] { - return true - } - - l = x + 1 - } - - return l > 0 && normalize6(ip, m.prefix6[l-1]) == m.ip6[l-1] -} - -// Match returns true if the given ip is included by the GeoIP. -func (m *GeoIPMatcher) Match(ip net.IP) bool { - switch len(ip) { - case 4: - if m.reverseMatch { - return !m.match4(binary.BigEndian.Uint32(ip)) - } - return m.match4(binary.BigEndian.Uint32(ip)) - case 16: - if m.reverseMatch { - return !m.match6(ipv6{ - a: binary.BigEndian.Uint64(ip[0:8]), - b: binary.BigEndian.Uint64(ip[8:16]), - }) - } - return m.match6(ipv6{ - a: binary.BigEndian.Uint64(ip[0:8]), - b: binary.BigEndian.Uint64(ip[8:16]), - }) - default: - return false - } -} - -// GeoIPMatcherContainer is a container for GeoIPMatchers. It keeps unique copies of GeoIPMatcher by country code. -type GeoIPMatcherContainer struct { - matchers []*GeoIPMatcher -} - -// Add adds a new GeoIP set into the container. -// If the country code of GeoIP is not empty, GeoIPMatcherContainer will try to find an existing one, instead of adding a new one. -func (c *GeoIPMatcherContainer) Add(geoip *GeoIP) (*GeoIPMatcher, error) { - if len(geoip.CountryCode) > 0 { - for _, m := range c.matchers { - if m.countryCode == geoip.CountryCode && m.reverseMatch == geoip.ReverseMatch { - return m, nil - } - } - } - - m := &GeoIPMatcher{ - countryCode: geoip.CountryCode, - reverseMatch: geoip.ReverseMatch, - } - if err := m.Init(geoip.Cidr); err != nil { - return nil, err - } - if len(geoip.CountryCode) > 0 { - c.matchers = append(c.matchers, m) - } - return m, nil -} - -var globalGeoIPContainer GeoIPMatcherContainer diff --git a/rule/geodata/standard/standard.go b/rule/geodata/standard/standard.go index 21e437a3..190b5bdc 100644 --- a/rule/geodata/standard/standard.go +++ b/rule/geodata/standard/standard.go @@ -2,7 +2,7 @@ package standard import ( "fmt" - "io/ioutil" + "io" "os" "strings" @@ -19,7 +19,7 @@ func ReadFile(path string) ([]byte, error) { } defer reader.Close() - return ioutil.ReadAll(reader) + return io.ReadAll(reader) } func ReadAsset(file string) ([]byte, error) { diff --git a/rule/geoip.go b/rule/geoip.go index f7c5f430..1783b7b7 100644 --- a/rule/geoip.go +++ b/rule/geoip.go @@ -1,22 +1,17 @@ package rules import ( - "fmt" "strings" + "github.com/Dreamacro/clash/component/mmdb" C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/rule/geodata" - "github.com/Dreamacro/clash/rule/geodata/router" - _ "github.com/Dreamacro/clash/rule/geodata/standard" ) type GEOIP struct { - country string - adapter string - noResolveIP bool - ruleExtra *C.RuleExtra - geoIPMatcher *router.GeoIPMatcher + country string + adapter string + noResolveIP bool + ruleExtra *C.RuleExtra } func (g *GEOIP) RuleType() C.RuleType { @@ -29,10 +24,11 @@ func (g *GEOIP) Match(metadata *C.Metadata) bool { return false } - if strings.EqualFold(g.country, "LAN") { + if strings.EqualFold(g.country, "LAN") || C.TunBroadcastAddr.Equal(ip) { return ip.IsPrivate() } - return g.geoIPMatcher.Match(ip) + record, _ := mmdb.Instance().Country(ip) + return strings.EqualFold(record.Country.IsoCode, g.country) } func (g *GEOIP) Adapter() string { @@ -51,39 +47,16 @@ func (g *GEOIP) RuleExtra() *C.RuleExtra { return g.ruleExtra } +func (g *GEOIP) GetCountry() string { + return g.country +} + func NewGEOIP(country string, adapter string, noResolveIP bool, ruleExtra *C.RuleExtra) (*GEOIP, error) { - geoLoaderName := "standard" - //geoLoaderName := "memconservative" - geoLoader, err := geodata.GetGeoDataLoader(geoLoaderName) - if err != nil { - return nil, fmt.Errorf("[GeoIP] %s", err.Error()) - } - - records, err := geoLoader.LoadGeoIP(strings.ReplaceAll(country, "!", "")) - if err != nil { - return nil, fmt.Errorf("[GeoIP] %s", err.Error()) - } - - geoIP := &router.GeoIP{ - CountryCode: country, - Cidr: records, - ReverseMatch: strings.Contains(country, "!"), - } - - geoIPMatcher, err := router.NewGeoIPMatcher(geoIP) - - if err != nil { - return nil, fmt.Errorf("[GeoIP] %s", err.Error()) - } - - log.Infoln("Start initial GeoIP rule %s => %s, records: %d", country, adapter, len(records)) - geoip := &GEOIP{ - country: country, - adapter: adapter, - noResolveIP: noResolveIP, - ruleExtra: ruleExtra, - geoIPMatcher: geoIPMatcher, + country: country, + adapter: adapter, + noResolveIP: noResolveIP, + ruleExtra: ruleExtra, } return geoip, nil diff --git a/rule/geosite.go b/rule/geosite.go index 9351b01e..8729138e 100644 --- a/rule/geosite.go +++ b/rule/geosite.go @@ -49,24 +49,24 @@ func (gs *GEOSITE) RuleExtra() *C.RuleExtra { func NewGEOSITE(country string, adapter string, ruleExtra *C.RuleExtra) (*GEOSITE, error) { geoLoaderName := "standard" - //geoLoaderName := "memconservative" geoLoader, err := geodata.GetGeoDataLoader(geoLoaderName) if err != nil { - return nil, fmt.Errorf("[GeoSite] %s", err.Error()) + return nil, fmt.Errorf("load GeoSite data error, %s", err.Error()) } domains, err := geoLoader.LoadGeoSite(country) if err != nil { - return nil, fmt.Errorf("[GeoSite] %s", err.Error()) + return nil, fmt.Errorf("load GeoSite data error, %s", err.Error()) } - //linear: linear algorithm - //matcher, err := router.NewDomainMatcher(domains) - - //mph:minimal perfect hash algorithm + /** + linear: linear algorithm + matcher, err := router.NewDomainMatcher(domains) + mph:minimal perfect hash algorithm + */ matcher, err := router.NewMphMatcherGroup(domains) if err != nil { - return nil, fmt.Errorf("[GeoSite] %s", err.Error()) + return nil, fmt.Errorf("load GeoSite data error, %s", err.Error()) } log.Infoln("Start initial GeoSite rule %s => %s, records: %d", country, adapter, len(domains)) diff --git a/transport/vless/conn.go b/transport/vless/conn.go index 36e8918e..e6e6e34c 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "net" "github.com/gofrs/uuid" @@ -87,7 +86,7 @@ func (vc *Conn) recvResponse() error { length := int64(buf[0]) if length != 0 { // addon data length > 0 - io.CopyN(ioutil.Discard, vc.Conn, length) // just discard + io.CopyN(io.Discard, vc.Conn, length) // just discard } return nil diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 294b36a4..af67ff6e 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -34,8 +34,6 @@ var ( udpTimeout = 60 * time.Second preProcessCacheFinder, _ = R.NewProcess("", "", nil) - - tunBroadcastAddr = net.IPv4(198, 18, 255, 255) ) func init() { @@ -143,7 +141,7 @@ func preHandleMetadata(metadata *C.Metadata) error { // redir-host should lookup the hosts metadata.DstIP = node.Data.(net.IP) } - } else if resolver.IsFakeIP(metadata.DstIP) && !tunBroadcastAddr.Equal(metadata.DstIP) { + } else if resolver.IsFakeIP(metadata.DstIP) && !C.TunBroadcastAddr.Equal(metadata.DstIP) { return fmt.Errorf("fake DNS record %s missing", metadata.DstIP) } } @@ -235,7 +233,7 @@ func handleUDPConn(packet *inbound.PacketAdapter) { switch true { case rule != nil: - log.Infoln("[UDP] %s(%s) --> %s:%s match %s(%s) using %s", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress(), metadata.DstPort, rule.RuleType().String(), rule.Payload(), rawPc.Chains().String()) + log.Infoln("[UDP] %s(%s) --> %s match %s(%s) using %s", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress(), rule.RuleType().String(), rule.Payload(), rawPc.Chains().String()) case mode == Global: log.Infoln("[UDP] %s(%s) --> %s using GLOBAL", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress()) case mode == Direct: @@ -285,7 +283,7 @@ func handleTCPConn(ctx C.ConnContext) { switch true { case rule != nil: - log.Infoln("[TCP] %s(%s) --> %s:%s match %s(%s) using %s", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress(), metadata.DstPort, rule.RuleType().String(), rule.Payload(), remoteConn.Chains().String()) + log.Infoln("[TCP] %s(%s) --> %s match %s(%s) using %s", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress(), rule.RuleType().String(), rule.Payload(), remoteConn.Chains().String()) case mode == Global: log.Infoln("[TCP] %s(%s) --> %s using GLOBAL", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress()) case mode == Direct: