Style: format code
This commit is contained in:
parent
febc9fb22c
commit
0387c93c56
23 changed files with 280 additions and 545 deletions
|
@ -158,9 +158,9 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsConfig := &tls.Config{
|
tlsConfig := &tls.Config{
|
||||||
NextProtos: option.ALPN,
|
NextProtos: option.ALPN,
|
||||||
MinVersion: tls.VersionTLS12,
|
MinVersion: tls.VersionTLS12,
|
||||||
//InsecureSkipVerify: tOption.SkipCertVerify,
|
InsecureSkipVerify: tOption.SkipCertVerify,
|
||||||
ServerName: tOption.ServerName,
|
ServerName: tOption.ServerName,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
45
component/mmdb/mmdb.go
Normal file
45
component/mmdb/mmdb.go
Normal file
|
@ -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
|
||||||
|
}
|
|
@ -6,18 +6,19 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/clash/component/mmdb"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
func downloadGeoIP(path string) (err error) {
|
func downloadMMDB(path string) (err error) {
|
||||||
resp, err := http.Get("https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geoip.dat")
|
resp, err := http.Get("https://cdn.jsdelivr.net/gh/Loyalsoldier/geoip@release/Country.mmdb")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -27,6 +28,45 @@ func downloadGeoIP(path string) (err error) {
|
||||||
return err
|
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) {
|
func downloadGeoSite(path string) (err error) {
|
||||||
resp, err := http.Get("https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat")
|
resp, err := http.Get("https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -34,7 +74,7 @@ func downloadGeoSite(path string) (err error) {
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -44,17 +84,18 @@ func downloadGeoSite(path string) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func initGeoIP() error {
|
//
|
||||||
if _, err := os.Stat(C.Path.GeoIP()); os.IsNotExist(err) {
|
//func initGeoIP() error {
|
||||||
log.Infoln("Can't find GeoIP.dat, start download")
|
// if _, err := os.Stat(C.Path.GeoIP()); os.IsNotExist(err) {
|
||||||
if err := downloadGeoIP(C.Path.GeoIP()); err != nil {
|
// log.Infoln("Can't find GeoIP.dat, start download")
|
||||||
return fmt.Errorf("can't download GeoIP.dat: %s", err.Error())
|
// 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")
|
// }
|
||||||
}
|
// log.Infoln("Download GeoIP.dat finish")
|
||||||
|
// }
|
||||||
return nil
|
//
|
||||||
}
|
// return nil
|
||||||
|
//}
|
||||||
|
|
||||||
func initGeoSite() error {
|
func initGeoSite() error {
|
||||||
if _, err := os.Stat(C.Path.GeoSite()); os.IsNotExist(err) {
|
if _, err := os.Stat(C.Path.GeoSite()); os.IsNotExist(err) {
|
||||||
|
@ -72,7 +113,7 @@ func initGeoSite() error {
|
||||||
func Init(dir string) error {
|
func Init(dir string) error {
|
||||||
// initial homedir
|
// initial homedir
|
||||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
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())
|
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
|
// initial config.yaml
|
||||||
if _, err := os.Stat(C.Path.Config()); os.IsNotExist(err) {
|
if _, err := os.Stat(C.Path.Config()); os.IsNotExist(err) {
|
||||||
log.Infoln("Can't find config, create a initial config file")
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("can't create file %s: %s", C.Path.Config(), err.Error())
|
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()
|
f.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// initial GeoIP
|
//// initial GeoIP
|
||||||
if err := initGeoIP(); err != nil {
|
//if err := initGeoIP(); err != nil {
|
||||||
return fmt.Errorf("can't initial GeoIP: %w", err)
|
// 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
|
// initial GeoSite
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package constant
|
package constant
|
||||||
|
|
||||||
|
import "net"
|
||||||
|
|
||||||
// Rule Type
|
// Rule Type
|
||||||
const (
|
const (
|
||||||
Domain RuleType = iota
|
Domain RuleType = iota
|
||||||
|
@ -54,3 +56,5 @@ type Rule interface {
|
||||||
ShouldResolveIP() bool
|
ShouldResolveIP() bool
|
||||||
RuleExtra() *RuleExtra
|
RuleExtra() *RuleExtra
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var TunBroadcastAddr = net.IPv4(198, 18, 255, 255)
|
||||||
|
|
|
@ -2,16 +2,13 @@ package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/clash/component/mmdb"
|
||||||
"github.com/Dreamacro/clash/component/trie"
|
"github.com/Dreamacro/clash/component/trie"
|
||||||
"github.com/Dreamacro/clash/log"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/rule/geodata"
|
|
||||||
"github.com/Dreamacro/clash/rule/geodata/router"
|
|
||||||
_ "github.com/Dreamacro/clash/rule/geodata/standard"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var multiGeoIPMatcher *router.MultiGeoIPMatcher
|
|
||||||
|
|
||||||
type fallbackIPFilter interface {
|
type fallbackIPFilter interface {
|
||||||
Match(net.IP) bool
|
Match(net.IP) bool
|
||||||
}
|
}
|
||||||
|
@ -21,49 +18,8 @@ type geoipFilter struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gf *geoipFilter) Match(ip net.IP) bool {
|
func (gf *geoipFilter) Match(ip net.IP) bool {
|
||||||
if multiGeoIPMatcher == nil {
|
record, _ := mmdb.Instance().Country(ip)
|
||||||
countryCode := gf.code
|
return !strings.EqualFold(record.Country.IsoCode, gf.code) && !ip.IsPrivate() && !ip.Equal(C.TunBroadcastAddr)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ipnetFilter struct {
|
type ipnetFilter struct {
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -12,6 +12,7 @@ require (
|
||||||
github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac
|
github.com/insomniacslk/dhcp v0.0.0-20210827173440-b95caade3eac
|
||||||
github.com/kr328/tun2socket v0.0.0-20210412191540-3d56c47e2d99
|
github.com/kr328/tun2socket v0.0.0-20210412191540-3d56c47e2d99
|
||||||
github.com/miekg/dns v1.1.43
|
github.com/miekg/dns v1.1.43
|
||||||
|
github.com/oschwald/geoip2-golang v1.5.0
|
||||||
github.com/sirupsen/logrus v1.8.1
|
github.com/sirupsen/logrus v1.8.1
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499
|
github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499
|
||||||
|
@ -28,6 +29,7 @@ require (
|
||||||
require (
|
require (
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/google/btree v1.0.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/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect
|
github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect
|
||||||
golang.org/x/text v0.3.6 // indirect
|
golang.org/x/text v0.3.6 // indirect
|
||||||
|
|
5
go.sum
5
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-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/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/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/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.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
|
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-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-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-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-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-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
|
|
@ -20,41 +20,36 @@ import (
|
||||||
"github.com/Dreamacro/clash/common/pool"
|
"github.com/Dreamacro/clash/common/pool"
|
||||||
)
|
)
|
||||||
|
|
||||||
const utunControlName = "com.apple.net.utun_control"
|
const (
|
||||||
const _IOC_OUT = 0x40000000
|
utunControlName = "com.apple.net.utun_control"
|
||||||
const _IOC_IN = 0x80000000
|
iocOut = 0x40000000
|
||||||
const _IOC_INOUT = _IOC_IN | _IOC_OUT
|
iocIn = 0x80000000
|
||||||
|
iocInout = iocIn | iocOut
|
||||||
|
)
|
||||||
|
|
||||||
// _CTLIOCGINFO value derived from /usr/include/sys/{kern_control,ioccom}.h
|
// _CTLIOCGINFO value derived from /usr/include/sys/{kern_control,ioccom}.h
|
||||||
// https://github.com/apple/darwin-xnu/blob/master/bsd/sys/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
|
// #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
|
const _CTLIOCGINFO = iocInout | ((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
|
|
||||||
|
|
||||||
// #define SIOCPROTOATTACH_IN6 _IOWR('i', 110, struct in6_aliasreq_64)
|
// #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)
|
// #define SIOCLL_START _IOWR('i', 130, struct in6Aliasreq)
|
||||||
const _SIOCLL_START = _IOC_INOUT | ((128 & 0x1fff) << 16) | uint32(byte('i'))<<8 | 130
|
const siocllStart = iocInout | ((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
|
|
||||||
|
|
||||||
// Following the wireguard-go solution:
|
// Following the wireguard-go solution:
|
||||||
// These unix.SYS_* constants were removed from golang.org/x/sys/unix
|
// These unix.SYS_* constants were removed from golang.org/x/sys/unix
|
||||||
// so copy them here for now.
|
// so copy them here for now.
|
||||||
// See https://github.com/golang/go/issues/41868
|
// See https://github.com/golang/go/issues/41868
|
||||||
const (
|
const (
|
||||||
sys_IOCTL = 54
|
sysIoctl = 54
|
||||||
sys_CONNECT = 98
|
sysConnect = 98
|
||||||
sys_GETSOCKOPT = 118
|
sysGetsockopt = 118
|
||||||
)
|
)
|
||||||
|
|
||||||
type tunDarwin struct {
|
type tunDarwin struct {
|
||||||
//url string
|
|
||||||
name string
|
name string
|
||||||
tunAddress string
|
tunAddress string
|
||||||
autoRoute bool
|
autoRoute bool
|
||||||
|
@ -75,6 +70,37 @@ type sockaddrCtl struct {
|
||||||
scReserved [5]uint32
|
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
|
// https://github.com/apple/darwin-xnu/blob/a449c6a3b8014d9406c2ddbdc81795da24aa7443/bsd/net/if.h#L402-L563
|
||||||
|
|
||||||
//type ifreqAddr struct {
|
//type ifreqAddr struct {
|
||||||
|
@ -87,7 +113,6 @@ var sockaddrCtlSize uintptr = 32
|
||||||
|
|
||||||
// OpenTunDevice return a TunDevice according a URL
|
// OpenTunDevice return a TunDevice according a URL
|
||||||
func OpenTunDevice(tunAddress string, autoRoute bool) (TunDevice, error) {
|
func OpenTunDevice(tunAddress string, autoRoute bool) (TunDevice, error) {
|
||||||
|
|
||||||
name := "utun"
|
name := "utun"
|
||||||
// TODO: configure the MTU
|
// TODO: configure the MTU
|
||||||
mtu := 9000
|
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)
|
fd, err := unix.Socket(unix.AF_SYSTEM, unix.SOCK_DGRAM, 2)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var ctlInfo = &struct {
|
ctlInfo1 := &ctlInfo{}
|
||||||
ctlID uint32
|
|
||||||
ctlName [96]byte
|
|
||||||
}{}
|
|
||||||
|
|
||||||
copy(ctlInfo.ctlName[:], []byte(utunControlName))
|
copy(ctlInfo1.ctlName[:], []byte(utunControlName))
|
||||||
|
|
||||||
_, _, errno := unix.Syscall(
|
_, _, errno := unix.Syscall(
|
||||||
sys_IOCTL,
|
sysIoctl,
|
||||||
uintptr(fd),
|
uintptr(fd),
|
||||||
uintptr(_CTLIOCGINFO),
|
uintptr(_CTLIOCGINFO),
|
||||||
uintptr(unsafe.Pointer(ctlInfo)),
|
uintptr(unsafe.Pointer(ctlInfo1)),
|
||||||
)
|
)
|
||||||
|
|
||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
|
@ -128,14 +149,14 @@ func OpenTunDevice(tunAddress string, autoRoute bool) (TunDevice, error) {
|
||||||
scLen: uint8(sockaddrCtlSize),
|
scLen: uint8(sockaddrCtlSize),
|
||||||
scFamily: unix.AF_SYSTEM,
|
scFamily: unix.AF_SYSTEM,
|
||||||
ssSysaddr: 2,
|
ssSysaddr: 2,
|
||||||
scID: ctlInfo.ctlID,
|
scID: ctlInfo1.ctlID,
|
||||||
scUnit: uint32(ifIndex) + 1,
|
scUnit: uint32(ifIndex) + 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
scPointer := unsafe.Pointer(&sc)
|
scPointer := unsafe.Pointer(&sc)
|
||||||
|
|
||||||
_, _, errno = unix.RawSyscall(
|
_, _, errno = unix.RawSyscall(
|
||||||
sys_CONNECT,
|
sysConnect,
|
||||||
uintptr(fd),
|
uintptr(fd),
|
||||||
uintptr(scPointer),
|
uintptr(scPointer),
|
||||||
uintptr(sockaddrCtlSize),
|
uintptr(sockaddrCtlSize),
|
||||||
|
@ -151,7 +172,6 @@ func OpenTunDevice(tunAddress string, autoRoute bool) (TunDevice, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
tun, err := CreateTUNFromFile(os.NewFile(uintptr(fd), ""), mtu, tunAddress, autoRoute)
|
tun, err := CreateTUNFromFile(os.NewFile(uintptr(fd), ""), mtu, tunAddress, autoRoute)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -271,7 +291,6 @@ func (t *tunDarwin) Close() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tunDarwin) getInterfaceMtu() (int, error) {
|
func (t *tunDarwin) getInterfaceMtu() (int, error) {
|
||||||
|
|
||||||
// open datagram socket
|
// open datagram socket
|
||||||
|
|
||||||
fd, err := unix.Socket(
|
fd, err := unix.Socket(
|
||||||
|
@ -279,7 +298,6 @@ func (t *tunDarwin) getInterfaceMtu() (int, error) {
|
||||||
unix.SOCK_DGRAM,
|
unix.SOCK_DGRAM,
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
@ -291,7 +309,7 @@ func (t *tunDarwin) getInterfaceMtu() (int, error) {
|
||||||
var ifr [64]byte
|
var ifr [64]byte
|
||||||
copy(ifr[:], t.name)
|
copy(ifr[:], t.name)
|
||||||
_, _, errno := unix.Syscall(
|
_, _, errno := unix.Syscall(
|
||||||
sys_IOCTL,
|
sysIoctl,
|
||||||
uintptr(fd),
|
uintptr(fd),
|
||||||
uintptr(unix.SIOCGIFMTU),
|
uintptr(unix.SIOCGIFMTU),
|
||||||
uintptr(unsafe.Pointer(&ifr[0])),
|
uintptr(unsafe.Pointer(&ifr[0])),
|
||||||
|
@ -312,7 +330,7 @@ func (t *tunDarwin) getName() (string, error) {
|
||||||
var errno syscall.Errno
|
var errno syscall.Errno
|
||||||
t.operateOnFd(func(fd uintptr) {
|
t.operateOnFd(func(fd uintptr) {
|
||||||
_, _, errno = unix.Syscall6(
|
_, _, errno = unix.Syscall6(
|
||||||
sys_GETSOCKOPT,
|
sysGetsockopt,
|
||||||
fd,
|
fd,
|
||||||
2, /* #define SYSPROTO_CONTROL 2 */
|
2, /* #define SYSPROTO_CONTROL 2 */
|
||||||
2, /* #define UTUN_OPT_IFNAME 2 */
|
2, /* #define UTUN_OPT_IFNAME 2 */
|
||||||
|
@ -335,7 +353,6 @@ func (t *tunDarwin) setMTU(n int) error {
|
||||||
unix.SOCK_DGRAM,
|
unix.SOCK_DGRAM,
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -348,7 +365,7 @@ func (t *tunDarwin) setMTU(n int) error {
|
||||||
copy(ifr[:], t.name)
|
copy(ifr[:], t.name)
|
||||||
*(*uint32)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = uint32(n)
|
*(*uint32)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = uint32(n)
|
||||||
_, _, errno := unix.Syscall(
|
_, _, errno := unix.Syscall(
|
||||||
sys_IOCTL,
|
sysIoctl,
|
||||||
uintptr(fd),
|
uintptr(fd),
|
||||||
uintptr(unix.SIOCSIFMTU),
|
uintptr(unix.SIOCSIFMTU),
|
||||||
uintptr(unsafe.Pointer(&ifr[0])),
|
uintptr(unsafe.Pointer(&ifr[0])),
|
||||||
|
@ -389,32 +406,22 @@ func (t *tunDarwin) setTunAddress(addr net.IP) error {
|
||||||
}
|
}
|
||||||
defer syscall.Close(fd4)
|
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
|
var ip4 [4]byte
|
||||||
copy(ip4[:], addr.To4())
|
copy(ip4[:], addr.To4())
|
||||||
ip4mask := [4]byte{255, 255, 0, 0}
|
ip4mask := [4]byte{255, 255, 0, 0}
|
||||||
ifra4 := aliasreq{
|
ifra4 := aliasreq{
|
||||||
ifra_name: ifr,
|
ifraName: ifr,
|
||||||
ifra_addr: unix.RawSockaddrInet4{
|
ifraAddr: unix.RawSockaddrInet4{
|
||||||
Len: unix.SizeofSockaddrInet4,
|
Len: unix.SizeofSockaddrInet4,
|
||||||
Family: unix.AF_INET,
|
Family: unix.AF_INET,
|
||||||
Addr: ip4,
|
Addr: ip4,
|
||||||
},
|
},
|
||||||
ifra_dstaddr: unix.RawSockaddrInet4{
|
ifraDstaddr: unix.RawSockaddrInet4{
|
||||||
Len: unix.SizeofSockaddrInet4,
|
Len: unix.SizeofSockaddrInet4,
|
||||||
Family: unix.AF_INET,
|
Family: unix.AF_INET,
|
||||||
Addr: ip4,
|
Addr: ip4,
|
||||||
},
|
},
|
||||||
ifra_mask: unix.RawSockaddrInet4{
|
ifraMask: unix.RawSockaddrInet4{
|
||||||
Len: unix.SizeofSockaddrInet4,
|
Len: unix.SizeofSockaddrInet4,
|
||||||
Family: unix.AF_INET,
|
Family: unix.AF_INET,
|
||||||
Addr: ip4mask,
|
Addr: ip4mask,
|
||||||
|
@ -422,7 +429,7 @@ func (t *tunDarwin) setTunAddress(addr net.IP) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, _, errno := unix.Syscall(
|
if _, _, errno := unix.Syscall(
|
||||||
sys_IOCTL,
|
sysIoctl,
|
||||||
uintptr(fd4),
|
uintptr(fd4),
|
||||||
uintptr(unix.SIOCAIFADDR),
|
uintptr(unix.SIOCAIFADDR),
|
||||||
uintptr(unsafe.Pointer(&ifra4)),
|
uintptr(unsafe.Pointer(&ifra4)),
|
||||||
|
@ -447,42 +454,24 @@ func (t *tunDarwin) attachLinkLocal() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer syscall.Close(fd6)
|
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
|
// Attach link-local address
|
||||||
ifra6 := in6_aliasreq{
|
ifra6 := in6Aliasreq{
|
||||||
ifra_name: ifr,
|
ifraName: ifr,
|
||||||
}
|
}
|
||||||
if _, _, errno := unix.Syscall(
|
if _, _, errno := unix.Syscall(
|
||||||
sys_IOCTL,
|
sysIoctl,
|
||||||
uintptr(fd6),
|
uintptr(fd6),
|
||||||
uintptr(_SIOCPROTOATTACH_IN6),
|
uintptr(siocprotoattachIn6),
|
||||||
uintptr(unsafe.Pointer(&ifra6)),
|
uintptr(unsafe.Pointer(&ifra6)),
|
||||||
); errno != 0 {
|
); errno != 0 {
|
||||||
return fmt.Errorf("failed to attach link-local address on %s: SIOCPROTOATTACH_IN6 %v", t.name, errno)
|
return fmt.Errorf("failed to attach link-local address on %s: SIOCPROTOATTACH_IN6 %v", t.name, errno)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, _, errno := unix.Syscall(
|
if _, _, errno := unix.Syscall(
|
||||||
sys_IOCTL,
|
sysIoctl,
|
||||||
uintptr(fd6),
|
uintptr(fd6),
|
||||||
uintptr(_SIOCLL_START),
|
uintptr(siocllStart),
|
||||||
uintptr(unsafe.Pointer(&ifra6)),
|
uintptr(unsafe.Pointer(&ifra6)),
|
||||||
); errno != 0 {
|
); errno != 0 {
|
||||||
return fmt.Errorf("failed to set ipv6 address on %s: SIOCLL_START %v", t.name, errno)
|
return fmt.Errorf("failed to set ipv6 address on %s: SIOCLL_START %v", t.name, errno)
|
||||||
|
|
30
listener/tun/ipstack/commons/dns.go
Normal file
30
listener/tun/ipstack/commons/dns.go
Normal file
|
@ -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()
|
||||||
|
}
|
|
@ -48,7 +48,6 @@ type gvisorAdapter struct {
|
||||||
|
|
||||||
// GvisorAdapter create GvisorAdapter
|
// GvisorAdapter create GvisorAdapter
|
||||||
func NewAdapter(device dev.TunDevice, conf config.Tun, tunAddress string, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) (ipstack.TunAdapter, error) {
|
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{
|
ipstack := stack.New(stack.Options{
|
||||||
NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol},
|
NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol},
|
||||||
TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol, udp.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()
|
mtu, err := t.device.MTU()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("unable to get device mtu")
|
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)
|
n, err := t.device.Read(packet)
|
||||||
if err != nil && !t.device.IsClose() {
|
if err != nil && !t.device.IsClose() {
|
||||||
log.Errorln("can not read from tun: %v", err)
|
log.Errorln("can not read from tun: %v", err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
var p tcpip.NetworkProtocolNumber
|
var p tcpip.NetworkProtocolNumber
|
||||||
switch header.IPVersion(packet) {
|
switch header.IPVersion(packet) {
|
||||||
|
|
|
@ -73,7 +73,6 @@ func (e *dnsEndpoint) Close() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *dnsEndpoint) Wait() {
|
func (e *dnsEndpoint) Wait() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *dnsEndpoint) HandleError(transErr stack.TransportError, pkt *stack.PacketBuffer) {
|
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)
|
_, err = w.Write(b)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *dnsResponseWriter) TsigStatus() error {
|
func (w *dnsResponseWriter) TsigStatus() error {
|
||||||
// Unsupported
|
// Unsupported
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *dnsResponseWriter) TsigTimersOnly(bool) {
|
func (w *dnsResponseWriter) TsigTimersOnly(bool) {
|
||||||
// Unsupported
|
// Unsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *dnsResponseWriter) Hijack() {
|
func (w *dnsResponseWriter) Hijack() {
|
||||||
// Unsupported
|
// Unsupported
|
||||||
}
|
}
|
||||||
|
@ -128,7 +130,6 @@ func (w *dnsResponseWriter) Close() error {
|
||||||
|
|
||||||
// CreateDNSServer create a dns server on given netstack
|
// 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) {
|
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 v4 bool
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,6 @@ func (c *fakeConn) Close() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeConn) Drop() {
|
func (c *fakeConn) Drop() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeConn) FakeIP() bool {
|
func (c *fakeConn) FakeIP() bool {
|
||||||
|
|
|
@ -6,10 +6,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/component/resolver"
|
D "github.com/Dreamacro/clash/listener/tun/ipstack/commons"
|
||||||
|
|
||||||
D "github.com/miekg/dns"
|
|
||||||
|
|
||||||
"github.com/kr328/tun2socket/binding"
|
"github.com/kr328/tun2socket/binding"
|
||||||
"github.com/kr328/tun2socket/redirect"
|
"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) {
|
func hijackUDPDns(pkt []byte, ep *binding.Endpoint, sender redirect.UDPSender) {
|
||||||
go func() {
|
go func() {
|
||||||
answer, err := relayDnsPacket(pkt)
|
answer, err := D.RelayDnsPacket(pkt)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -41,7 +37,9 @@ func hijackUDPDns(pkt []byte, ep *binding.Endpoint, sender redirect.UDPSender) {
|
||||||
|
|
||||||
func hijackTCPDns(conn net.Conn) {
|
func hijackTCPDns(conn net.Conn) {
|
||||||
go func() {
|
go func() {
|
||||||
defer conn.Close()
|
defer func(conn net.Conn) {
|
||||||
|
_ = conn.Close()
|
||||||
|
}(conn)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if err := conn.SetReadDeadline(time.Now().Add(defaultDnsReadTimeout)); err != nil {
|
if err := conn.SetReadDeadline(time.Now().Add(defaultDnsReadTimeout)); err != nil {
|
||||||
|
@ -60,7 +58,7 @@ func hijackTCPDns(conn net.Conn) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rb, err := relayDnsPacket(data)
|
rb, err := D.RelayDnsPacket(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
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()
|
|
||||||
}
|
|
||||||
|
|
|
@ -16,12 +16,18 @@ func handleTCP(conn net.Conn, endpoint *binding.Endpoint, tcpIn chan<- C.ConnCon
|
||||||
Port: int(endpoint.Source.Port),
|
Port: int(endpoint.Source.Port),
|
||||||
Zone: "",
|
Zone: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
dst := &net.TCPAddr{
|
dst := &net.TCPAddr{
|
||||||
IP: endpoint.Target.IP,
|
IP: endpoint.Target.IP,
|
||||||
Port: int(endpoint.Target.Port),
|
Port: int(endpoint.Target.Port),
|
||||||
Zone: "",
|
Zone: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addrType := C.AtypIPv4
|
||||||
|
if dst.IP.To4() == nil {
|
||||||
|
addrType = C.AtypIPv6
|
||||||
|
}
|
||||||
|
|
||||||
metadata := &C.Metadata{
|
metadata := &C.Metadata{
|
||||||
NetWork: C.TCP,
|
NetWork: C.TCP,
|
||||||
Type: C.TUN,
|
Type: C.TUN,
|
||||||
|
@ -29,9 +35,12 @@ func handleTCP(conn net.Conn, endpoint *binding.Endpoint, tcpIn chan<- C.ConnCon
|
||||||
DstIP: dst.IP,
|
DstIP: dst.IP,
|
||||||
SrcPort: strconv.Itoa(src.Port),
|
SrcPort: strconv.Itoa(src.Port),
|
||||||
DstPort: strconv.Itoa(dst.Port),
|
DstPort: strconv.Itoa(dst.Port),
|
||||||
AddrType: C.AtypIPv4,
|
AddrType: addrType,
|
||||||
Host: "",
|
Host: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//if c, ok := conn.(*net.TCPConn); ok {
|
||||||
|
// c.SetKeepAlive(true)
|
||||||
|
//}
|
||||||
tcpIn <- context.NewConnContext(conn, metadata)
|
tcpIn <- context.NewConnContext(conn, metadata)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
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{
|
adapter := &systemAdapter{
|
||||||
device: device,
|
device: device,
|
||||||
stackName: conf.Stack,
|
stackName: conf.Stack,
|
||||||
|
@ -37,8 +36,6 @@ func NewAdapter(device dev.TunDevice, conf config.Tun, mtu int, gateway, mirror
|
||||||
adapter.lock.Lock()
|
adapter.lock.Lock()
|
||||||
defer adapter.lock.Unlock()
|
defer adapter.lock.Unlock()
|
||||||
|
|
||||||
//adapter.stopLocked()
|
|
||||||
|
|
||||||
dnsHost, dnsPort, err := net.SplitHostPort(conf.DNSListen)
|
dnsHost, dnsPort, err := net.SplitHostPort(conf.DNSListen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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) {
|
t.SetTCPHandler(func(conn net.Conn, endpoint *binding.Endpoint) {
|
||||||
if shouldHijackDns(dnsAddr, endpoint.Target) {
|
if shouldHijackDns(dnsAddr, endpoint.Target) {
|
||||||
hijackTCPDns(conn)
|
hijackTCPDns(conn)
|
||||||
|
log.Debugln("[TUN] hijack dns tcp: %s:%d", endpoint.Target.IP.String(), endpoint.Target.Port)
|
||||||
if log.Level() == log.DEBUG {
|
|
||||||
log.Debugln("[TUN] hijack dns tcp: %s:%d", endpoint.Target.IP.String(), endpoint.Target.Port)
|
|
||||||
}
|
|
||||||
return
|
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) {
|
t.SetUDPHandler(func(payload []byte, endpoint *binding.Endpoint, sender redirect.UDPSender) {
|
||||||
if shouldHijackDns(dnsAddr, endpoint.Target) {
|
if shouldHijackDns(dnsAddr, endpoint.Target) {
|
||||||
hijackUDPDns(payload, endpoint, sender)
|
hijackUDPDns(payload, endpoint, sender)
|
||||||
|
log.Debugln("[TUN] hijack dns udp: %s:%d", endpoint.Target.IP.String(), endpoint.Target.Port)
|
||||||
if log.Level() == log.DEBUG {
|
|
||||||
log.Debugln("[TUN] hijack dns udp: %s:%d", endpoint.Target.IP.String(), endpoint.Target.Port)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ package memconservative
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
@ -54,7 +54,7 @@ func (g GeoIPCache) Unmarshal(filename, code string) (*router.GeoIP, error) {
|
||||||
case errFailedToReadBytes, errFailedToReadExpectedLenBytes,
|
case errFailedToReadBytes, errFailedToReadExpectedLenBytes,
|
||||||
errInvalidGeodataFile, errInvalidGeodataVarintLength:
|
errInvalidGeodataFile, errInvalidGeodataVarintLength:
|
||||||
log.Warnln("failed to decode geoip file: %s%s", filename, ", fallback to the original ReadFile method")
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ func (g GeoSiteCache) Unmarshal(filename, code string) (*router.GeoSite, error)
|
||||||
case errFailedToReadBytes, errFailedToReadExpectedLenBytes,
|
case errFailedToReadBytes, errFailedToReadExpectedLenBytes,
|
||||||
errInvalidGeodataFile, errInvalidGeodataVarintLength:
|
errInvalidGeodataFile, errInvalidGeodataVarintLength:
|
||||||
log.Warnln("failed to decode geoip file: %s%s", filename, ", fallback to the original ReadFile method")
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package router
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/rule/geodata/strmatcher"
|
"github.com/Dreamacro/clash/rule/geodata/strmatcher"
|
||||||
|
@ -69,44 +68,3 @@ func NewDomainMatcher(domains []*Domain) (*DomainMatcher, error) {
|
||||||
func (m *DomainMatcher) ApplyDomain(domain string) bool {
|
func (m *DomainMatcher) ApplyDomain(domain string) bool {
|
||||||
return len(m.matchers.Match(strings.ToLower(domain))) > 0
|
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
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
|
|
@ -2,7 +2,7 @@ package standard
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ func ReadFile(path string) ([]byte, error) {
|
||||||
}
|
}
|
||||||
defer reader.Close()
|
defer reader.Close()
|
||||||
|
|
||||||
return ioutil.ReadAll(reader)
|
return io.ReadAll(reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadAsset(file string) ([]byte, error) {
|
func ReadAsset(file string) ([]byte, error) {
|
||||||
|
|
|
@ -1,22 +1,17 @@
|
||||||
package rules
|
package rules
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/clash/component/mmdb"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
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 {
|
type GEOIP struct {
|
||||||
country string
|
country string
|
||||||
adapter string
|
adapter string
|
||||||
noResolveIP bool
|
noResolveIP bool
|
||||||
ruleExtra *C.RuleExtra
|
ruleExtra *C.RuleExtra
|
||||||
geoIPMatcher *router.GeoIPMatcher
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GEOIP) RuleType() C.RuleType {
|
func (g *GEOIP) RuleType() C.RuleType {
|
||||||
|
@ -29,10 +24,11 @@ func (g *GEOIP) Match(metadata *C.Metadata) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.EqualFold(g.country, "LAN") {
|
if strings.EqualFold(g.country, "LAN") || C.TunBroadcastAddr.Equal(ip) {
|
||||||
return ip.IsPrivate()
|
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 {
|
func (g *GEOIP) Adapter() string {
|
||||||
|
@ -51,39 +47,16 @@ func (g *GEOIP) RuleExtra() *C.RuleExtra {
|
||||||
return g.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) {
|
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{
|
geoip := &GEOIP{
|
||||||
country: country,
|
country: country,
|
||||||
adapter: adapter,
|
adapter: adapter,
|
||||||
noResolveIP: noResolveIP,
|
noResolveIP: noResolveIP,
|
||||||
ruleExtra: ruleExtra,
|
ruleExtra: ruleExtra,
|
||||||
geoIPMatcher: geoIPMatcher,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return geoip, nil
|
return geoip, nil
|
||||||
|
|
|
@ -49,24 +49,24 @@ func (gs *GEOSITE) RuleExtra() *C.RuleExtra {
|
||||||
|
|
||||||
func NewGEOSITE(country string, adapter string, ruleExtra *C.RuleExtra) (*GEOSITE, error) {
|
func NewGEOSITE(country string, adapter string, ruleExtra *C.RuleExtra) (*GEOSITE, error) {
|
||||||
geoLoaderName := "standard"
|
geoLoaderName := "standard"
|
||||||
//geoLoaderName := "memconservative"
|
|
||||||
geoLoader, err := geodata.GetGeoDataLoader(geoLoaderName)
|
geoLoader, err := geodata.GetGeoDataLoader(geoLoaderName)
|
||||||
if err != nil {
|
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)
|
domains, err := geoLoader.LoadGeoSite(country)
|
||||||
if err != nil {
|
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)
|
linear: linear algorithm
|
||||||
|
matcher, err := router.NewDomainMatcher(domains)
|
||||||
//mph:minimal perfect hash algorithm
|
mph:minimal perfect hash algorithm
|
||||||
|
*/
|
||||||
matcher, err := router.NewMphMatcherGroup(domains)
|
matcher, err := router.NewMphMatcherGroup(domains)
|
||||||
if err != nil {
|
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))
|
log.Infoln("Start initial GeoSite rule %s => %s, records: %d", country, adapter, len(domains))
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/gofrs/uuid"
|
"github.com/gofrs/uuid"
|
||||||
|
@ -87,7 +86,7 @@ func (vc *Conn) recvResponse() error {
|
||||||
|
|
||||||
length := int64(buf[0])
|
length := int64(buf[0])
|
||||||
if length != 0 { // addon data length > 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
|
return nil
|
||||||
|
|
|
@ -34,8 +34,6 @@ var (
|
||||||
udpTimeout = 60 * time.Second
|
udpTimeout = 60 * time.Second
|
||||||
|
|
||||||
preProcessCacheFinder, _ = R.NewProcess("", "", nil)
|
preProcessCacheFinder, _ = R.NewProcess("", "", nil)
|
||||||
|
|
||||||
tunBroadcastAddr = net.IPv4(198, 18, 255, 255)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -143,7 +141,7 @@ func preHandleMetadata(metadata *C.Metadata) error {
|
||||||
// redir-host should lookup the hosts
|
// redir-host should lookup the hosts
|
||||||
metadata.DstIP = node.Data.(net.IP)
|
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)
|
return fmt.Errorf("fake DNS record %s missing", metadata.DstIP)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -235,7 +233,7 @@ func handleUDPConn(packet *inbound.PacketAdapter) {
|
||||||
|
|
||||||
switch true {
|
switch true {
|
||||||
case rule != nil:
|
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:
|
case mode == Global:
|
||||||
log.Infoln("[UDP] %s(%s) --> %s using GLOBAL", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress())
|
log.Infoln("[UDP] %s(%s) --> %s using GLOBAL", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress())
|
||||||
case mode == Direct:
|
case mode == Direct:
|
||||||
|
@ -285,7 +283,7 @@ func handleTCPConn(ctx C.ConnContext) {
|
||||||
|
|
||||||
switch true {
|
switch true {
|
||||||
case rule != nil:
|
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:
|
case mode == Global:
|
||||||
log.Infoln("[TCP] %s(%s) --> %s using GLOBAL", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress())
|
log.Infoln("[TCP] %s(%s) --> %s using GLOBAL", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress())
|
||||||
case mode == Direct:
|
case mode == Direct:
|
||||||
|
|
Loading…
Reference in a new issue