update
This commit is contained in:
parent
db31cfbd7f
commit
b8c9a1bf6d
37 changed files with 329 additions and 727 deletions
|
@ -1,8 +1,10 @@
|
||||||
package router
|
package router
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/component/geodata/strmatcher"
|
"github.com/Dreamacro/clash/component/geodata/strmatcher"
|
||||||
|
@ -71,6 +73,241 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
type MultiGeoIPMatcher struct {
|
type MultiGeoIPMatcher struct {
|
||||||
matchers []*GeoIPMatcher
|
matchers []*GeoIPMatcher
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ func resolveSocketByNetlink(network string, ip net.IP, srcPort int) (int32, int3
|
||||||
return 0, 0, fmt.Errorf("invalid uid(%d) or inode(%d)", uid, inode)
|
return 0, 0, fmt.Errorf("invalid uid(%d) or inode(%d)", uid, inode)
|
||||||
}
|
}
|
||||||
|
|
||||||
return uid, inode, nil
|
return inode, uid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func packSocketDiagRequest(family, protocol byte, source net.IP, sourcePort uint16) []byte {
|
func packSocketDiagRequest(family, protocol byte, source net.IP, sourcePort uint16) []byte {
|
||||||
|
|
|
@ -237,15 +237,6 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
|
||||||
DNSHijack: []string{"198.18.0.2:53"}, // default hijack all dns query
|
DNSHijack: []string{"198.18.0.2:53"}, // default hijack all dns query
|
||||||
AutoRoute: true,
|
AutoRoute: true,
|
||||||
},
|
},
|
||||||
Proxy: []map[string]any{},
|
|
||||||
ProxyGroup: []map[string]any{},
|
|
||||||
Tun: RawTun{
|
|
||||||
Enable: false,
|
|
||||||
Device: "",
|
|
||||||
Stack: C.TunGvisor,
|
|
||||||
DNSHijack: []string{"0.0.0.0:53"}, // default hijack all dns query
|
|
||||||
AutoRoute: true,
|
|
||||||
},
|
|
||||||
DNS: RawDNS{
|
DNS: RawDNS{
|
||||||
Enable: false,
|
Enable: false,
|
||||||
UseHosts: true,
|
UseHosts: true,
|
||||||
|
@ -589,7 +580,7 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[strin
|
||||||
payload = strings.Join(rule[1:l-1], ",")
|
payload = strings.Join(rule[1:l-1], ",")
|
||||||
} else {
|
} else {
|
||||||
if l < 2 {
|
if l < 2 {
|
||||||
return nil, fmt.Errorf("rules[%d] [%s] error: format invalid", idx, line)
|
return nil, nil, fmt.Errorf("rules[%d] [%s] error: format invalid", idx, line)
|
||||||
}
|
}
|
||||||
if l < 4 {
|
if l < 4 {
|
||||||
rule = append(rule, make([]string, 4-l)...)
|
rule = append(rule, make([]string, 4-l)...)
|
||||||
|
@ -604,7 +595,6 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[strin
|
||||||
target = rule[l-1]
|
target = rule[l-1]
|
||||||
params = rule[l:]
|
params = rule[l:]
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := proxies[target]; mode != T.Script && !ok {
|
if _, ok := proxies[target]; mode != T.Script && !ok {
|
||||||
return nil, nil, fmt.Errorf("rules[%d] [%s] error: proxy [%s] not found", idx, line, target)
|
return nil, nil, fmt.Errorf("rules[%d] [%s] error: proxy [%s] not found", idx, line, target)
|
||||||
|
|
14
go.mod
14
go.mod
|
@ -11,21 +11,19 @@ require (
|
||||||
github.com/gofrs/uuid v4.2.0+incompatible
|
github.com/gofrs/uuid v4.2.0+incompatible
|
||||||
github.com/gorilla/websocket v1.5.0
|
github.com/gorilla/websocket v1.5.0
|
||||||
github.com/insomniacslk/dhcp v0.0.0-20220119180841-3c283ff8b7dd
|
github.com/insomniacslk/dhcp v0.0.0-20220119180841-3c283ff8b7dd
|
||||||
|
github.com/lucas-clemente/quic-go v0.25.0
|
||||||
github.com/miekg/dns v1.1.47
|
github.com/miekg/dns v1.1.47
|
||||||
github.com/oschwald/geoip2-golang v1.6.1
|
github.com/oschwald/geoip2-golang v1.6.1
|
||||||
github.com/sirupsen/logrus v1.8.1
|
github.com/sirupsen/logrus v1.8.1
|
||||||
github.com/stretchr/testify v1.7.1
|
github.com/stretchr/testify v1.7.1
|
||||||
github.com/xtls/go v0.0.0-20210920065950-d4af136d3672
|
github.com/xtls/go v0.0.0-20210920065950-d4af136d3672
|
||||||
go.etcd.io/bbolt v1.3.6
|
go.etcd.io/bbolt v1.3.6
|
||||||
github.com/lucas-clemente/quic-go v0.25.0
|
|
||||||
go.uber.org/atomic v1.9.0
|
go.uber.org/atomic v1.9.0
|
||||||
go.uber.org/automaxprocs v1.4.0
|
go.uber.org/automaxprocs v1.4.0
|
||||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
|
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
|
||||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
|
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||||
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86
|
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86
|
||||||
golang.zx2c4.com/wireguard/windows v0.5.1
|
|
||||||
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86
|
|
||||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65
|
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20220310012736-ae6bc4dd64e1
|
golang.zx2c4.com/wireguard v0.0.0-20220310012736-ae6bc4dd64e1
|
||||||
golang.zx2c4.com/wireguard/windows v0.5.3
|
golang.zx2c4.com/wireguard/windows v0.5.3
|
||||||
|
@ -41,8 +39,6 @@ require (
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||||
github.com/google/btree v1.0.1 // indirect
|
github.com/google/btree v1.0.1 // indirect
|
||||||
github.com/kr/pretty v0.2.1 // indirect
|
github.com/kr/pretty v0.2.1 // indirect
|
||||||
github.com/oschwald/maxminddb-golang v1.8.0 // indirect
|
|
||||||
github.com/kr/pretty v0.2.1 // indirect
|
|
||||||
github.com/marten-seemann/qtls-go1-16 v0.1.4 // indirect
|
github.com/marten-seemann/qtls-go1-16 v0.1.4 // indirect
|
||||||
github.com/marten-seemann/qtls-go1-17 v0.1.0 // indirect
|
github.com/marten-seemann/qtls-go1-17 v0.1.0 // indirect
|
||||||
github.com/marten-seemann/qtls-go1-18 v0.1.0 // indirect
|
github.com/marten-seemann/qtls-go1-18 v0.1.0 // indirect
|
||||||
|
@ -50,18 +46,12 @@ require (
|
||||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||||
github.com/oschwald/maxminddb-golang v1.8.0 // 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
|
|
||||||
golang.org/x/mod v0.5.1 // indirect
|
|
||||||
golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab // indirect
|
|
||||||
golang.org/x/tools v0.1.9 // indirect
|
|
||||||
github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4 // indirect
|
github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4 // indirect
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||||
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 // indirect
|
golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab // indirect
|
||||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
|
|
||||||
golang.org/x/tools v0.1.10 // indirect
|
golang.org/x/tools v0.1.10 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||||
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
|
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
|
||||||
golang.zx2c4.com/go118/netip v0.0.0-20211106132939-9d41d90554dd // indirect
|
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
|
||||||
)
|
)
|
||||||
|
|
25
go.sum
25
go.sum
|
@ -104,8 +104,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr328/tun2socket v0.0.0-20210412191540-3d56c47e2d99 h1:dkEFEnGUg2z/FAPywWr4yfR/sWDQK76qn3J4Y5H2hJs=
|
|
||||||
github.com/kr328/tun2socket v0.0.0-20210412191540-3d56c47e2d99/go.mod h1:FWfSixjrLgtK+dHkDoN6lHMNhvER24gnjUZd/wt8Z9o=
|
|
||||||
github.com/lucas-clemente/quic-go v0.25.0 h1:K+X9Gvd7JXsOHtU0N2icZ2Nw3rx82uBej3mP4CLgibc=
|
github.com/lucas-clemente/quic-go v0.25.0 h1:K+X9Gvd7JXsOHtU0N2icZ2Nw3rx82uBej3mP4CLgibc=
|
||||||
github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg=
|
github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg=
|
||||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||||
|
@ -196,8 +194,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||||
github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA=
|
github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA=
|
||||||
github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4 h1:hl6sK6aFgTLISijk6xIzeqnPzQcsLqqvL6vEfTPinME=
|
github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4 h1:hl6sK6aFgTLISijk6xIzeqnPzQcsLqqvL6vEfTPinME=
|
||||||
|
@ -323,8 +322,8 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 h1:GLw7MR8AfAG2GmGcmVgObFOHXYypgGjnGno25RDwn3Y=
|
golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab h1:eHo2TTVBaAPw9lDGK2Gb9GyPMXT6g7O63W6sx3ylbzU=
|
||||||
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
|
golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
|
||||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs=
|
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs=
|
||||||
|
@ -352,12 +351,12 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1N
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.zx2c4.com/go118/netip v0.0.0-20211106132939-9d41d90554dd h1:gUHae7sCd+tFJLcCximWeBFD2b6Jg3O7UaNaPvjIJHc=
|
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY=
|
||||||
golang.zx2c4.com/go118/netip v0.0.0-20211106132939-9d41d90554dd/go.mod h1:5yyfuiqVIJ7t+3MqrpTQ+QqRkMWiESiyDvPNvKYCecg=
|
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
||||||
golang.zx2c4.com/wireguard/windows v0.5.1 h1:OnYw96PF+CsIMrqWo5QP3Q59q5hY1rFErk/yN3cS+JQ=
|
golang.zx2c4.com/wireguard v0.0.0-20220310012736-ae6bc4dd64e1 h1:iuQdvJn3LrXxz3Iony1qBGVS7kEy2uHYnnjHsVbzq/s=
|
||||||
golang.zx2c4.com/wireguard/windows v0.5.1/go.mod h1:EApyTk/ZNrkbZjurHL1nleDYnsPpJYBO7LZEBCyDAHk=
|
golang.zx2c4.com/wireguard v0.0.0-20220310012736-ae6bc4dd64e1/go.mod h1:TjUWrnD5ATh7bFvmm/ALEJZQ4ivKbETb6pmyj1vUoNI=
|
||||||
golang.zx2c4.com/wireguard/windows v0.5.2 h1:C3kUahG6QPhXUYSMesW0t1mDo1XCwls2c8Bz16umS44=
|
golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE=
|
||||||
golang.zx2c4.com/wireguard/windows v0.5.2/go.mod h1:KptYG5fXTsP1sHafw0BnWHxobtR6QZHWY6SVWq5R0PM=
|
golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI=
|
||||||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||||
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||||
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
|
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
|
||||||
|
@ -400,8 +399,8 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
||||||
gvisor.dev/gvisor v0.0.0-20220129032118-ed00636ef990 h1:fTgWAYpliP19U3FX8+tI2TZGXnnk45g18frOuZxKay4=
|
gvisor.dev/gvisor v0.0.0-20220315202956-f1399ecf1672 h1:aXIFpjZYl3zv2rQyr4rSit5Uq0k7BVXC8lJaDa4Cg7M=
|
||||||
gvisor.dev/gvisor v0.0.0-20220129032118-ed00636ef990/go.mod h1:vmN0Pug/s8TJmpnt30DvrEfZ5vDl52psGLU04tFuK2U=
|
gvisor.dev/gvisor v0.0.0-20220315202956-f1399ecf1672/go.mod h1:V4WNP2Uwtx69eOhvLDSQ734EaTJTaBI3P8KgRAlROsg=
|
||||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/listener/tproxy"
|
"github.com/Dreamacro/clash/listener/tproxy"
|
||||||
|
@ -28,7 +27,6 @@ import (
|
||||||
"github.com/Dreamacro/clash/dns"
|
"github.com/Dreamacro/clash/dns"
|
||||||
P "github.com/Dreamacro/clash/listener"
|
P "github.com/Dreamacro/clash/listener"
|
||||||
authStore "github.com/Dreamacro/clash/listener/auth"
|
authStore "github.com/Dreamacro/clash/listener/auth"
|
||||||
"github.com/Dreamacro/clash/listener/tproxy"
|
|
||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
"github.com/Dreamacro/clash/tunnel"
|
"github.com/Dreamacro/clash/tunnel"
|
||||||
)
|
)
|
||||||
|
@ -83,9 +81,9 @@ func ApplyConfig(cfg *config.Config, force bool) {
|
||||||
updateGeneral(cfg.General, cfg.Tun, force)
|
updateGeneral(cfg.General, cfg.Tun, force)
|
||||||
updateProxies(cfg.Proxies, cfg.Providers)
|
updateProxies(cfg.Proxies, cfg.Providers)
|
||||||
updateRules(cfg.Rules, cfg.RuleProviders)
|
updateRules(cfg.Rules, cfg.RuleProviders)
|
||||||
updateIPTables(cfg.DNS, cfg.General, cfg.Tun)
|
updateIPTables(cfg.DNS, cfg.General.TProxyPort, cfg.General.Interface, cfg.Tun.Enable)
|
||||||
updateDNS(cfg.DNS, cfg.Tun)
|
updateDNS(cfg.DNS, cfg.Tun)
|
||||||
updateTun(cfg.Tun)
|
updateTun(cfg.Tun, cfg.DNS.FakeIPRange.IPNet().String())
|
||||||
updateExperimental(cfg)
|
updateExperimental(cfg)
|
||||||
loadProvider(cfg.RuleProviders, cfg.Providers)
|
loadProvider(cfg.RuleProviders, cfg.Providers)
|
||||||
updateProfile(cfg)
|
updateProfile(cfg)
|
||||||
|
|
|
@ -78,10 +78,6 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) {
|
||||||
P.ReCreateTProxy(pointerOrDefault(general.TProxyPort, ports.TProxyPort), tcpIn, udpIn)
|
P.ReCreateTProxy(pointerOrDefault(general.TProxyPort, ports.TProxyPort), tcpIn, udpIn)
|
||||||
P.ReCreateMixed(pointerOrDefault(general.MixedPort, ports.MixedPort), tcpIn, udpIn)
|
P.ReCreateMixed(pointerOrDefault(general.MixedPort, ports.MixedPort), tcpIn, udpIn)
|
||||||
|
|
||||||
if general.Tun != nil {
|
|
||||||
P.ReCreateTun(*general.Tun, tcpIn, udpIn)
|
|
||||||
}
|
|
||||||
|
|
||||||
if general.Mode != nil {
|
if general.Mode != nil {
|
||||||
tunnel.SetMode(*general.Mode)
|
tunnel.SetMode(*general.Mode)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"github.com/Dreamacro/clash/listener/inner"
|
"github.com/Dreamacro/clash/listener/inner"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
|
|
@ -1,398 +0,0 @@
|
||||||
//go:build windows
|
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package dev
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"sort"
|
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/listener/tun/dev/wintun"
|
|
||||||
"github.com/Dreamacro/clash/log"
|
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
|
||||||
)
|
|
||||||
|
|
||||||
const messageTransportHeaderSize = 0 // size of data preceding content in transport message
|
|
||||||
|
|
||||||
type tunWindows struct {
|
|
||||||
wt *wintun.Adapter
|
|
||||||
handle windows.Handle
|
|
||||||
close int32
|
|
||||||
running sync.WaitGroup
|
|
||||||
forcedMTU int
|
|
||||||
rate rateJuggler
|
|
||||||
session wintun.Session
|
|
||||||
readWait windows.Handle
|
|
||||||
closeOnce sync.Once
|
|
||||||
|
|
||||||
url string
|
|
||||||
name string
|
|
||||||
tunAddress string
|
|
||||||
autoRoute bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenTunDevice return a TunDevice according a URL
|
|
||||||
func OpenTunDevice(tunAddress string, autoRoute bool) (TunDevice, error) {
|
|
||||||
|
|
||||||
requestedGUID, err := windows.GUIDFromString("{330EAEF8-7578-5DF2-D97B-8DADC0EA85CB}")
|
|
||||||
if err == nil {
|
|
||||||
WintunStaticRequestedGUID = &requestedGUID
|
|
||||||
log.Debugln("Generate GUID: %s", WintunStaticRequestedGUID.String())
|
|
||||||
} else {
|
|
||||||
log.Warnln("Error parese GUID from string: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
interfaceName := "Meta Tunnel"
|
|
||||||
mtu := 9000
|
|
||||||
|
|
||||||
tun, err := CreateTUN(interfaceName, mtu, tunAddress, autoRoute)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return tun, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// CreateTUN creates a Wintun interface with the given name. Should a Wintun
|
|
||||||
// interface with the same name exist, it is reused.
|
|
||||||
//
|
|
||||||
func CreateTUN(ifname string, mtu int, tunAddress string, autoRoute bool) (TunDevice, error) {
|
|
||||||
return CreateTUNWithRequestedGUID(ifname, WintunStaticRequestedGUID, mtu, tunAddress, autoRoute)
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// CreateTUNWithRequestedGUID creates a Wintun interface with the given name and
|
|
||||||
// a requested GUID. Should a Wintun interface with the same name exist, it is reused.
|
|
||||||
//
|
|
||||||
func CreateTUNWithRequestedGUID(ifname string, requestedGUID *windows.GUID, mtu int, tunAddress string, autoRoute bool) (TunDevice, error) {
|
|
||||||
wt, err := wintun.CreateAdapter(ifname, WintunTunnelType, requestedGUID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Error creating interface: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
forcedMTU := 1420
|
|
||||||
if mtu > 0 {
|
|
||||||
forcedMTU = mtu
|
|
||||||
}
|
|
||||||
|
|
||||||
tun := &tunWindows{
|
|
||||||
name: ifname,
|
|
||||||
wt: wt,
|
|
||||||
handle: windows.InvalidHandle,
|
|
||||||
forcedMTU: forcedMTU,
|
|
||||||
tunAddress: tunAddress,
|
|
||||||
autoRoute: autoRoute,
|
|
||||||
}
|
|
||||||
|
|
||||||
// config tun ip
|
|
||||||
err = tun.configureInterface()
|
|
||||||
if err != nil {
|
|
||||||
tun.wt.Close()
|
|
||||||
return nil, fmt.Errorf("error configure interface: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tun.session, err = wt.StartSession(0x800000) // Ring capacity, 8 MiB
|
|
||||||
if err != nil {
|
|
||||||
tun.wt.Close()
|
|
||||||
return nil, fmt.Errorf("error starting session: %w", err)
|
|
||||||
}
|
|
||||||
tun.readWait = tun.session.ReadWaitEvent()
|
|
||||||
return tun, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tun *tunWindows) Name() string {
|
|
||||||
return tun.name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tun *tunWindows) IsClose() bool {
|
|
||||||
return atomic.LoadInt32(&tun.close) == 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tun *tunWindows) Read(buff []byte) (int, error) {
|
|
||||||
return tun.Read0(buff, messageTransportHeaderSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tun *tunWindows) Write(buff []byte) (int, error) {
|
|
||||||
return tun.Write0(buff, messageTransportHeaderSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tun *tunWindows) URL() string {
|
|
||||||
return fmt.Sprintf("dev://%s", tun.Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tun *tunWindows) configureInterface() error {
|
|
||||||
retryOnFailure := wintun.StartedAtBoot()
|
|
||||||
tryTimes := 0
|
|
||||||
startOver:
|
|
||||||
var err error
|
|
||||||
if tryTimes > 0 {
|
|
||||||
log.Infoln("Retrying interface configuration after failure because system just booted (T+%v): %v", windows.DurationSinceBoot(), err)
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
retryOnFailure = retryOnFailure && tryTimes < 15
|
|
||||||
}
|
|
||||||
tryTimes++
|
|
||||||
|
|
||||||
luid := winipcfg.LUID(tun.LUID())
|
|
||||||
log.Infoln("[wintun]: tun adapter LUID: %d", luid)
|
|
||||||
mtu, err := tun.MTU()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("unable to get device mtu")
|
|
||||||
}
|
|
||||||
|
|
||||||
family := winipcfg.AddressFamily(windows.AF_INET)
|
|
||||||
familyV6 := winipcfg.AddressFamily(windows.AF_INET6)
|
|
||||||
|
|
||||||
tunAddress := wintun.ParseIPCidr(tun.tunAddress + "/16")
|
|
||||||
|
|
||||||
addresses := []net.IPNet{tunAddress.IPNet()}
|
|
||||||
|
|
||||||
err = luid.FlushIPAddresses(familyV6)
|
|
||||||
if err == windows.ERROR_NOT_FOUND && retryOnFailure {
|
|
||||||
goto startOver
|
|
||||||
} else if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = luid.FlushDNS(family)
|
|
||||||
if err == windows.ERROR_NOT_FOUND && retryOnFailure {
|
|
||||||
goto startOver
|
|
||||||
} else if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = luid.FlushDNS(familyV6)
|
|
||||||
if err == windows.ERROR_NOT_FOUND && retryOnFailure {
|
|
||||||
goto startOver
|
|
||||||
} else if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = luid.FlushRoutes(familyV6)
|
|
||||||
if err == windows.ERROR_NOT_FOUND && retryOnFailure {
|
|
||||||
goto startOver
|
|
||||||
} else if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
foundDefault4 := false
|
|
||||||
foundDefault6 := false
|
|
||||||
|
|
||||||
if tun.autoRoute {
|
|
||||||
allowedIPs := []*wintun.IPCidr{
|
|
||||||
//wintun.ParseIPCidr("0.0.0.0/0"),
|
|
||||||
wintun.ParseIPCidr("1.0.0.0/8"),
|
|
||||||
wintun.ParseIPCidr("2.0.0.0/7"),
|
|
||||||
wintun.ParseIPCidr("4.0.0.0/6"),
|
|
||||||
wintun.ParseIPCidr("8.0.0.0/5"),
|
|
||||||
wintun.ParseIPCidr("16.0.0.0/4"),
|
|
||||||
wintun.ParseIPCidr("32.0.0.0/3"),
|
|
||||||
wintun.ParseIPCidr("64.0.0.0/2"),
|
|
||||||
wintun.ParseIPCidr("128.0.0.0/1"),
|
|
||||||
wintun.ParseIPCidr("224.0.0.0/4"),
|
|
||||||
wintun.ParseIPCidr("255.255.255.255/32"),
|
|
||||||
}
|
|
||||||
|
|
||||||
estimatedRouteCount := len(allowedIPs)
|
|
||||||
routes := make([]winipcfg.RouteData, 0, estimatedRouteCount)
|
|
||||||
var haveV4Address, haveV6Address bool = true, false
|
|
||||||
|
|
||||||
for _, allowedip := range allowedIPs {
|
|
||||||
allowedip.MaskSelf()
|
|
||||||
if (allowedip.Bits() == 32 && !haveV4Address) || (allowedip.Bits() == 128 && !haveV6Address) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
route := winipcfg.RouteData{
|
|
||||||
Destination: allowedip.IPNet(),
|
|
||||||
Metric: 0,
|
|
||||||
}
|
|
||||||
if allowedip.Bits() == 32 {
|
|
||||||
if allowedip.Cidr == 0 {
|
|
||||||
foundDefault4 = true
|
|
||||||
}
|
|
||||||
route.NextHop = net.IPv4zero
|
|
||||||
} else if allowedip.Bits() == 128 {
|
|
||||||
if allowedip.Cidr == 0 {
|
|
||||||
foundDefault6 = true
|
|
||||||
}
|
|
||||||
route.NextHop = net.IPv6zero
|
|
||||||
}
|
|
||||||
routes = append(routes, route)
|
|
||||||
}
|
|
||||||
|
|
||||||
deduplicatedRoutes := make([]*winipcfg.RouteData, 0, len(routes))
|
|
||||||
sort.Slice(routes, func(i, j int) bool {
|
|
||||||
if routes[i].Metric != routes[j].Metric {
|
|
||||||
return routes[i].Metric < routes[j].Metric
|
|
||||||
}
|
|
||||||
if c := bytes.Compare(routes[i].NextHop, routes[j].NextHop); c != 0 {
|
|
||||||
return c < 0
|
|
||||||
}
|
|
||||||
if c := bytes.Compare(routes[i].Destination.IP, routes[j].Destination.IP); c != 0 {
|
|
||||||
return c < 0
|
|
||||||
}
|
|
||||||
if c := bytes.Compare(routes[i].Destination.Mask, routes[j].Destination.Mask); c != 0 {
|
|
||||||
return c < 0
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
for i := 0; i < len(routes); i++ {
|
|
||||||
if i > 0 && routes[i].Metric == routes[i-1].Metric &&
|
|
||||||
bytes.Equal(routes[i].NextHop, routes[i-1].NextHop) &&
|
|
||||||
bytes.Equal(routes[i].Destination.IP, routes[i-1].Destination.IP) &&
|
|
||||||
bytes.Equal(routes[i].Destination.Mask, routes[i-1].Destination.Mask) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
deduplicatedRoutes = append(deduplicatedRoutes, &routes[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
err = luid.SetRoutesForFamily(family, deduplicatedRoutes)
|
|
||||||
if err == windows.ERROR_NOT_FOUND && retryOnFailure {
|
|
||||||
goto startOver
|
|
||||||
} else if err != nil {
|
|
||||||
return fmt.Errorf("unable to set routes: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = luid.SetIPAddressesForFamily(family, addresses)
|
|
||||||
if err == windows.ERROR_OBJECT_ALREADY_EXISTS {
|
|
||||||
cleanupAddressesOnDisconnectedInterfaces(family, addresses)
|
|
||||||
err = luid.SetIPAddressesForFamily(family, addresses)
|
|
||||||
}
|
|
||||||
if err == windows.ERROR_NOT_FOUND && retryOnFailure {
|
|
||||||
goto startOver
|
|
||||||
} else if err != nil {
|
|
||||||
return fmt.Errorf("unable to set ips: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var ipif *winipcfg.MibIPInterfaceRow
|
|
||||||
ipif, err = luid.IPInterface(family)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ipif.RouterDiscoveryBehavior = winipcfg.RouterDiscoveryDisabled
|
|
||||||
ipif.DadTransmits = 0
|
|
||||||
ipif.ManagedAddressConfigurationSupported = false
|
|
||||||
ipif.OtherStatefulConfigurationSupported = false
|
|
||||||
if mtu > 0 {
|
|
||||||
ipif.NLMTU = uint32(mtu)
|
|
||||||
}
|
|
||||||
if (family == windows.AF_INET && foundDefault4) || (family == windows.AF_INET6 && foundDefault6) {
|
|
||||||
ipif.UseAutomaticMetric = false
|
|
||||||
ipif.Metric = 0
|
|
||||||
}
|
|
||||||
err = ipif.Set()
|
|
||||||
if err == windows.ERROR_NOT_FOUND && retryOnFailure {
|
|
||||||
goto startOver
|
|
||||||
} else if err != nil {
|
|
||||||
return fmt.Errorf("unable to set metric and MTU: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var ipif6 *winipcfg.MibIPInterfaceRow
|
|
||||||
ipif6, err = luid.IPInterface(familyV6)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ipif6.RouterDiscoveryBehavior = winipcfg.RouterDiscoveryDisabled
|
|
||||||
ipif6.DadTransmits = 0
|
|
||||||
ipif6.ManagedAddressConfigurationSupported = false
|
|
||||||
ipif6.OtherStatefulConfigurationSupported = false
|
|
||||||
|
|
||||||
err = ipif6.Set()
|
|
||||||
if err == windows.ERROR_NOT_FOUND && retryOnFailure {
|
|
||||||
goto startOver
|
|
||||||
} else if err != nil {
|
|
||||||
return fmt.Errorf("unable to set v6 metric and MTU: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = luid.SetDNS(family, []net.IP{net.ParseIP("198.18.0.2")}, nil)
|
|
||||||
if err == windows.ERROR_NOT_FOUND && retryOnFailure {
|
|
||||||
goto startOver
|
|
||||||
} else if err != nil {
|
|
||||||
return fmt.Errorf("unable to set DNS %s %s: %w", "198.18.0.2", "nil", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func cleanupAddressesOnDisconnectedInterfaces(family winipcfg.AddressFamily, addresses []net.IPNet) {
|
|
||||||
if len(addresses) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
addrToStr := func(ip *net.IP) string {
|
|
||||||
if ip4 := ip.To4(); ip4 != nil {
|
|
||||||
return string(ip4)
|
|
||||||
}
|
|
||||||
return string(*ip)
|
|
||||||
}
|
|
||||||
addrHash := make(map[string]bool, len(addresses))
|
|
||||||
for i := range addresses {
|
|
||||||
addrHash[addrToStr(&addresses[i].IP)] = true
|
|
||||||
}
|
|
||||||
interfaces, err := winipcfg.GetAdaptersAddresses(family, winipcfg.GAAFlagDefault)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, iface := range interfaces {
|
|
||||||
if iface.OperStatus == winipcfg.IfOperStatusUp {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for address := iface.FirstUnicastAddress; address != nil; address = address.Next {
|
|
||||||
ip := address.Address.IP()
|
|
||||||
if addrHash[addrToStr(&ip)] {
|
|
||||||
ipnet := net.IPNet{IP: ip, Mask: net.CIDRMask(int(address.OnLinkPrefixLength), 8*len(ip))}
|
|
||||||
log.Infoln("Cleaning up stale address %s from interface ‘%s’", ipnet.String(), iface.FriendlyName())
|
|
||||||
iface.LUID.DeleteIPAddress(ipnet)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAutoDetectInterface get ethernet interface
|
|
||||||
func GetAutoDetectInterface() (string, error) {
|
|
||||||
ifname, err := getAutoDetectInterfaceByFamily(winipcfg.AddressFamily(windows.AF_INET))
|
|
||||||
if err == nil {
|
|
||||||
return ifname, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return getAutoDetectInterfaceByFamily(winipcfg.AddressFamily(windows.AF_INET6))
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAutoDetectInterfaceByFamily(family winipcfg.AddressFamily) (string, error) {
|
|
||||||
interfaces, err := winipcfg.GetAdaptersAddresses(family, winipcfg.GAAFlagIncludeGateways)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("get ethernet interface failure. %w", err)
|
|
||||||
}
|
|
||||||
for _, iface := range interfaces {
|
|
||||||
if iface.OperStatus != winipcfg.IfOperStatusUp {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
ifname := iface.FriendlyName()
|
|
||||||
if ifname == "Clash" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for gatewayAddress := iface.FirstGatewayAddress; gatewayAddress != nil; gatewayAddress = gatewayAddress.Next {
|
|
||||||
nextHop := gatewayAddress.Address.IP()
|
|
||||||
|
|
||||||
var ipnet net.IPNet
|
|
||||||
if family == windows.AF_INET {
|
|
||||||
ipnet = net.IPNet{IP: net.IPv4zero, Mask: net.CIDRMask(0, 32)}
|
|
||||||
} else {
|
|
||||||
ipnet = net.IPNet{IP: net.IPv6zero, Mask: net.CIDRMask(0, 128)}
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = iface.LUID.Route(ipnet, nextHop); err == nil {
|
|
||||||
return ifname, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "", errors.New("ethernet interface not found")
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
//go:build windows
|
|
||||||
// +build windows
|
|
||||||
|
|
||||||
/* SPDX-License-Identifier: MIT
|
|
||||||
*
|
|
||||||
* Copyright (C) 2019-2021 WireGuard LLC. All Rights Reserved.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package wintun
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"log"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
"golang.org/x/sys/windows/svc"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
startedAtBoot bool
|
|
||||||
startedAtBootOnce sync.Once
|
|
||||||
)
|
|
||||||
|
|
||||||
func StartedAtBoot() bool {
|
|
||||||
startedAtBootOnce.Do(func() {
|
|
||||||
if isService, err := svc.IsWindowsService(); err == nil && !isService {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if reason, err := svc.DynamicStartReason(); err == nil {
|
|
||||||
startedAtBoot = (reason&svc.StartReasonAuto) != 0 || (reason&svc.StartReasonDelayedAuto) != 0
|
|
||||||
} else if errors.Is(err, windows.ERROR_PROC_NOT_FOUND) {
|
|
||||||
// TODO: Below this line is Windows 7 compatibility code, which hopefully we can delete at some point.
|
|
||||||
startedAtBoot = windows.DurationSinceBoot() < time.Minute*10
|
|
||||||
} else {
|
|
||||||
log.Printf("Unable to determine service start reason: %v", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return startedAtBoot
|
|
||||||
}
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,21 +0,0 @@
|
||||||
package embed_dll
|
|
||||||
|
|
||||||
// Copyright 2020 MeshStep Authors.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "embed"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:embed x86/wintun.dll
|
|
||||||
var DDlContent []byte
|
|
|
@ -1,21 +0,0 @@
|
||||||
package embed_dll
|
|
||||||
|
|
||||||
// Copyright 2020 MeshStep Authors.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "embed"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:embed amd64/wintun.dll
|
|
||||||
var DDlContent []byte
|
|
|
@ -1,21 +0,0 @@
|
||||||
package embed_dll
|
|
||||||
|
|
||||||
// Copyright 2020 MeshStep Authors.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "embed"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:embed arm/wintun.dll
|
|
||||||
var DDlContent []byte
|
|
|
@ -1,21 +0,0 @@
|
||||||
package embed_dll
|
|
||||||
|
|
||||||
// Copyright 2020 MeshStep Authors.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "embed"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:embed arm64/wintun.dll
|
|
||||||
var DDlContent []byte
|
|
Binary file not shown.
|
@ -53,7 +53,7 @@ func New(tunConf *config.Tun, tunAddressPrefix string, tcpIn chan<- C.ConnContex
|
||||||
if err != nil {
|
if err != nil {
|
||||||
for i := 1; i < 3; i++ {
|
for i := 1; i < 3; i++ {
|
||||||
time.Sleep(time.Second * 1)
|
time.Sleep(time.Second * 1)
|
||||||
device, err = dev.OpenTunDevice(tunAddress, autoRoute)
|
tunDevice, err = parseDevice(devName, uint32(mtu))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,10 @@ func (b *Base) ShouldFindProcess() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Base) ShouldResolveIP() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func HasNoResolve(params []string) bool {
|
func HasNoResolve(params []string) bool {
|
||||||
for _, p := range params {
|
for _, p := range params {
|
||||||
if p == noResolve {
|
if p == noResolve {
|
||||||
|
|
|
@ -31,14 +31,6 @@ func (d *Domain) Payload() string {
|
||||||
return d.domain
|
return d.domain
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Domain) ShouldResolveIP() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Domain) ShouldFindProcess() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDomain(domain string, adapter string) *Domain {
|
func NewDomain(domain string, adapter string) *Domain {
|
||||||
return &Domain{
|
return &Domain{
|
||||||
Base: &Base{},
|
Base: &Base{},
|
||||||
|
|
|
@ -32,14 +32,6 @@ func (dk *DomainKeyword) Payload() string {
|
||||||
return dk.keyword
|
return dk.keyword
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dk *DomainKeyword) ShouldResolveIP() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dk *DomainKeyword) ShouldFindProcess() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDomainKeyword(keyword string, adapter string) *DomainKeyword {
|
func NewDomainKeyword(keyword string, adapter string) *DomainKeyword {
|
||||||
return &DomainKeyword{
|
return &DomainKeyword{
|
||||||
Base: &Base{},
|
Base: &Base{},
|
||||||
|
|
|
@ -32,14 +32,6 @@ func (ds *DomainSuffix) Payload() string {
|
||||||
return ds.suffix
|
return ds.suffix
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ds *DomainSuffix) ShouldResolveIP() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ds *DomainSuffix) ShouldFindProcess() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDomainSuffix(suffix string, adapter string) *DomainSuffix {
|
func NewDomainSuffix(suffix string, adapter string) *DomainSuffix {
|
||||||
return &DomainSuffix{
|
return &DomainSuffix{
|
||||||
Base: &Base{},
|
Base: &Base{},
|
||||||
|
|
|
@ -25,14 +25,6 @@ func (f *Match) Payload() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Match) ShouldResolveIP() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Match) ShouldFindProcess() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMatch(adapter string) *Match {
|
func NewMatch(adapter string) *Match {
|
||||||
return &Match{
|
return &Match{
|
||||||
Base: &Base{},
|
Base: &Base{},
|
||||||
|
|
|
@ -20,10 +20,6 @@ type GEOIP struct {
|
||||||
geoIPMatcher *router.GeoIPMatcher
|
geoIPMatcher *router.GeoIPMatcher
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GEOIP) ShouldFindProcess() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *GEOIP) RuleType() C.RuleType {
|
func (g *GEOIP) RuleType() C.RuleType {
|
||||||
return C.GEOIP
|
return C.GEOIP
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,19 +40,11 @@ func (gs *GEOSITE) Payload() string {
|
||||||
return gs.country
|
return gs.country
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gs *GEOSITE) ShouldResolveIP() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gs *GEOSITE) ShouldFindProcess() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gs *GEOSITE) GetDomainMatcher() *router.DomainMatcher {
|
func (gs *GEOSITE) GetDomainMatcher() *router.DomainMatcher {
|
||||||
return gs.matcher
|
return gs.matcher
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGEOSITE(country string, adapter string, ruleExtra *C.RuleExtra) (*GEOSITE, error) {
|
func NewGEOSITE(country string, adapter string) (*GEOSITE, error) {
|
||||||
matcher, recordsCount, err := geodata.LoadGeoSiteMatcher(country)
|
matcher, recordsCount, err := geodata.LoadGeoSiteMatcher(country)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("load GeoSite data error, %s", err.Error())
|
return nil, fmt.Errorf("load GeoSite data error, %s", err.Error())
|
||||||
|
|
|
@ -55,10 +55,6 @@ func (i *IPCIDR) ShouldResolveIP() bool {
|
||||||
return !i.noResolveIP
|
return !i.noResolveIP
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *IPCIDR) ShouldFindProcess() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewIPCIDR(s string, adapter string, opts ...IPCIDROption) (*IPCIDR, error) {
|
func NewIPCIDR(s string, adapter string, opts ...IPCIDROption) (*IPCIDR, error) {
|
||||||
_, ipnet, err := net.ParseCIDR(s)
|
_, ipnet, err := net.ParseCIDR(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -7,14 +7,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type NetworkType struct {
|
type NetworkType struct {
|
||||||
|
*Base
|
||||||
network C.NetWork
|
network C.NetWork
|
||||||
adapter string
|
adapter string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NetworkType) ShouldFindProcess() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewNetworkType(network, adapter string) (*NetworkType, error) {
|
func NewNetworkType(network, adapter string) (*NetworkType, error) {
|
||||||
ntType := new(NetworkType)
|
ntType := new(NetworkType)
|
||||||
ntType.adapter = adapter
|
ntType.adapter = adapter
|
||||||
|
@ -47,11 +44,3 @@ func (n *NetworkType) Adapter() string {
|
||||||
func (n *NetworkType) Payload() string {
|
func (n *NetworkType) Payload() string {
|
||||||
return n.network.String()
|
return n.network.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NetworkType) ShouldResolveIP() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NetworkType) RuleExtra() *C.RuleExtra {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -21,10 +21,6 @@ type Port struct {
|
||||||
portList []portReal
|
portList []portReal
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Port) ShouldFindProcess() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Port) RuleType() C.RuleType {
|
func (p *Port) RuleType() C.RuleType {
|
||||||
if p.isSource {
|
if p.isSource {
|
||||||
return C.SrcPort
|
return C.SrcPort
|
||||||
|
@ -47,10 +43,6 @@ func (p *Port) Payload() string {
|
||||||
return p.port
|
return p.port
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Port) ShouldResolveIP() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Port) matchPortReal(portRef string) bool {
|
func (p *Port) matchPortReal(portRef string) bool {
|
||||||
port, _ := strconv.Atoi(portRef)
|
port, _ := strconv.Atoi(portRef)
|
||||||
var rs bool
|
var rs bool
|
||||||
|
|
|
@ -14,14 +14,10 @@ import (
|
||||||
var processCache = cache.NewLRUCache(cache.WithAge(2), cache.WithSize(64))
|
var processCache = cache.NewLRUCache(cache.WithAge(2), cache.WithSize(64))
|
||||||
|
|
||||||
type Process struct {
|
type Process struct {
|
||||||
|
*Base
|
||||||
adapter string
|
adapter string
|
||||||
process string
|
process string
|
||||||
nameOnly bool
|
nameOnly bool
|
||||||
ruleExtra *C.RuleExtra
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ps *Process) ShouldFindProcess() bool {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *Process) RuleType() C.RuleType {
|
func (ps *Process) RuleType() C.RuleType {
|
||||||
|
@ -67,19 +63,11 @@ func (ps *Process) Payload() string {
|
||||||
return ps.process
|
return ps.process
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *Process) ShouldResolveIP() bool {
|
func NewProcess(process string, adapter string, nameOnly bool) (*Process, error) {
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ps *Process) RuleExtra() *C.RuleExtra {
|
|
||||||
return ps.ruleExtra
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewProcess(process string, adapter string, nameOnly bool, ruleExtra *C.RuleExtra) (*Process, error) {
|
|
||||||
return &Process{
|
return &Process{
|
||||||
|
Base: &Base{},
|
||||||
adapter: adapter,
|
adapter: adapter,
|
||||||
process: process,
|
process: process,
|
||||||
nameOnly: nameOnly,
|
nameOnly: nameOnly,
|
||||||
ruleExtra: ruleExtra,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
package logic
|
package logic
|
||||||
|
|
||||||
import C "github.com/Dreamacro/clash/constant"
|
import (
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
"github.com/Dreamacro/clash/rule/common"
|
||||||
|
)
|
||||||
|
|
||||||
type AND struct {
|
type AND struct {
|
||||||
|
common.Base
|
||||||
rules []C.Rule
|
rules []C.Rule
|
||||||
payload string
|
payload string
|
||||||
adapter string
|
adapter string
|
||||||
|
@ -56,7 +60,3 @@ func (A *AND) Payload() string {
|
||||||
func (A *AND) ShouldResolveIP() bool {
|
func (A *AND) ShouldResolveIP() bool {
|
||||||
return A.needIP
|
return A.needIP
|
||||||
}
|
}
|
||||||
|
|
||||||
func (A *AND) RuleExtra() *C.RuleExtra {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -74,31 +74,31 @@ func parseRule(tp, payload string, params []string) (C.Rule, error) {
|
||||||
|
|
||||||
switch tp {
|
switch tp {
|
||||||
case "DOMAIN":
|
case "DOMAIN":
|
||||||
parsed = RC.NewDomain(payload, "", nil)
|
parsed = RC.NewDomain(payload, "")
|
||||||
case "DOMAIN-SUFFIX":
|
case "DOMAIN-SUFFIX":
|
||||||
parsed = RC.NewDomainSuffix(payload, "", nil)
|
parsed = RC.NewDomainSuffix(payload, "")
|
||||||
case "DOMAIN-KEYWORD":
|
case "DOMAIN-KEYWORD":
|
||||||
parsed = RC.NewDomainKeyword(payload, "", nil)
|
parsed = RC.NewDomainKeyword(payload, "")
|
||||||
case "GEOSITE":
|
case "GEOSITE":
|
||||||
parsed, parseErr = RC.NewGEOSITE(payload, "", nil)
|
parsed, parseErr = RC.NewGEOSITE(payload, "")
|
||||||
case "GEOIP":
|
case "GEOIP":
|
||||||
noResolve := RC.HasNoResolve(params)
|
noResolve := RC.HasNoResolve(params)
|
||||||
parsed, parseErr = RC.NewGEOIP(payload, "", noResolve, nil)
|
parsed, parseErr = RC.NewGEOIP(payload, "", noResolve)
|
||||||
case "IP-CIDR", "IP-CIDR6":
|
case "IP-CIDR", "IP-CIDR6":
|
||||||
noResolve := RC.HasNoResolve(params)
|
noResolve := RC.HasNoResolve(params)
|
||||||
parsed, parseErr = RC.NewIPCIDR(payload, "", nil, RC.WithIPCIDRNoResolve(noResolve))
|
parsed, parseErr = RC.NewIPCIDR(payload, "", nil, RC.WithIPCIDRNoResolve(noResolve))
|
||||||
case "SRC-IP-CIDR":
|
case "SRC-IP-CIDR":
|
||||||
parsed, parseErr = RC.NewIPCIDR(payload, "", nil, RC.WithIPCIDRSourceIP(true), RC.WithIPCIDRNoResolve(true))
|
parsed, parseErr = RC.NewIPCIDR(payload, "", nil, RC.WithIPCIDRSourceIP(true), RC.WithIPCIDRNoResolve(true))
|
||||||
case "SRC-PORT":
|
case "SRC-PORT":
|
||||||
parsed, parseErr = RC.NewPort(payload, "", true, nil)
|
parsed, parseErr = RC.NewPort(payload, "", true)
|
||||||
case "DST-PORT":
|
case "DST-PORT":
|
||||||
parsed, parseErr = RC.NewPort(payload, "", false, nil)
|
parsed, parseErr = RC.NewPort(payload, "", false)
|
||||||
case "PROCESS-NAME":
|
case "PROCESS-NAME":
|
||||||
parsed, parseErr = RC.NewProcess(payload, "", true, nil)
|
parsed, parseErr = RC.NewProcess(payload, "", true)
|
||||||
case "PROCESS-PATH":
|
case "PROCESS-PATH":
|
||||||
parsed, parseErr = RC.NewProcess(payload, "", false, nil)
|
parsed, parseErr = RC.NewProcess(payload, "", false)
|
||||||
case "RULE-SET":
|
case "RULE-SET":
|
||||||
parsed, parseErr = provider.NewRuleSet(payload, "", nil)
|
parsed, parseErr = provider.NewRuleSet(payload, "")
|
||||||
case "NOT":
|
case "NOT":
|
||||||
parsed, parseErr = NewNOT(payload, "")
|
parsed, parseErr = NewNOT(payload, "")
|
||||||
case "AND":
|
case "AND":
|
||||||
|
|
|
@ -3,9 +3,11 @@ package logic
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
"github.com/Dreamacro/clash/rule/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NOT struct {
|
type NOT struct {
|
||||||
|
common.Base
|
||||||
rule C.Rule
|
rule C.Rule
|
||||||
payload string
|
payload string
|
||||||
adapter string
|
adapter string
|
||||||
|
@ -49,7 +51,3 @@ func (not *NOT) Payload() string {
|
||||||
func (not *NOT) ShouldResolveIP() bool {
|
func (not *NOT) ShouldResolveIP() bool {
|
||||||
return not.rule.ShouldResolveIP()
|
return not.rule.ShouldResolveIP()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (not *NOT) RuleExtra() *C.RuleExtra {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
package logic
|
package logic
|
||||||
|
|
||||||
import C "github.com/Dreamacro/clash/constant"
|
import (
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
"github.com/Dreamacro/clash/rule/common"
|
||||||
|
)
|
||||||
|
|
||||||
type OR struct {
|
type OR struct {
|
||||||
|
common.Base
|
||||||
rules []C.Rule
|
rules []C.Rule
|
||||||
payload string
|
payload string
|
||||||
adapter string
|
adapter string
|
||||||
|
@ -39,10 +43,6 @@ func (or *OR) ShouldResolveIP() bool {
|
||||||
return or.needIP
|
return or.needIP
|
||||||
}
|
}
|
||||||
|
|
||||||
func (or *OR) RuleExtra() *C.RuleExtra {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewOR(payload string, adapter string) (*OR, error) {
|
func NewOR(payload string, adapter string) (*OR, error) {
|
||||||
or := &OR{payload: payload, adapter: adapter}
|
or := &OR{payload: payload, adapter: adapter}
|
||||||
rules, err := parseRuleByPayload(payload)
|
rules, err := parseRuleByPayload(payload)
|
||||||
|
|
|
@ -57,39 +57,38 @@ func parseRule(tp, payload, target string, params []string) (C.Rule, error) {
|
||||||
parsed C.Rule
|
parsed C.Rule
|
||||||
)
|
)
|
||||||
|
|
||||||
|
switch tp {
|
||||||
|
case "DOMAIN":
|
||||||
|
parsed = RC.NewDomain(payload, target)
|
||||||
|
case "DOMAIN-SUFFIX":
|
||||||
|
parsed = RC.NewDomainSuffix(payload, target)
|
||||||
|
case "DOMAIN-KEYWORD":
|
||||||
|
parsed = RC.NewDomainKeyword(payload, target)
|
||||||
|
case "GEOSITE":
|
||||||
|
parsed, parseErr = RC.NewGEOSITE(payload, target)
|
||||||
|
case "IP-CIDR", "IP-CIDR6":
|
||||||
|
noResolve := RC.HasNoResolve(params)
|
||||||
|
parsed, parseErr = RC.NewIPCIDR(payload, target, RC.WithIPCIDRNoResolve(noResolve))
|
||||||
|
case "SRC-IP-CIDR":
|
||||||
|
parsed, parseErr = RC.NewIPCIDR(payload, target, RC.WithIPCIDRSourceIP(true), RC.WithIPCIDRNoResolve(true))
|
||||||
|
case "SRC-PORT":
|
||||||
|
parsed, parseErr = RC.NewPort(payload, target, true)
|
||||||
|
case "DST-PORT":
|
||||||
|
parsed, parseErr = RC.NewPort(payload, target, false)
|
||||||
|
case "PROCESS-NAME":
|
||||||
|
parsed, parseErr = RC.NewProcess(payload, target, true)
|
||||||
|
case "PROCESS-PATH":
|
||||||
|
parsed, parseErr = RC.NewProcess(payload, target, false)
|
||||||
|
case "GEOIP":
|
||||||
|
noResolve := RC.HasNoResolve(params)
|
||||||
|
parsed, parseErr = RC.NewGEOIP(payload, target, noResolve)
|
||||||
|
default:
|
||||||
|
parseErr = fmt.Errorf("unsupported rule type %s", tp)
|
||||||
|
}
|
||||||
ruleExtra := &C.RuleExtra{
|
ruleExtra := &C.RuleExtra{
|
||||||
Network: RC.FindNetwork(params),
|
Network: RC.FindNetwork(params),
|
||||||
SourceIPs: RC.FindSourceIPs(params),
|
SourceIPs: RC.FindSourceIPs(params),
|
||||||
}
|
}
|
||||||
|
parsed.SetRuleExtra(ruleExtra)
|
||||||
switch tp {
|
|
||||||
case "DOMAIN":
|
|
||||||
parsed = RC.NewDomain(payload, target, ruleExtra)
|
|
||||||
case "DOMAIN-SUFFIX":
|
|
||||||
parsed = RC.NewDomainSuffix(payload, target, ruleExtra)
|
|
||||||
case "DOMAIN-KEYWORD":
|
|
||||||
parsed = RC.NewDomainKeyword(payload, target, ruleExtra)
|
|
||||||
case "GEOSITE":
|
|
||||||
parsed, parseErr = RC.NewGEOSITE(payload, target, ruleExtra)
|
|
||||||
case "IP-CIDR", "IP-CIDR6":
|
|
||||||
noResolve := RC.HasNoResolve(params)
|
|
||||||
parsed, parseErr = RC.NewIPCIDR(payload, target, ruleExtra, RC.WithIPCIDRNoResolve(noResolve))
|
|
||||||
case "SRC-IP-CIDR":
|
|
||||||
parsed, parseErr = RC.NewIPCIDR(payload, target, ruleExtra, RC.WithIPCIDRSourceIP(true), RC.WithIPCIDRNoResolve(true))
|
|
||||||
case "SRC-PORT":
|
|
||||||
parsed, parseErr = RC.NewPort(payload, target, true, ruleExtra)
|
|
||||||
case "DST-PORT":
|
|
||||||
parsed, parseErr = RC.NewPort(payload, target, false, ruleExtra)
|
|
||||||
case "PROCESS-NAME":
|
|
||||||
parsed, parseErr = RC.NewProcess(payload, target, true, ruleExtra)
|
|
||||||
case "PROCESS-PATH":
|
|
||||||
parsed, parseErr = RC.NewProcess(payload, target, false, ruleExtra)
|
|
||||||
case "GEOIP":
|
|
||||||
noResolve := RC.HasNoResolve(params)
|
|
||||||
parsed, parseErr = RC.NewGEOIP(payload, target, noResolve, ruleExtra)
|
|
||||||
default:
|
|
||||||
parseErr = fmt.Errorf("unsupported rule type %s", tp)
|
|
||||||
}
|
|
||||||
|
|
||||||
return parsed, parseErr
|
return parsed, parseErr
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,14 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
P "github.com/Dreamacro/clash/constant/provider"
|
P "github.com/Dreamacro/clash/constant/provider"
|
||||||
|
"github.com/Dreamacro/clash/rule/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RuleSet struct {
|
type RuleSet struct {
|
||||||
|
common.Base
|
||||||
ruleProviderName string
|
ruleProviderName string
|
||||||
adapter string
|
adapter string
|
||||||
ruleProvider P.RuleProvider
|
ruleProvider P.RuleProvider
|
||||||
ruleExtra *C.RuleExtra
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *RuleSet) ShouldFindProcess() bool {
|
func (rs *RuleSet) ShouldFindProcess() bool {
|
||||||
|
@ -45,11 +46,7 @@ func (rs *RuleSet) getProviders() P.RuleProvider {
|
||||||
return rs.ruleProvider
|
return rs.ruleProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *RuleSet) RuleExtra() *C.RuleExtra {
|
func NewRuleSet(ruleProviderName string, adapter string) (*RuleSet, error) {
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewRuleSet(ruleProviderName string, adapter string, ruleExtra *C.RuleExtra) (*RuleSet, error) {
|
|
||||||
rp, ok := RuleProviders()[ruleProviderName]
|
rp, ok := RuleProviders()[ruleProviderName]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("rule set %s not found", ruleProviderName)
|
return nil, fmt.Errorf("rule set %s not found", ruleProviderName)
|
||||||
|
@ -58,6 +55,5 @@ func NewRuleSet(ruleProviderName string, adapter string, ruleExtra *C.RuleExtra)
|
||||||
ruleProviderName: ruleProviderName,
|
ruleProviderName: ruleProviderName,
|
||||||
adapter: adapter,
|
adapter: adapter,
|
||||||
ruleProvider: rp,
|
ruleProvider: rp,
|
||||||
ruleExtra: ruleExtra,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package tunnel
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
R "github.com/Dreamacro/clash/rule/common"
|
|
||||||
"net"
|
"net"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -343,7 +342,6 @@ func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) {
|
||||||
defer configMux.RUnlock()
|
defer configMux.RUnlock()
|
||||||
|
|
||||||
var resolved bool
|
var resolved bool
|
||||||
var processFound bool
|
|
||||||
|
|
||||||
if node := resolver.DefaultHosts.Search(metadata.Host); node != nil {
|
if node := resolver.DefaultHosts.Search(metadata.Host); node != nil {
|
||||||
ip := node.Data.(net.IP)
|
ip := node.Data.(net.IP)
|
||||||
|
|
Loading…
Reference in a new issue