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:
|
||||
NAME: Clash.Meta
|
||||
BINDIR: bin
|
||||
run: make -j releases
|
||||
run: make -j$(($(nproc) + 1)) releases
|
||||
|
||||
- name: Delete current release assets
|
||||
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:
|
||||
NAME: Clash.Meta
|
||||
BINDIR: bin
|
||||
run: make -j releases
|
||||
run: make -j$(($(nproc) + 1)) releases
|
||||
|
||||
- name: Upload Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
|
@ -4,6 +4,9 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/Dreamacro/clash/common/queue"
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
@ -11,10 +14,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Dreamacro/clash/common/queue"
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
|
||||
"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")
|
||||
}
|
||||
|
||||
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
|
||||
func (b *Base) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
|
||||
return nil, errors.New("no support")
|
||||
|
@ -1,6 +1,8 @@
|
||||
package outboundgroup
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/Dreamacro/clash/adapter/outbound"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"github.com/Dreamacro/clash/constant/provider"
|
||||
@ -105,6 +107,34 @@ func (gb *GroupBase) GetProxies(touch bool) []C.Proxy {
|
||||
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() {
|
||||
if gb.failedTesting.Load() {
|
||||
return
|
||||
|
@ -38,7 +38,9 @@ func FindUid(network string, srcIP netip.Addr, srcPort int) (int32, error) {
|
||||
}
|
||||
|
||||
func ShouldFindProcess(metadata *C.Metadata) bool {
|
||||
if !enableFindProcess || metadata.Process != "" || metadata.ProcessPath != "" {
|
||||
if !enableFindProcess ||
|
||||
metadata.Process != "" ||
|
||||
metadata.ProcessPath != "" {
|
||||
return false
|
||||
}
|
||||
for _, ip := range localIPs {
|
||||
|
@ -89,24 +89,39 @@ func ResolveIP(host string) (netip.Addr, error) {
|
||||
// ResolveIPv4ProxyServerHost proxies server host only
|
||||
func ResolveIPv4ProxyServerHost(host string) (netip.Addr, error) {
|
||||
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)
|
||||
}
|
||||
|
||||
// ResolveIPv6ProxyServerHost proxies server host only
|
||||
func ResolveIPv6ProxyServerHost(host string) (netip.Addr, error) {
|
||||
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)
|
||||
}
|
||||
|
||||
// ResolveProxyServerHost proxies server host only
|
||||
func ResolveProxyServerHost(host string) (netip.Addr, error) {
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -108,6 +108,11 @@ type ProxyAdapter interface {
|
||||
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 {
|
||||
Time time.Time `json:"time"`
|
||||
Delay uint16 `json:"delay"`
|
||||
|
@ -1,7 +1,7 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"github.com/Dreamacro/clash/constant"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
)
|
||||
|
||||
// Vehicle Type
|
||||
@ -65,10 +65,10 @@ type Provider interface {
|
||||
// ProxyProvider interface
|
||||
type ProxyProvider interface {
|
||||
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.
|
||||
// Commonly used in DialContext and DialPacketConn
|
||||
ProxiesWithTouch() []constant.Proxy
|
||||
ProxiesWithTouch() []C.Proxy
|
||||
HealthCheck()
|
||||
Version() uint
|
||||
}
|
||||
@ -100,7 +100,7 @@ func (rt RuleType) String() string {
|
||||
type RuleProvider interface {
|
||||
Provider
|
||||
Behavior() RuleType
|
||||
Match(*constant.Metadata) bool
|
||||
Match(*C.Metadata) bool
|
||||
ShouldResolveIP() bool
|
||||
AsRule(adaptor string) constant.Rule
|
||||
AsRule(adaptor string) C.Rule
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ const (
|
||||
GEOIP
|
||||
IPCIDR
|
||||
SrcIPCIDR
|
||||
IPSuffix
|
||||
SrcIPSuffix
|
||||
SrcPort
|
||||
DstPort
|
||||
Process
|
||||
@ -41,6 +43,10 @@ func (rt RuleType) String() string {
|
||||
return "IPCIDR"
|
||||
case SrcIPCIDR:
|
||||
return "SrcIPCIDR"
|
||||
case IPSuffix:
|
||||
return "IPSuffix"
|
||||
case SrcIPSuffix:
|
||||
return "SrcIPSuffix"
|
||||
case SrcPort:
|
||||
return "SrcPort"
|
||||
case DstPort:
|
||||
|
2
go.mod
2
go.mod
@ -59,6 +59,4 @@ require (
|
||||
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
|
||||
|
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/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/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/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=
|
||||
@ -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-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
|
||||
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/go.mod h1:bVQfyl2sCM/QIIGHpWbFGfHPuDvqnCNkT6MQLTCjO/U=
|
||||
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.Mount("/configs", configRouter())
|
||||
r.Mount("/proxies", proxyRouter())
|
||||
r.Mount("/group", GroupRouter())
|
||||
r.Mount("/rules", ruleRouter())
|
||||
r.Mount("/connections", connectionRouter())
|
||||
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
|
||||
// +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
|
||||
*
|
||||
* Copyright (C) 2019-2021 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package wintun
|
||||
package driver
|
@ -3,7 +3,6 @@
|
||||
package tun
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
@ -43,11 +42,11 @@ func Open(name string, mtu uint32) (_ device.Device, err error) {
|
||||
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
|
||||
if err != nil && runtime.GOOS == "windows" && errors.Is(err, os.ErrExist) {
|
||||
nt, err = tun.CreateTUN(t.name, forcedMTU)
|
||||
// retry if abnormal exit at last time on Windows
|
||||
if err != nil && runtime.GOOS == "windows" && os.IsExist(err) {
|
||||
nt, err = newDevice(t.name, forcedMTU)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
@ -2,7 +2,13 @@
|
||||
|
||||
package tun
|
||||
|
||||
import "golang.zx2c4.com/wireguard/tun"
|
||||
|
||||
const (
|
||||
offset = 4 /* 4 bytes TUN_PI */
|
||||
defaultMTU = 1500
|
||||
)
|
||||
|
||||
func newDevice(name string, mtu int) (tun.Device, error) {
|
||||
return tun.CreateTUN(name, mtu)
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package tun
|
||||
|
||||
import (
|
||||
"github.com/Dreamacro/clash/listener/tun/device/tun/driver"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.zx2c4.com/wireguard/tun"
|
||||
)
|
||||
@ -20,3 +22,11 @@ func init() {
|
||||
func (t *TUN) LUID() uint64 {
|
||||
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
|
||||
}
|
||||
|
||||
if err = netlink.AddrAdd(metaLink, naddr); err != nil {
|
||||
if err = netlink.AddrAdd(metaLink, naddr); err != nil && err.Error() != "file exists" {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,6 @@ package commons
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Dreamacro/clash/common/cmd"
|
||||
"github.com/Dreamacro/clash/listener/tun/device"
|
||||
"github.com/vishvananda/netlink"
|
||||
"net"
|
||||
@ -46,12 +45,12 @@ func ConfigInterfaceAddress(dev device.Device, addr netip.Prefix, forceMTU int,
|
||||
return err
|
||||
}
|
||||
|
||||
naddr, err := netlink.ParseAddr(addr.String())
|
||||
nlAddr, err := netlink.ParseAddr(addr.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = netlink.AddrAdd(metaLink, naddr); err != nil {
|
||||
if err = netlink.AddrAdd(metaLink, nlAddr); err != nil && err.Error() != "file exists" {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -59,23 +58,13 @@ func ConfigInterfaceAddress(dev device.Device, addr netip.Prefix, forceMTU int,
|
||||
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 {
|
||||
_ = configInterfaceRouting(metaLink.Attrs().Index, interfaceName, ip)
|
||||
_ = configInterfaceRouting(metaLink.Attrs().Index, ip)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func configInterfaceRouting(index int, interfaceName string, ip netip.Addr) error {
|
||||
func configInterfaceRouting(index int, ip netip.Addr) error {
|
||||
for _, route := range defaultRoutes {
|
||||
_, ipn, err := net.ParseCIDR(route)
|
||||
if err != nil {
|
||||
@ -97,11 +86,4 @@ func configInterfaceRouting(index int, interfaceName string, ip netip.Addr) erro
|
||||
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() {}
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
|
||||
var (
|
||||
errPayload = errors.New("payload error")
|
||||
|
||||
initFlag bool
|
||||
noResolve = "no-resolve"
|
||||
)
|
||||
|
||||
|
@ -2,6 +2,9 @@ package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/Dreamacro/clash/component/geodata"
|
||||
"github.com/Dreamacro/clash/component/geodata/router"
|
||||
@ -50,6 +53,14 @@ func (gs *GEOSITE) GetRecodeSize() int {
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
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)
|
||||
|
||||
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
|
||||
payloads := make([]string, 0, len(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() {
|
||||
and.needIP = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
and.payload = strings.Join(payloads, " && ")
|
||||
|
||||
and.payload = fmt.Sprintf("(%s)", strings.Join(payloads, " && "))
|
||||
return and, nil
|
||||
}
|
||||
|
||||
|
@ -4,12 +4,9 @@ import (
|
||||
"fmt"
|
||||
"github.com/Dreamacro/clash/common/collections"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
RC "github.com/Dreamacro/clash/rule/common"
|
||||
"github.com/Dreamacro/clash/rule/provider"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
RP "github.com/Dreamacro/clash/rule/provider"
|
||||
"github.com/Dreamacro/clash/rule/ruleparser"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
@ -60,64 +57,23 @@ func payloadToRule(subPayload string) (C.Rule, error) {
|
||||
if tp == "NOT" || tp == "OR" || tp == "AND" {
|
||||
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, ",")
|
||||
return parseRule(tp, param[0], param[1:])
|
||||
}
|
||||
|
||||
func parseRule(tp, payload string, params []string) (C.Rule, error) {
|
||||
var (
|
||||
parseErr error
|
||||
parsed C.Rule
|
||||
)
|
||||
|
||||
func parseRule(tp, payload string, params []string) (parsed C.Rule, parseErr error) {
|
||||
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":
|
||||
parsed, parseErr = NewAND(payload, "")
|
||||
case "OR":
|
||||
parsed, parseErr = NewOR(payload, "")
|
||||
case "NETWORK":
|
||||
parsed, parseErr = RC.NewNetworkType(payload, "")
|
||||
case "NOT":
|
||||
parsed, parseErr = NewNOT(payload, "")
|
||||
case "RULE-SET":
|
||||
noResolve := RC.HasNoResolve(params)
|
||||
parsed, parseErr = RP.NewRuleSet(payload, "", noResolve)
|
||||
default:
|
||||
parsed, parseErr = nil, fmt.Errorf("unsupported rule type %s", tp)
|
||||
parsed, parseErr = ruleparser.ParseSameRule(tp, payload, "", params)
|
||||
}
|
||||
|
||||
if parseErr != nil {
|
||||
@ -202,32 +158,3 @@ func findSubRuleRange(payload string, ruleRanges []Range) []Range {
|
||||
|
||||
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.payload = fmt.Sprintf("!(%s)", rule[0].Payload())
|
||||
not.payload = fmt.Sprintf("(!(%s,%s))", rule[0].RuleType(), rule[0].Payload())
|
||||
|
||||
return not, nil
|
||||
}
|
||||
|
@ -55,13 +55,13 @@ func NewOR(payload string, adapter string) (*OR, error) {
|
||||
or.rules = rules
|
||||
payloads := make([]string, 0, len(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() {
|
||||
or.needIP = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
or.payload = strings.Join(payloads, " || ")
|
||||
or.payload = fmt.Sprintf("(%s)", strings.Join(payloads, " || "))
|
||||
return or, nil
|
||||
}
|
||||
|
@ -1,50 +1,15 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
RC "github.com/Dreamacro/clash/rule/common"
|
||||
"github.com/Dreamacro/clash/rule/logic"
|
||||
RP "github.com/Dreamacro/clash/rule/provider"
|
||||
"github.com/Dreamacro/clash/rule/ruleparser"
|
||||
)
|
||||
|
||||
func ParseRule(tp, payload, target string, params []string) (C.Rule, error) {
|
||||
var (
|
||||
parseErr error
|
||||
parsed C.Rule
|
||||
)
|
||||
|
||||
func ParseRule(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 "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":
|
||||
parsed, parseErr = logic.NewAND(payload, target)
|
||||
case "OR":
|
||||
@ -56,8 +21,9 @@ func ParseRule(tp, payload, target string, params []string) (C.Rule, error) {
|
||||
parsed, parseErr = RP.NewRuleSet(payload, target, noResolve)
|
||||
case "MATCH":
|
||||
parsed = RC.NewMatch(target)
|
||||
parseErr = nil
|
||||
default:
|
||||
parseErr = fmt.Errorf("unsupported rule type %s", tp)
|
||||
parsed, parseErr = ruleparser.ParseSameRule(tp, payload, target, params)
|
||||
}
|
||||
|
||||
if parseErr != nil {
|
||||
@ -72,5 +38,5 @@ func ParseRule(tp, payload, target string, params []string) (C.Rule, error) {
|
||||
|
||||
parsed.SetRuleExtra(ruleExtra)
|
||||
|
||||
return parsed, nil
|
||||
return
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
P "github.com/Dreamacro/clash/constant/provider"
|
||||
RC "github.com/Dreamacro/clash/rule/common"
|
||||
"github.com/Dreamacro/clash/rule/ruleparser"
|
||||
"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
|
||||
}
|
||||
|
||||
func parseRule(tp, payload, target string, params []string) (C.Rule, error) {
|
||||
var (
|
||||
parseErr error
|
||||
parsed C.Rule
|
||||
)
|
||||
func parseRule(tp, payload, target string, params []string) (parsed C.Rule, parseErr error) {
|
||||
parsed, parseErr = ruleparser.ParseSameRule(tp, payload, target, params)
|
||||
|
||||
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 {
|
||||
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