Merge branch 'dev' into release
This commit is contained in:
commit
582c0763ba
2
.github/workflows/prerelease.yml
vendored
2
.github/workflows/prerelease.yml
vendored
@ -43,7 +43,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
NAME: Clash.Meta
|
NAME: Clash.Meta
|
||||||
BINDIR: bin
|
BINDIR: bin
|
||||||
run: make -j releases
|
run: make -j$(($(nproc) + 1)) releases
|
||||||
|
|
||||||
- name: Delete current release assets
|
- name: Delete current release assets
|
||||||
uses: andreaswilli/delete-release-assets-action@v2.0.0
|
uses: andreaswilli/delete-release-assets-action@v2.0.0
|
||||||
|
2
.github/workflows/release.yaml
vendored
2
.github/workflows/release.yaml
vendored
@ -33,7 +33,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
NAME: Clash.Meta
|
NAME: Clash.Meta
|
||||||
BINDIR: bin
|
BINDIR: bin
|
||||||
run: make -j releases
|
run: make -j$(($(nproc) + 1)) releases
|
||||||
|
|
||||||
- name: Upload Release
|
- name: Upload Release
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v1
|
||||||
|
@ -4,6 +4,9 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/Dreamacro/clash/common/queue"
|
||||||
|
"github.com/Dreamacro/clash/component/dialer"
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
@ -11,10 +14,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/queue"
|
|
||||||
"github.com/Dreamacro/clash/component/dialer"
|
|
||||||
C "github.com/Dreamacro/clash/constant"
|
|
||||||
|
|
||||||
"go.uber.org/atomic"
|
"go.uber.org/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -51,6 +51,10 @@ func (b *Base) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
|||||||
return c, errors.New("no support")
|
return c, errors.New("no support")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Base) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
|
||||||
|
return nil, errors.New("no support")
|
||||||
|
}
|
||||||
|
|
||||||
// ListenPacketContext implements C.ProxyAdapter
|
// ListenPacketContext implements C.ProxyAdapter
|
||||||
func (b *Base) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
|
func (b *Base) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
|
||||||
return nil, errors.New("no support")
|
return nil, errors.New("no support")
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package outboundgroup
|
package outboundgroup
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
"github.com/Dreamacro/clash/adapter/outbound"
|
"github.com/Dreamacro/clash/adapter/outbound"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/constant/provider"
|
"github.com/Dreamacro/clash/constant/provider"
|
||||||
@ -105,6 +107,34 @@ func (gb *GroupBase) GetProxies(touch bool) []C.Proxy {
|
|||||||
return proxies
|
return proxies
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gb *GroupBase) URLTest(ctx context.Context, url string) (map[string]uint16, error) {
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
var lock sync.Mutex
|
||||||
|
mp := map[string]uint16{}
|
||||||
|
proxies := gb.GetProxies(false)
|
||||||
|
for _, proxy := range proxies {
|
||||||
|
proxy := proxy
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
delay, err := proxy.URLTest(ctx, url)
|
||||||
|
lock.Lock()
|
||||||
|
if err == nil {
|
||||||
|
mp[proxy.Name()] = delay
|
||||||
|
}
|
||||||
|
lock.Unlock()
|
||||||
|
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
if len(mp) == 0 {
|
||||||
|
return mp, fmt.Errorf("get delay: all proxies timeout")
|
||||||
|
} else {
|
||||||
|
return mp, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (gb *GroupBase) onDialFailed() {
|
func (gb *GroupBase) onDialFailed() {
|
||||||
if gb.failedTesting.Load() {
|
if gb.failedTesting.Load() {
|
||||||
return
|
return
|
||||||
|
@ -38,7 +38,9 @@ func FindUid(network string, srcIP netip.Addr, srcPort int) (int32, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ShouldFindProcess(metadata *C.Metadata) bool {
|
func ShouldFindProcess(metadata *C.Metadata) bool {
|
||||||
if !enableFindProcess || metadata.Process != "" || metadata.ProcessPath != "" {
|
if !enableFindProcess ||
|
||||||
|
metadata.Process != "" ||
|
||||||
|
metadata.ProcessPath != "" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for _, ip := range localIPs {
|
for _, ip := range localIPs {
|
||||||
|
@ -89,24 +89,39 @@ func ResolveIP(host string) (netip.Addr, error) {
|
|||||||
// ResolveIPv4ProxyServerHost proxies server host only
|
// ResolveIPv4ProxyServerHost proxies server host only
|
||||||
func ResolveIPv4ProxyServerHost(host string) (netip.Addr, error) {
|
func ResolveIPv4ProxyServerHost(host string) (netip.Addr, error) {
|
||||||
if ProxyServerHostResolver != nil {
|
if ProxyServerHostResolver != nil {
|
||||||
return ResolveIPv4WithResolver(host, ProxyServerHostResolver)
|
if ip, err := ResolveIPv4WithResolver(host, ProxyServerHostResolver); err != nil {
|
||||||
|
return ResolveIPv4(host)
|
||||||
|
} else {
|
||||||
|
return ip, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResolveIPv4(host)
|
return ResolveIPv4(host)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResolveIPv6ProxyServerHost proxies server host only
|
// ResolveIPv6ProxyServerHost proxies server host only
|
||||||
func ResolveIPv6ProxyServerHost(host string) (netip.Addr, error) {
|
func ResolveIPv6ProxyServerHost(host string) (netip.Addr, error) {
|
||||||
if ProxyServerHostResolver != nil {
|
if ProxyServerHostResolver != nil {
|
||||||
return ResolveIPv6WithResolver(host, ProxyServerHostResolver)
|
if ip, err := ResolveIPv6WithResolver(host, ProxyServerHostResolver); err != nil {
|
||||||
|
return ResolveIPv6(host)
|
||||||
|
} else {
|
||||||
|
return ip, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResolveIPv6(host)
|
return ResolveIPv6(host)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResolveProxyServerHost proxies server host only
|
// ResolveProxyServerHost proxies server host only
|
||||||
func ResolveProxyServerHost(host string) (netip.Addr, error) {
|
func ResolveProxyServerHost(host string) (netip.Addr, error) {
|
||||||
if ProxyServerHostResolver != nil {
|
if ProxyServerHostResolver != nil {
|
||||||
return ResolveIPWithResolver(host, ProxyServerHostResolver)
|
if ip, err := ResolveIPWithResolver(host, ProxyServerHostResolver); err != nil {
|
||||||
|
return ResolveIP(host)
|
||||||
|
} else {
|
||||||
|
return ip, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResolveIP(host)
|
return ResolveIP(host)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,6 +108,11 @@ type ProxyAdapter interface {
|
|||||||
Unwrap(metadata *Metadata) Proxy
|
Unwrap(metadata *Metadata) Proxy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Group interface {
|
||||||
|
URLTest(ctx context.Context, url string) (mp map[string]uint16, err error)
|
||||||
|
GetProxies(touch bool) []Proxy
|
||||||
|
}
|
||||||
|
|
||||||
type DelayHistory struct {
|
type DelayHistory struct {
|
||||||
Time time.Time `json:"time"`
|
Time time.Time `json:"time"`
|
||||||
Delay uint16 `json:"delay"`
|
Delay uint16 `json:"delay"`
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package provider
|
package provider
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Vehicle Type
|
// Vehicle Type
|
||||||
@ -65,10 +65,10 @@ type Provider interface {
|
|||||||
// ProxyProvider interface
|
// ProxyProvider interface
|
||||||
type ProxyProvider interface {
|
type ProxyProvider interface {
|
||||||
Provider
|
Provider
|
||||||
Proxies() []constant.Proxy
|
Proxies() []C.Proxy
|
||||||
// ProxiesWithTouch is used to inform the provider that the proxy is actually being used while getting the list of proxies.
|
// ProxiesWithTouch is used to inform the provider that the proxy is actually being used while getting the list of proxies.
|
||||||
// Commonly used in DialContext and DialPacketConn
|
// Commonly used in DialContext and DialPacketConn
|
||||||
ProxiesWithTouch() []constant.Proxy
|
ProxiesWithTouch() []C.Proxy
|
||||||
HealthCheck()
|
HealthCheck()
|
||||||
Version() uint
|
Version() uint
|
||||||
}
|
}
|
||||||
@ -100,7 +100,7 @@ func (rt RuleType) String() string {
|
|||||||
type RuleProvider interface {
|
type RuleProvider interface {
|
||||||
Provider
|
Provider
|
||||||
Behavior() RuleType
|
Behavior() RuleType
|
||||||
Match(*constant.Metadata) bool
|
Match(*C.Metadata) bool
|
||||||
ShouldResolveIP() bool
|
ShouldResolveIP() bool
|
||||||
AsRule(adaptor string) constant.Rule
|
AsRule(adaptor string) C.Rule
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@ const (
|
|||||||
GEOIP
|
GEOIP
|
||||||
IPCIDR
|
IPCIDR
|
||||||
SrcIPCIDR
|
SrcIPCIDR
|
||||||
|
IPSuffix
|
||||||
|
SrcIPSuffix
|
||||||
SrcPort
|
SrcPort
|
||||||
DstPort
|
DstPort
|
||||||
Process
|
Process
|
||||||
@ -41,6 +43,10 @@ func (rt RuleType) String() string {
|
|||||||
return "IPCIDR"
|
return "IPCIDR"
|
||||||
case SrcIPCIDR:
|
case SrcIPCIDR:
|
||||||
return "SrcIPCIDR"
|
return "SrcIPCIDR"
|
||||||
|
case IPSuffix:
|
||||||
|
return "IPSuffix"
|
||||||
|
case SrcIPSuffix:
|
||||||
|
return "SrcIPSuffix"
|
||||||
case SrcPort:
|
case SrcPort:
|
||||||
return "SrcPort"
|
return "SrcPort"
|
||||||
case DstPort:
|
case DstPort:
|
||||||
|
2
go.mod
2
go.mod
@ -59,6 +59,4 @@ require (
|
|||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 => github.com/MetaCubeX/wintun-go v0.0.0-20220319102620-bbc5e6b2015e
|
|
||||||
|
|
||||||
replace github.com/vishvananda/netlink v1.2.0-beta.0.20220404152918-5e915e014938 => github.com/MetaCubeX/netlink v1.2.0-beta.0.20220529072258-d6853f887820
|
replace github.com/vishvananda/netlink v1.2.0-beta.0.20220404152918-5e915e014938 => github.com/MetaCubeX/netlink v1.2.0-beta.0.20220529072258-d6853f887820
|
||||||
|
4
go.sum
4
go.sum
@ -12,8 +12,6 @@ github.com/Dreamacro/go-shadowsocks2 v0.1.8 h1:Ixejp5JscEc866gAvm/l6TFd7BOBvDviK
|
|||||||
github.com/Dreamacro/go-shadowsocks2 v0.1.8/go.mod h1:51y4Q6tJoCE7e8TmYXcQRqfoxPfE9Cvn79V6pB6Df7Y=
|
github.com/Dreamacro/go-shadowsocks2 v0.1.8/go.mod h1:51y4Q6tJoCE7e8TmYXcQRqfoxPfE9Cvn79V6pB6Df7Y=
|
||||||
github.com/MetaCubeX/netlink v1.2.0-beta.0.20220529072258-d6853f887820 h1:fGKWZ25VApYnuPZoNeqdH/nZtHa2XMajwH6Yj/OgoVc=
|
github.com/MetaCubeX/netlink v1.2.0-beta.0.20220529072258-d6853f887820 h1:fGKWZ25VApYnuPZoNeqdH/nZtHa2XMajwH6Yj/OgoVc=
|
||||||
github.com/MetaCubeX/netlink v1.2.0-beta.0.20220529072258-d6853f887820/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
|
github.com/MetaCubeX/netlink v1.2.0-beta.0.20220529072258-d6853f887820/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
|
||||||
github.com/MetaCubeX/wintun-go v0.0.0-20220319102620-bbc5e6b2015e h1:GRfT5Lf8HP7RNczKIwTYLoCh1PPuIs/sY9hj+W+3deg=
|
|
||||||
github.com/MetaCubeX/wintun-go v0.0.0-20220319102620-bbc5e6b2015e/go.mod h1:ARUuShAtcziEJ/vnZ2hgoP+zc0J7Ukcca2S/NPDoQCc=
|
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||||
@ -345,6 +343,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
|
|||||||
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-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
|
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
|
||||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY=
|
||||||
|
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d h1:q4JksJ2n0fmbXC0Aj0eOs6E0AcPqnKglxWXWFqGD6x0=
|
golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d h1:q4JksJ2n0fmbXC0Aj0eOs6E0AcPqnKglxWXWFqGD6x0=
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d/go.mod h1:bVQfyl2sCM/QIIGHpWbFGfHPuDvqnCNkT6MQLTCjO/U=
|
golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d/go.mod h1:bVQfyl2sCM/QIIGHpWbFGfHPuDvqnCNkT6MQLTCjO/U=
|
||||||
golang.zx2c4.com/wireguard/windows v0.5.4-0.20220317000008-6432784c2469 h1:SEYkJAIuYAsSAPkCffOiYLtq5brBDSI+L0mRjSsvSTY=
|
golang.zx2c4.com/wireguard/windows v0.5.4-0.20220317000008-6432784c2469 h1:SEYkJAIuYAsSAPkCffOiYLtq5brBDSI+L0mRjSsvSTY=
|
||||||
|
79
hub/route/groups.go
Normal file
79
hub/route/groups.go
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
package route
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/Dreamacro/clash/adapter"
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
"github.com/Dreamacro/clash/tunnel"
|
||||||
|
"github.com/go-chi/chi/v5"
|
||||||
|
"github.com/go-chi/render"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GroupRouter() http.Handler {
|
||||||
|
r := chi.NewRouter()
|
||||||
|
r.Get("/", getGroups)
|
||||||
|
|
||||||
|
r.Route("/{name}", func(r chi.Router) {
|
||||||
|
r.Use(parseProxyName, findProxyByName)
|
||||||
|
r.Get("/", getGroup)
|
||||||
|
r.Get("/delay", getGroupDelay)
|
||||||
|
})
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGroups(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var gs []C.Proxy
|
||||||
|
for _, p := range tunnel.Proxies() {
|
||||||
|
if _, ok := p.(*adapter.Proxy).ProxyAdapter.(C.Group); ok {
|
||||||
|
gs = append(gs, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render.JSON(w, r, render.M{
|
||||||
|
"proxies": gs,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGroup(w http.ResponseWriter, r *http.Request) {
|
||||||
|
proxy := r.Context().Value(CtxKeyProxy).(C.Proxy)
|
||||||
|
if _, ok := proxy.(*adapter.Proxy).ProxyAdapter.(C.Group); ok {
|
||||||
|
render.JSON(w, r, proxy)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
render.Status(r, http.StatusNotFound)
|
||||||
|
render.JSON(w, r, ErrNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGroupDelay(w http.ResponseWriter, r *http.Request) {
|
||||||
|
proxy := r.Context().Value(CtxKeyProxy).(C.Proxy)
|
||||||
|
group, ok := proxy.(*adapter.Proxy).ProxyAdapter.(C.Group)
|
||||||
|
if !ok {
|
||||||
|
render.Status(r, http.StatusNotFound)
|
||||||
|
render.JSON(w, r, ErrNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
query := r.URL.Query()
|
||||||
|
url := query.Get("url")
|
||||||
|
timeout, err := strconv.ParseInt(query.Get("timeout"), 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
render.Status(r, http.StatusBadRequest)
|
||||||
|
render.JSON(w, r, ErrBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(timeout))
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
dm, err := group.URLTest(ctx, url)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
render.Status(r, http.StatusGatewayTimeout)
|
||||||
|
render.JSON(w, r, newError(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
render.JSON(w, r, dm)
|
||||||
|
}
|
@ -68,6 +68,7 @@ func Start(addr string, secret string) {
|
|||||||
r.Get("/version", version)
|
r.Get("/version", version)
|
||||||
r.Mount("/configs", configRouter())
|
r.Mount("/configs", configRouter())
|
||||||
r.Mount("/proxies", proxyRouter())
|
r.Mount("/proxies", proxyRouter())
|
||||||
|
r.Mount("/group", GroupRouter())
|
||||||
r.Mount("/rules", ruleRouter())
|
r.Mount("/rules", ruleRouter())
|
||||||
r.Mount("/connections", connectionRouter())
|
r.Mount("/connections", connectionRouter())
|
||||||
r.Mount("/providers/proxies", proxyProviderRouter())
|
r.Mount("/providers/proxies", proxyProviderRouter())
|
||||||
|
233
listener/tun/device/tun/driver/dll_windows.go
Normal file
233
listener/tun/device/tun/driver/dll_windows.go
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package driver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/clash/log"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
"golang.zx2c4.com/wireguard/windows/driver/memmod"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:linkname modwintun golang.zx2c4.com/wintun.modwintun
|
||||||
|
|
||||||
|
//go:linkname procWintunCreateAdapter golang.zx2c4.com/wintun.procWintunCreateAdapter
|
||||||
|
|
||||||
|
//go:linkname procWintunOpenAdapter golang.zx2c4.com/wintun.procWintunOpenAdapter
|
||||||
|
|
||||||
|
//go:linkname procWintunCloseAdapter golang.zx2c4.com/wintun.procWintunCloseAdapter
|
||||||
|
|
||||||
|
//go:linkname procWintunDeleteDriver golang.zx2c4.com/wintun.procWintunDeleteDriver
|
||||||
|
|
||||||
|
//go:linkname procWintunGetAdapterLUID golang.zx2c4.com/wintun.procWintunGetAdapterLUID
|
||||||
|
|
||||||
|
//go:linkname procWintunGetRunningDriverVersion golang.zx2c4.com/wintun.procWintunGetRunningDriverVersion
|
||||||
|
|
||||||
|
//go:linkname procWintunAllocateSendPacket golang.zx2c4.com/wintun.procWintunAllocateSendPacket
|
||||||
|
|
||||||
|
//go:linkname procWintunEndSession golang.zx2c4.com/wintun.procWintunEndSession
|
||||||
|
|
||||||
|
//go:linkname procWintunGetReadWaitEvent golang.zx2c4.com/wintun.procWintunGetReadWaitEvent
|
||||||
|
|
||||||
|
//go:linkname procWintunReceivePacket golang.zx2c4.com/wintun.procWintunReceivePacket
|
||||||
|
|
||||||
|
//go:linkname procWintunReleaseReceivePacket golang.zx2c4.com/wintun.procWintunReleaseReceivePacket
|
||||||
|
|
||||||
|
//go:linkname procWintunSendPacket golang.zx2c4.com/wintun.procWintunSendPacket
|
||||||
|
|
||||||
|
//go:linkname procWintunStartSession golang.zx2c4.com/wintun.procWintunStartSession
|
||||||
|
|
||||||
|
var (
|
||||||
|
modwintun *lazyDLL
|
||||||
|
procWintunCreateAdapter *lazyProc
|
||||||
|
procWintunOpenAdapter *lazyProc
|
||||||
|
procWintunCloseAdapter *lazyProc
|
||||||
|
procWintunDeleteDriver *lazyProc
|
||||||
|
procWintunGetAdapterLUID *lazyProc
|
||||||
|
procWintunGetRunningDriverVersion *lazyProc
|
||||||
|
procWintunAllocateSendPacket *lazyProc
|
||||||
|
procWintunEndSession *lazyProc
|
||||||
|
procWintunGetReadWaitEvent *lazyProc
|
||||||
|
procWintunReceivePacket *lazyProc
|
||||||
|
procWintunReleaseReceivePacket *lazyProc
|
||||||
|
procWintunSendPacket *lazyProc
|
||||||
|
procWintunStartSession *lazyProc
|
||||||
|
)
|
||||||
|
|
||||||
|
type loggerLevel int
|
||||||
|
|
||||||
|
const (
|
||||||
|
logInfo loggerLevel = iota
|
||||||
|
logWarn
|
||||||
|
logErr
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
modwintun = newLazyDLL("wintun.dll", setupLogger)
|
||||||
|
procWintunCreateAdapter = modwintun.NewProc("WintunCreateAdapter")
|
||||||
|
procWintunOpenAdapter = modwintun.NewProc("WintunOpenAdapter")
|
||||||
|
procWintunCloseAdapter = modwintun.NewProc("WintunCloseAdapter")
|
||||||
|
procWintunDeleteDriver = modwintun.NewProc("WintunDeleteDriver")
|
||||||
|
procWintunGetAdapterLUID = modwintun.NewProc("WintunGetAdapterLUID")
|
||||||
|
procWintunGetRunningDriverVersion = modwintun.NewProc("WintunGetRunningDriverVersion")
|
||||||
|
procWintunAllocateSendPacket = modwintun.NewProc("WintunAllocateSendPacket")
|
||||||
|
procWintunEndSession = modwintun.NewProc("WintunEndSession")
|
||||||
|
procWintunGetReadWaitEvent = modwintun.NewProc("WintunGetReadWaitEvent")
|
||||||
|
procWintunReceivePacket = modwintun.NewProc("WintunReceivePacket")
|
||||||
|
procWintunReleaseReceivePacket = modwintun.NewProc("WintunReleaseReceivePacket")
|
||||||
|
procWintunSendPacket = modwintun.NewProc("WintunSendPacket")
|
||||||
|
procWintunStartSession = modwintun.NewProc("WintunStartSession")
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitWintun() (err error) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
err = fmt.Errorf("init wintun.dll error: %v", r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err = modwintun.Load(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
procWintunCreateAdapter.Addr()
|
||||||
|
procWintunOpenAdapter.Addr()
|
||||||
|
procWintunCloseAdapter.Addr()
|
||||||
|
procWintunDeleteDriver.Addr()
|
||||||
|
procWintunGetAdapterLUID.Addr()
|
||||||
|
procWintunGetRunningDriverVersion.Addr()
|
||||||
|
procWintunAllocateSendPacket.Addr()
|
||||||
|
procWintunEndSession.Addr()
|
||||||
|
procWintunGetReadWaitEvent.Addr()
|
||||||
|
procWintunReceivePacket.Addr()
|
||||||
|
procWintunReleaseReceivePacket.Addr()
|
||||||
|
procWintunSendPacket.Addr()
|
||||||
|
procWintunStartSession.Addr()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLazyDLL(name string, onLoad func(d *lazyDLL)) *lazyDLL {
|
||||||
|
return &lazyDLL{Name: name, onLoad: onLoad}
|
||||||
|
}
|
||||||
|
|
||||||
|
func logMessage(level loggerLevel, _ uint64, msg *uint16) int {
|
||||||
|
switch level {
|
||||||
|
case logInfo:
|
||||||
|
log.Infoln("[TUN] %s", windows.UTF16PtrToString(msg))
|
||||||
|
case logWarn:
|
||||||
|
log.Warnln("[TUN] %s", windows.UTF16PtrToString(msg))
|
||||||
|
case logErr:
|
||||||
|
log.Errorln("[TUN] %s", windows.UTF16PtrToString(msg))
|
||||||
|
default:
|
||||||
|
log.Debugln("[TUN] %s", windows.UTF16PtrToString(msg))
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupLogger(dll *lazyDLL) {
|
||||||
|
var callback uintptr
|
||||||
|
if runtime.GOARCH == "386" {
|
||||||
|
callback = windows.NewCallback(func(level loggerLevel, _, _ uint32, msg *uint16) int {
|
||||||
|
return logMessage(level, 0, msg)
|
||||||
|
})
|
||||||
|
} else if runtime.GOARCH == "arm" {
|
||||||
|
callback = windows.NewCallback(func(level loggerLevel, _, _, _ uint32, msg *uint16) int {
|
||||||
|
return logMessage(level, 0, msg)
|
||||||
|
})
|
||||||
|
} else if runtime.GOARCH == "amd64" || runtime.GOARCH == "arm64" {
|
||||||
|
callback = windows.NewCallback(logMessage)
|
||||||
|
}
|
||||||
|
_, _, _ = syscall.SyscallN(dll.NewProc("WintunSetLogger").Addr(), callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *lazyDLL) NewProc(name string) *lazyProc {
|
||||||
|
return &lazyProc{dll: d, Name: name}
|
||||||
|
}
|
||||||
|
|
||||||
|
type lazyProc struct {
|
||||||
|
Name string
|
||||||
|
mu sync.Mutex
|
||||||
|
dll *lazyDLL
|
||||||
|
addr uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *lazyProc) Find() error {
|
||||||
|
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.addr))) != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
if p.addr != 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := p.dll.Load()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error loading DLL: %s, MODULE: %s, error: %w", p.dll.Name, p.Name, err)
|
||||||
|
}
|
||||||
|
addr, err := p.nameToAddr()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error getting %s address: %w", p.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.addr)), unsafe.Pointer(addr))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *lazyProc) Addr() uintptr {
|
||||||
|
err := p.Find()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return p.addr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *lazyProc) Load() error {
|
||||||
|
return p.dll.Load()
|
||||||
|
}
|
||||||
|
|
||||||
|
type lazyDLL struct {
|
||||||
|
Name string
|
||||||
|
Base windows.Handle
|
||||||
|
mu sync.Mutex
|
||||||
|
module *memmod.Module
|
||||||
|
onLoad func(d *lazyDLL)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *lazyDLL) Load() error {
|
||||||
|
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.module))) != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
|
if d.module != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
module, err := memmod.LoadLibrary(dllContent)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to load library: %w", err)
|
||||||
|
}
|
||||||
|
d.Base = windows.Handle(module.BaseAddr())
|
||||||
|
|
||||||
|
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.module)), unsafe.Pointer(module))
|
||||||
|
if d.onLoad != nil {
|
||||||
|
d.onLoad(d)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *lazyProc) nameToAddr() (uintptr, error) {
|
||||||
|
return p.dll.module.ProcAddressByName(p.Name)
|
||||||
|
}
|
13
listener/tun/device/tun/driver/dll_windows_386.go
Normal file
13
listener/tun/device/tun/driver/dll_windows_386.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package driver
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed x86/wintun.dll
|
||||||
|
var dllContent []byte
|
13
listener/tun/device/tun/driver/dll_windows_amd64.go
Normal file
13
listener/tun/device/tun/driver/dll_windows_amd64.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package driver
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed amd64/wintun.dll
|
||||||
|
var dllContent []byte
|
13
listener/tun/device/tun/driver/dll_windows_arm.go
Normal file
13
listener/tun/device/tun/driver/dll_windows_arm.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package driver
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed arm/wintun.dll
|
||||||
|
var dllContent []byte
|
13
listener/tun/device/tun/driver/dll_windows_arm64.go
Normal file
13
listener/tun/device/tun/driver/dll_windows_arm64.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package driver
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed arm64/wintun.dll
|
||||||
|
var dllContent []byte
|
5
listener/tun/device/tun/wintun/package_info.go → listener/tun/device/tun/driver/package_info.go
Executable file → Normal file
5
listener/tun/device/tun/wintun/package_info.go → listener/tun/device/tun/driver/package_info.go
Executable file → Normal file
@ -1,11 +1,10 @@
|
|||||||
//go:build windows
|
//go:build windows
|
||||||
// +build windows
|
|
||||||
|
|
||||||
// Modified from: https://git.zx2c4.com/wireguard-go/tree/tun/wintun
|
// https://git.zx2c4.com/wireguard-go/tree/tun/wintun
|
||||||
|
|
||||||
/* SPDX-License-Identifier: MIT
|
/* SPDX-License-Identifier: MIT
|
||||||
*
|
*
|
||||||
* Copyright (C) 2019-2021 WireGuard LLC. All Rights Reserved.
|
* Copyright (C) 2019-2021 WireGuard LLC. All Rights Reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package wintun
|
package driver
|
@ -3,7 +3,6 @@
|
|||||||
package tun
|
package tun
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -43,11 +42,11 @@ func Open(name string, mtu uint32) (_ device.Device, err error) {
|
|||||||
forcedMTU = int(t.mtu)
|
forcedMTU = int(t.mtu)
|
||||||
}
|
}
|
||||||
|
|
||||||
nt, err := tun.CreateTUN(t.name, forcedMTU) // forcedMTU do not work on wintun, need to be setting by other way
|
nt, err := newDevice(t.name, forcedMTU) // forcedMTU do not work on wintun, need to be setting by other way
|
||||||
|
|
||||||
// retry if abnormal exit on Windows at last time
|
// retry if abnormal exit at last time on Windows
|
||||||
if err != nil && runtime.GOOS == "windows" && errors.Is(err, os.ErrExist) {
|
if err != nil && runtime.GOOS == "windows" && os.IsExist(err) {
|
||||||
nt, err = tun.CreateTUN(t.name, forcedMTU)
|
nt, err = newDevice(t.name, forcedMTU)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -2,7 +2,13 @@
|
|||||||
|
|
||||||
package tun
|
package tun
|
||||||
|
|
||||||
|
import "golang.zx2c4.com/wireguard/tun"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
offset = 4 /* 4 bytes TUN_PI */
|
offset = 4 /* 4 bytes TUN_PI */
|
||||||
defaultMTU = 1500
|
defaultMTU = 1500
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func newDevice(name string, mtu int) (tun.Device, error) {
|
||||||
|
return tun.CreateTUN(name, mtu)
|
||||||
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package tun
|
package tun
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/Dreamacro/clash/listener/tun/device/tun/driver"
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
"golang.zx2c4.com/wireguard/tun"
|
"golang.zx2c4.com/wireguard/tun"
|
||||||
)
|
)
|
||||||
@ -20,3 +22,11 @@ func init() {
|
|||||||
func (t *TUN) LUID() uint64 {
|
func (t *TUN) LUID() uint64 {
|
||||||
return t.nt.LUID()
|
return t.nt.LUID()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newDevice(name string, mtu int) (nt tun.Device, err error) {
|
||||||
|
if err = driver.InitWintun(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return tun.CreateTUN(name, mtu)
|
||||||
|
}
|
||||||
|
@ -1,94 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: MIT
|
|
||||||
*
|
|
||||||
* Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package wintun
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"golang.zx2c4.com/wintun/embed_dll"
|
|
||||||
"golang.zx2c4.com/wireguard/windows/driver/memmod"
|
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
func newLazyDLL(name string, onLoad func(d *lazyDLL)) *lazyDLL {
|
|
||||||
return &lazyDLL{Name: name, onLoad: onLoad}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *lazyDLL) NewProc(name string) *lazyProc {
|
|
||||||
return &lazyProc{dll: d, Name: name}
|
|
||||||
}
|
|
||||||
|
|
||||||
type lazyProc struct {
|
|
||||||
Name string
|
|
||||||
mu sync.Mutex
|
|
||||||
dll *lazyDLL
|
|
||||||
addr uintptr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *lazyProc) Find() error {
|
|
||||||
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.addr))) != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
p.mu.Lock()
|
|
||||||
defer p.mu.Unlock()
|
|
||||||
if p.addr != 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
err := p.dll.Load()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Error loading %v DLL: %w", p.dll.Name, err)
|
|
||||||
}
|
|
||||||
addr, err := p.nameToAddr()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Error getting %v address: %w", p.Name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.addr)), unsafe.Pointer(addr))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *lazyProc) Addr() uintptr {
|
|
||||||
err := p.Find()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return p.addr
|
|
||||||
}
|
|
||||||
|
|
||||||
type lazyDLL struct {
|
|
||||||
Name string
|
|
||||||
mu sync.Mutex
|
|
||||||
module *memmod.Module
|
|
||||||
onLoad func(d *lazyDLL)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *lazyDLL) Load() error {
|
|
||||||
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.module))) != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
d.mu.Lock()
|
|
||||||
defer d.mu.Unlock()
|
|
||||||
if d.module != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
module, err := memmod.LoadLibrary(embed_dll.DDlContent)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unable to load library: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.module)), unsafe.Pointer(module))
|
|
||||||
if d.onLoad != nil {
|
|
||||||
d.onLoad(d)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *lazyProc) nameToAddr() (uintptr, error) {
|
|
||||||
return p.dll.module.ProcAddressByName(p.Name)
|
|
||||||
}
|
|
@ -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
|
|
@ -1,8 +0,0 @@
|
|||||||
module golang.zx2c4.com/wintun
|
|
||||||
|
|
||||||
go 1.18
|
|
||||||
|
|
||||||
require (
|
|
||||||
golang.org/x/sys v0.0.0-20220318055525-2edf467146b5
|
|
||||||
golang.zx2c4.com/wireguard/windows v0.5.3
|
|
||||||
)
|
|
@ -1,17 +0,0 @@
|
|||||||
github.com/MetaCubeX/Clash.Meta v1.9.1 h1:jHZhVRBxFuaCRBN9vxB/FL5R16wY4kIgNqjszdXPeLs=
|
|
||||||
github.com/MetaCubeX/Clash.Meta v1.9.1/go.mod h1:/I4cSh+PcgmtS5SEnFp8RANL6aVRd3i9YOult+mKLhU=
|
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
|
||||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
|
||||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20220317061510-51cd9980dadf h1:Fm4IcnUL803i92qDlmB0obyHmosDrxZWxJL3gIeNqOw=
|
|
||||||
golang.org/x/sys v0.0.0-20220317061510-51cd9980dadf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE=
|
|
||||||
golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
|
@ -1,90 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: MIT
|
|
||||||
*
|
|
||||||
* Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package wintun
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Session struct {
|
|
||||||
handle uintptr
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
PacketSizeMax = 0xffff // Maximum packet size
|
|
||||||
RingCapacityMin = 0x20000 // Minimum ring capacity (128 kiB)
|
|
||||||
RingCapacityMax = 0x4000000 // Maximum ring capacity (64 MiB)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Packet with data
|
|
||||||
type Packet struct {
|
|
||||||
Next *Packet // Pointer to next packet in queue
|
|
||||||
Size uint32 // Size of packet (max WINTUN_MAX_IP_PACKET_SIZE)
|
|
||||||
Data *[PacketSizeMax]byte // Pointer to layer 3 IPv4 or IPv6 packet
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
procWintunAllocateSendPacket = modwintun.NewProc("WintunAllocateSendPacket")
|
|
||||||
procWintunEndSession = modwintun.NewProc("WintunEndSession")
|
|
||||||
procWintunGetReadWaitEvent = modwintun.NewProc("WintunGetReadWaitEvent")
|
|
||||||
procWintunReceivePacket = modwintun.NewProc("WintunReceivePacket")
|
|
||||||
procWintunReleaseReceivePacket = modwintun.NewProc("WintunReleaseReceivePacket")
|
|
||||||
procWintunSendPacket = modwintun.NewProc("WintunSendPacket")
|
|
||||||
procWintunStartSession = modwintun.NewProc("WintunStartSession")
|
|
||||||
)
|
|
||||||
|
|
||||||
func (wintun *Adapter) StartSession(capacity uint32) (session Session, err error) {
|
|
||||||
r0, _, e1 := syscall.Syscall(procWintunStartSession.Addr(), 2, uintptr(wintun.handle), uintptr(capacity), 0)
|
|
||||||
if r0 == 0 {
|
|
||||||
err = e1
|
|
||||||
} else {
|
|
||||||
session = Session{r0}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (session Session) End() {
|
|
||||||
syscall.Syscall(procWintunEndSession.Addr(), 1, session.handle, 0, 0)
|
|
||||||
session.handle = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (session Session) ReadWaitEvent() (handle windows.Handle) {
|
|
||||||
r0, _, _ := syscall.Syscall(procWintunGetReadWaitEvent.Addr(), 1, session.handle, 0, 0)
|
|
||||||
handle = windows.Handle(r0)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (session Session) ReceivePacket() (packet []byte, err error) {
|
|
||||||
var packetSize uint32
|
|
||||||
r0, _, e1 := syscall.Syscall(procWintunReceivePacket.Addr(), 2, session.handle, uintptr(unsafe.Pointer(&packetSize)), 0)
|
|
||||||
if r0 == 0 {
|
|
||||||
err = e1
|
|
||||||
return
|
|
||||||
}
|
|
||||||
packet = unsafe.Slice((*byte)(unsafe.Pointer(r0)), packetSize)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (session Session) ReleaseReceivePacket(packet []byte) {
|
|
||||||
syscall.Syscall(procWintunReleaseReceivePacket.Addr(), 2, session.handle, uintptr(unsafe.Pointer(&packet[0])), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (session Session) AllocateSendPacket(packetSize int) (packet []byte, err error) {
|
|
||||||
r0, _, e1 := syscall.Syscall(procWintunAllocateSendPacket.Addr(), 2, session.handle, uintptr(packetSize), 0)
|
|
||||||
if r0 == 0 {
|
|
||||||
err = e1
|
|
||||||
return
|
|
||||||
}
|
|
||||||
packet = unsafe.Slice((*byte)(unsafe.Pointer(r0)), packetSize)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (session Session) SendPacket(packet []byte) {
|
|
||||||
syscall.Syscall(procWintunSendPacket.Addr(), 2, session.handle, uintptr(unsafe.Pointer(&packet[0])), 0)
|
|
||||||
}
|
|
@ -1,152 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
/* SPDX-License-Identifier: MIT
|
|
||||||
*
|
|
||||||
* Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package wintun
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"runtime"
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
type loggerLevel int
|
|
||||||
|
|
||||||
const (
|
|
||||||
logInfo loggerLevel = iota
|
|
||||||
logWarn
|
|
||||||
logErr
|
|
||||||
)
|
|
||||||
|
|
||||||
const AdapterNameMax = 128
|
|
||||||
|
|
||||||
type Adapter struct {
|
|
||||||
handle uintptr
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
modwintun = newLazyDLL("wintun.dll", setupLogger)
|
|
||||||
procWintunCreateAdapter = modwintun.NewProc("WintunCreateAdapter")
|
|
||||||
procWintunOpenAdapter = modwintun.NewProc("WintunOpenAdapter")
|
|
||||||
procWintunCloseAdapter = modwintun.NewProc("WintunCloseAdapter")
|
|
||||||
procWintunDeleteDriver = modwintun.NewProc("WintunDeleteDriver")
|
|
||||||
procWintunGetAdapterLUID = modwintun.NewProc("WintunGetAdapterLUID")
|
|
||||||
procWintunGetRunningDriverVersion = modwintun.NewProc("WintunGetRunningDriverVersion")
|
|
||||||
)
|
|
||||||
|
|
||||||
type TimestampedWriter interface {
|
|
||||||
WriteWithTimestamp(p []byte, ts int64) (n int, err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func logMessage(level loggerLevel, timestamp uint64, msg *uint16) int {
|
|
||||||
if tw, ok := log.Default().Writer().(TimestampedWriter); ok {
|
|
||||||
tw.WriteWithTimestamp([]byte(log.Default().Prefix()+windows.UTF16PtrToString(msg)), (int64(timestamp)-116444736000000000)*100)
|
|
||||||
} else {
|
|
||||||
log.Println(windows.UTF16PtrToString(msg))
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupLogger(dll *lazyDLL) {
|
|
||||||
var callback uintptr
|
|
||||||
if runtime.GOARCH == "386" {
|
|
||||||
callback = windows.NewCallback(func(level loggerLevel, timestampLow, timestampHigh uint32, msg *uint16) int {
|
|
||||||
return logMessage(level, uint64(timestampHigh)<<32|uint64(timestampLow), msg)
|
|
||||||
})
|
|
||||||
} else if runtime.GOARCH == "arm" {
|
|
||||||
callback = windows.NewCallback(func(level loggerLevel, _, timestampLow, timestampHigh uint32, msg *uint16) int {
|
|
||||||
return logMessage(level, uint64(timestampHigh)<<32|uint64(timestampLow), msg)
|
|
||||||
})
|
|
||||||
} else if runtime.GOARCH == "amd64" || runtime.GOARCH == "arm64" {
|
|
||||||
callback = windows.NewCallback(logMessage)
|
|
||||||
}
|
|
||||||
syscall.Syscall(dll.NewProc("WintunSetLogger").Addr(), 1, callback, 0, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func closeAdapter(wintun *Adapter) {
|
|
||||||
syscall.Syscall(procWintunCloseAdapter.Addr(), 1, wintun.handle, 0, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateAdapter creates a Wintun adapter. name is the cosmetic name of the adapter.
|
|
||||||
// tunnelType represents the type of adapter and should be "Wintun". requestedGUID is
|
|
||||||
// the GUID of the created network adapter, which then influences NLA generation
|
|
||||||
// deterministically. If it is set to nil, the GUID is chosen by the system at random,
|
|
||||||
// and hence a new NLA entry is created for each new adapter.
|
|
||||||
func CreateAdapter(name string, tunnelType string, requestedGUID *windows.GUID) (wintun *Adapter, err error) {
|
|
||||||
var name16 *uint16
|
|
||||||
name16, err = windows.UTF16PtrFromString(name)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var tunnelType16 *uint16
|
|
||||||
tunnelType16, err = windows.UTF16PtrFromString(tunnelType)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, e1 := syscall.Syscall(procWintunCreateAdapter.Addr(), 3, uintptr(unsafe.Pointer(name16)), uintptr(unsafe.Pointer(tunnelType16)), uintptr(unsafe.Pointer(requestedGUID)))
|
|
||||||
if r0 == 0 {
|
|
||||||
err = e1
|
|
||||||
return
|
|
||||||
}
|
|
||||||
wintun = &Adapter{handle: r0}
|
|
||||||
runtime.SetFinalizer(wintun, closeAdapter)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenAdapter opens an existing Wintun adapter by name.
|
|
||||||
func OpenAdapter(name string) (wintun *Adapter, err error) {
|
|
||||||
var name16 *uint16
|
|
||||||
name16, err = windows.UTF16PtrFromString(name)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, e1 := syscall.Syscall(procWintunOpenAdapter.Addr(), 1, uintptr(unsafe.Pointer(name16)), 0, 0)
|
|
||||||
if r0 == 0 {
|
|
||||||
err = e1
|
|
||||||
return
|
|
||||||
}
|
|
||||||
wintun = &Adapter{handle: r0}
|
|
||||||
runtime.SetFinalizer(wintun, closeAdapter)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close closes a Wintun adapter.
|
|
||||||
func (wintun *Adapter) Close() (err error) {
|
|
||||||
runtime.SetFinalizer(wintun, nil)
|
|
||||||
r1, _, e1 := syscall.Syscall(procWintunCloseAdapter.Addr(), 1, wintun.handle, 0, 0)
|
|
||||||
if r1 == 0 {
|
|
||||||
err = e1
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uninstall removes the driver from the system if no drivers are currently in use.
|
|
||||||
func Uninstall() (err error) {
|
|
||||||
r1, _, e1 := syscall.Syscall(procWintunDeleteDriver.Addr(), 0, 0, 0, 0)
|
|
||||||
if r1 == 0 {
|
|
||||||
err = e1
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunningVersion returns the version of the loaded driver.
|
|
||||||
func RunningVersion() (version uint32, err error) {
|
|
||||||
r0, _, e1 := syscall.Syscall(procWintunGetRunningDriverVersion.Addr(), 0, 0, 0, 0)
|
|
||||||
version = uint32(r0)
|
|
||||||
if version == 0 {
|
|
||||||
err = e1
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// LUID returns the LUID of the adapter.
|
|
||||||
func (wintun *Adapter) LUID() (luid uint64) {
|
|
||||||
syscall.Syscall(procWintunGetAdapterLUID.Addr(), 2, uintptr(wintun.handle), uintptr(unsafe.Pointer(&luid)), 0)
|
|
||||||
return
|
|
||||||
}
|
|
@ -44,7 +44,7 @@ func ConfigInterfaceAddress(dev device.Device, addr netip.Prefix, forceMTU int,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = netlink.AddrAdd(metaLink, naddr); err != nil {
|
if err = netlink.AddrAdd(metaLink, naddr); err != nil && err.Error() != "file exists" {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ package commons
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Dreamacro/clash/common/cmd"
|
|
||||||
"github.com/Dreamacro/clash/listener/tun/device"
|
"github.com/Dreamacro/clash/listener/tun/device"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
"net"
|
"net"
|
||||||
@ -46,12 +45,12 @@ func ConfigInterfaceAddress(dev device.Device, addr netip.Prefix, forceMTU int,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
naddr, err := netlink.ParseAddr(addr.String())
|
nlAddr, err := netlink.ParseAddr(addr.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = netlink.AddrAdd(metaLink, naddr); err != nil {
|
if err = netlink.AddrAdd(metaLink, nlAddr); err != nil && err.Error() != "file exists" {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,23 +58,13 @@ func ConfigInterfaceAddress(dev device.Device, addr netip.Prefix, forceMTU int,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = netlink.RouteAdd(&netlink.Route{
|
|
||||||
LinkIndex: metaLink.Attrs().Index,
|
|
||||||
Scope: netlink.SCOPE_LINK,
|
|
||||||
Protocol: 2,
|
|
||||||
Src: ip.AsSlice(),
|
|
||||||
Table: 254,
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if autoRoute {
|
if autoRoute {
|
||||||
_ = configInterfaceRouting(metaLink.Attrs().Index, interfaceName, ip)
|
_ = configInterfaceRouting(metaLink.Attrs().Index, ip)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func configInterfaceRouting(index int, interfaceName string, ip netip.Addr) error {
|
func configInterfaceRouting(index int, ip netip.Addr) error {
|
||||||
for _, route := range defaultRoutes {
|
for _, route := range defaultRoutes {
|
||||||
_, ipn, err := net.ParseCIDR(route)
|
_, ipn, err := net.ParseCIDR(route)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -97,11 +86,4 @@ func configInterfaceRouting(index int, interfaceName string, ip netip.Addr) erro
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func execRouterCmd(action, route, interfaceName, linkIP, table string) error {
|
|
||||||
cmdStr := fmt.Sprintf("ip route %s %s dev %s proto kernel scope link src %s table %s", action, route, interfaceName, linkIP, table)
|
|
||||||
|
|
||||||
_, err := cmd.ExecCmd(cmdStr)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func CleanupRule() {}
|
func CleanupRule() {}
|
||||||
|
@ -10,8 +10,8 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
errPayload = errors.New("payload error")
|
errPayload = errors.New("payload error")
|
||||||
|
initFlag bool
|
||||||
noResolve = "no-resolve"
|
noResolve = "no-resolve"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Base struct {
|
type Base struct {
|
||||||
|
@ -2,6 +2,9 @@ package common
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/component/geodata"
|
"github.com/Dreamacro/clash/component/geodata"
|
||||||
"github.com/Dreamacro/clash/component/geodata/router"
|
"github.com/Dreamacro/clash/component/geodata/router"
|
||||||
@ -50,6 +53,14 @@ func (gs *GEOSITE) GetRecodeSize() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewGEOSITE(country string, adapter string) (*GEOSITE, error) {
|
func NewGEOSITE(country string, adapter string) (*GEOSITE, error) {
|
||||||
|
if !initFlag {
|
||||||
|
if err := initGeoSite(); err != nil {
|
||||||
|
log.Errorln("can't initial GeoSite: %s", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
initFlag = true
|
||||||
|
}
|
||||||
|
|
||||||
matcher, size, err := geodata.LoadGeoSiteMatcher(country)
|
matcher, size, 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())
|
||||||
@ -69,3 +80,45 @@ func NewGEOSITE(country string, adapter string) (*GEOSITE, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var _ C.Rule = (*GEOSITE)(nil)
|
var _ C.Rule = (*GEOSITE)(nil)
|
||||||
|
|
||||||
|
func downloadGeoSite(path string) (err error) {
|
||||||
|
resp, err := http.Get(C.GeoSiteUrl)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0o644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
_, err = io.Copy(f, resp.Body)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func initGeoSite() error {
|
||||||
|
if _, err := os.Stat(C.Path.GeoSite()); os.IsNotExist(err) {
|
||||||
|
log.Infoln("Can't find GeoSite.dat, start download")
|
||||||
|
if err := downloadGeoSite(C.Path.GeoSite()); err != nil {
|
||||||
|
return fmt.Errorf("can't download GeoSite.dat: %s", err.Error())
|
||||||
|
}
|
||||||
|
log.Infoln("Download GeoSite.dat finish")
|
||||||
|
}
|
||||||
|
if !initFlag {
|
||||||
|
err := geodata.Verify(C.GeositeName)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnln("GeoSite.dat invalid, remove and download: %s", err)
|
||||||
|
if err := os.Remove(C.Path.GeoSite()); err != nil {
|
||||||
|
return fmt.Errorf("can't remove invalid GeoSite.dat: %s", err.Error())
|
||||||
|
}
|
||||||
|
if err := downloadGeoSite(C.Path.GeoSite()); err != nil {
|
||||||
|
return fmt.Errorf("can't download GeoSite.dat: %s", err.Error())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
initFlag = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
79
rule/common/ipsuffix.go
Normal file
79
rule/common/ipsuffix.go
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
"net/netip"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IPSuffix struct {
|
||||||
|
*Base
|
||||||
|
ipBytes []byte
|
||||||
|
bits int
|
||||||
|
payload string
|
||||||
|
adapter string
|
||||||
|
isSourceIP bool
|
||||||
|
noResolveIP bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (is *IPSuffix) RuleType() C.RuleType {
|
||||||
|
if is.isSourceIP {
|
||||||
|
return C.SrcIPSuffix
|
||||||
|
}
|
||||||
|
return C.IPSuffix
|
||||||
|
}
|
||||||
|
|
||||||
|
func (is *IPSuffix) Match(metadata *C.Metadata) bool {
|
||||||
|
ip := metadata.DstIP
|
||||||
|
if is.isSourceIP {
|
||||||
|
ip = metadata.SrcIP
|
||||||
|
}
|
||||||
|
|
||||||
|
mIPBytes := ip.AsSlice()
|
||||||
|
if len(is.ipBytes) != len(mIPBytes) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
size := len(mIPBytes)
|
||||||
|
bits := is.bits
|
||||||
|
|
||||||
|
for i := bits / 8; i > 0; i-- {
|
||||||
|
if is.ipBytes[size-i] != mIPBytes[size-i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is.ipBytes[size-bits/8-1] << (8 - bits%8)) != (mIPBytes[size-bits/8-1] << (8 - bits%8)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (is *IPSuffix) Adapter() string {
|
||||||
|
return is.adapter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (is *IPSuffix) Payload() string {
|
||||||
|
return is.payload
|
||||||
|
}
|
||||||
|
|
||||||
|
func (is *IPSuffix) ShouldResolveIP() bool {
|
||||||
|
return !is.noResolveIP
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIPSuffix(payload, adapter string, isSrc, noResolveIP bool) (*IPSuffix, error) {
|
||||||
|
ipnet, err := netip.ParsePrefix(payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errPayload
|
||||||
|
}
|
||||||
|
|
||||||
|
return &IPSuffix{
|
||||||
|
Base: &Base{},
|
||||||
|
payload: payload,
|
||||||
|
ipBytes: ipnet.Addr().AsSlice(),
|
||||||
|
bits: ipnet.Bits(),
|
||||||
|
adapter: adapter,
|
||||||
|
isSourceIP: isSrc,
|
||||||
|
noResolveIP: noResolveIP,
|
||||||
|
}, nil
|
||||||
|
}
|
@ -29,15 +29,14 @@ func NewAND(payload string, adapter string) (*AND, error) {
|
|||||||
and.rules = rules
|
and.rules = rules
|
||||||
payloads := make([]string, 0, len(rules))
|
payloads := make([]string, 0, len(rules))
|
||||||
for _, rule := range rules {
|
for _, rule := range rules {
|
||||||
payloads = append(payloads, fmt.Sprintf("(%s)", rule.Payload()))
|
payloads = append(payloads, fmt.Sprintf("(%s,%s)", rule.RuleType().String(), rule.Payload()))
|
||||||
if rule.ShouldResolveIP() {
|
if rule.ShouldResolveIP() {
|
||||||
and.needIP = true
|
and.needIP = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
and.payload = strings.Join(payloads, " && ")
|
and.payload = fmt.Sprintf("(%s)", strings.Join(payloads, " && "))
|
||||||
|
|
||||||
return and, nil
|
return and, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,12 +4,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Dreamacro/clash/common/collections"
|
"github.com/Dreamacro/clash/common/collections"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/log"
|
|
||||||
RC "github.com/Dreamacro/clash/rule/common"
|
RC "github.com/Dreamacro/clash/rule/common"
|
||||||
"github.com/Dreamacro/clash/rule/provider"
|
RP "github.com/Dreamacro/clash/rule/provider"
|
||||||
"io"
|
"github.com/Dreamacro/clash/rule/ruleparser"
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@ -60,64 +57,23 @@ func payloadToRule(subPayload string) (C.Rule, error) {
|
|||||||
if tp == "NOT" || tp == "OR" || tp == "AND" {
|
if tp == "NOT" || tp == "OR" || tp == "AND" {
|
||||||
return parseRule(tp, payload, nil)
|
return parseRule(tp, payload, nil)
|
||||||
}
|
}
|
||||||
if tp == "GEOSITE" {
|
|
||||||
if err := initGeoSite(); err != nil {
|
|
||||||
log.Errorln("can't initial GeoSite: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
param := strings.Split(payload, ",")
|
param := strings.Split(payload, ",")
|
||||||
return parseRule(tp, param[0], param[1:])
|
return parseRule(tp, param[0], param[1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseRule(tp, payload string, params []string) (C.Rule, error) {
|
func parseRule(tp, payload string, params []string) (parsed C.Rule, parseErr error) {
|
||||||
var (
|
|
||||||
parseErr error
|
|
||||||
parsed C.Rule
|
|
||||||
)
|
|
||||||
|
|
||||||
switch tp {
|
switch tp {
|
||||||
case "DOMAIN":
|
|
||||||
parsed = RC.NewDomain(payload, "")
|
|
||||||
case "DOMAIN-SUFFIX":
|
|
||||||
parsed = RC.NewDomainSuffix(payload, "")
|
|
||||||
case "DOMAIN-KEYWORD":
|
|
||||||
parsed = RC.NewDomainKeyword(payload, "")
|
|
||||||
case "GEOSITE":
|
|
||||||
parsed, parseErr = RC.NewGEOSITE(payload, "")
|
|
||||||
case "GEOIP":
|
|
||||||
noResolve := RC.HasNoResolve(params)
|
|
||||||
parsed, parseErr = RC.NewGEOIP(payload, "", noResolve)
|
|
||||||
case "IP-CIDR", "IP-CIDR6":
|
|
||||||
noResolve := RC.HasNoResolve(params)
|
|
||||||
parsed, parseErr = RC.NewIPCIDR(payload, "", RC.WithIPCIDRNoResolve(noResolve))
|
|
||||||
case "SRC-IP-CIDR":
|
|
||||||
parsed, parseErr = RC.NewIPCIDR(payload, "", RC.WithIPCIDRSourceIP(true), RC.WithIPCIDRNoResolve(true))
|
|
||||||
case "SRC-PORT":
|
|
||||||
parsed, parseErr = RC.NewPort(payload, "", true)
|
|
||||||
case "DST-PORT":
|
|
||||||
parsed, parseErr = RC.NewPort(payload, "", false)
|
|
||||||
case "PROCESS-NAME":
|
|
||||||
parsed, parseErr = RC.NewProcess(payload, "", true)
|
|
||||||
case "PROCESS-PATH":
|
|
||||||
parsed, parseErr = RC.NewProcess(payload, "", false)
|
|
||||||
case "RULE-SET":
|
|
||||||
noResolve := RC.HasNoResolve(params)
|
|
||||||
parsed, parseErr = provider.NewRuleSet(payload, "", noResolve)
|
|
||||||
case "UID":
|
|
||||||
parsed, parseErr = RC.NewUid(payload, "")
|
|
||||||
case "IN-TYPE":
|
|
||||||
parsed, parseErr = RC.NewInType(payload, "")
|
|
||||||
case "NOT":
|
|
||||||
parsed, parseErr = NewNOT(payload, "")
|
|
||||||
case "AND":
|
case "AND":
|
||||||
parsed, parseErr = NewAND(payload, "")
|
parsed, parseErr = NewAND(payload, "")
|
||||||
case "OR":
|
case "OR":
|
||||||
parsed, parseErr = NewOR(payload, "")
|
parsed, parseErr = NewOR(payload, "")
|
||||||
case "NETWORK":
|
case "NOT":
|
||||||
parsed, parseErr = RC.NewNetworkType(payload, "")
|
parsed, parseErr = NewNOT(payload, "")
|
||||||
|
case "RULE-SET":
|
||||||
|
noResolve := RC.HasNoResolve(params)
|
||||||
|
parsed, parseErr = RP.NewRuleSet(payload, "", noResolve)
|
||||||
default:
|
default:
|
||||||
parsed, parseErr = nil, fmt.Errorf("unsupported rule type %s", tp)
|
parsed, parseErr = ruleparser.ParseSameRule(tp, payload, "", params)
|
||||||
}
|
}
|
||||||
|
|
||||||
if parseErr != nil {
|
if parseErr != nil {
|
||||||
@ -202,32 +158,3 @@ func findSubRuleRange(payload string, ruleRanges []Range) []Range {
|
|||||||
|
|
||||||
return subRuleRange
|
return subRuleRange
|
||||||
}
|
}
|
||||||
|
|
||||||
func downloadGeoSite(path string) (err error) {
|
|
||||||
resp, err := http.Get("https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0o644)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
_, err = io.Copy(f, resp.Body)
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func initGeoSite() error {
|
|
||||||
if _, err := os.Stat(C.Path.GeoSite()); os.IsNotExist(err) {
|
|
||||||
log.Infoln("Need GeoSite but can't find GeoSite.dat, start download")
|
|
||||||
if err := downloadGeoSite(C.Path.GeoSite()); err != nil {
|
|
||||||
return fmt.Errorf("can't download GeoSite.dat: %s", err.Error())
|
|
||||||
}
|
|
||||||
log.Infoln("Download GeoSite.dat finish")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
@ -29,7 +29,7 @@ func NewNOT(payload string, adapter string) (*NOT, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
not.rule = rule[0]
|
not.rule = rule[0]
|
||||||
not.payload = fmt.Sprintf("!(%s)", rule[0].Payload())
|
not.payload = fmt.Sprintf("(!(%s,%s))", rule[0].RuleType(), rule[0].Payload())
|
||||||
|
|
||||||
return not, nil
|
return not, nil
|
||||||
}
|
}
|
||||||
|
@ -55,13 +55,13 @@ func NewOR(payload string, adapter string) (*OR, error) {
|
|||||||
or.rules = rules
|
or.rules = rules
|
||||||
payloads := make([]string, 0, len(rules))
|
payloads := make([]string, 0, len(rules))
|
||||||
for _, rule := range rules {
|
for _, rule := range rules {
|
||||||
payloads = append(payloads, fmt.Sprintf("(%s)", rule.Payload()))
|
payloads = append(payloads, fmt.Sprintf("(%s,%s)", rule.RuleType(), rule.Payload()))
|
||||||
if rule.ShouldResolveIP() {
|
if rule.ShouldResolveIP() {
|
||||||
or.needIP = true
|
or.needIP = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
or.payload = strings.Join(payloads, " || ")
|
or.payload = fmt.Sprintf("(%s)", strings.Join(payloads, " || "))
|
||||||
return or, nil
|
return or, nil
|
||||||
}
|
}
|
||||||
|
@ -1,50 +1,15 @@
|
|||||||
package rules
|
package rules
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
RC "github.com/Dreamacro/clash/rule/common"
|
RC "github.com/Dreamacro/clash/rule/common"
|
||||||
"github.com/Dreamacro/clash/rule/logic"
|
"github.com/Dreamacro/clash/rule/logic"
|
||||||
RP "github.com/Dreamacro/clash/rule/provider"
|
RP "github.com/Dreamacro/clash/rule/provider"
|
||||||
|
"github.com/Dreamacro/clash/rule/ruleparser"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParseRule(tp, payload, target string, params []string) (C.Rule, error) {
|
func ParseRule(tp, payload, target string, params []string) (parsed C.Rule, parseErr error) {
|
||||||
var (
|
|
||||||
parseErr error
|
|
||||||
parsed C.Rule
|
|
||||||
)
|
|
||||||
|
|
||||||
switch tp {
|
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 "GEOIP":
|
|
||||||
noResolve := RC.HasNoResolve(params)
|
|
||||||
parsed, parseErr = RC.NewGEOIP(payload, target, noResolve)
|
|
||||||
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 "NETWORK":
|
|
||||||
parsed, parseErr = RC.NewNetworkType(payload, target)
|
|
||||||
case "UID":
|
|
||||||
parsed, parseErr = RC.NewUid(payload, target)
|
|
||||||
case "IN-TYPE":
|
|
||||||
parsed, parseErr = RC.NewInType(payload, target)
|
|
||||||
case "AND":
|
case "AND":
|
||||||
parsed, parseErr = logic.NewAND(payload, target)
|
parsed, parseErr = logic.NewAND(payload, target)
|
||||||
case "OR":
|
case "OR":
|
||||||
@ -56,8 +21,9 @@ func ParseRule(tp, payload, target string, params []string) (C.Rule, error) {
|
|||||||
parsed, parseErr = RP.NewRuleSet(payload, target, noResolve)
|
parsed, parseErr = RP.NewRuleSet(payload, target, noResolve)
|
||||||
case "MATCH":
|
case "MATCH":
|
||||||
parsed = RC.NewMatch(target)
|
parsed = RC.NewMatch(target)
|
||||||
|
parseErr = nil
|
||||||
default:
|
default:
|
||||||
parseErr = fmt.Errorf("unsupported rule type %s", tp)
|
parsed, parseErr = ruleparser.ParseSameRule(tp, payload, target, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
if parseErr != nil {
|
if parseErr != nil {
|
||||||
@ -72,5 +38,5 @@ func ParseRule(tp, payload, target string, params []string) (C.Rule, error) {
|
|||||||
|
|
||||||
parsed.SetRuleExtra(ruleExtra)
|
parsed.SetRuleExtra(ruleExtra)
|
||||||
|
|
||||||
return parsed, nil
|
return
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
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"
|
||||||
RC "github.com/Dreamacro/clash/rule/common"
|
RC "github.com/Dreamacro/clash/rule/common"
|
||||||
|
"github.com/Dreamacro/clash/rule/ruleparser"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -51,46 +52,9 @@ func ParseRuleProvider(name string, mapping map[string]interface{}) (P.RuleProvi
|
|||||||
return NewRuleSetProvider(name, behavior, time.Duration(uint(schema.Interval))*time.Second, vehicle), nil
|
return NewRuleSetProvider(name, behavior, time.Duration(uint(schema.Interval))*time.Second, vehicle), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseRule(tp, payload, target string, params []string) (C.Rule, error) {
|
func parseRule(tp, payload, target string, params []string) (parsed C.Rule, parseErr error) {
|
||||||
var (
|
parsed, parseErr = ruleparser.ParseSameRule(tp, payload, target, params)
|
||||||
parseErr error
|
|
||||||
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 "GEOIP":
|
|
||||||
noResolve := RC.HasNoResolve(params)
|
|
||||||
parsed, parseErr = RC.NewGEOIP(payload, target, noResolve)
|
|
||||||
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 "NETWORK":
|
|
||||||
parsed, parseErr = RC.NewNetworkType(payload, target)
|
|
||||||
case "UID":
|
|
||||||
parsed, parseErr = RC.NewUid(payload, target)
|
|
||||||
case "IN-TYPE":
|
|
||||||
parsed, parseErr = RC.NewInType(payload, target)
|
|
||||||
default:
|
|
||||||
parseErr = fmt.Errorf("unsupported rule type %s", tp)
|
|
||||||
}
|
|
||||||
if parseErr != nil {
|
if parseErr != nil {
|
||||||
return nil, parseErr
|
return nil, parseErr
|
||||||
}
|
}
|
||||||
|
50
rule/ruleparser/ruleparser.go
Normal file
50
rule/ruleparser/ruleparser.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package ruleparser
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
RC "github.com/Dreamacro/clash/rule/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ParseSameRule(tp, payload, target string, params []string) (parsed C.Rule, parseErr error) {
|
||||||
|
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 "GEOIP":
|
||||||
|
noResolve := RC.HasNoResolve(params)
|
||||||
|
parsed, parseErr = RC.NewGEOIP(payload, target, noResolve)
|
||||||
|
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 "IP-SUFFIX":
|
||||||
|
noResolve := RC.HasNoResolve(params)
|
||||||
|
parsed, parseErr = RC.NewIPSuffix(payload, target, false, noResolve)
|
||||||
|
case "SRC-IP-SUFFIX":
|
||||||
|
parsed, parseErr = RC.NewIPSuffix(payload, target, true, 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 "NETWORK":
|
||||||
|
parsed, parseErr = RC.NewNetworkType(payload, target)
|
||||||
|
case "UID":
|
||||||
|
parsed, parseErr = RC.NewUid(payload, target)
|
||||||
|
case "IN-TYPE":
|
||||||
|
parsed, parseErr = RC.NewInType(payload, target)
|
||||||
|
default:
|
||||||
|
parseErr = fmt.Errorf("unsupported rule type %s", tp)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
Reference in New Issue
Block a user