mirror of
https://github.com/bolucat/Archive.git
synced 2025-10-18 06:02:24 +08:00
Update On Sun Jul 28 20:32:35 CEST 2024
This commit is contained in:
1
.github/update.log
vendored
1
.github/update.log
vendored
@@ -716,3 +716,4 @@ Update On Wed Jul 24 20:33:56 CEST 2024
|
||||
Update On Thu Jul 25 20:31:26 CEST 2024
|
||||
Update On Fri Jul 26 20:35:53 CEST 2024
|
||||
Update On Sat Jul 27 20:31:51 CEST 2024
|
||||
Update On Sun Jul 28 20:32:24 CEST 2024
|
||||
|
@@ -40,8 +40,8 @@ subprojects {
|
||||
minSdk = 21
|
||||
targetSdk = 31
|
||||
|
||||
versionName = "2.10.1"
|
||||
versionCode = 210001
|
||||
versionName = "2.10.2"
|
||||
versionCode = 210002
|
||||
|
||||
resValue("string", "release_name", "v$versionName")
|
||||
resValue("integer", "release_code", "$versionCode")
|
||||
|
@@ -69,3 +69,5 @@ func WithDSCP(dscp uint8) Addition {
|
||||
metadata.DSCP = dscp
|
||||
}
|
||||
}
|
||||
|
||||
func Placeholder(metadata *C.Metadata) {}
|
||||
|
@@ -205,7 +205,6 @@ func strategyStickySessions(url string) strategyFn {
|
||||
proxy := proxies[nowIdx]
|
||||
if proxy.AliveForTestUrl(url) {
|
||||
if nowIdx != idx {
|
||||
lruCache.Delete(key)
|
||||
lruCache.Set(key, nowIdx)
|
||||
}
|
||||
|
||||
@@ -215,7 +214,6 @@ func strategyStickySessions(url string) strategyFn {
|
||||
}
|
||||
}
|
||||
|
||||
lruCache.Delete(key)
|
||||
lruCache.Set(key, 0)
|
||||
return proxies[0]
|
||||
}
|
||||
|
@@ -69,7 +69,7 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide
|
||||
}
|
||||
|
||||
if groupOption.IncludeAllProviders {
|
||||
groupOption.Use = append(groupOption.Use, AllProviders...)
|
||||
groupOption.Use = AllProviders
|
||||
}
|
||||
if groupOption.IncludeAllProxies {
|
||||
if groupOption.Filter != "" {
|
||||
|
@@ -223,6 +223,10 @@ func (c *LruCache[K, V]) Delete(key K) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
c.delete(key)
|
||||
}
|
||||
|
||||
func (c *LruCache[K, V]) delete(key K) {
|
||||
if le, ok := c.cache[key]; ok {
|
||||
c.deleteElement(le)
|
||||
}
|
||||
@@ -255,6 +259,34 @@ func (c *LruCache[K, V]) Clear() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Compute either sets the computed new value for the key or deletes
|
||||
// the value for the key. When the delete result of the valueFn function
|
||||
// is set to true, the value will be deleted, if it exists. When delete
|
||||
// is set to false, the value is updated to the newValue.
|
||||
// The ok result indicates whether value was computed and stored, thus, is
|
||||
// present in the map. The actual result contains the new value in cases where
|
||||
// the value was computed and stored.
|
||||
func (c *LruCache[K, V]) Compute(
|
||||
key K,
|
||||
valueFn func(oldValue V, loaded bool) (newValue V, delete bool),
|
||||
) (actual V, ok bool) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
if el := c.get(key); el != nil {
|
||||
actual, ok = el.value, true
|
||||
}
|
||||
if newValue, del := valueFn(actual, ok); del {
|
||||
if ok { // data not in cache, so needn't delete
|
||||
c.delete(key)
|
||||
}
|
||||
return lo.Empty[V](), false
|
||||
} else {
|
||||
c.set(key, newValue)
|
||||
return newValue, true
|
||||
}
|
||||
}
|
||||
|
||||
type entry[K comparable, V any] struct {
|
||||
key K
|
||||
value V
|
||||
|
@@ -59,8 +59,8 @@ func (q *Queue[T]) Copy() []T {
|
||||
|
||||
// Len returns the number of items in this queue.
|
||||
func (q *Queue[T]) Len() int64 {
|
||||
q.lock.Lock()
|
||||
defer q.lock.Unlock()
|
||||
q.lock.RLock()
|
||||
defer q.lock.RUnlock()
|
||||
|
||||
return int64(len(q.items))
|
||||
}
|
||||
|
@@ -17,8 +17,8 @@ func NewCallback[T any]() *Callback[T] {
|
||||
}
|
||||
|
||||
func (c *Callback[T]) Register(item func(T)) io.Closer {
|
||||
c.mutex.RLock()
|
||||
defer c.mutex.RUnlock()
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
element := c.list.PushBack(item)
|
||||
return &callbackCloser[T]{
|
||||
element: element,
|
||||
|
@@ -57,6 +57,16 @@ func (set *IpCidrSet) Merge() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (set *IpCidrSet) Foreach(f func(prefix netip.Prefix) bool) {
|
||||
for _, r := range set.rr {
|
||||
for _, prefix := range r.Prefixes() {
|
||||
if !f(prefix) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ToIPSet not safe convert to *netipx.IPSet
|
||||
// be careful, must be used after Merge
|
||||
func (set *IpCidrSet) ToIPSet() *netipx.IPSet {
|
||||
|
@@ -0,0 +1,77 @@
|
||||
package cidr
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"net/netip"
|
||||
|
||||
"go4.org/netipx"
|
||||
)
|
||||
|
||||
func (ss *IpCidrSet) WriteBin(w io.Writer) (err error) {
|
||||
// version
|
||||
_, err = w.Write([]byte{1})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// rr
|
||||
err = binary.Write(w, binary.BigEndian, int64(len(ss.rr)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, r := range ss.rr {
|
||||
err = binary.Write(w, binary.BigEndian, r.From().As16())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Write(w, binary.BigEndian, r.To().As16())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ReadIpCidrSet(r io.Reader) (ss *IpCidrSet, err error) {
|
||||
// version
|
||||
version := make([]byte, 1)
|
||||
_, err = io.ReadFull(r, version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if version[0] != 1 {
|
||||
return nil, errors.New("version is invalid")
|
||||
}
|
||||
|
||||
ss = NewIpCidrSet()
|
||||
var length int64
|
||||
|
||||
// rr
|
||||
err = binary.Read(r, binary.BigEndian, &length)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if length < 1 {
|
||||
return nil, errors.New("length is invalid")
|
||||
}
|
||||
ss.rr = make([]netipx.IPRange, length)
|
||||
for i := int64(0); i < length; i++ {
|
||||
var a16 [16]byte
|
||||
err = binary.Read(r, binary.BigEndian, &a16)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
from := netip.AddrFrom16(a16).Unmap()
|
||||
err = binary.Read(r, binary.BigEndian, &a16)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
to := netip.AddrFrom16(a16).Unmap()
|
||||
ss.rr[i] = netipx.IPRangeFrom(from, to)
|
||||
}
|
||||
|
||||
return ss, nil
|
||||
}
|
@@ -3,6 +3,8 @@ package process
|
||||
import (
|
||||
"errors"
|
||||
"net/netip"
|
||||
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -19,3 +21,18 @@ const (
|
||||
func FindProcessName(network string, srcIP netip.Addr, srcPort int) (uint32, string, error) {
|
||||
return findProcessName(network, srcIP, srcPort)
|
||||
}
|
||||
|
||||
// PackageNameResolver
|
||||
// never change type traits because it's used in CFMA
|
||||
type PackageNameResolver func(metadata *C.Metadata) (string, error)
|
||||
|
||||
// DefaultPackageNameResolver
|
||||
// never change type traits because it's used in CFMA
|
||||
var DefaultPackageNameResolver PackageNameResolver
|
||||
|
||||
func FindPackageName(metadata *C.Metadata) (string, error) {
|
||||
if resolver := DefaultPackageNameResolver; resolver != nil {
|
||||
return resolver(metadata)
|
||||
}
|
||||
return "", ErrPlatformNotSupport
|
||||
}
|
||||
|
@@ -1,16 +0,0 @@
|
||||
//go:build android && cmfa
|
||||
|
||||
package process
|
||||
|
||||
import "github.com/metacubex/mihomo/constant"
|
||||
|
||||
type PackageNameResolver func(metadata *constant.Metadata) (string, error)
|
||||
|
||||
var DefaultPackageNameResolver PackageNameResolver
|
||||
|
||||
func FindPackageName(metadata *constant.Metadata) (string, error) {
|
||||
if resolver := DefaultPackageNameResolver; resolver != nil {
|
||||
return resolver(metadata)
|
||||
}
|
||||
return "", ErrPlatformNotSupport
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
//go:build !(android && cmfa)
|
||||
|
||||
package process
|
||||
|
||||
import "github.com/metacubex/mihomo/constant"
|
||||
|
||||
func FindPackageName(metadata *constant.Metadata) (string, error) {
|
||||
return "", nil
|
||||
}
|
@@ -46,12 +46,12 @@ func findProcessName(network string, ip netip.Addr, port int) (uint32, string, e
|
||||
|
||||
isIPv4 := ip.Is4()
|
||||
|
||||
value, err := syscall.Sysctl(spath)
|
||||
value, err := unix.SysctlRaw(spath)
|
||||
if err != nil {
|
||||
return 0, "", err
|
||||
}
|
||||
|
||||
buf := []byte(value)
|
||||
buf := value
|
||||
itemSize := structSize
|
||||
if network == TCP {
|
||||
// rup8(sizeof(xtcpcb_n))
|
||||
|
@@ -2,23 +2,19 @@ package process
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unicode"
|
||||
"unsafe"
|
||||
|
||||
"github.com/metacubex/mihomo/log"
|
||||
|
||||
"github.com/mdlayher/netlink"
|
||||
tun "github.com/metacubex/sing-tun"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
@@ -63,25 +59,11 @@ type inetDiagResponse struct {
|
||||
INode uint32
|
||||
}
|
||||
|
||||
type MyCallback struct{}
|
||||
|
||||
var (
|
||||
packageManager tun.PackageManager
|
||||
once sync.Once
|
||||
)
|
||||
|
||||
func (cb *MyCallback) OnPackagesUpdated(packageCount int, sharedCount int) {}
|
||||
|
||||
func (cb *MyCallback) NewError(ctx context.Context, err error) {
|
||||
log.Warnln("%s", err)
|
||||
}
|
||||
|
||||
func findProcessName(network string, ip netip.Addr, srcPort int) (uint32, string, error) {
|
||||
uid, inode, err := resolveSocketByNetlink(network, ip, srcPort)
|
||||
if err != nil {
|
||||
return 0, "", err
|
||||
}
|
||||
|
||||
pp, err := resolveProcessNameByProcSearch(inode, uid)
|
||||
return uid, pp, err
|
||||
}
|
||||
@@ -177,44 +159,38 @@ func resolveProcessNameByProcSearch(inode, uid uint32) (string, error) {
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if runtime.GOOS == "android" {
|
||||
if bytes.Equal(buffer[:n], socket) {
|
||||
return findPackageName(uid), nil
|
||||
cmdline, err := os.ReadFile(path.Join(processPath, "cmdline"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return splitCmdline(cmdline), nil
|
||||
}
|
||||
} else {
|
||||
if bytes.Equal(buffer[:n], socket) {
|
||||
return os.Readlink(filepath.Join(processPath, "exe"))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("process of uid(%d),inode(%d) not found", uid, inode)
|
||||
}
|
||||
|
||||
func findPackageName(uid uint32) string {
|
||||
once.Do(func() {
|
||||
callback := &MyCallback{}
|
||||
var err error
|
||||
packageManager, err = tun.NewPackageManager(callback)
|
||||
if err != nil {
|
||||
log.Warnln("%s", err)
|
||||
}
|
||||
err = packageManager.Start()
|
||||
if err != nil {
|
||||
log.Warnln("%s", err)
|
||||
return
|
||||
}
|
||||
func splitCmdline(cmdline []byte) string {
|
||||
cmdline = bytes.Trim(cmdline, " ")
|
||||
|
||||
idx := bytes.IndexFunc(cmdline, func(r rune) bool {
|
||||
return unicode.IsControl(r) || unicode.IsSpace(r)
|
||||
})
|
||||
|
||||
if sharedPackage, loaded := packageManager.SharedPackageByID(uid % 100000); loaded {
|
||||
return sharedPackage
|
||||
if idx == -1 {
|
||||
return filepath.Base(string(cmdline))
|
||||
}
|
||||
if packageName, loaded := packageManager.PackageByID(uid % 100000); loaded {
|
||||
return packageName
|
||||
}
|
||||
return ""
|
||||
return filepath.Base(string(cmdline[:idx]))
|
||||
}
|
||||
|
||||
func isPid(s string) bool {
|
||||
|
@@ -10,6 +10,7 @@ import (
|
||||
types "github.com/metacubex/mihomo/constant/provider"
|
||||
"github.com/metacubex/mihomo/log"
|
||||
|
||||
"github.com/sagernet/fswatch"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
@@ -30,6 +31,7 @@ type Fetcher[V any] struct {
|
||||
parser Parser[V]
|
||||
interval time.Duration
|
||||
OnUpdate func(V)
|
||||
watcher *fswatch.Watcher
|
||||
}
|
||||
|
||||
func (f *Fetcher[V]) Name() string {
|
||||
@@ -113,7 +115,20 @@ func (f *Fetcher[V]) Initial() (V, error) {
|
||||
f.hash = md5.Sum(buf)
|
||||
|
||||
// pull contents automatically
|
||||
if f.interval > 0 {
|
||||
if f.vehicle.Type() == types.File {
|
||||
f.watcher, err = fswatch.NewWatcher(fswatch.Options{
|
||||
Path: []string{f.vehicle.Path()},
|
||||
Direct: true,
|
||||
Callback: f.update,
|
||||
})
|
||||
if err != nil {
|
||||
return lo.Empty[V](), err
|
||||
}
|
||||
err = f.watcher.Start()
|
||||
if err != nil {
|
||||
return lo.Empty[V](), err
|
||||
}
|
||||
} else if f.interval > 0 {
|
||||
go f.pullLoop()
|
||||
}
|
||||
|
||||
@@ -155,6 +170,9 @@ func (f *Fetcher[V]) Destroy() error {
|
||||
if f.interval > 0 {
|
||||
f.done <- struct{}{}
|
||||
}
|
||||
if f.watcher != nil {
|
||||
_ = f.watcher.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -170,25 +188,29 @@ func (f *Fetcher[V]) pullLoop() {
|
||||
select {
|
||||
case <-timer.C:
|
||||
timer.Reset(f.interval)
|
||||
f.update(f.vehicle.Path())
|
||||
case <-f.done:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Fetcher[V]) update(path string) {
|
||||
elm, same, err := f.Update()
|
||||
if err != nil {
|
||||
log.Errorln("[Provider] %s pull error: %s", f.Name(), err.Error())
|
||||
continue
|
||||
return
|
||||
}
|
||||
|
||||
if same {
|
||||
log.Debugln("[Provider] %s's content doesn't change", f.Name())
|
||||
continue
|
||||
return
|
||||
}
|
||||
|
||||
log.Infoln("[Provider] %s's content update", f.Name())
|
||||
if f.OnUpdate != nil {
|
||||
f.OnUpdate(elm)
|
||||
}
|
||||
case <-f.done:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func safeWrite(path string, buf []byte) error {
|
||||
|
@@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/metacubex/mihomo/common/lru"
|
||||
@@ -30,7 +29,6 @@ type SnifferDispatcher struct {
|
||||
forceDomain *trie.DomainSet
|
||||
skipSNI *trie.DomainSet
|
||||
skipList *lru.LruCache[string, uint8]
|
||||
rwMux sync.RWMutex
|
||||
forceDnsMapping bool
|
||||
parsePureIp bool
|
||||
}
|
||||
@@ -85,14 +83,11 @@ func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata
|
||||
return false
|
||||
}
|
||||
|
||||
sd.rwMux.RLock()
|
||||
dst := fmt.Sprintf("%s:%d", metadata.DstIP, metadata.DstPort)
|
||||
if count, ok := sd.skipList.Get(dst); ok && count > 5 {
|
||||
log.Debugln("[Sniffer] Skip sniffing[%s] due to multiple failures", dst)
|
||||
defer sd.rwMux.RUnlock()
|
||||
return false
|
||||
}
|
||||
sd.rwMux.RUnlock()
|
||||
|
||||
if host, err := sd.sniffDomain(conn, metadata); err != nil {
|
||||
sd.cacheSniffFailed(metadata)
|
||||
@@ -104,9 +99,7 @@ func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata
|
||||
return false
|
||||
}
|
||||
|
||||
sd.rwMux.RLock()
|
||||
sd.skipList.Delete(dst)
|
||||
sd.rwMux.RUnlock()
|
||||
|
||||
sd.replaceDomain(metadata, host, overrideDest)
|
||||
return true
|
||||
@@ -176,14 +169,13 @@ func (sd *SnifferDispatcher) sniffDomain(conn *N.BufferedConn, metadata *C.Metad
|
||||
}
|
||||
|
||||
func (sd *SnifferDispatcher) cacheSniffFailed(metadata *C.Metadata) {
|
||||
sd.rwMux.Lock()
|
||||
dst := fmt.Sprintf("%s:%d", metadata.DstIP, metadata.DstPort)
|
||||
count, _ := sd.skipList.Get(dst)
|
||||
if count <= 5 {
|
||||
count++
|
||||
sd.skipList.Compute(dst, func(oldValue uint8, loaded bool) (newValue uint8, delete bool) {
|
||||
if oldValue <= 5 {
|
||||
oldValue++
|
||||
}
|
||||
sd.skipList.Set(dst, count)
|
||||
sd.rwMux.Unlock()
|
||||
return oldValue, false
|
||||
})
|
||||
}
|
||||
|
||||
func NewCloseSnifferDispatcher() (*SnifferDispatcher, error) {
|
||||
|
@@ -123,16 +123,18 @@ func (t *DomainTrie[T]) Optimize() {
|
||||
t.root.optimize()
|
||||
}
|
||||
|
||||
func (t *DomainTrie[T]) Foreach(print func(domain string, data T)) {
|
||||
func (t *DomainTrie[T]) Foreach(fn func(domain string, data T) bool) {
|
||||
for key, data := range t.root.getChildren() {
|
||||
recursion([]string{key}, data, print)
|
||||
recursion([]string{key}, data, fn)
|
||||
if data != nil && data.inited {
|
||||
print(joinDomain([]string{key}), data.data)
|
||||
if !fn(joinDomain([]string{key}), data.data) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func recursion[T any](items []string, node *Node[T], fn func(domain string, data T)) {
|
||||
func recursion[T any](items []string, node *Node[T], fn func(domain string, data T) bool) bool {
|
||||
for key, data := range node.getChildren() {
|
||||
newItems := append([]string{key}, items...)
|
||||
if data != nil && data.inited {
|
||||
@@ -140,10 +142,15 @@ func recursion[T any](items []string, node *Node[T], fn func(domain string, data
|
||||
if domain[0] == domainStepByte {
|
||||
domain = complexWildcard + domain
|
||||
}
|
||||
fn(domain, data.Data())
|
||||
if !fn(domain, data.Data()) {
|
||||
return false
|
||||
}
|
||||
recursion(newItems, data, fn)
|
||||
}
|
||||
if !recursion(newItems, data, fn) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func joinDomain(items []string) string {
|
||||
|
@@ -28,8 +28,9 @@ type qElt struct{ s, e, col int }
|
||||
// NewDomainSet creates a new *DomainSet struct, from a DomainTrie.
|
||||
func (t *DomainTrie[T]) NewDomainSet() *DomainSet {
|
||||
reserveDomains := make([]string, 0)
|
||||
t.Foreach(func(domain string, data T) {
|
||||
t.Foreach(func(domain string, data T) bool {
|
||||
reserveDomains = append(reserveDomains, utils.Reverse(domain))
|
||||
return true
|
||||
})
|
||||
// ensure that the same prefix is continuous
|
||||
// and according to the ascending sequence of length
|
||||
@@ -136,6 +137,41 @@ func (ss *DomainSet) Has(key string) bool {
|
||||
|
||||
}
|
||||
|
||||
func (ss *DomainSet) keys(f func(key string) bool) {
|
||||
var currentKey []byte
|
||||
var traverse func(int, int) bool
|
||||
traverse = func(nodeId, bmIdx int) bool {
|
||||
if getBit(ss.leaves, nodeId) != 0 {
|
||||
if !f(string(currentKey)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
for ; ; bmIdx++ {
|
||||
if getBit(ss.labelBitmap, bmIdx) != 0 {
|
||||
return true
|
||||
}
|
||||
nextLabel := ss.labels[bmIdx-nodeId]
|
||||
currentKey = append(currentKey, nextLabel)
|
||||
nextNodeId := countZeros(ss.labelBitmap, ss.ranks, bmIdx+1)
|
||||
nextBmIdx := selectIthOne(ss.labelBitmap, ss.ranks, ss.selects, nextNodeId-1) + 1
|
||||
if !traverse(nextNodeId, nextBmIdx) {
|
||||
return false
|
||||
}
|
||||
currentKey = currentKey[:len(currentKey)-1]
|
||||
}
|
||||
}
|
||||
|
||||
traverse(0, 0)
|
||||
return
|
||||
}
|
||||
|
||||
func (ss *DomainSet) Foreach(f func(key string) bool) {
|
||||
ss.keys(func(key string) bool {
|
||||
return f(utils.Reverse(key))
|
||||
})
|
||||
}
|
||||
|
||||
func setBit(bm *[]uint64, i int, v int) {
|
||||
for i>>6 >= len(*bm) {
|
||||
*bm = append(*bm, 0)
|
||||
|
@@ -0,0 +1,115 @@
|
||||
package trie
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
func (ss *DomainSet) WriteBin(w io.Writer) (err error) {
|
||||
// version
|
||||
_, err = w.Write([]byte{1})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// leaves
|
||||
err = binary.Write(w, binary.BigEndian, int64(len(ss.leaves)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, d := range ss.leaves {
|
||||
err = binary.Write(w, binary.BigEndian, d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// labelBitmap
|
||||
err = binary.Write(w, binary.BigEndian, int64(len(ss.labelBitmap)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, d := range ss.labelBitmap {
|
||||
err = binary.Write(w, binary.BigEndian, d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// labels
|
||||
err = binary.Write(w, binary.BigEndian, int64(len(ss.labels)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = w.Write(ss.labels)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ReadDomainSetBin(r io.Reader) (ds *DomainSet, err error) {
|
||||
// version
|
||||
version := make([]byte, 1)
|
||||
_, err = io.ReadFull(r, version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if version[0] != 1 {
|
||||
return nil, errors.New("version is invalid")
|
||||
}
|
||||
|
||||
ds = &DomainSet{}
|
||||
var length int64
|
||||
|
||||
// leaves
|
||||
err = binary.Read(r, binary.BigEndian, &length)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if length < 1 {
|
||||
return nil, errors.New("length is invalid")
|
||||
}
|
||||
ds.leaves = make([]uint64, length)
|
||||
for i := int64(0); i < length; i++ {
|
||||
err = binary.Read(r, binary.BigEndian, &ds.leaves[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// labelBitmap
|
||||
err = binary.Read(r, binary.BigEndian, &length)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if length < 1 {
|
||||
return nil, errors.New("length is invalid")
|
||||
}
|
||||
ds.labelBitmap = make([]uint64, length)
|
||||
for i := int64(0); i < length; i++ {
|
||||
err = binary.Read(r, binary.BigEndian, &ds.labelBitmap[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// labels
|
||||
err = binary.Read(r, binary.BigEndian, &length)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if length < 1 {
|
||||
return nil, errors.New("length is invalid")
|
||||
}
|
||||
ds.labels = make([]byte, length)
|
||||
_, err = io.ReadFull(r, ds.labels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ds.init()
|
||||
return ds, nil
|
||||
}
|
@@ -1,12 +1,29 @@
|
||||
package trie_test
|
||||
|
||||
import (
|
||||
"golang.org/x/exp/slices"
|
||||
"testing"
|
||||
|
||||
"github.com/metacubex/mihomo/component/trie"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func testDump(t *testing.T, tree *trie.DomainTrie[struct{}], set *trie.DomainSet) {
|
||||
var dataSrc []string
|
||||
tree.Foreach(func(domain string, data struct{}) bool {
|
||||
dataSrc = append(dataSrc, domain)
|
||||
return true
|
||||
})
|
||||
slices.Sort(dataSrc)
|
||||
var dataSet []string
|
||||
set.Foreach(func(key string) bool {
|
||||
dataSet = append(dataSet, key)
|
||||
return true
|
||||
})
|
||||
slices.Sort(dataSet)
|
||||
assert.Equal(t, dataSrc, dataSet)
|
||||
}
|
||||
|
||||
func TestDomainSet(t *testing.T) {
|
||||
tree := trie.New[struct{}]()
|
||||
domainSet := []string{
|
||||
@@ -33,6 +50,7 @@ func TestDomainSet(t *testing.T) {
|
||||
assert.True(t, set.Has("google.com"))
|
||||
assert.False(t, set.Has("qq.com"))
|
||||
assert.False(t, set.Has("www.baidu.com"))
|
||||
testDump(t, tree, set)
|
||||
}
|
||||
|
||||
func TestDomainSetComplexWildcard(t *testing.T) {
|
||||
@@ -55,6 +73,7 @@ func TestDomainSetComplexWildcard(t *testing.T) {
|
||||
assert.False(t, set.Has("google.com"))
|
||||
assert.True(t, set.Has("www.baidu.com"))
|
||||
assert.True(t, set.Has("test.test.baidu.com"))
|
||||
testDump(t, tree, set)
|
||||
}
|
||||
|
||||
func TestDomainSetWildcard(t *testing.T) {
|
||||
@@ -82,4 +101,5 @@ func TestDomainSetWildcard(t *testing.T) {
|
||||
assert.False(t, set.Has("a.www.google.com"))
|
||||
assert.False(t, set.Has("test.qq.com"))
|
||||
assert.False(t, set.Has("test.test.test.qq.com"))
|
||||
testDump(t, tree, set)
|
||||
}
|
||||
|
@@ -121,8 +121,9 @@ func TestTrie_Foreach(t *testing.T) {
|
||||
assert.NoError(t, tree.Insert(domain, localIP))
|
||||
}
|
||||
count := 0
|
||||
tree.Foreach(func(domain string, data netip.Addr) {
|
||||
tree.Foreach(func(domain string, data netip.Addr) bool {
|
||||
count++
|
||||
return true
|
||||
})
|
||||
assert.Equal(t, 7, count)
|
||||
}
|
||||
|
@@ -42,6 +42,7 @@ import (
|
||||
T "github.com/metacubex/mihomo/tunnel"
|
||||
|
||||
orderedmap "github.com/wk8/go-ordered-map/v2"
|
||||
"golang.org/x/exp/slices"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
@@ -96,6 +97,7 @@ type Controller struct {
|
||||
ExternalControllerTLS string `json:"-"`
|
||||
ExternalControllerUnix string `json:"-"`
|
||||
ExternalUI string `json:"-"`
|
||||
ExternalDohServer string `json:"-"`
|
||||
Secret string `json:"-"`
|
||||
}
|
||||
|
||||
@@ -322,6 +324,7 @@ type RawConfig struct {
|
||||
ExternalUI string `yaml:"external-ui"`
|
||||
ExternalUIURL string `yaml:"external-ui-url" json:"external-ui-url"`
|
||||
ExternalUIName string `yaml:"external-ui-name" json:"external-ui-name"`
|
||||
ExternalDohServer string `yaml:"external-doh-server"`
|
||||
Secret string `yaml:"secret"`
|
||||
Interface string `yaml:"interface-name"`
|
||||
RoutingMark int `yaml:"routing-mark"`
|
||||
@@ -504,7 +507,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
|
||||
},
|
||||
Sniffer: RawSniffer{
|
||||
Enable: false,
|
||||
Sniffing: []string{},
|
||||
Sniff: map[string]RawSniffingConfig{},
|
||||
ForceDomain: []string{},
|
||||
SkipDomain: []string{},
|
||||
Ports: []string{},
|
||||
@@ -697,6 +700,7 @@ func parseGeneral(cfg *RawConfig) (*General, error) {
|
||||
Secret: cfg.Secret,
|
||||
ExternalControllerUnix: cfg.ExternalControllerUnix,
|
||||
ExternalControllerTLS: cfg.ExternalControllerTLS,
|
||||
ExternalDohServer: cfg.ExternalDohServer,
|
||||
},
|
||||
UnifiedDelay: cfg.UnifiedDelay,
|
||||
Mode: cfg.Mode,
|
||||
@@ -789,6 +793,9 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
|
||||
AllProviders = append(AllProviders, name)
|
||||
}
|
||||
|
||||
slices.Sort(AllProxies)
|
||||
slices.Sort(AllProviders)
|
||||
|
||||
// parse proxy group
|
||||
for idx, mapping := range groupsConfig {
|
||||
group, err := outboundgroup.ParseProxyGroup(mapping, proxies, providersMap, AllProxies, AllProviders)
|
||||
@@ -1087,13 +1094,16 @@ func parseNameServer(servers []string, respectRules bool, preferH3 bool) ([]dns.
|
||||
case "tls":
|
||||
addr, err = hostWithDefaultPort(u.Host, "853")
|
||||
dnsNetType = "tcp-tls" // DNS over TLS
|
||||
case "https":
|
||||
case "http", "https":
|
||||
addr, err = hostWithDefaultPort(u.Host, "443")
|
||||
dnsNetType = "https" // DNS over HTTPS
|
||||
if u.Scheme == "http" {
|
||||
addr, err = hostWithDefaultPort(u.Host, "80")
|
||||
}
|
||||
if err == nil {
|
||||
proxyName = ""
|
||||
clearURL := url.URL{Scheme: "https", Host: addr, Path: u.Path, User: u.User}
|
||||
clearURL := url.URL{Scheme: u.Scheme, Host: addr, Path: u.Path, User: u.User}
|
||||
addr = clearURL.String()
|
||||
dnsNetType = "https" // DNS over HTTPS
|
||||
if len(u.Fragment) != 0 {
|
||||
for _, s := range strings.Split(u.Fragment, "&") {
|
||||
arr := strings.Split(s, "=")
|
||||
@@ -1566,7 +1576,7 @@ func parseSniffer(snifferRaw RawSniffer) (*Sniffer, error) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if sniffer.Enable {
|
||||
if sniffer.Enable && len(snifferRaw.Sniffing) != 0 {
|
||||
// Deprecated: Use Sniff instead
|
||||
log.Warnln("Deprecated: Use Sniff instead")
|
||||
}
|
||||
|
@@ -1,6 +1,8 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/metacubex/mihomo/common/utils"
|
||||
"github.com/metacubex/mihomo/constant"
|
||||
)
|
||||
@@ -110,9 +112,37 @@ func (rt RuleBehavior) String() string {
|
||||
}
|
||||
}
|
||||
|
||||
func (rt RuleBehavior) Byte() byte {
|
||||
switch rt {
|
||||
case Domain:
|
||||
return 0
|
||||
case IPCIDR:
|
||||
return 1
|
||||
case Classical:
|
||||
return 2
|
||||
default:
|
||||
return 255
|
||||
}
|
||||
}
|
||||
|
||||
func ParseBehavior(s string) (behavior RuleBehavior, err error) {
|
||||
switch s {
|
||||
case "domain":
|
||||
behavior = Domain
|
||||
case "ipcidr":
|
||||
behavior = IPCIDR
|
||||
case "classical":
|
||||
behavior = Classical
|
||||
default:
|
||||
err = fmt.Errorf("unsupported behavior type: %s", s)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const (
|
||||
YamlRule RuleFormat = iota
|
||||
TextRule
|
||||
MrsRule
|
||||
)
|
||||
|
||||
type RuleFormat int
|
||||
@@ -123,11 +153,27 @@ func (rf RuleFormat) String() string {
|
||||
return "YamlRule"
|
||||
case TextRule:
|
||||
return "TextRule"
|
||||
case MrsRule:
|
||||
return "MrsRule"
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
func ParseRuleFormat(s string) (format RuleFormat, err error) {
|
||||
switch s {
|
||||
case "", "yaml":
|
||||
format = YamlRule
|
||||
case "text":
|
||||
format = TextRule
|
||||
case "mrs":
|
||||
format = MrsRule
|
||||
default:
|
||||
err = fmt.Errorf("unsupported format type: %s", s)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type Tunnel interface {
|
||||
Providers() map[string]ProxyProvider
|
||||
RuleProviders() map[string]RuleProvider
|
||||
|
@@ -61,10 +61,12 @@ type dnsOverHTTPS struct {
|
||||
// for this upstream.
|
||||
quicConfig *quic.Config
|
||||
quicConfigGuard sync.Mutex
|
||||
|
||||
url *url.URL
|
||||
httpVersions []C.HTTPVersion
|
||||
dialer *dnsDialer
|
||||
addr string
|
||||
skipCertVerify bool
|
||||
}
|
||||
|
||||
// type check
|
||||
@@ -93,6 +95,10 @@ func newDoHClient(urlString string, r *Resolver, preferH3 bool, params map[strin
|
||||
httpVersions: httpVersions,
|
||||
}
|
||||
|
||||
if params["skip-cert-verify"] == "true" {
|
||||
doh.skipCertVerify = true
|
||||
}
|
||||
|
||||
runtime.SetFinalizer(doh, (*dnsOverHTTPS).Close)
|
||||
|
||||
return doh
|
||||
@@ -102,6 +108,7 @@ func newDoHClient(urlString string, r *Resolver, preferH3 bool, params map[strin
|
||||
func (doh *dnsOverHTTPS) Address() string {
|
||||
return doh.addr
|
||||
}
|
||||
|
||||
func (doh *dnsOverHTTPS) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) {
|
||||
// Quote from https://www.rfc-editor.org/rfc/rfc8484.html:
|
||||
// In order to maximize HTTP cache friendliness, DoH clients using media
|
||||
@@ -178,19 +185,9 @@ func (doh *dnsOverHTTPS) closeClient(client *http.Client) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// exchangeHTTPS logs the request and its result and calls exchangeHTTPSClient.
|
||||
func (doh *dnsOverHTTPS) exchangeHTTPS(ctx context.Context, client *http.Client, req *D.Msg) (resp *D.Msg, err error) {
|
||||
resp, err = doh.exchangeHTTPSClient(ctx, client, req)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// exchangeHTTPSClient sends the DNS query to a DoH resolver using the specified
|
||||
// exchangeHTTPS sends the DNS query to a DoH resolver using the specified
|
||||
// http.Client instance.
|
||||
func (doh *dnsOverHTTPS) exchangeHTTPSClient(
|
||||
ctx context.Context,
|
||||
client *http.Client,
|
||||
req *D.Msg,
|
||||
) (resp *D.Msg, err error) {
|
||||
func (doh *dnsOverHTTPS) exchangeHTTPS(ctx context.Context, client *http.Client, req *D.Msg) (resp *D.Msg, err error) {
|
||||
buf, err := req.Pack()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("packing message: %w", err)
|
||||
@@ -204,24 +201,24 @@ func (doh *dnsOverHTTPS) exchangeHTTPSClient(
|
||||
method = http3.MethodGet0RTT
|
||||
}
|
||||
|
||||
url := doh.url
|
||||
url.RawQuery = fmt.Sprintf("dns=%s", base64.RawURLEncoding.EncodeToString(buf))
|
||||
httpReq, err := http.NewRequestWithContext(ctx, method, url.String(), nil)
|
||||
requestUrl := *doh.url // don't modify origin url
|
||||
requestUrl.RawQuery = fmt.Sprintf("dns=%s", base64.RawURLEncoding.EncodeToString(buf))
|
||||
httpReq, err := http.NewRequestWithContext(ctx, method, requestUrl.String(), nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating http request to %s: %w", url, err)
|
||||
return nil, fmt.Errorf("creating http request to %s: %w", doh.url, err)
|
||||
}
|
||||
|
||||
httpReq.Header.Set("Accept", "application/dns-message")
|
||||
httpReq.Header.Set("User-Agent", "")
|
||||
httpResp, err := client.Do(httpReq)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("requesting %s: %w", url, err)
|
||||
return nil, fmt.Errorf("requesting %s: %w", doh.url, err)
|
||||
}
|
||||
defer httpResp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(httpResp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading %s: %w", url, err)
|
||||
return nil, fmt.Errorf("reading %s: %w", doh.url, err)
|
||||
}
|
||||
|
||||
if httpResp.StatusCode != http.StatusOK {
|
||||
@@ -230,7 +227,7 @@ func (doh *dnsOverHTTPS) exchangeHTTPSClient(
|
||||
"expected status %d, got %d from %s",
|
||||
http.StatusOK,
|
||||
httpResp.StatusCode,
|
||||
url,
|
||||
doh.url,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -239,7 +236,7 @@ func (doh *dnsOverHTTPS) exchangeHTTPSClient(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"unpacking response from %s: body is %s: %w",
|
||||
url,
|
||||
doh.url,
|
||||
body,
|
||||
err,
|
||||
)
|
||||
@@ -373,9 +370,21 @@ func (doh *dnsOverHTTPS) createClient(ctx context.Context) (*http.Client, error)
|
||||
// HTTP3 is enabled in the upstream options). If this attempt is successful,
|
||||
// it returns an HTTP3 transport, otherwise it returns the H1/H2 transport.
|
||||
func (doh *dnsOverHTTPS) createTransport(ctx context.Context) (t http.RoundTripper, err error) {
|
||||
transport := &http.Transport{
|
||||
DisableCompression: true,
|
||||
DialContext: doh.dialer.DialContext,
|
||||
IdleConnTimeout: transportDefaultIdleConnTimeout,
|
||||
MaxConnsPerHost: dohMaxConnsPerHost,
|
||||
MaxIdleConns: dohMaxIdleConns,
|
||||
}
|
||||
|
||||
if doh.url.Scheme == "http" {
|
||||
return transport, nil
|
||||
}
|
||||
|
||||
tlsConfig := ca.GetGlobalTLSConfig(
|
||||
&tls.Config{
|
||||
InsecureSkipVerify: false,
|
||||
InsecureSkipVerify: doh.skipCertVerify,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
SessionTicketsDisabled: false,
|
||||
})
|
||||
@@ -384,6 +393,7 @@ func (doh *dnsOverHTTPS) createTransport(ctx context.Context) (t http.RoundTripp
|
||||
nextProtos = append(nextProtos, string(v))
|
||||
}
|
||||
tlsConfig.NextProtos = nextProtos
|
||||
transport.TLSClientConfig = tlsConfig
|
||||
|
||||
if slices.Contains(doh.httpVersions, C.HTTPVersion3) {
|
||||
// First, we attempt to create an HTTP3 transport. If the probe QUIC
|
||||
@@ -402,18 +412,10 @@ func (doh *dnsOverHTTPS) createTransport(ctx context.Context) (t http.RoundTripp
|
||||
return nil, errors.New("HTTP1/1 and HTTP2 are not supported by this upstream")
|
||||
}
|
||||
|
||||
transport := &http.Transport{
|
||||
TLSClientConfig: tlsConfig,
|
||||
DisableCompression: true,
|
||||
DialContext: doh.dialer.DialContext,
|
||||
IdleConnTimeout: transportDefaultIdleConnTimeout,
|
||||
MaxConnsPerHost: dohMaxConnsPerHost,
|
||||
MaxIdleConns: dohMaxIdleConns,
|
||||
// Since we have a custom DialContext, we need to use this field to
|
||||
// make golang http.Client attempt to use HTTP/2. Otherwise, it would
|
||||
// only be used when negotiated on the TLS level.
|
||||
ForceAttemptHTTP2: true,
|
||||
}
|
||||
transport.ForceAttemptHTTP2 = true
|
||||
|
||||
// Explicitly configure transport to use HTTP/2.
|
||||
//
|
||||
|
@@ -146,9 +146,12 @@ func (r *Resolver) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, e
|
||||
}()
|
||||
|
||||
q := m.Question[0]
|
||||
domain := msgToDomain(m)
|
||||
_, qTypeStr := msgToQtype(m)
|
||||
cacheM, expireTime, hit := r.cache.GetWithExpire(q.String())
|
||||
if hit {
|
||||
log.Debugln("[DNS] cache hit for %s, expire at %s", q.Name, expireTime.Format("2006-01-02 15:04:05"))
|
||||
ips := msgToIP(cacheM)
|
||||
log.Debugln("[DNS] cache hit %s --> %s %s, expire at %s", domain, ips, qTypeStr, expireTime.Format("2006-01-02 15:04:05"))
|
||||
now := time.Now()
|
||||
msg = cacheM.Copy()
|
||||
if expireTime.Before(now) {
|
||||
|
@@ -173,11 +173,20 @@ func msgToDomain(msg *D.Msg) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func msgToQtype(msg *D.Msg) (uint16, string) {
|
||||
if len(msg.Question) > 0 {
|
||||
qType := msg.Question[0].Qtype
|
||||
return qType, D.Type(qType).String()
|
||||
}
|
||||
return 0, ""
|
||||
}
|
||||
|
||||
func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.Msg, cache bool, err error) {
|
||||
cache = true
|
||||
fast, ctx := picker.WithTimeout[*D.Msg](ctx, resolver.DefaultDNSTimeout)
|
||||
defer fast.Close()
|
||||
domain := msgToDomain(m)
|
||||
qType, qTypeStr := msgToQtype(m)
|
||||
var noIpMsg *D.Msg
|
||||
for _, client := range clients {
|
||||
if _, isRCodeClient := client.(rcodeClient); isRCodeClient {
|
||||
@@ -186,7 +195,7 @@ func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.M
|
||||
}
|
||||
client := client // shadow define client to ensure the value captured by the closure will not be changed in the next loop
|
||||
fast.Go(func() (*D.Msg, error) {
|
||||
log.Debugln("[DNS] resolve %s from %s", domain, client.Address())
|
||||
log.Debugln("[DNS] resolve %s %s from %s", domain, qTypeStr, client.Address())
|
||||
m, err := client.ExchangeContext(ctx, m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -195,9 +204,8 @@ func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.M
|
||||
// so we would ignore RCode errors from RCode clients.
|
||||
return nil, errors.New("server failure: " + D.RcodeToString[m.Rcode])
|
||||
}
|
||||
if ips := msgToIP(m); len(m.Question) > 0 {
|
||||
qType := m.Question[0].Qtype
|
||||
log.Debugln("[DNS] %s --> %s %s from %s", domain, ips, D.Type(qType), client.Address())
|
||||
ips := msgToIP(m)
|
||||
log.Debugln("[DNS] %s --> %s %s from %s", domain, ips, qTypeStr, client.Address())
|
||||
switch qType {
|
||||
case D.TypeAAAA:
|
||||
if len(ips) == 0 {
|
||||
@@ -210,7 +218,6 @@ func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.M
|
||||
return nil, resolver.ErrIPNotFound
|
||||
}
|
||||
}
|
||||
}
|
||||
return m, nil
|
||||
})
|
||||
}
|
||||
|
@@ -70,6 +70,10 @@ external-ui: /path/to/ui/folder/
|
||||
external-ui-name: xd
|
||||
external-ui-url: "https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip"
|
||||
|
||||
# 在RESTful API端口上开启DOH服务器
|
||||
# !!!该URL不会验证secret, 如果开启请自行保证安全问题 !!!
|
||||
external-doh-server: /dns-query
|
||||
|
||||
# interface-name: en0 # 设置出口网卡
|
||||
|
||||
# 全局 TLS 指纹,优先低于 proxy 内的 client-fingerprint
|
||||
@@ -938,6 +942,24 @@ rule-providers:
|
||||
interval: 259200
|
||||
path: /path/to/save/file.yaml
|
||||
type: file
|
||||
rule3:
|
||||
# mrs类型ruleset,目前仅支持domain和ipcidr(即不支持classical),
|
||||
#
|
||||
# 对于behavior=domain:
|
||||
# - format=yaml 可以通过“mihomo convert-ruleset domain yaml XXX.yaml XXX.mrs”转换到mrs格式
|
||||
# - format=text 可以通过“mihomo convert-ruleset domain text XXX.text XXX.mrs”转换到mrs格式
|
||||
# - XXX.mrs 可以通过"mihomo convert-ruleset domain mrs XXX.mrs XXX.text"转换回text格式(暂不支持转换回ymal格式)
|
||||
#
|
||||
# 对于behavior=ipcidr:
|
||||
# - format=yaml 可以通过“mihomo convert-ruleset ipcidr yaml XXX.yaml XXX.mrs”转换到mrs格式
|
||||
# - format=text 可以通过“mihomo convert-ruleset ipcidr text XXX.text XXX.mrs”转换到mrs格式
|
||||
# - XXX.mrs 可以通过"mihomo convert-ruleset ipcidr mrs XXX.mrs XXX.text"转换回text格式(暂不支持转换回ymal格式)
|
||||
#
|
||||
type: http
|
||||
url: "url"
|
||||
format: mrs
|
||||
behavior: domain
|
||||
path: /path/to/save/file.mrs
|
||||
rules:
|
||||
- RULE-SET,rule1,REJECT
|
||||
- IP-ASN,1,PROXY
|
||||
|
@@ -4,7 +4,6 @@ go 1.20
|
||||
|
||||
require (
|
||||
github.com/3andne/restls-client-go v0.1.6
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da
|
||||
github.com/bahlo/generic-list-go v0.2.0
|
||||
github.com/cilium/ebpf v0.12.3
|
||||
github.com/coreos/go-iptables v0.7.0
|
||||
@@ -15,17 +14,19 @@ require (
|
||||
github.com/gobwas/ws v1.4.0
|
||||
github.com/gofrs/uuid/v5 v5.2.0
|
||||
github.com/insomniacslk/dhcp v0.0.0-20240529192340-51bc6136a0a6
|
||||
github.com/klauspost/compress v1.17.9
|
||||
github.com/klauspost/cpuid/v2 v2.2.8
|
||||
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40
|
||||
github.com/mdlayher/netlink v1.7.2
|
||||
github.com/metacubex/chacha v0.1.0
|
||||
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759
|
||||
github.com/metacubex/quic-go v0.45.1-0.20240610004319-163fee60637e
|
||||
github.com/metacubex/randv2 v0.2.0
|
||||
github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72
|
||||
github.com/metacubex/sing-shadowsocks v0.2.6
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.0
|
||||
github.com/metacubex/sing-tun v0.2.7-0.20240627012306-9d1f5fc0b45e
|
||||
github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f
|
||||
github.com/metacubex/sing-shadowsocks v0.2.7
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.1
|
||||
github.com/metacubex/sing-tun v0.2.7-0.20240719141246-19c49ac9589d
|
||||
github.com/metacubex/sing-vmess v0.1.9-0.20240719134745-1df6fb20bbf9
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20240618022557-a6efaa37127a
|
||||
github.com/metacubex/tfo-go v0.0.0-20240228025757-be1269474a66
|
||||
github.com/metacubex/utls v1.6.6
|
||||
@@ -35,8 +36,9 @@ require (
|
||||
github.com/oschwald/maxminddb-golang v1.12.0
|
||||
github.com/puzpuzpuz/xsync/v3 v3.2.0
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a
|
||||
github.com/sagernet/fswatch v0.1.1
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a
|
||||
github.com/sagernet/sing v0.5.0-alpha.10
|
||||
github.com/sagernet/sing v0.5.0-alpha.13
|
||||
github.com/sagernet/sing-mux v0.2.1-0.20240124034317-9bfb33698bb6
|
||||
github.com/sagernet/sing-shadowtls v0.1.4
|
||||
github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e
|
||||
@@ -45,13 +47,14 @@ require (
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8
|
||||
gitlab.com/go-extension/aes-ccm v0.0.0-20230221065045-e58665ef23c7
|
||||
go.uber.org/automaxprocs v1.5.3
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||
golang.org/x/crypto v0.24.0
|
||||
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8
|
||||
golang.org/x/net v0.26.0
|
||||
golang.org/x/sync v0.7.0
|
||||
golang.org/x/sys v0.21.0
|
||||
golang.org/x/sys v0.22.0
|
||||
google.golang.org/protobuf v1.34.2
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
lukechampine.com/blake3 v1.3.0
|
||||
@@ -80,7 +83,6 @@ require (
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
|
||||
github.com/hashicorp/yamux v0.1.1 // indirect
|
||||
github.com/josharian/native v1.1.0 // indirect
|
||||
github.com/klauspost/compress v1.17.4 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mdlayher/socket v0.4.1 // indirect
|
||||
@@ -111,4 +113,4 @@ require (
|
||||
golang.org/x/tools v0.22.0 // indirect
|
||||
)
|
||||
|
||||
replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20240617013425-3e3bd9dab6a2
|
||||
replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20240724044459-6f3cf5896297
|
||||
|
@@ -5,8 +5,6 @@ github.com/RyuaNerin/go-krypto v1.2.4 h1:mXuNdK6M317aPV0llW6Xpjbo4moOlPF7Yxz4tb4
|
||||
github.com/RyuaNerin/go-krypto v1.2.4/go.mod h1:QqCYkoutU3yInyD9INt2PGolVRsc3W4oraQadVGXJ/8=
|
||||
github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 h1:cDVUiFo+npB0ZASqnw4q90ylaVAbnYyx0JYqK4YcGok=
|
||||
github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344/go.mod h1:9pIqrY6SXNL8vjRQE5Hd/OL5GyK/9MrGUWs87z/eFfk=
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
|
||||
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
||||
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
||||
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
||||
@@ -83,8 +81,8 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF
|
||||
github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
||||
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
|
||||
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
@@ -99,6 +97,8 @@ github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/
|
||||
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
|
||||
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
|
||||
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
|
||||
github.com/metacubex/chacha v0.1.0 h1:tg9RSJ18NvL38cCWNyYH1eiG6qDCyyXIaTLQthon0sc=
|
||||
github.com/metacubex/chacha v0.1.0/go.mod h1:Djn9bPZxLTXbJFSeyo0/qzEzQI+gUSSzttuzZM75GH8=
|
||||
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvOzK9ubNCCkQ+ldc4YSH/rILn53l/xGBFHHI=
|
||||
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88=
|
||||
github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec h1:HxreOiFTUrJXJautEo8rnE1uKTVGY8wtZepY1Tii/Nc=
|
||||
@@ -107,18 +107,18 @@ github.com/metacubex/quic-go v0.45.1-0.20240610004319-163fee60637e h1:bLYn3GuRvW
|
||||
github.com/metacubex/quic-go v0.45.1-0.20240610004319-163fee60637e/go.mod h1:Yza2H7Ax1rxWPUcJx0vW+oAt9EsPuSiyQFhFabUPzwU=
|
||||
github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs=
|
||||
github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY=
|
||||
github.com/metacubex/sing v0.0.0-20240617013425-3e3bd9dab6a2 h1:N5tidgg/FRmkgPw/AjRwhLUinKDx/ODCSbvv9xqRoLM=
|
||||
github.com/metacubex/sing v0.0.0-20240617013425-3e3bd9dab6a2/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/metacubex/sing v0.0.0-20240724044459-6f3cf5896297 h1:YG/JkwGPbca5rUtEMHIu8ZuqzR7BSVm1iqY8hNoMeMA=
|
||||
github.com/metacubex/sing v0.0.0-20240724044459-6f3cf5896297/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72 h1:Wr4g1HCb5Z/QIFwFiVNjO2qL+dRu25+Mdn9xtAZZ+ew=
|
||||
github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72/go.mod h1:g7Mxj7b7zm7YVqD975mk/hSmrb0A0G4bVvIMr2MMzn8=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwVSgtE9R3QeFQ=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.6/go.mod h1:zIkMeSnb8Mbf4hdqhw0pjzkn1d99YJ3JQm/VBg5WMTg=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.0 h1:hqwT/AfI5d5UdPefIzR6onGHJfDXs5zgOM5QSgaM/9A=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.0/go.mod h1:LCKF6j1P94zN8ZS+LXRK1gmYTVGB3squivBSXAFnOg8=
|
||||
github.com/metacubex/sing-tun v0.2.7-0.20240627012306-9d1f5fc0b45e h1:o+zohxPRo45P35fS9u1zfdBgr+L/7S0ObGU6YjbVBIc=
|
||||
github.com/metacubex/sing-tun v0.2.7-0.20240627012306-9d1f5fc0b45e/go.mod h1:WwJGbCx7bQcBzuQXiDOJvZH27R0kIjKNNlISIWsL6kM=
|
||||
github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f h1:QjXrHKbTMBip/C+R79bvbfr42xH1gZl3uFb0RELdZiQ=
|
||||
github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f/go.mod h1:olVkD4FChQ5gKMHG4ZzuD7+fMkJY1G8vwOKpRehjrmY=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.7 h1:9f3Dt2+71TNp0e202llA2ug5h/rkWs2EZxQ5IMpf+9g=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.7/go.mod h1:X3x88XtJpBxG0W0/ECOJL6Ib0SJ3xdniAkU/6/RMWU0=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.1 h1:XIZBXlazp8EEoPp1S0DViAhLkJakjQ2f+AOwwdKKNYg=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.1/go.mod h1:BhOug03a/RbI7y6hp6q+6ITM1dXjnLTmeWBHSTwvv2Q=
|
||||
github.com/metacubex/sing-tun v0.2.7-0.20240719141246-19c49ac9589d h1:iYlepjRCYlPXtELupDL+pQjGqkCnQz4KQOfKImP9sog=
|
||||
github.com/metacubex/sing-tun v0.2.7-0.20240719141246-19c49ac9589d/go.mod h1:olbEx9yVcaw5tHTNlRamRoxmMKcvDvcVS1YLnQGzvWE=
|
||||
github.com/metacubex/sing-vmess v0.1.9-0.20240719134745-1df6fb20bbf9 h1:OAXiCosqY8xKDp3pqTW3qbrCprZ1l6WkrXSFSCwyY4I=
|
||||
github.com/metacubex/sing-vmess v0.1.9-0.20240719134745-1df6fb20bbf9/go.mod h1:olVkD4FChQ5gKMHG4ZzuD7+fMkJY1G8vwOKpRehjrmY=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20240618022557-a6efaa37127a h1:NpSGclHJUYndUwBmyIpFBSoBVg8PoVX7QQKhYg0DjM0=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20240618022557-a6efaa37127a/go.mod h1:uY+BYb0UEknLrqvbGcwi9i++KgrKxsurysgI6G1Pveo=
|
||||
github.com/metacubex/tfo-go v0.0.0-20240228025757-be1269474a66 h1:as/aO/fM8nv4W4pOr9EETP6kV/Oaujk3fUNyQSJK61c=
|
||||
@@ -158,6 +158,8 @@ github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkkD2QgdTuzQG263YZ+2emfpeyGqW0=
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM=
|
||||
github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs=
|
||||
github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o=
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis=
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||
github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I=
|
||||
@@ -212,6 +214,8 @@ github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
gitlab.com/go-extension/aes-ccm v0.0.0-20230221065045-e58665ef23c7 h1:UNrDfkQqiEYzdMlNsVvBYOAJWZjdktqFE9tQh5BT2+4=
|
||||
gitlab.com/go-extension/aes-ccm v0.0.0-20230221065045-e58665ef23c7/go.mod h1:E+rxHvJG9H6PUdzq9NRG6csuLN3XUx98BfGOVWNYnXs=
|
||||
gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec h1:FpfFs4EhNehiVfzQttTuxanPIT43FtkkCFypIod8LHo=
|
||||
gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec/go.mod h1:BZ1RAoRPbCxum9Grlv5aeksu2H8BiKehBYooU2LFiOQ=
|
||||
go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
|
||||
@@ -252,8 +256,9 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
|
@@ -50,11 +50,12 @@ func Parse(options ...Option) error {
|
||||
|
||||
if cfg.General.ExternalController != "" {
|
||||
go route.Start(cfg.General.ExternalController, cfg.General.ExternalControllerTLS,
|
||||
cfg.General.Secret, cfg.TLS.Certificate, cfg.TLS.PrivateKey, cfg.General.LogLevel == log.DEBUG)
|
||||
cfg.General.Secret, cfg.TLS.Certificate, cfg.TLS.PrivateKey, cfg.General.ExternalDohServer,
|
||||
cfg.General.LogLevel == log.DEBUG)
|
||||
}
|
||||
|
||||
if cfg.General.ExternalControllerUnix != "" {
|
||||
go route.StartUnix(cfg.General.ExternalControllerUnix, cfg.General.LogLevel == log.DEBUG)
|
||||
go route.StartUnix(cfg.General.ExternalControllerUnix, cfg.General.ExternalDohServer, cfg.General.LogLevel == log.DEBUG)
|
||||
}
|
||||
|
||||
executor.ApplyConfig(cfg, true)
|
||||
|
@@ -0,0 +1,63 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/metacubex/mihomo/component/resolver"
|
||||
|
||||
"github.com/go-chi/render"
|
||||
)
|
||||
|
||||
func dohRouter() http.Handler {
|
||||
return http.HandlerFunc(dohHandler)
|
||||
}
|
||||
|
||||
func dohHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if resolver.DefaultResolver == nil {
|
||||
render.Status(r, http.StatusInternalServerError)
|
||||
render.PlainText(w, r, "DNS section is disabled")
|
||||
return
|
||||
}
|
||||
|
||||
var dnsData []byte
|
||||
var err error
|
||||
switch r.Method {
|
||||
case "GET":
|
||||
dnsData, err = base64.RawURLEncoding.DecodeString(r.URL.Query().Get("dns"))
|
||||
case "POST":
|
||||
if r.Header.Get("Content-Type") != "application/dns-message" {
|
||||
render.Status(r, http.StatusInternalServerError)
|
||||
render.PlainText(w, r, "invalid content-type")
|
||||
return
|
||||
}
|
||||
reader := io.LimitReader(r.Body, 65535) // according to rfc8484, the maximum size of the DNS message is 65535 bytes
|
||||
dnsData, err = io.ReadAll(reader)
|
||||
_ = r.Body.Close()
|
||||
default:
|
||||
render.Status(r, http.StatusMethodNotAllowed)
|
||||
render.PlainText(w, r, "method not allowed")
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
render.Status(r, http.StatusInternalServerError)
|
||||
render.PlainText(w, r, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), resolver.DefaultDNSTimeout)
|
||||
defer cancel()
|
||||
|
||||
dnsData, err = resolver.RelayDnsPacket(ctx, dnsData, dnsData)
|
||||
if err != nil {
|
||||
render.Status(r, http.StatusInternalServerError)
|
||||
render.PlainText(w, r, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/dns-message")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write(dnsData)
|
||||
}
|
@@ -50,7 +50,7 @@ func SetUIPath(path string) {
|
||||
uiPath = C.Path.Resolve(path)
|
||||
}
|
||||
|
||||
func router(isDebug bool, withAuth bool) *chi.Mux {
|
||||
func router(isDebug bool, withAuth bool, dohServer string) *chi.Mux {
|
||||
r := chi.NewRouter()
|
||||
corsM := cors.New(cors.Options{
|
||||
AllowedOrigins: []string{"*"},
|
||||
@@ -104,11 +104,15 @@ func router(isDebug bool, withAuth bool) *chi.Mux {
|
||||
})
|
||||
})
|
||||
}
|
||||
if len(dohServer) > 0 && dohServer[0] == '/' {
|
||||
r.Mount(dohServer, dohRouter())
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func Start(addr string, tlsAddr string, secret string,
|
||||
certificate, privateKey string, isDebug bool) {
|
||||
certificate, privateKey string, dohServer string, isDebug bool) {
|
||||
if serverAddr != "" {
|
||||
return
|
||||
}
|
||||
@@ -133,7 +137,7 @@ func Start(addr string, tlsAddr string, secret string,
|
||||
serverAddr = l.Addr().String()
|
||||
log.Infoln("RESTful API tls listening at: %s", serverAddr)
|
||||
tlsServe := &http.Server{
|
||||
Handler: router(isDebug, true),
|
||||
Handler: router(isDebug, true, dohServer),
|
||||
TLSConfig: &tls.Config{
|
||||
Certificates: []tls.Certificate{c},
|
||||
},
|
||||
@@ -152,13 +156,13 @@ func Start(addr string, tlsAddr string, secret string,
|
||||
serverAddr = l.Addr().String()
|
||||
log.Infoln("RESTful API listening at: %s", serverAddr)
|
||||
|
||||
if err = http.Serve(l, router(isDebug, true)); err != nil {
|
||||
if err = http.Serve(l, router(isDebug, true, dohServer)); err != nil {
|
||||
log.Errorln("External controller serve error: %s", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func StartUnix(addr string, isDebug bool) {
|
||||
func StartUnix(addr string, dohServer string, isDebug bool) {
|
||||
addr = C.Path.Resolve(addr)
|
||||
|
||||
dir := filepath.Dir(addr)
|
||||
@@ -186,7 +190,7 @@ func StartUnix(addr string, isDebug bool) {
|
||||
serverAddr = l.Addr().String()
|
||||
log.Infoln("RESTful API unix listening at: %s", serverAddr)
|
||||
|
||||
if err = http.Serve(l, router(isDebug, false)); err != nil {
|
||||
if err = http.Serve(l, router(isDebug, false, dohServer)); err != nil {
|
||||
log.Errorln("External controller unix serve error: %s", err)
|
||||
}
|
||||
}
|
||||
|
@@ -13,7 +13,7 @@ import (
|
||||
"github.com/metacubex/mihomo/transport/socks5"
|
||||
)
|
||||
|
||||
func newClient(srcConn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) *http.Client {
|
||||
func newClient(srcConn net.Conn, tunnel C.Tunnel, additions []inbound.Addition) *http.Client { // additions using slice let caller can change its value (without size) after newClient return
|
||||
return &http.Client{
|
||||
Transport: &http.Transport{
|
||||
// from http.DefaultTransport
|
||||
@@ -21,6 +21,7 @@ func newClient(srcConn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition)
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
DisableCompression: true, // prevents the Transport add "Accept-Encoding: gzip"
|
||||
DialContext: func(context context.Context, network, address string) (net.Conn, error) {
|
||||
if network != "tcp" && network != "tcp4" && network != "tcp6" {
|
||||
return nil, errors.New("unsupported network " + network)
|
||||
|
@@ -10,10 +10,9 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/metacubex/mihomo/adapter/inbound"
|
||||
"github.com/metacubex/mihomo/common/lru"
|
||||
N "github.com/metacubex/mihomo/common/net"
|
||||
"github.com/metacubex/mihomo/component/auth"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
authStore "github.com/metacubex/mihomo/listener/auth"
|
||||
"github.com/metacubex/mihomo/log"
|
||||
)
|
||||
|
||||
@@ -31,8 +30,10 @@ func (b *bodyWrapper) Read(p []byte) (n int, err error) {
|
||||
return n, err
|
||||
}
|
||||
|
||||
func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool], additions ...inbound.Addition) {
|
||||
client := newClient(c, tunnel, additions...)
|
||||
func HandleConn(c net.Conn, tunnel C.Tunnel, authenticator auth.Authenticator, additions ...inbound.Addition) {
|
||||
additions = append(additions, inbound.Placeholder) // Add a placeholder for InUser
|
||||
inUserIdx := len(additions) - 1
|
||||
client := newClient(c, tunnel, additions)
|
||||
defer client.CloseIdleConnections()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
@@ -41,7 +42,8 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool],
|
||||
conn := N.NewBufferedConn(c)
|
||||
|
||||
keepAlive := true
|
||||
trusted := cache == nil // disable authenticate if lru is nil
|
||||
trusted := authenticator == nil // disable authenticate if lru is nil
|
||||
lastUser := ""
|
||||
|
||||
for keepAlive {
|
||||
peekMutex.Lock()
|
||||
@@ -57,12 +59,10 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool],
|
||||
|
||||
var resp *http.Response
|
||||
|
||||
if !trusted {
|
||||
var user string
|
||||
resp, user = authenticate(request, cache)
|
||||
additions = append(additions, inbound.WithInUser(user))
|
||||
trusted = resp == nil
|
||||
}
|
||||
resp, user = authenticate(request, authenticator) // always call authenticate function to get user
|
||||
trusted = trusted || resp == nil
|
||||
additions[inUserIdx] = inbound.WithInUser(user)
|
||||
|
||||
if trusted {
|
||||
if request.Method == http.MethodConnect {
|
||||
@@ -89,6 +89,13 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool],
|
||||
return // hijack connection
|
||||
}
|
||||
|
||||
// ensure there is a client with correct additions
|
||||
// when the authenticated user changed, outbound client should close idle connections
|
||||
if user != lastUser {
|
||||
client.CloseIdleConnections()
|
||||
lastUser = user
|
||||
}
|
||||
|
||||
removeHopByHopHeaders(request.Header)
|
||||
removeExtraHTTPHostPort(request)
|
||||
|
||||
@@ -138,34 +145,24 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool],
|
||||
_ = conn.Close()
|
||||
}
|
||||
|
||||
func authenticate(request *http.Request, cache *lru.LruCache[string, bool]) (resp *http.Response, u string) {
|
||||
authenticator := authStore.Authenticator()
|
||||
func authenticate(request *http.Request, authenticator auth.Authenticator) (resp *http.Response, user string) {
|
||||
if inbound.SkipAuthRemoteAddress(request.RemoteAddr) {
|
||||
authenticator = nil
|
||||
}
|
||||
if authenticator != nil {
|
||||
credential := parseBasicProxyAuthorization(request)
|
||||
if credential == "" {
|
||||
resp := responseWith(request, http.StatusProxyAuthRequired)
|
||||
if credential == "" && authenticator != nil {
|
||||
resp = responseWith(request, http.StatusProxyAuthRequired)
|
||||
resp.Header.Set("Proxy-Authenticate", "Basic")
|
||||
return resp, ""
|
||||
return
|
||||
}
|
||||
|
||||
authed, exist := cache.Get(credential)
|
||||
if !exist {
|
||||
user, pass, err := decodeBasicProxyAuthorization(credential)
|
||||
authed = err == nil && authenticator.Verify(user, pass)
|
||||
u = user
|
||||
cache.Set(credential, authed)
|
||||
}
|
||||
authed := authenticator == nil || (err == nil && authenticator.Verify(user, pass))
|
||||
if !authed {
|
||||
log.Infoln("Auth failed from %s", request.RemoteAddr)
|
||||
|
||||
return responseWith(request, http.StatusForbidden), u
|
||||
return responseWith(request, http.StatusForbidden), user
|
||||
}
|
||||
}
|
||||
|
||||
return nil, u
|
||||
log.Debugln("Auth success from %s -> %s", request.RemoteAddr, user)
|
||||
return
|
||||
}
|
||||
|
||||
func responseWith(request *http.Request, statusCode int) *http.Response {
|
||||
|
@@ -4,9 +4,10 @@ import (
|
||||
"net"
|
||||
|
||||
"github.com/metacubex/mihomo/adapter/inbound"
|
||||
"github.com/metacubex/mihomo/common/lru"
|
||||
"github.com/metacubex/mihomo/component/auth"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
"github.com/metacubex/mihomo/constant/features"
|
||||
authStore "github.com/metacubex/mihomo/listener/auth"
|
||||
)
|
||||
|
||||
type Listener struct {
|
||||
@@ -32,10 +33,20 @@ func (l *Listener) Close() error {
|
||||
}
|
||||
|
||||
func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) {
|
||||
return NewWithAuthenticate(addr, tunnel, true, additions...)
|
||||
return NewWithAuthenticator(addr, tunnel, authStore.Authenticator(), additions...)
|
||||
}
|
||||
|
||||
// NewWithAuthenticate
|
||||
// never change type traits because it's used in CFMA
|
||||
func NewWithAuthenticate(addr string, tunnel C.Tunnel, authenticate bool, additions ...inbound.Addition) (*Listener, error) {
|
||||
authenticator := authStore.Authenticator()
|
||||
if !authenticate {
|
||||
authenticator = nil
|
||||
}
|
||||
return NewWithAuthenticator(addr, tunnel, authenticator, additions...)
|
||||
}
|
||||
|
||||
func NewWithAuthenticator(addr string, tunnel C.Tunnel, authenticator auth.Authenticator, additions ...inbound.Addition) (*Listener, error) {
|
||||
isDefault := false
|
||||
if len(additions) == 0 {
|
||||
isDefault = true
|
||||
@@ -50,11 +61,6 @@ func NewWithAuthenticate(addr string, tunnel C.Tunnel, authenticate bool, additi
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var c *lru.LruCache[string, bool]
|
||||
if authenticate {
|
||||
c = lru.New[string, bool](lru.WithAge[string, bool](30))
|
||||
}
|
||||
|
||||
hl := &Listener{
|
||||
listener: l,
|
||||
addr: addr,
|
||||
@@ -79,7 +85,7 @@ func NewWithAuthenticate(addr string, tunnel C.Tunnel, authenticate bool, additi
|
||||
continue
|
||||
}
|
||||
}
|
||||
go HandleConn(conn, tunnel, c, additions...)
|
||||
go HandleConn(conn, tunnel, authenticator, additions...)
|
||||
}
|
||||
}()
|
||||
|
||||
|
@@ -4,9 +4,9 @@ import (
|
||||
"net"
|
||||
|
||||
"github.com/metacubex/mihomo/adapter/inbound"
|
||||
"github.com/metacubex/mihomo/common/lru"
|
||||
N "github.com/metacubex/mihomo/common/net"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
authStore "github.com/metacubex/mihomo/listener/auth"
|
||||
"github.com/metacubex/mihomo/listener/http"
|
||||
"github.com/metacubex/mihomo/listener/socks"
|
||||
"github.com/metacubex/mihomo/transport/socks4"
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
type Listener struct {
|
||||
listener net.Listener
|
||||
addr string
|
||||
cache *lru.LruCache[string, bool]
|
||||
closed bool
|
||||
}
|
||||
|
||||
@@ -53,7 +52,6 @@ func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener
|
||||
ml := &Listener{
|
||||
listener: l,
|
||||
addr: addr,
|
||||
cache: lru.New[string, bool](lru.WithAge[string, bool](30)),
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
@@ -70,14 +68,14 @@ func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener
|
||||
continue
|
||||
}
|
||||
}
|
||||
go handleConn(c, tunnel, ml.cache, additions...)
|
||||
go handleConn(c, tunnel, additions...)
|
||||
}
|
||||
}()
|
||||
|
||||
return ml, nil
|
||||
}
|
||||
|
||||
func handleConn(conn net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool], additions ...inbound.Addition) {
|
||||
func handleConn(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) {
|
||||
N.TCPKeepAlive(conn)
|
||||
|
||||
bufConn := N.NewBufferedConn(conn)
|
||||
@@ -92,6 +90,6 @@ func handleConn(conn net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool
|
||||
case socks5.Version:
|
||||
socks.HandleSocks5(bufConn, tunnel, additions...)
|
||||
default:
|
||||
http.HandleConn(bufConn, tunnel, cache, additions...)
|
||||
http.HandleConn(bufConn, tunnel, authStore.Authenticator(), additions...)
|
||||
}
|
||||
}
|
||||
|
@@ -1,29 +1,80 @@
|
||||
package sing_tun
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"github.com/metacubex/mihomo/component/process"
|
||||
"github.com/metacubex/mihomo/constant"
|
||||
"github.com/metacubex/mihomo/constant/features"
|
||||
"github.com/metacubex/mihomo/log"
|
||||
tun "github.com/metacubex/sing-tun"
|
||||
|
||||
"github.com/metacubex/sing-tun"
|
||||
"github.com/sagernet/netlink"
|
||||
"golang.org/x/sys/unix"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func (l *Listener) buildAndroidRules(tunOptions *tun.Options) error {
|
||||
packageManager, err := tun.NewPackageManager(l.handler)
|
||||
type packageManagerCallback struct{}
|
||||
|
||||
func (cb *packageManagerCallback) OnPackagesUpdated(packageCount int, sharedCount int) {}
|
||||
|
||||
func newPackageManager() (tun.PackageManager, error) {
|
||||
packageManager, err := tun.NewPackageManager(tun.PackageManagerOptions{
|
||||
Callback: &packageManagerCallback{},
|
||||
Logger: log.SingLogger,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
err = packageManager.Start()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return packageManager, nil
|
||||
}
|
||||
|
||||
var (
|
||||
globalPM tun.PackageManager
|
||||
pmOnce sync.Once
|
||||
pmErr error
|
||||
)
|
||||
|
||||
func getPackageManager() (tun.PackageManager, error) {
|
||||
pmOnce.Do(func() {
|
||||
globalPM, pmErr = newPackageManager()
|
||||
})
|
||||
return globalPM, pmErr
|
||||
}
|
||||
|
||||
func (l *Listener) buildAndroidRules(tunOptions *tun.Options) error {
|
||||
packageManager, err := getPackageManager()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l.packageManager = packageManager
|
||||
tunOptions.BuildAndroidRules(packageManager, l.handler)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *ListenerHandler) OnPackagesUpdated(packages int, sharedUsers int) {
|
||||
return
|
||||
func findPackageName(metadata *constant.Metadata) (string, error) {
|
||||
packageManager, err := getPackageManager()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
uid := metadata.Uid
|
||||
if sharedPackage, loaded := packageManager.SharedPackageByID(uid % 100000); loaded {
|
||||
return sharedPackage, nil
|
||||
}
|
||||
if packageName, loaded := packageManager.PackageByID(uid % 100000); loaded {
|
||||
return packageName, nil
|
||||
}
|
||||
return "", errors.New("package not found")
|
||||
}
|
||||
|
||||
func init() {
|
||||
if !features.CMFA {
|
||||
process.DefaultPackageNameResolver = findPackageName
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Listener) openAndroidHotspot(tunOptions tun.Options) {
|
||||
|
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/metacubex/mihomo/hub"
|
||||
"github.com/metacubex/mihomo/hub/executor"
|
||||
"github.com/metacubex/mihomo/log"
|
||||
"github.com/metacubex/mihomo/rules/provider"
|
||||
|
||||
"go.uber.org/automaxprocs/maxprocs"
|
||||
)
|
||||
@@ -48,6 +49,12 @@ func init() {
|
||||
|
||||
func main() {
|
||||
_, _ = maxprocs.Set(maxprocs.Logger(func(string, ...any) {}))
|
||||
|
||||
if len(os.Args) > 1 && os.Args[1] == "convert-ruleset" {
|
||||
provider.ConvertMain(os.Args[2:])
|
||||
return
|
||||
}
|
||||
|
||||
if version {
|
||||
fmt.Printf("Mihomo Meta %s %s %s with %s %s\n",
|
||||
C.Version, runtime.GOOS, runtime.GOARCH, runtime.Version(), C.BuildTime)
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"strings"
|
||||
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
P "github.com/metacubex/mihomo/constant/provider"
|
||||
"github.com/metacubex/mihomo/log"
|
||||
)
|
||||
|
||||
@@ -16,6 +17,10 @@ type classicalStrategy struct {
|
||||
parse func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error)
|
||||
}
|
||||
|
||||
func (c *classicalStrategy) Behavior() P.RuleBehavior {
|
||||
return P.Classical
|
||||
}
|
||||
|
||||
func (c *classicalStrategy) Match(metadata *C.Metadata) bool {
|
||||
for _, rule := range c.rules {
|
||||
if m, _ := rule.Match(metadata); m {
|
||||
|
@@ -1,9 +1,16 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/metacubex/mihomo/component/trie"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
P "github.com/metacubex/mihomo/constant/provider"
|
||||
"github.com/metacubex/mihomo/log"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
type domainStrategy struct {
|
||||
@@ -12,6 +19,10 @@ type domainStrategy struct {
|
||||
domainSet *trie.DomainSet
|
||||
}
|
||||
|
||||
func (d *domainStrategy) Behavior() P.RuleBehavior {
|
||||
return P.Domain
|
||||
}
|
||||
|
||||
func (d *domainStrategy) ShouldFindProcess() bool {
|
||||
return false
|
||||
}
|
||||
@@ -35,6 +46,10 @@ func (d *domainStrategy) Reset() {
|
||||
}
|
||||
|
||||
func (d *domainStrategy) Insert(rule string) {
|
||||
if strings.ContainsRune(rule, '/') {
|
||||
log.Warnln("invalid domain:[%s]", rule)
|
||||
return
|
||||
}
|
||||
err := d.domainTrie.Insert(rule, struct{}{})
|
||||
if err != nil {
|
||||
log.Warnln("invalid domain:[%s]", rule)
|
||||
@@ -48,6 +63,45 @@ func (d *domainStrategy) FinishInsert() {
|
||||
d.domainTrie = nil
|
||||
}
|
||||
|
||||
func (d *domainStrategy) FromMrs(r io.Reader, count int) error {
|
||||
domainSet, err := trie.ReadDomainSetBin(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.count = count
|
||||
d.domainSet = domainSet
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *domainStrategy) WriteMrs(w io.Writer) error {
|
||||
if d.domainSet == nil {
|
||||
return errors.New("nil domainSet")
|
||||
}
|
||||
return d.domainSet.WriteBin(w)
|
||||
}
|
||||
|
||||
func (d *domainStrategy) DumpMrs(f func(key string) bool) {
|
||||
if d.domainSet != nil {
|
||||
var keys []string
|
||||
d.domainSet.Foreach(func(key string) bool {
|
||||
keys = append(keys, key)
|
||||
return true
|
||||
})
|
||||
slices.Sort(keys)
|
||||
|
||||
for _, key := range keys {
|
||||
if _, ok := slices.BinarySearch(keys, "+."+key); ok {
|
||||
continue // ignore the rules added by trie internal processing
|
||||
}
|
||||
if !f(key) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var _ mrsRuleStrategy = (*domainStrategy)(nil)
|
||||
|
||||
func NewDomainStrategy() *domainStrategy {
|
||||
return &domainStrategy{}
|
||||
}
|
||||
|
@@ -1,8 +1,13 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net/netip"
|
||||
|
||||
"github.com/metacubex/mihomo/component/cidr"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
P "github.com/metacubex/mihomo/constant/provider"
|
||||
"github.com/metacubex/mihomo/log"
|
||||
|
||||
"go4.org/netipx"
|
||||
@@ -15,6 +20,10 @@ type ipcidrStrategy struct {
|
||||
//trie *trie.IpCidrTrie
|
||||
}
|
||||
|
||||
func (i *ipcidrStrategy) Behavior() P.RuleBehavior {
|
||||
return P.IPCIDR
|
||||
}
|
||||
|
||||
func (i *ipcidrStrategy) ShouldFindProcess() bool {
|
||||
return false
|
||||
}
|
||||
@@ -54,6 +63,34 @@ func (i *ipcidrStrategy) FinishInsert() {
|
||||
i.cidrSet.Merge()
|
||||
}
|
||||
|
||||
func (i *ipcidrStrategy) FromMrs(r io.Reader, count int) error {
|
||||
cidrSet, err := cidr.ReadIpCidrSet(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.count = count
|
||||
i.cidrSet = cidrSet
|
||||
if i.count > 0 {
|
||||
i.shouldResolveIP = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *ipcidrStrategy) WriteMrs(w io.Writer) error {
|
||||
if i.cidrSet == nil {
|
||||
return errors.New("nil cidrSet")
|
||||
}
|
||||
return i.cidrSet.WriteBin(w)
|
||||
}
|
||||
|
||||
func (i *ipcidrStrategy) DumpMrs(f func(key string) bool) {
|
||||
if i.cidrSet != nil {
|
||||
i.cidrSet.Foreach(func(prefix netip.Prefix) bool {
|
||||
return f(prefix.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (i *ipcidrStrategy) ToIpCidr() *netipx.IPSet {
|
||||
return i.cidrSet.ToIPSet()
|
||||
}
|
||||
|
@@ -0,0 +1,120 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
P "github.com/metacubex/mihomo/constant/provider"
|
||||
|
||||
"github.com/klauspost/compress/zstd"
|
||||
)
|
||||
|
||||
func ConvertToMrs(buf []byte, behavior P.RuleBehavior, format P.RuleFormat, w io.Writer) (err error) {
|
||||
strategy := newStrategy(behavior, nil)
|
||||
strategy, err = rulesParse(buf, strategy, format)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if strategy.Count() == 0 {
|
||||
return errors.New("empty rule")
|
||||
}
|
||||
if _strategy, ok := strategy.(mrsRuleStrategy); ok {
|
||||
if format == P.MrsRule { // export to TextRule
|
||||
_strategy.DumpMrs(func(key string) bool {
|
||||
_, err = fmt.Fprintln(w, key)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
var encoder *zstd.Encoder
|
||||
encoder, err = zstd.NewWriter(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
zstdErr := encoder.Close()
|
||||
if err == nil {
|
||||
err = zstdErr
|
||||
}
|
||||
}()
|
||||
|
||||
// header
|
||||
_, err = encoder.Write(MrsMagicBytes[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// behavior
|
||||
_behavior := []byte{behavior.Byte()}
|
||||
_, err = encoder.Write(_behavior[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// count
|
||||
count := int64(_strategy.Count())
|
||||
err = binary.Write(encoder, binary.BigEndian, count)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// extra (reserved for future using)
|
||||
var extra []byte
|
||||
err = binary.Write(encoder, binary.BigEndian, int64(len(extra)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = encoder.Write(extra)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return _strategy.WriteMrs(encoder)
|
||||
} else {
|
||||
return ErrInvalidFormat
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertMain(args []string) {
|
||||
if len(args) > 3 {
|
||||
behavior, err := P.ParseBehavior(args[0])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
format, err := P.ParseRuleFormat(args[1])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
source := args[2]
|
||||
target := args[3]
|
||||
|
||||
sourceFile, err := os.ReadFile(source)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
targetFile, err := os.OpenFile(target, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = ConvertToMrs(sourceFile, behavior, format, targetFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = targetFile.Close()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
panic("Usage: convert-ruleset <behavior> <format> <source file> <target file>")
|
||||
}
|
||||
}
|
@@ -0,0 +1,72 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/klauspost/compress/zstd"
|
||||
)
|
||||
|
||||
var MrsMagicBytes = [4]byte{'M', 'R', 'S', 1} // MRSv1
|
||||
|
||||
func rulesMrsParse(buf []byte, strategy ruleStrategy) (ruleStrategy, error) {
|
||||
if _strategy, ok := strategy.(mrsRuleStrategy); ok {
|
||||
reader, err := zstd.NewReader(bytes.NewReader(buf))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer reader.Close()
|
||||
|
||||
// header
|
||||
var header [4]byte
|
||||
_, err = io.ReadFull(reader, header[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if header != MrsMagicBytes {
|
||||
return nil, fmt.Errorf("invalid MrsMagic bytes")
|
||||
}
|
||||
|
||||
// behavior
|
||||
var _behavior [1]byte
|
||||
_, err = io.ReadFull(reader, _behavior[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _behavior[0] != strategy.Behavior().Byte() {
|
||||
return nil, fmt.Errorf("invalid behavior")
|
||||
}
|
||||
|
||||
// count
|
||||
var count int64
|
||||
err = binary.Read(reader, binary.BigEndian, &count)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// extra (reserved for future using)
|
||||
var length int64
|
||||
err = binary.Read(reader, binary.BigEndian, &length)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if length < 0 {
|
||||
return nil, errors.New("length is invalid")
|
||||
}
|
||||
if length > 0 {
|
||||
extra := make([]byte, length)
|
||||
_, err = io.ReadFull(reader, extra)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = _strategy.FromMrs(reader, int(count))
|
||||
return strategy, err
|
||||
} else {
|
||||
return nil, ErrInvalidFormat
|
||||
}
|
||||
}
|
@@ -32,28 +32,13 @@ func ParseRuleProvider(name string, mapping map[string]interface{}, parse func(t
|
||||
if err := decoder.Decode(mapping, schema); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var behavior P.RuleBehavior
|
||||
|
||||
switch schema.Behavior {
|
||||
case "domain":
|
||||
behavior = P.Domain
|
||||
case "ipcidr":
|
||||
behavior = P.IPCIDR
|
||||
case "classical":
|
||||
behavior = P.Classical
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported behavior type: %s", schema.Behavior)
|
||||
behavior, err := P.ParseBehavior(schema.Behavior)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var format P.RuleFormat
|
||||
|
||||
switch schema.Format {
|
||||
case "", "yaml":
|
||||
format = P.YamlRule
|
||||
case "text":
|
||||
format = P.TextRule
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported format type: %s", schema.Format)
|
||||
format, err := P.ParseRuleFormat(schema.Format)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var vehicle P.Vehicle
|
||||
|
@@ -4,16 +4,17 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/metacubex/mihomo/common/pool"
|
||||
"github.com/metacubex/mihomo/component/resource"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
P "github.com/metacubex/mihomo/constant/provider"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var tunnel P.Tunnel
|
||||
@@ -43,6 +44,7 @@ type RulePayload struct {
|
||||
}
|
||||
|
||||
type ruleStrategy interface {
|
||||
Behavior() P.RuleBehavior
|
||||
Match(metadata *C.Metadata) bool
|
||||
Count() int
|
||||
ShouldResolveIP() bool
|
||||
@@ -52,6 +54,13 @@ type ruleStrategy interface {
|
||||
FinishInsert()
|
||||
}
|
||||
|
||||
type mrsRuleStrategy interface {
|
||||
ruleStrategy
|
||||
FromMrs(r io.Reader, count int) error
|
||||
WriteMrs(w io.Writer) error
|
||||
DumpMrs(f func(key string) bool)
|
||||
}
|
||||
|
||||
func (rp *ruleSetProvider) Type() P.ProviderType {
|
||||
return P.Rule
|
||||
}
|
||||
@@ -152,9 +161,13 @@ func newStrategy(behavior P.RuleBehavior, parse func(tp, payload, target string,
|
||||
}
|
||||
|
||||
var ErrNoPayload = errors.New("file must have a `payload` field")
|
||||
var ErrInvalidFormat = errors.New("invalid format")
|
||||
|
||||
func rulesParse(buf []byte, strategy ruleStrategy, format P.RuleFormat) (ruleStrategy, error) {
|
||||
strategy.Reset()
|
||||
if format == P.MrsRule {
|
||||
return rulesMrsParse(buf, strategy)
|
||||
}
|
||||
|
||||
schema := &RulePayload{}
|
||||
|
||||
@@ -228,6 +241,8 @@ func rulesParse(buf []byte, strategy ruleStrategy, format P.RuleFormat) (ruleStr
|
||||
if len(schema.Payload) > 0 {
|
||||
str = schema.Payload[0]
|
||||
}
|
||||
default:
|
||||
return nil, ErrInvalidFormat
|
||||
}
|
||||
|
||||
if str == "" {
|
||||
|
@@ -34,6 +34,11 @@ const (
|
||||
aeadAes256Gcm = "AEAD_AES_256_GCM"
|
||||
aeadChacha20Poly1305 = "AEAD_CHACHA20_POLY1305"
|
||||
aeadXChacha20Poly1305 = "AEAD_XCHACHA20_POLY1305"
|
||||
aeadChacha8Poly1305 = "AEAD_CHACHA8_POLY1305"
|
||||
aeadXChacha8Poly1305 = "AEAD_XCHACHA8_POLY1305"
|
||||
aeadAes128Ccm = "AEAD_AES_128_CCM"
|
||||
aeadAes192Ccm = "AEAD_AES_192_CCM"
|
||||
aeadAes256Ccm = "AEAD_AES_256_CCM"
|
||||
)
|
||||
|
||||
// List of AEAD ciphers: key size in bytes and constructor
|
||||
@@ -46,6 +51,11 @@ var aeadList = map[string]struct {
|
||||
aeadAes256Gcm: {32, shadowaead.AESGCM},
|
||||
aeadChacha20Poly1305: {32, shadowaead.Chacha20Poly1305},
|
||||
aeadXChacha20Poly1305: {32, shadowaead.XChacha20Poly1305},
|
||||
aeadChacha8Poly1305: {32, shadowaead.Chacha8Poly1305},
|
||||
aeadXChacha8Poly1305: {32, shadowaead.XChacha8Poly1305},
|
||||
aeadAes128Ccm: {16, shadowaead.AESCCM},
|
||||
aeadAes192Ccm: {24, shadowaead.AESCCM},
|
||||
aeadAes256Ccm: {32, shadowaead.AESCCM},
|
||||
}
|
||||
|
||||
// List of stream ciphers: key size in bytes and constructor
|
||||
@@ -95,6 +105,16 @@ func PickCipher(name string, key []byte, password string) (Cipher, error) {
|
||||
name = aeadAes192Gcm
|
||||
case "AES-256-GCM":
|
||||
name = aeadAes256Gcm
|
||||
case "CHACHA8-IETF-POLY1305":
|
||||
name = aeadChacha8Poly1305
|
||||
case "XCHACHA8-IETF-POLY1305":
|
||||
name = aeadXChacha8Poly1305
|
||||
case "AES-128-CCM":
|
||||
name = aeadAes128Ccm
|
||||
case "AES-192-CCM":
|
||||
name = aeadAes192Ccm
|
||||
case "AES-256-CCM":
|
||||
name = aeadAes256Ccm
|
||||
}
|
||||
|
||||
if choice, ok := aeadList[name]; ok {
|
||||
|
@@ -7,6 +7,8 @@ import (
|
||||
"io"
|
||||
"strconv"
|
||||
|
||||
"github.com/metacubex/chacha"
|
||||
"gitlab.com/go-extension/aes-ccm"
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
"golang.org/x/crypto/hkdf"
|
||||
)
|
||||
@@ -75,6 +77,25 @@ func AESGCM(psk []byte) (Cipher, error) {
|
||||
return &metaCipher{psk: psk, makeAEAD: aesGCM}, nil
|
||||
}
|
||||
|
||||
func aesCCM(key []byte) (cipher.AEAD, error) {
|
||||
blk, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ccm.NewCCM(blk)
|
||||
}
|
||||
|
||||
// AESCCM creates a new Cipher with a pre-shared key. len(psk) must be
|
||||
// one of 16, 24, or 32 to select AES-128/196/256-GCM.
|
||||
func AESCCM(psk []byte) (Cipher, error) {
|
||||
switch l := len(psk); l {
|
||||
case 16, 24, 32: // AES 128/196/256
|
||||
default:
|
||||
return nil, aes.KeySizeError(l)
|
||||
}
|
||||
return &metaCipher{psk: psk, makeAEAD: aesCCM}, nil
|
||||
}
|
||||
|
||||
// Chacha20Poly1305 creates a new Cipher with a pre-shared key. len(psk)
|
||||
// must be 32.
|
||||
func Chacha20Poly1305(psk []byte) (Cipher, error) {
|
||||
@@ -92,3 +113,21 @@ func XChacha20Poly1305(psk []byte) (Cipher, error) {
|
||||
}
|
||||
return &metaCipher{psk: psk, makeAEAD: chacha20poly1305.NewX}, nil
|
||||
}
|
||||
|
||||
// Chacha8Poly1305 creates a new Cipher with a pre-shared key. len(psk)
|
||||
// must be 32.
|
||||
func Chacha8Poly1305(psk []byte) (Cipher, error) {
|
||||
if len(psk) != chacha.KeySize {
|
||||
return nil, KeySizeError(chacha.KeySize)
|
||||
}
|
||||
return &metaCipher{psk: psk, makeAEAD: chacha.NewChaCha8IETFPoly1305}, nil
|
||||
}
|
||||
|
||||
// XChacha8Poly1305 creates a new Cipher with a pre-shared key. len(psk)
|
||||
// must be 32.
|
||||
func XChacha8Poly1305(psk []byte) (Cipher, error) {
|
||||
if len(psk) != chacha.KeySize {
|
||||
return nil, KeySizeError(chacha.KeySize)
|
||||
}
|
||||
return &metaCipher{psk: psk, makeAEAD: chacha.NewXChaCha20IETFPoly1305}, nil
|
||||
}
|
||||
|
@@ -2,7 +2,8 @@ package shadowstream
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"github.com/aead/chacha20/chacha"
|
||||
|
||||
"github.com/metacubex/chacha"
|
||||
)
|
||||
|
||||
type chacha20key []byte
|
||||
@@ -11,7 +12,7 @@ func (k chacha20key) IVSize() int {
|
||||
return chacha.NonceSize
|
||||
}
|
||||
func (k chacha20key) Encrypter(iv []byte) cipher.Stream {
|
||||
c, _ := chacha.NewCipher(iv, k, 20)
|
||||
c, _ := chacha.NewChaCha20(iv, k)
|
||||
return c
|
||||
}
|
||||
func (k chacha20key) Decrypter(iv []byte) cipher.Stream {
|
||||
|
@@ -622,6 +622,10 @@ func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) {
|
||||
metadata.Process = filepath.Base(path)
|
||||
metadata.ProcessPath = path
|
||||
metadata.Uid = uid
|
||||
|
||||
if pkg, err := P.FindPackageName(metadata); err == nil { // for android (not CMFA) package names
|
||||
metadata.Process = pkg
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// check package names
|
||||
|
@@ -11,7 +11,6 @@ require (
|
||||
github.com/Kr328/tun2socket v0.0.0-20220414050025-d07c78d06d34 // indirect
|
||||
github.com/RyuaNerin/go-krypto v1.2.4 // indirect
|
||||
github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 // indirect
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
|
||||
github.com/andybalholm/brotli v1.0.6 // indirect
|
||||
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
@@ -37,23 +36,24 @@ require (
|
||||
github.com/hashicorp/yamux v0.1.1 // indirect
|
||||
github.com/insomniacslk/dhcp v0.0.0-20240529192340-51bc6136a0a6 // indirect
|
||||
github.com/josharian/native v1.1.0 // indirect
|
||||
github.com/klauspost/compress v1.17.4 // indirect
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mdlayher/netlink v1.7.2 // indirect
|
||||
github.com/mdlayher/socket v0.4.1 // indirect
|
||||
github.com/metacubex/chacha v0.1.0 // indirect
|
||||
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect
|
||||
github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec // indirect
|
||||
github.com/metacubex/mihomo v1.7.0 // indirect
|
||||
github.com/metacubex/quic-go v0.45.1-0.20240610004319-163fee60637e // indirect
|
||||
github.com/metacubex/randv2 v0.2.0 // indirect
|
||||
github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72 // indirect
|
||||
github.com/metacubex/sing-shadowsocks v0.2.6 // indirect
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.0 // indirect
|
||||
github.com/metacubex/sing-tun v0.2.7-0.20240627012306-9d1f5fc0b45e // indirect
|
||||
github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f // indirect
|
||||
github.com/metacubex/sing-shadowsocks v0.2.7 // indirect
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.1 // indirect
|
||||
github.com/metacubex/sing-tun v0.2.7-0.20240719141246-19c49ac9589d // indirect
|
||||
github.com/metacubex/sing-vmess v0.1.9-0.20240719134745-1df6fb20bbf9 // indirect
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20240618022557-a6efaa37127a // indirect
|
||||
github.com/metacubex/tfo-go v0.0.0-20240228025757-be1269474a66 // indirect
|
||||
github.com/metacubex/utls v1.6.6 // indirect
|
||||
@@ -69,9 +69,10 @@ require (
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect
|
||||
github.com/sagernet/fswatch v0.1.1 // indirect
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect
|
||||
github.com/sagernet/nftables v0.3.0-beta.4 // indirect
|
||||
github.com/sagernet/sing v0.5.0-alpha.10 // indirect
|
||||
github.com/sagernet/sing v0.5.0-alpha.13 // indirect
|
||||
github.com/sagernet/sing-mux v0.2.1-0.20240124034317-9bfb33698bb6 // indirect
|
||||
github.com/sagernet/sing-shadowtls v0.1.4 // indirect
|
||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect
|
||||
@@ -89,6 +90,7 @@ require (
|
||||
github.com/vishvananda/netns v0.0.4 // indirect
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
gitlab.com/go-extension/aes-ccm v0.0.0-20230221065045-e58665ef23c7 // indirect
|
||||
gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect
|
||||
go.uber.org/mock v0.4.0 // indirect
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
||||
@@ -97,7 +99,7 @@ require (
|
||||
golang.org/x/mod v0.18.0 // indirect
|
||||
golang.org/x/net v0.26.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.21.0 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.22.0 // indirect
|
||||
@@ -107,7 +109,7 @@ require (
|
||||
lukechampine.com/blake3 v1.3.0 // indirect
|
||||
)
|
||||
|
||||
replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20240617013425-3e3bd9dab6a2
|
||||
replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20240724044459-6f3cf5896297
|
||||
|
||||
replace cfa => ../../main/golang
|
||||
|
||||
|
@@ -7,8 +7,6 @@ github.com/RyuaNerin/go-krypto v1.2.4 h1:mXuNdK6M317aPV0llW6Xpjbo4moOlPF7Yxz4tb4
|
||||
github.com/RyuaNerin/go-krypto v1.2.4/go.mod h1:QqCYkoutU3yInyD9INt2PGolVRsc3W4oraQadVGXJ/8=
|
||||
github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 h1:cDVUiFo+npB0ZASqnw4q90ylaVAbnYyx0JYqK4YcGok=
|
||||
github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344/go.mod h1:9pIqrY6SXNL8vjRQE5Hd/OL5GyK/9MrGUWs87z/eFfk=
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
|
||||
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
||||
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
|
||||
@@ -77,8 +75,8 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF
|
||||
github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
||||
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
|
||||
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
@@ -93,6 +91,8 @@ github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/
|
||||
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
|
||||
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
|
||||
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
|
||||
github.com/metacubex/chacha v0.1.0 h1:tg9RSJ18NvL38cCWNyYH1eiG6qDCyyXIaTLQthon0sc=
|
||||
github.com/metacubex/chacha v0.1.0/go.mod h1:Djn9bPZxLTXbJFSeyo0/qzEzQI+gUSSzttuzZM75GH8=
|
||||
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvOzK9ubNCCkQ+ldc4YSH/rILn53l/xGBFHHI=
|
||||
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88=
|
||||
github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec h1:HxreOiFTUrJXJautEo8rnE1uKTVGY8wtZepY1Tii/Nc=
|
||||
@@ -101,18 +101,18 @@ github.com/metacubex/quic-go v0.45.1-0.20240610004319-163fee60637e h1:bLYn3GuRvW
|
||||
github.com/metacubex/quic-go v0.45.1-0.20240610004319-163fee60637e/go.mod h1:Yza2H7Ax1rxWPUcJx0vW+oAt9EsPuSiyQFhFabUPzwU=
|
||||
github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs=
|
||||
github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY=
|
||||
github.com/metacubex/sing v0.0.0-20240617013425-3e3bd9dab6a2 h1:N5tidgg/FRmkgPw/AjRwhLUinKDx/ODCSbvv9xqRoLM=
|
||||
github.com/metacubex/sing v0.0.0-20240617013425-3e3bd9dab6a2/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/metacubex/sing v0.0.0-20240724044459-6f3cf5896297 h1:YG/JkwGPbca5rUtEMHIu8ZuqzR7BSVm1iqY8hNoMeMA=
|
||||
github.com/metacubex/sing v0.0.0-20240724044459-6f3cf5896297/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72 h1:Wr4g1HCb5Z/QIFwFiVNjO2qL+dRu25+Mdn9xtAZZ+ew=
|
||||
github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72/go.mod h1:g7Mxj7b7zm7YVqD975mk/hSmrb0A0G4bVvIMr2MMzn8=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwVSgtE9R3QeFQ=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.6/go.mod h1:zIkMeSnb8Mbf4hdqhw0pjzkn1d99YJ3JQm/VBg5WMTg=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.0 h1:hqwT/AfI5d5UdPefIzR6onGHJfDXs5zgOM5QSgaM/9A=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.0/go.mod h1:LCKF6j1P94zN8ZS+LXRK1gmYTVGB3squivBSXAFnOg8=
|
||||
github.com/metacubex/sing-tun v0.2.7-0.20240627012306-9d1f5fc0b45e h1:o+zohxPRo45P35fS9u1zfdBgr+L/7S0ObGU6YjbVBIc=
|
||||
github.com/metacubex/sing-tun v0.2.7-0.20240627012306-9d1f5fc0b45e/go.mod h1:WwJGbCx7bQcBzuQXiDOJvZH27R0kIjKNNlISIWsL6kM=
|
||||
github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f h1:QjXrHKbTMBip/C+R79bvbfr42xH1gZl3uFb0RELdZiQ=
|
||||
github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f/go.mod h1:olVkD4FChQ5gKMHG4ZzuD7+fMkJY1G8vwOKpRehjrmY=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.7 h1:9f3Dt2+71TNp0e202llA2ug5h/rkWs2EZxQ5IMpf+9g=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.7/go.mod h1:X3x88XtJpBxG0W0/ECOJL6Ib0SJ3xdniAkU/6/RMWU0=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.1 h1:XIZBXlazp8EEoPp1S0DViAhLkJakjQ2f+AOwwdKKNYg=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.1/go.mod h1:BhOug03a/RbI7y6hp6q+6ITM1dXjnLTmeWBHSTwvv2Q=
|
||||
github.com/metacubex/sing-tun v0.2.7-0.20240719141246-19c49ac9589d h1:iYlepjRCYlPXtELupDL+pQjGqkCnQz4KQOfKImP9sog=
|
||||
github.com/metacubex/sing-tun v0.2.7-0.20240719141246-19c49ac9589d/go.mod h1:olbEx9yVcaw5tHTNlRamRoxmMKcvDvcVS1YLnQGzvWE=
|
||||
github.com/metacubex/sing-vmess v0.1.9-0.20240719134745-1df6fb20bbf9 h1:OAXiCosqY8xKDp3pqTW3qbrCprZ1l6WkrXSFSCwyY4I=
|
||||
github.com/metacubex/sing-vmess v0.1.9-0.20240719134745-1df6fb20bbf9/go.mod h1:olVkD4FChQ5gKMHG4ZzuD7+fMkJY1G8vwOKpRehjrmY=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20240618022557-a6efaa37127a h1:NpSGclHJUYndUwBmyIpFBSoBVg8PoVX7QQKhYg0DjM0=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20240618022557-a6efaa37127a/go.mod h1:uY+BYb0UEknLrqvbGcwi9i++KgrKxsurysgI6G1Pveo=
|
||||
github.com/metacubex/tfo-go v0.0.0-20240228025757-be1269474a66 h1:as/aO/fM8nv4W4pOr9EETP6kV/Oaujk3fUNyQSJK61c=
|
||||
@@ -151,6 +151,8 @@ github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkkD2QgdTuzQG263YZ+2emfpeyGqW0=
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM=
|
||||
github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs=
|
||||
github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o=
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis=
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||
github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I=
|
||||
@@ -205,6 +207,8 @@ github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
gitlab.com/go-extension/aes-ccm v0.0.0-20230221065045-e58665ef23c7 h1:UNrDfkQqiEYzdMlNsVvBYOAJWZjdktqFE9tQh5BT2+4=
|
||||
gitlab.com/go-extension/aes-ccm v0.0.0-20230221065045-e58665ef23c7/go.mod h1:E+rxHvJG9H6PUdzq9NRG6csuLN3XUx98BfGOVWNYnXs=
|
||||
gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec h1:FpfFs4EhNehiVfzQttTuxanPIT43FtkkCFypIod8LHo=
|
||||
gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec/go.mod h1:BZ1RAoRPbCxum9Grlv5aeksu2H8BiKehBYooU2LFiOQ=
|
||||
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
||||
@@ -243,8 +247,9 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
|
@@ -14,13 +14,12 @@ require (
|
||||
|
||||
replace github.com/metacubex/mihomo => ../../foss/golang/clash
|
||||
|
||||
replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20240617013425-3e3bd9dab6a2
|
||||
replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20240724044459-6f3cf5896297
|
||||
|
||||
require (
|
||||
github.com/3andne/restls-client-go v0.1.6 // indirect
|
||||
github.com/RyuaNerin/go-krypto v1.2.4 // indirect
|
||||
github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 // indirect
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
|
||||
github.com/andybalholm/brotli v1.0.6 // indirect
|
||||
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
@@ -45,22 +44,23 @@ require (
|
||||
github.com/hashicorp/yamux v0.1.1 // indirect
|
||||
github.com/insomniacslk/dhcp v0.0.0-20240529192340-51bc6136a0a6 // indirect
|
||||
github.com/josharian/native v1.1.0 // indirect
|
||||
github.com/klauspost/compress v1.17.4 // indirect
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mdlayher/netlink v1.7.2 // indirect
|
||||
github.com/mdlayher/socket v0.4.1 // indirect
|
||||
github.com/metacubex/chacha v0.1.0 // indirect
|
||||
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect
|
||||
github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec // indirect
|
||||
github.com/metacubex/quic-go v0.45.1-0.20240610004319-163fee60637e // indirect
|
||||
github.com/metacubex/randv2 v0.2.0 // indirect
|
||||
github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72 // indirect
|
||||
github.com/metacubex/sing-shadowsocks v0.2.6 // indirect
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.0 // indirect
|
||||
github.com/metacubex/sing-tun v0.2.7-0.20240627012306-9d1f5fc0b45e // indirect
|
||||
github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f // indirect
|
||||
github.com/metacubex/sing-shadowsocks v0.2.7 // indirect
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.1 // indirect
|
||||
github.com/metacubex/sing-tun v0.2.7-0.20240719141246-19c49ac9589d // indirect
|
||||
github.com/metacubex/sing-vmess v0.1.9-0.20240719134745-1df6fb20bbf9 // indirect
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20240618022557-a6efaa37127a // indirect
|
||||
github.com/metacubex/tfo-go v0.0.0-20240228025757-be1269474a66 // indirect
|
||||
github.com/metacubex/utls v1.6.6 // indirect
|
||||
@@ -74,9 +74,10 @@ require (
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect
|
||||
github.com/sagernet/fswatch v0.1.1 // indirect
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect
|
||||
github.com/sagernet/nftables v0.3.0-beta.4 // indirect
|
||||
github.com/sagernet/sing v0.5.0-alpha.10 // indirect
|
||||
github.com/sagernet/sing v0.5.0-alpha.13 // indirect
|
||||
github.com/sagernet/sing-mux v0.2.1-0.20240124034317-9bfb33698bb6 // indirect
|
||||
github.com/sagernet/sing-shadowtls v0.1.4 // indirect
|
||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect
|
||||
@@ -94,6 +95,7 @@ require (
|
||||
github.com/vishvananda/netns v0.0.4 // indirect
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
gitlab.com/go-extension/aes-ccm v0.0.0-20230221065045-e58665ef23c7 // indirect
|
||||
gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect
|
||||
go.uber.org/mock v0.4.0 // indirect
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
||||
@@ -101,7 +103,7 @@ require (
|
||||
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect
|
||||
golang.org/x/mod v0.18.0 // indirect
|
||||
golang.org/x/net v0.26.0 // indirect
|
||||
golang.org/x/sys v0.21.0 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.22.0 // indirect
|
||||
|
@@ -7,8 +7,6 @@ github.com/RyuaNerin/go-krypto v1.2.4 h1:mXuNdK6M317aPV0llW6Xpjbo4moOlPF7Yxz4tb4
|
||||
github.com/RyuaNerin/go-krypto v1.2.4/go.mod h1:QqCYkoutU3yInyD9INt2PGolVRsc3W4oraQadVGXJ/8=
|
||||
github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 h1:cDVUiFo+npB0ZASqnw4q90ylaVAbnYyx0JYqK4YcGok=
|
||||
github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344/go.mod h1:9pIqrY6SXNL8vjRQE5Hd/OL5GyK/9MrGUWs87z/eFfk=
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
|
||||
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
||||
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
|
||||
@@ -77,8 +75,8 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF
|
||||
github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
||||
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
|
||||
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
@@ -93,6 +91,8 @@ github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/
|
||||
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
|
||||
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
|
||||
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
|
||||
github.com/metacubex/chacha v0.1.0 h1:tg9RSJ18NvL38cCWNyYH1eiG6qDCyyXIaTLQthon0sc=
|
||||
github.com/metacubex/chacha v0.1.0/go.mod h1:Djn9bPZxLTXbJFSeyo0/qzEzQI+gUSSzttuzZM75GH8=
|
||||
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvOzK9ubNCCkQ+ldc4YSH/rILn53l/xGBFHHI=
|
||||
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88=
|
||||
github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec h1:HxreOiFTUrJXJautEo8rnE1uKTVGY8wtZepY1Tii/Nc=
|
||||
@@ -101,18 +101,18 @@ github.com/metacubex/quic-go v0.45.1-0.20240610004319-163fee60637e h1:bLYn3GuRvW
|
||||
github.com/metacubex/quic-go v0.45.1-0.20240610004319-163fee60637e/go.mod h1:Yza2H7Ax1rxWPUcJx0vW+oAt9EsPuSiyQFhFabUPzwU=
|
||||
github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs=
|
||||
github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY=
|
||||
github.com/metacubex/sing v0.0.0-20240617013425-3e3bd9dab6a2 h1:N5tidgg/FRmkgPw/AjRwhLUinKDx/ODCSbvv9xqRoLM=
|
||||
github.com/metacubex/sing v0.0.0-20240617013425-3e3bd9dab6a2/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/metacubex/sing v0.0.0-20240724044459-6f3cf5896297 h1:YG/JkwGPbca5rUtEMHIu8ZuqzR7BSVm1iqY8hNoMeMA=
|
||||
github.com/metacubex/sing v0.0.0-20240724044459-6f3cf5896297/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72 h1:Wr4g1HCb5Z/QIFwFiVNjO2qL+dRu25+Mdn9xtAZZ+ew=
|
||||
github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72/go.mod h1:g7Mxj7b7zm7YVqD975mk/hSmrb0A0G4bVvIMr2MMzn8=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwVSgtE9R3QeFQ=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.6/go.mod h1:zIkMeSnb8Mbf4hdqhw0pjzkn1d99YJ3JQm/VBg5WMTg=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.0 h1:hqwT/AfI5d5UdPefIzR6onGHJfDXs5zgOM5QSgaM/9A=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.0/go.mod h1:LCKF6j1P94zN8ZS+LXRK1gmYTVGB3squivBSXAFnOg8=
|
||||
github.com/metacubex/sing-tun v0.2.7-0.20240627012306-9d1f5fc0b45e h1:o+zohxPRo45P35fS9u1zfdBgr+L/7S0ObGU6YjbVBIc=
|
||||
github.com/metacubex/sing-tun v0.2.7-0.20240627012306-9d1f5fc0b45e/go.mod h1:WwJGbCx7bQcBzuQXiDOJvZH27R0kIjKNNlISIWsL6kM=
|
||||
github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f h1:QjXrHKbTMBip/C+R79bvbfr42xH1gZl3uFb0RELdZiQ=
|
||||
github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f/go.mod h1:olVkD4FChQ5gKMHG4ZzuD7+fMkJY1G8vwOKpRehjrmY=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.7 h1:9f3Dt2+71TNp0e202llA2ug5h/rkWs2EZxQ5IMpf+9g=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.7/go.mod h1:X3x88XtJpBxG0W0/ECOJL6Ib0SJ3xdniAkU/6/RMWU0=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.1 h1:XIZBXlazp8EEoPp1S0DViAhLkJakjQ2f+AOwwdKKNYg=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.1/go.mod h1:BhOug03a/RbI7y6hp6q+6ITM1dXjnLTmeWBHSTwvv2Q=
|
||||
github.com/metacubex/sing-tun v0.2.7-0.20240719141246-19c49ac9589d h1:iYlepjRCYlPXtELupDL+pQjGqkCnQz4KQOfKImP9sog=
|
||||
github.com/metacubex/sing-tun v0.2.7-0.20240719141246-19c49ac9589d/go.mod h1:olbEx9yVcaw5tHTNlRamRoxmMKcvDvcVS1YLnQGzvWE=
|
||||
github.com/metacubex/sing-vmess v0.1.9-0.20240719134745-1df6fb20bbf9 h1:OAXiCosqY8xKDp3pqTW3qbrCprZ1l6WkrXSFSCwyY4I=
|
||||
github.com/metacubex/sing-vmess v0.1.9-0.20240719134745-1df6fb20bbf9/go.mod h1:olVkD4FChQ5gKMHG4ZzuD7+fMkJY1G8vwOKpRehjrmY=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20240618022557-a6efaa37127a h1:NpSGclHJUYndUwBmyIpFBSoBVg8PoVX7QQKhYg0DjM0=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20240618022557-a6efaa37127a/go.mod h1:uY+BYb0UEknLrqvbGcwi9i++KgrKxsurysgI6G1Pveo=
|
||||
github.com/metacubex/tfo-go v0.0.0-20240228025757-be1269474a66 h1:as/aO/fM8nv4W4pOr9EETP6kV/Oaujk3fUNyQSJK61c=
|
||||
@@ -151,6 +151,8 @@ github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkkD2QgdTuzQG263YZ+2emfpeyGqW0=
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM=
|
||||
github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs=
|
||||
github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o=
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis=
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||
github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I=
|
||||
@@ -205,6 +207,8 @@ github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
gitlab.com/go-extension/aes-ccm v0.0.0-20230221065045-e58665ef23c7 h1:UNrDfkQqiEYzdMlNsVvBYOAJWZjdktqFE9tQh5BT2+4=
|
||||
gitlab.com/go-extension/aes-ccm v0.0.0-20230221065045-e58665ef23c7/go.mod h1:E+rxHvJG9H6PUdzq9NRG6csuLN3XUx98BfGOVWNYnXs=
|
||||
gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec h1:FpfFs4EhNehiVfzQttTuxanPIT43FtkkCFypIod8LHo=
|
||||
gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec/go.mod h1:BZ1RAoRPbCxum9Grlv5aeksu2H8BiKehBYooU2LFiOQ=
|
||||
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
||||
@@ -243,8 +247,9 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
|
@@ -57,6 +57,16 @@ func (set *IpCidrSet) Merge() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (set *IpCidrSet) Foreach(f func(prefix netip.Prefix) bool) {
|
||||
for _, r := range set.rr {
|
||||
for _, prefix := range r.Prefixes() {
|
||||
if !f(prefix) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ToIPSet not safe convert to *netipx.IPSet
|
||||
// be careful, must be used after Merge
|
||||
func (set *IpCidrSet) ToIPSet() *netipx.IPSet {
|
||||
|
@@ -123,16 +123,18 @@ func (t *DomainTrie[T]) Optimize() {
|
||||
t.root.optimize()
|
||||
}
|
||||
|
||||
func (t *DomainTrie[T]) Foreach(print func(domain string, data T)) {
|
||||
func (t *DomainTrie[T]) Foreach(fn func(domain string, data T) bool) {
|
||||
for key, data := range t.root.getChildren() {
|
||||
recursion([]string{key}, data, print)
|
||||
recursion([]string{key}, data, fn)
|
||||
if data != nil && data.inited {
|
||||
print(joinDomain([]string{key}), data.data)
|
||||
if !fn(joinDomain([]string{key}), data.data) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func recursion[T any](items []string, node *Node[T], fn func(domain string, data T)) {
|
||||
func recursion[T any](items []string, node *Node[T], fn func(domain string, data T) bool) bool {
|
||||
for key, data := range node.getChildren() {
|
||||
newItems := append([]string{key}, items...)
|
||||
if data != nil && data.inited {
|
||||
@@ -140,10 +142,15 @@ func recursion[T any](items []string, node *Node[T], fn func(domain string, data
|
||||
if domain[0] == domainStepByte {
|
||||
domain = complexWildcard + domain
|
||||
}
|
||||
fn(domain, data.Data())
|
||||
if !fn(domain, data.Data()) {
|
||||
return false
|
||||
}
|
||||
recursion(newItems, data, fn)
|
||||
}
|
||||
if !recursion(newItems, data, fn) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func joinDomain(items []string) string {
|
||||
|
@@ -28,8 +28,9 @@ type qElt struct{ s, e, col int }
|
||||
// NewDomainSet creates a new *DomainSet struct, from a DomainTrie.
|
||||
func (t *DomainTrie[T]) NewDomainSet() *DomainSet {
|
||||
reserveDomains := make([]string, 0)
|
||||
t.Foreach(func(domain string, data T) {
|
||||
t.Foreach(func(domain string, data T) bool {
|
||||
reserveDomains = append(reserveDomains, utils.Reverse(domain))
|
||||
return true
|
||||
})
|
||||
// ensure that the same prefix is continuous
|
||||
// and according to the ascending sequence of length
|
||||
@@ -136,6 +137,41 @@ func (ss *DomainSet) Has(key string) bool {
|
||||
|
||||
}
|
||||
|
||||
func (ss *DomainSet) keys(f func(key string) bool) {
|
||||
var currentKey []byte
|
||||
var traverse func(int, int) bool
|
||||
traverse = func(nodeId, bmIdx int) bool {
|
||||
if getBit(ss.leaves, nodeId) != 0 {
|
||||
if !f(string(currentKey)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
for ; ; bmIdx++ {
|
||||
if getBit(ss.labelBitmap, bmIdx) != 0 {
|
||||
return true
|
||||
}
|
||||
nextLabel := ss.labels[bmIdx-nodeId]
|
||||
currentKey = append(currentKey, nextLabel)
|
||||
nextNodeId := countZeros(ss.labelBitmap, ss.ranks, bmIdx+1)
|
||||
nextBmIdx := selectIthOne(ss.labelBitmap, ss.ranks, ss.selects, nextNodeId-1) + 1
|
||||
if !traverse(nextNodeId, nextBmIdx) {
|
||||
return false
|
||||
}
|
||||
currentKey = currentKey[:len(currentKey)-1]
|
||||
}
|
||||
}
|
||||
|
||||
traverse(0, 0)
|
||||
return
|
||||
}
|
||||
|
||||
func (ss *DomainSet) Foreach(f func(key string) bool) {
|
||||
ss.keys(func(key string) bool {
|
||||
return f(utils.Reverse(key))
|
||||
})
|
||||
}
|
||||
|
||||
func setBit(bm *[]uint64, i int, v int) {
|
||||
for i>>6 >= len(*bm) {
|
||||
*bm = append(*bm, 0)
|
||||
|
@@ -1,12 +1,29 @@
|
||||
package trie_test
|
||||
|
||||
import (
|
||||
"golang.org/x/exp/slices"
|
||||
"testing"
|
||||
|
||||
"github.com/metacubex/mihomo/component/trie"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func testDump(t *testing.T, tree *trie.DomainTrie[struct{}], set *trie.DomainSet) {
|
||||
var dataSrc []string
|
||||
tree.Foreach(func(domain string, data struct{}) bool {
|
||||
dataSrc = append(dataSrc, domain)
|
||||
return true
|
||||
})
|
||||
slices.Sort(dataSrc)
|
||||
var dataSet []string
|
||||
set.Foreach(func(key string) bool {
|
||||
dataSet = append(dataSet, key)
|
||||
return true
|
||||
})
|
||||
slices.Sort(dataSet)
|
||||
assert.Equal(t, dataSrc, dataSet)
|
||||
}
|
||||
|
||||
func TestDomainSet(t *testing.T) {
|
||||
tree := trie.New[struct{}]()
|
||||
domainSet := []string{
|
||||
@@ -33,6 +50,7 @@ func TestDomainSet(t *testing.T) {
|
||||
assert.True(t, set.Has("google.com"))
|
||||
assert.False(t, set.Has("qq.com"))
|
||||
assert.False(t, set.Has("www.baidu.com"))
|
||||
testDump(t, tree, set)
|
||||
}
|
||||
|
||||
func TestDomainSetComplexWildcard(t *testing.T) {
|
||||
@@ -55,6 +73,7 @@ func TestDomainSetComplexWildcard(t *testing.T) {
|
||||
assert.False(t, set.Has("google.com"))
|
||||
assert.True(t, set.Has("www.baidu.com"))
|
||||
assert.True(t, set.Has("test.test.baidu.com"))
|
||||
testDump(t, tree, set)
|
||||
}
|
||||
|
||||
func TestDomainSetWildcard(t *testing.T) {
|
||||
@@ -82,4 +101,5 @@ func TestDomainSetWildcard(t *testing.T) {
|
||||
assert.False(t, set.Has("a.www.google.com"))
|
||||
assert.False(t, set.Has("test.qq.com"))
|
||||
assert.False(t, set.Has("test.test.test.qq.com"))
|
||||
testDump(t, tree, set)
|
||||
}
|
||||
|
@@ -121,8 +121,9 @@ func TestTrie_Foreach(t *testing.T) {
|
||||
assert.NoError(t, tree.Insert(domain, localIP))
|
||||
}
|
||||
count := 0
|
||||
tree.Foreach(func(domain string, data netip.Addr) {
|
||||
tree.Foreach(func(domain string, data netip.Addr) bool {
|
||||
count++
|
||||
return true
|
||||
})
|
||||
assert.Equal(t, 7, count)
|
||||
}
|
||||
|
@@ -944,10 +944,17 @@ rule-providers:
|
||||
type: file
|
||||
rule3:
|
||||
# mrs类型ruleset,目前仅支持domain和ipcidr(即不支持classical),
|
||||
# behavior=domain,format=yaml 可以通过“mihomo convert-ruleset domain yaml XXX.yaml XXX.mrs”转换得到
|
||||
# behavior=domain,format=text 可以通过“mihomo convert-ruleset domain text XXX.text XXX.mrs”转换得到
|
||||
# behavior=ipcidr,format=yaml 可以通过“mihomo convert-ruleset ipcidr yaml XXX.yaml XXX.mrs”转换得到
|
||||
# behavior=ipcidr,format=text 可以通过“mihomo convert-ruleset ipcidr text XXX.text XXX.mrs”转换得到
|
||||
#
|
||||
# 对于behavior=domain:
|
||||
# - format=yaml 可以通过“mihomo convert-ruleset domain yaml XXX.yaml XXX.mrs”转换到mrs格式
|
||||
# - format=text 可以通过“mihomo convert-ruleset domain text XXX.text XXX.mrs”转换到mrs格式
|
||||
# - XXX.mrs 可以通过"mihomo convert-ruleset domain mrs XXX.mrs XXX.text"转换回text格式(暂不支持转换回ymal格式)
|
||||
#
|
||||
# 对于behavior=ipcidr:
|
||||
# - format=yaml 可以通过“mihomo convert-ruleset ipcidr yaml XXX.yaml XXX.mrs”转换到mrs格式
|
||||
# - format=text 可以通过“mihomo convert-ruleset ipcidr text XXX.text XXX.mrs”转换到mrs格式
|
||||
# - XXX.mrs 可以通过"mihomo convert-ruleset ipcidr mrs XXX.mrs XXX.text"转换回text格式(暂不支持转换回ymal格式)
|
||||
#
|
||||
type: http
|
||||
url: "url"
|
||||
format: mrs
|
||||
|
@@ -9,6 +9,8 @@ import (
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
P "github.com/metacubex/mihomo/constant/provider"
|
||||
"github.com/metacubex/mihomo/log"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
type domainStrategy struct {
|
||||
@@ -78,6 +80,26 @@ func (d *domainStrategy) WriteMrs(w io.Writer) error {
|
||||
return d.domainSet.WriteBin(w)
|
||||
}
|
||||
|
||||
func (d *domainStrategy) DumpMrs(f func(key string) bool) {
|
||||
if d.domainSet != nil {
|
||||
var keys []string
|
||||
d.domainSet.Foreach(func(key string) bool {
|
||||
keys = append(keys, key)
|
||||
return true
|
||||
})
|
||||
slices.Sort(keys)
|
||||
|
||||
for _, key := range keys {
|
||||
if _, ok := slices.BinarySearch(keys, "+."+key); ok {
|
||||
continue // ignore the rules added by trie internal processing
|
||||
}
|
||||
if !f(key) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var _ mrsRuleStrategy = (*domainStrategy)(nil)
|
||||
|
||||
func NewDomainStrategy() *domainStrategy {
|
||||
|
@@ -3,6 +3,7 @@ package provider
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net/netip"
|
||||
|
||||
"github.com/metacubex/mihomo/component/cidr"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
@@ -82,6 +83,14 @@ func (i *ipcidrStrategy) WriteMrs(w io.Writer) error {
|
||||
return i.cidrSet.WriteBin(w)
|
||||
}
|
||||
|
||||
func (i *ipcidrStrategy) DumpMrs(f func(key string) bool) {
|
||||
if i.cidrSet != nil {
|
||||
i.cidrSet.Foreach(func(prefix netip.Prefix) bool {
|
||||
return f(prefix.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (i *ipcidrStrategy) ToIpCidr() *netipx.IPSet {
|
||||
return i.cidrSet.ToIPSet()
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package provider
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
@@ -21,6 +22,17 @@ func ConvertToMrs(buf []byte, behavior P.RuleBehavior, format P.RuleFormat, w io
|
||||
return errors.New("empty rule")
|
||||
}
|
||||
if _strategy, ok := strategy.(mrsRuleStrategy); ok {
|
||||
if format == P.MrsRule { // export to TextRule
|
||||
_strategy.DumpMrs(func(key string) bool {
|
||||
_, err = fmt.Fprintln(w, key)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
var encoder *zstd.Encoder
|
||||
encoder, err = zstd.NewWriter(w)
|
||||
if err != nil {
|
||||
|
@@ -58,6 +58,7 @@ type mrsRuleStrategy interface {
|
||||
ruleStrategy
|
||||
FromMrs(r io.Reader, count int) error
|
||||
WriteMrs(w io.Writer) error
|
||||
DumpMrs(f func(key string) bool)
|
||||
}
|
||||
|
||||
func (rp *ruleSetProvider) Type() P.ProviderType {
|
||||
|
@@ -1,4 +1 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
pnpm commitlint --edit ${1}
|
||||
|
@@ -1,6 +1,3 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
# If tty is available, apply fix from https://github.com/typicode/husky/issues/968#issuecomment-1176848345
|
||||
if sh -c ": >/dev/tty" >/dev/null 2>/dev/null; then exec >/dev/tty 2>&1; fi
|
||||
|
||||
|
148
clash-nyanpasu/backend/Cargo.lock
generated
148
clash-nyanpasu/backend/Cargo.lock
generated
@@ -477,6 +477,17 @@ version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||
|
||||
[[package]]
|
||||
name = "atomic_enum"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99e1aca718ea7b89985790c94aad72d77533063fe00bc497bb79a7c2dae6a661"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "auto-launch"
|
||||
version = "0.5.0"
|
||||
@@ -517,6 +528,64 @@ dependencies = [
|
||||
"arrayvec 0.7.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum-core",
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.1",
|
||||
"http-body-util",
|
||||
"hyper 1.4.1",
|
||||
"hyper-util",
|
||||
"itoa 1.0.11",
|
||||
"matchit",
|
||||
"memchr",
|
||||
"mime",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rustversion",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_path_to_error",
|
||||
"serde_urlencoded",
|
||||
"sha1",
|
||||
"sync_wrapper 1.0.1",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum-core"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.1",
|
||||
"http-body-util",
|
||||
"mime",
|
||||
"pin-project-lite",
|
||||
"rustversion",
|
||||
"sync_wrapper 0.1.2",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backon"
|
||||
version = "0.4.4"
|
||||
@@ -937,6 +1006,7 @@ dependencies = [
|
||||
"ansi-str",
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"atomic_enum",
|
||||
"auto-launch",
|
||||
"backon",
|
||||
"base64 0.22.1",
|
||||
@@ -1417,6 +1487,12 @@ dependencies = [
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data-encoding"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2"
|
||||
|
||||
[[package]]
|
||||
name = "deelevate"
|
||||
version = "0.2.0"
|
||||
@@ -1623,7 +1699,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "dirs-utils"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/LibNyanpasu/nyanpasu-utils.git#a4d554586049a548528ed88c3f33a44450610f51"
|
||||
source = "git+https://github.com/LibNyanpasu/nyanpasu-utils.git#28f4f6234b67a2d806bd28a90112cb1da67bd0f6"
|
||||
dependencies = [
|
||||
"dirs-next",
|
||||
"thiserror",
|
||||
@@ -3575,6 +3651,12 @@ version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
|
||||
|
||||
[[package]]
|
||||
name = "matchit"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
|
||||
|
||||
[[package]]
|
||||
name = "maybe-rayon"
|
||||
version = "0.1.1"
|
||||
@@ -3977,10 +4059,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nyanpasu-ipc"
|
||||
version = "1.0.3"
|
||||
source = "git+https://github.com/LibNyanpasu/nyanpasu-service.git#10b455d0ee1c366f1ed3fcaa26b37764ab00c69b"
|
||||
version = "1.0.4"
|
||||
source = "git+https://github.com/LibNyanpasu/nyanpasu-service.git#0978120ffa67cda1d50fd5cf80bda320d7e744f3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
"derive_builder",
|
||||
"futures",
|
||||
"futures-util",
|
||||
@@ -4002,7 +4085,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "nyanpasu-utils"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/LibNyanpasu/nyanpasu-utils.git#a4d554586049a548528ed88c3f33a44450610f51"
|
||||
source = "git+https://github.com/LibNyanpasu/nyanpasu-utils.git#28f4f6234b67a2d806bd28a90112cb1da67bd0f6"
|
||||
dependencies = [
|
||||
"constcat",
|
||||
"derive_builder",
|
||||
@@ -4284,7 +4367,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "os-utils"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/LibNyanpasu/nyanpasu-utils.git#a4d554586049a548528ed88c3f33a44450610f51"
|
||||
source = "git+https://github.com/LibNyanpasu/nyanpasu-utils.git#28f4f6234b67a2d806bd28a90112cb1da67bd0f6"
|
||||
dependencies = [
|
||||
"nix 0.29.0",
|
||||
"shared_child",
|
||||
@@ -5189,7 +5272,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper",
|
||||
"sync_wrapper 0.1.2",
|
||||
"system-configuration",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
@@ -5606,6 +5689,16 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_path_to_error"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6"
|
||||
dependencies = [
|
||||
"itoa 1.0.11",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_repr"
|
||||
version = "0.1.19"
|
||||
@@ -6069,6 +6162,12 @@ version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
|
||||
|
||||
[[package]]
|
||||
name = "sys-locale"
|
||||
version = "0.2.4"
|
||||
@@ -6683,9 +6782,9 @@ checksum = "c7c4ceeeca15c8384bbc3e011dbd8fccb7f068a440b752b7d9b32ceb0ca0e2e8"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.39.1"
|
||||
version = "1.39.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d040ac2b29ab03b09d4129c2f5bbd012a3ac2f79d38ff506a4bf8dd34b0eac8a"
|
||||
checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
@@ -6730,6 +6829,18 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-tungstenite"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"log",
|
||||
"tokio",
|
||||
"tungstenite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.11"
|
||||
@@ -6835,6 +6946,7 @@ dependencies = [
|
||||
"tokio",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6855,6 +6967,7 @@ version = "0.1.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
|
||||
dependencies = [
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
@@ -6988,6 +7101,25 @@ version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||
|
||||
[[package]]
|
||||
name = "tungstenite"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"data-encoding",
|
||||
"http 1.1.0",
|
||||
"httparse",
|
||||
"log",
|
||||
"rand 0.8.5",
|
||||
"sha1",
|
||||
"thiserror",
|
||||
"url",
|
||||
"utf-8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
|
@@ -18,7 +18,9 @@ rustc_version = "0.4"
|
||||
semver = "1.0"
|
||||
|
||||
[dependencies]
|
||||
nyanpasu-ipc = { git = "https://github.com/LibNyanpasu/nyanpasu-service.git" }
|
||||
nyanpasu-ipc = { git = "https://github.com/LibNyanpasu/nyanpasu-service.git", features = [
|
||||
"client",
|
||||
] }
|
||||
nyanpasu-utils = { git = "https://github.com/LibNyanpasu/nyanpasu-utils.git" }
|
||||
which = "6"
|
||||
anyhow = "1.0"
|
||||
@@ -112,6 +114,7 @@ humansize = "2.1.3"
|
||||
convert_case = "0.6.0"
|
||||
os_pipe = "1.2.0"
|
||||
whoami = "1.5.1"
|
||||
atomic_enum = "0.3.0"
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
cocoa = "0.25.0"
|
||||
|
@@ -6,7 +6,10 @@ use crate::{
|
||||
utils::dirs,
|
||||
};
|
||||
use anyhow::{bail, Result};
|
||||
use nyanpasu_ipc::{api::status::CoreState, utils::get_current_ts};
|
||||
use nyanpasu_ipc::{
|
||||
api::{core::start::CoreStartReq, status::CoreState},
|
||||
utils::get_current_ts,
|
||||
};
|
||||
use nyanpasu_utils::{
|
||||
core::{
|
||||
instance::{CoreInstance, CoreInstanceBuilder},
|
||||
@@ -40,13 +43,18 @@ pub enum RunType {
|
||||
|
||||
impl Default for RunType {
|
||||
fn default() -> Self {
|
||||
let enable_service = Config::verge()
|
||||
let enable_service = {
|
||||
*Config::verge()
|
||||
.latest()
|
||||
.enable_service_mode
|
||||
.unwrap_or(false);
|
||||
if enable_service {
|
||||
.as_ref()
|
||||
.unwrap_or(&false)
|
||||
};
|
||||
if enable_service && crate::core::service::ipc::get_ipc_state().is_connected() {
|
||||
tracing::info!("run core as service");
|
||||
RunType::Service
|
||||
} else {
|
||||
tracing::info!("run core as child process");
|
||||
RunType::Normal
|
||||
}
|
||||
}
|
||||
@@ -59,7 +67,10 @@ enum Instance {
|
||||
stated_changed_at: Arc<AtomicI64>,
|
||||
kill_flag: Arc<AtomicBool>,
|
||||
},
|
||||
Service,
|
||||
Service {
|
||||
config_path: PathBuf,
|
||||
core_type: nyanpasu_utils::core::CoreType,
|
||||
},
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
@@ -93,7 +104,10 @@ impl Instance {
|
||||
stated_changed_at: Arc::new(AtomicI64::new(get_current_ts())),
|
||||
})
|
||||
}
|
||||
RunType::Service => Ok(Instance::Service),
|
||||
RunType::Service => Ok(Instance::Service {
|
||||
config_path,
|
||||
core_type,
|
||||
}),
|
||||
RunType::Elevated => {
|
||||
todo!()
|
||||
}
|
||||
@@ -111,13 +125,16 @@ impl Instance {
|
||||
let child = child.lock();
|
||||
child.clone()
|
||||
};
|
||||
let is_premium = {
|
||||
let (is_premium, core_type) = {
|
||||
let child = child.lock();
|
||||
(
|
||||
matches!(
|
||||
child.core_type,
|
||||
nyanpasu_utils::core::CoreType::Clash(
|
||||
nyanpasu_utils::core::ClashCoreType::ClashPremium
|
||||
)
|
||||
),
|
||||
child.core_type.clone(),
|
||||
)
|
||||
};
|
||||
let (tx, mut rx) = tokio::sync::mpsc::channel::<anyhow::Result<()>>(1); // use mpsc channel just to avoid type moved error, though it never fails
|
||||
@@ -127,7 +144,7 @@ impl Instance {
|
||||
tokio::spawn(async move {
|
||||
match instance.run().await {
|
||||
Ok((_, mut rx)) => {
|
||||
kill_flag.store(false, Ordering::Relaxed); // reset kill flag
|
||||
kill_flag.store(false, Ordering::Release); // reset kill flag
|
||||
let mut err_buf: Vec<String> = Vec::with_capacity(6);
|
||||
loop {
|
||||
if let Some(event) = rx.recv().await {
|
||||
@@ -135,19 +152,19 @@ impl Instance {
|
||||
CommandEvent::Stdout(line) => {
|
||||
if is_premium {
|
||||
let log = api::parse_log(line.clone());
|
||||
log::info!(target: "app", "[clash]: {}", log);
|
||||
log::info!(target: "app", "[{}]: {}", core_type, log);
|
||||
} else {
|
||||
log::info!(target: "app", "[clash]: {}", line);
|
||||
log::info!(target: "app", "[{}]: {}", core_type, line);
|
||||
}
|
||||
Logger::global().set_log(line);
|
||||
}
|
||||
CommandEvent::Stderr(line) => {
|
||||
log::error!(target: "app", "[clash]: {}", line);
|
||||
log::error!(target: "app", "[{}]: {}", core_type, line);
|
||||
err_buf.push(line.clone());
|
||||
Logger::global().set_log(line);
|
||||
}
|
||||
CommandEvent::Error(e) => {
|
||||
log::error!(target: "app", "[clash]: {}", e);
|
||||
log::error!(target: "app", "[{}]: {}", core_type, e);
|
||||
let err = anyhow::anyhow!(format!(
|
||||
"{}\n{}",
|
||||
e,
|
||||
@@ -177,7 +194,7 @@ impl Instance {
|
||||
));
|
||||
tracing::error!("{}\n{}", err, err_buf.join("\n"));
|
||||
if tx.send(Err(err)).await.is_err()
|
||||
&& !kill_flag.load(Ordering::Relaxed)
|
||||
&& !kill_flag.load(Ordering::Acquire)
|
||||
{
|
||||
std::thread::spawn(move || {
|
||||
block_on(async {
|
||||
@@ -213,14 +230,24 @@ impl Instance {
|
||||
rx.recv().await.unwrap()?;
|
||||
Ok(())
|
||||
}
|
||||
Instance::Service => {
|
||||
todo!()
|
||||
Instance::Service {
|
||||
config_path,
|
||||
core_type,
|
||||
} => {
|
||||
let payload = CoreStartReq {
|
||||
config_file: Cow::Borrowed(config_path),
|
||||
core_type: Cow::Borrowed(core_type),
|
||||
};
|
||||
nyanpasu_ipc::client::shortcuts::Client::service_default()
|
||||
.start_core(&payload)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn stop(&self) -> Result<()> {
|
||||
let state = self.state();
|
||||
let state = self.state().await;
|
||||
match self {
|
||||
Instance::Child {
|
||||
child,
|
||||
@@ -230,7 +257,7 @@ impl Instance {
|
||||
if matches!(state.as_ref(), CoreState::Stopped(_)) {
|
||||
anyhow::bail!("core is already stopped");
|
||||
}
|
||||
kill_flag.store(true, Ordering::Relaxed);
|
||||
kill_flag.store(true, Ordering::Release);
|
||||
let child = {
|
||||
let child = child.lock();
|
||||
child.clone()
|
||||
@@ -239,35 +266,47 @@ impl Instance {
|
||||
stated_changed_at.store(get_current_ts(), Ordering::Relaxed);
|
||||
Ok(())
|
||||
}
|
||||
Instance::Service => {
|
||||
todo!()
|
||||
Instance::Service { .. } => {
|
||||
Ok(nyanpasu_ipc::client::shortcuts::Client::service_default()
|
||||
.stop_core()
|
||||
.await?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn restart(&self) -> Result<()> {
|
||||
let state = self.state();
|
||||
let state = self.state().await;
|
||||
if matches!(state.as_ref(), CoreState::Running) {
|
||||
self.stop().await?;
|
||||
}
|
||||
self.start().await
|
||||
}
|
||||
|
||||
pub fn state<'a>(&self) -> Cow<'a, CoreState> {
|
||||
pub async fn state<'a>(&self) -> Cow<'a, CoreState> {
|
||||
match self {
|
||||
Instance::Child { child, .. } => {
|
||||
let this = child.lock();
|
||||
Cow::Owned(match this.state() {
|
||||
Cow::Borrowed(match this.state() {
|
||||
nyanpasu_utils::core::instance::CoreInstanceState::Running => {
|
||||
CoreState::Running
|
||||
&CoreState::Running
|
||||
}
|
||||
nyanpasu_utils::core::instance::CoreInstanceState::Stopped => {
|
||||
CoreState::Stopped(None)
|
||||
&CoreState::Stopped(None)
|
||||
}
|
||||
})
|
||||
}
|
||||
Instance::Service => {
|
||||
todo!()
|
||||
Instance::Service { .. } => {
|
||||
let status = nyanpasu_ipc::client::shortcuts::Client::service_default()
|
||||
.status()
|
||||
.await
|
||||
.map(|info| match info.core_infos.state {
|
||||
nyanpasu_ipc::api::status::CoreState::Running => CoreState::Running,
|
||||
nyanpasu_ipc::api::status::CoreState::Stopped(_) => {
|
||||
CoreState::Stopped(None)
|
||||
}
|
||||
})
|
||||
.unwrap_or(CoreState::Stopped(None));
|
||||
Cow::Owned(status)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -331,7 +370,7 @@ impl CoreManager {
|
||||
instance.as_ref().cloned()
|
||||
};
|
||||
if let Some(instance) = instance.as_ref() {
|
||||
if matches!(instance.state().as_ref(), CoreState::Running) {
|
||||
if matches!(instance.state().await.as_ref(), CoreState::Running) {
|
||||
log::debug!(target: "app", "core is already running, stop it first...");
|
||||
instance.stop().await?;
|
||||
}
|
||||
@@ -343,7 +382,7 @@ impl CoreManager {
|
||||
Config::clash()
|
||||
.latest()
|
||||
.prepare_external_controller_port()?;
|
||||
let instance = Arc::new(Instance::try_new(RunType::Normal)?);
|
||||
let instance = Arc::new(Instance::try_new(RunType::default())?);
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
@@ -406,7 +445,7 @@ impl CoreManager {
|
||||
this.take()
|
||||
};
|
||||
if let Some(instance) = instance {
|
||||
if matches!(instance.state().as_ref(), CoreState::Running) {
|
||||
if matches!(instance.state().await.as_ref(), CoreState::Running) {
|
||||
log::debug!(target: "app", "core is running, stop it first...");
|
||||
instance.stop().await?;
|
||||
}
|
||||
|
@@ -8,7 +8,6 @@ pub mod sysopt;
|
||||
pub mod tasks;
|
||||
pub mod tray;
|
||||
pub mod updater;
|
||||
pub mod win_service;
|
||||
pub mod win_uwp;
|
||||
pub use self::clash::core::*;
|
||||
pub mod migration;
|
||||
|
@@ -41,6 +41,28 @@ pub async fn install_service() -> anyhow::Result<()> {
|
||||
child.code().unwrap()
|
||||
);
|
||||
}
|
||||
// Due to most platform, the service will be started automatically after installed
|
||||
if !super::ipc::HEALTH_CHECK_RUNNING.load(std::sync::atomic::Ordering::Relaxed) {
|
||||
super::ipc::spawn_health_check();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_service() -> anyhow::Result<()> {
|
||||
let child = tokio::task::spawn_blocking(move || {
|
||||
RunasCommand::new(SERVICE_PATH.as_path())
|
||||
.args(&["update"])
|
||||
.gui(true)
|
||||
.show(true)
|
||||
.status()
|
||||
})
|
||||
.await??;
|
||||
if !child.success() {
|
||||
anyhow::bail!(
|
||||
"failed to update service, exit code: {}",
|
||||
child.code().unwrap()
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -59,6 +81,12 @@ pub async fn uninstall_service() -> anyhow::Result<()> {
|
||||
child.code().unwrap()
|
||||
);
|
||||
}
|
||||
let _ = super::ipc::KILL_FLAG.compare_exchange(
|
||||
false,
|
||||
true,
|
||||
std::sync::atomic::Ordering::Acquire,
|
||||
std::sync::atomic::Ordering::Relaxed,
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -77,6 +105,9 @@ pub async fn start_service() -> anyhow::Result<()> {
|
||||
child.code().unwrap()
|
||||
);
|
||||
}
|
||||
if !super::ipc::HEALTH_CHECK_RUNNING.load(std::sync::atomic::Ordering::Acquire) {
|
||||
super::ipc::spawn_health_check();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -95,6 +126,12 @@ pub async fn stop_service() -> anyhow::Result<()> {
|
||||
child.code().unwrap()
|
||||
);
|
||||
}
|
||||
let _ = super::ipc::KILL_FLAG.compare_exchange_weak(
|
||||
false,
|
||||
true,
|
||||
std::sync::atomic::Ordering::Acquire,
|
||||
std::sync::atomic::Ordering::Relaxed,
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -113,10 +150,13 @@ pub async fn restart_service() -> anyhow::Result<()> {
|
||||
child.code().unwrap()
|
||||
);
|
||||
}
|
||||
if !super::ipc::HEALTH_CHECK_RUNNING.load(std::sync::atomic::Ordering::Acquire) {
|
||||
super::ipc::spawn_health_check();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn status() -> anyhow::Result<nyanpasu_ipc::types::ServiceStatus> {
|
||||
pub async fn status<'a>() -> anyhow::Result<nyanpasu_ipc::types::StatusInfo<'a>> {
|
||||
let child = tokio::process::Command::new(SERVICE_PATH.as_path())
|
||||
.args(["status", "--json"])
|
||||
.output()
|
||||
@@ -128,6 +168,5 @@ pub async fn status() -> anyhow::Result<nyanpasu_ipc::types::ServiceStatus> {
|
||||
);
|
||||
}
|
||||
let mut status = String::from_utf8(child.stdout)?;
|
||||
let status: nyanpasu_ipc::types::ServiceStatus = unsafe { simd_json::from_str(&mut status)? };
|
||||
Ok(status)
|
||||
Ok(unsafe { simd_json::serde::from_str(&mut status)? })
|
||||
}
|
||||
|
@@ -1,4 +1,84 @@
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use atomic_enum::atomic_enum;
|
||||
|
||||
use delay_timer::prelude::future_lite::block_on;
|
||||
use nyanpasu_ipc::types::ServiceStatus;
|
||||
use serde::Serialize;
|
||||
use tracing_attributes::instrument;
|
||||
|
||||
#[derive(PartialEq, Eq, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[atomic_enum]
|
||||
pub enum IpcState {
|
||||
Connected,
|
||||
Disconnected,
|
||||
}
|
||||
|
||||
impl IpcState {
|
||||
pub fn is_connected(&self) -> bool {
|
||||
*self == IpcState::Connected
|
||||
}
|
||||
}
|
||||
|
||||
static IPC_STATE: AtomicIpcState = AtomicIpcState::new(IpcState::Disconnected);
|
||||
pub(super) static KILL_FLAG: AtomicBool = AtomicBool::new(false);
|
||||
pub(super) static HEALTH_CHECK_RUNNING: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
pub fn get_ipc_state() -> IpcState {
|
||||
IPC_STATE.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub(super) fn set_ipc_state(state: IpcState) {
|
||||
IPC_STATE.store(state, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub(super) fn spawn_health_check() {
|
||||
KILL_FLAG.store(false, Ordering::Relaxed);
|
||||
std::thread::spawn(|| {
|
||||
HEALTH_CHECK_RUNNING.store(true, Ordering::Release);
|
||||
block_on(async {
|
||||
loop {
|
||||
if KILL_FLAG.load(Ordering::Acquire) {
|
||||
HEALTH_CHECK_RUNNING.store(false, Ordering::Release);
|
||||
break;
|
||||
}
|
||||
health_check().await;
|
||||
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
async fn health_check() {
|
||||
match super::control::status().await {
|
||||
Ok(info) => match info.status {
|
||||
ServiceStatus::Running => {
|
||||
let _ = IPC_STATE.compare_exchange_weak(
|
||||
IpcState::Disconnected,
|
||||
IpcState::Connected,
|
||||
Ordering::SeqCst,
|
||||
Ordering::Relaxed,
|
||||
);
|
||||
}
|
||||
ServiceStatus::Stopped | ServiceStatus::NotInstalled => {
|
||||
let _ = IPC_STATE.compare_exchange_weak(
|
||||
IpcState::Connected,
|
||||
IpcState::Disconnected,
|
||||
Ordering::SeqCst,
|
||||
Ordering::Relaxed,
|
||||
);
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
tracing::error!("IPC health check failed: {}", e);
|
||||
let _ = IPC_STATE.compare_exchange_weak(
|
||||
IpcState::Connected,
|
||||
IpcState::Disconnected,
|
||||
Ordering::SeqCst,
|
||||
Ordering::Relaxed,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,9 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use nyanpasu_ipc::types::StatusInfo;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::utils::dirs::app_install_dir;
|
||||
use crate::{config::Config, utils::dirs::app_install_dir};
|
||||
|
||||
pub mod control;
|
||||
pub mod ipc;
|
||||
@@ -12,3 +13,24 @@ static SERVICE_PATH: Lazy<PathBuf> = Lazy::new(|| {
|
||||
let app_path = app_install_dir().unwrap();
|
||||
app_path.join(format!("{}{}", SERVICE_NAME, std::env::consts::EXE_SUFFIX))
|
||||
});
|
||||
|
||||
pub async fn init_service() {
|
||||
let enable_service = {
|
||||
*Config::verge()
|
||||
.latest()
|
||||
.enable_service_mode
|
||||
.as_ref()
|
||||
.unwrap_or(&false)
|
||||
};
|
||||
if let Ok(StatusInfo {
|
||||
status: nyanpasu_ipc::types::ServiceStatus::Running,
|
||||
..
|
||||
}) = control::status().await
|
||||
{
|
||||
if !enable_service {
|
||||
control::stop_service().await.unwrap();
|
||||
} else {
|
||||
ipc::spawn_health_check()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,181 +0,0 @@
|
||||
#![cfg(target_os = "windows")]
|
||||
|
||||
use crate::{
|
||||
config::{nyanpasu::ClashCore, Config},
|
||||
utils::dirs,
|
||||
};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use deelevate::{PrivilegeLevel, Token};
|
||||
use runas::Command as RunasCommand;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
collections::HashMap, env::current_exe, os::windows::process::CommandExt, path::PathBuf,
|
||||
process::Command as StdCommand, time::Duration,
|
||||
};
|
||||
use tokio::time::sleep;
|
||||
|
||||
const SERVICE_URL: &str = "http://127.0.0.1:33211";
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct ResponseBody {
|
||||
pub core_type: Option<String>,
|
||||
pub bin_path: String,
|
||||
pub config_dir: String,
|
||||
pub log_file: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct JsonResponse {
|
||||
pub code: u64,
|
||||
pub msg: String,
|
||||
pub data: Option<ResponseBody>,
|
||||
}
|
||||
|
||||
/// Install the Clash Nyanpasu Service
|
||||
/// 该函数应该在协程或者线程中执行,避免UAC弹窗阻塞主线程
|
||||
pub async fn install_service() -> Result<()> {
|
||||
let binary_path = dirs::service_path()?;
|
||||
let install_path = binary_path.with_file_name("install-service.exe");
|
||||
|
||||
if !install_path.exists() {
|
||||
bail!("installer exe not found");
|
||||
}
|
||||
|
||||
let token = Token::with_current_process()?;
|
||||
let level = token.privilege_level()?;
|
||||
|
||||
let status = match level {
|
||||
PrivilegeLevel::NotPrivileged => RunasCommand::new(install_path).show(false).status()?,
|
||||
_ => StdCommand::new(install_path)
|
||||
.creation_flags(0x08000000)
|
||||
.status()?,
|
||||
};
|
||||
|
||||
if !status.success() {
|
||||
bail!(
|
||||
"failed to install service with status {}",
|
||||
status.code().unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Uninstall the Clash Nyanpasu Service
|
||||
/// 该函数应该在协程或者线程中执行,避免UAC弹窗阻塞主线程
|
||||
pub async fn uninstall_service() -> Result<()> {
|
||||
let binary_path = dirs::service_path()?;
|
||||
let uninstall_path = binary_path.with_file_name("uninstall-service.exe");
|
||||
|
||||
if !uninstall_path.exists() {
|
||||
bail!("uninstaller exe not found");
|
||||
}
|
||||
|
||||
let token = Token::with_current_process()?;
|
||||
let level = token.privilege_level()?;
|
||||
|
||||
let status = match level {
|
||||
PrivilegeLevel::NotPrivileged => RunasCommand::new(uninstall_path).show(false).status()?,
|
||||
_ => StdCommand::new(uninstall_path)
|
||||
.creation_flags(0x08000000)
|
||||
.status()?,
|
||||
};
|
||||
|
||||
if !status.success() {
|
||||
bail!(
|
||||
"failed to uninstall service with status {}",
|
||||
status.code().unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// check the windows service status
|
||||
pub async fn check_service() -> Result<JsonResponse> {
|
||||
let url = format!("{SERVICE_URL}/get_clash");
|
||||
let response = reqwest::ClientBuilder::new()
|
||||
.no_proxy()
|
||||
.build()?
|
||||
.get(url)
|
||||
.send()
|
||||
.await
|
||||
.context("failed to connect to the Clash Nyanpasu Service")?
|
||||
.json::<JsonResponse>()
|
||||
.await
|
||||
.context("failed to parse the Clash Nyanpasu Service response")?;
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
/// start the clash by service
|
||||
pub(super) async fn run_core_by_service(config_file: &PathBuf) -> Result<()> {
|
||||
let status = check_service().await?;
|
||||
|
||||
if status.code == 0 {
|
||||
stop_core_by_service().await?;
|
||||
sleep(Duration::from_secs(1)).await;
|
||||
}
|
||||
|
||||
let clash_core = { Config::verge().latest().clash_core.clone() };
|
||||
let clash_core = clash_core.unwrap_or(ClashCore::ClashPremium);
|
||||
|
||||
let clash_bin = format!("{clash_core}.exe");
|
||||
let bin_path = current_exe()?.with_file_name(clash_bin);
|
||||
let bin_path = dirs::path_to_str(&bin_path)?;
|
||||
|
||||
let config_dir = dirs::app_home_dir()?;
|
||||
let config_dir = dirs::path_to_str(&config_dir)?;
|
||||
|
||||
let log_path = dirs::service_log_file()?;
|
||||
let log_path = dirs::path_to_str(&log_path)?;
|
||||
|
||||
let config_file = dirs::path_to_str(config_file)?;
|
||||
|
||||
let mut map = HashMap::new();
|
||||
// TODO: confirm the backend service logic
|
||||
let core_type = clash_core.to_string();
|
||||
map.insert("core_type", core_type.as_str());
|
||||
map.insert("bin_path", bin_path);
|
||||
map.insert("config_dir", config_dir);
|
||||
map.insert("config_file", config_file);
|
||||
map.insert("log_file", log_path);
|
||||
|
||||
let url = format!("{SERVICE_URL}/start_clash");
|
||||
let res = reqwest::ClientBuilder::new()
|
||||
.no_proxy()
|
||||
.build()?
|
||||
.post(url)
|
||||
.json(&map)
|
||||
.send()
|
||||
.await?
|
||||
.json::<JsonResponse>()
|
||||
.await
|
||||
.context("failed to connect to the Clash Nyanpasu Service")?;
|
||||
|
||||
if res.code != 0 {
|
||||
bail!(res.msg);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// stop the clash by service
|
||||
pub(super) async fn stop_core_by_service() -> Result<()> {
|
||||
let url = format!("{SERVICE_URL}/stop_clash");
|
||||
let res = reqwest::ClientBuilder::new()
|
||||
.no_proxy()
|
||||
.build()?
|
||||
.post(url)
|
||||
.send()
|
||||
.await?
|
||||
.json::<JsonResponse>()
|
||||
.await
|
||||
.context("failed to connect to the Clash Nyanpasu Service")?;
|
||||
|
||||
if res.code != 0 {
|
||||
bail!(res.msg);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
@@ -464,42 +464,38 @@ pub mod uwp {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub mod service {
|
||||
use super::{wrap_err, CmdResult};
|
||||
use crate::core::win_service;
|
||||
use crate::core::service;
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn check_service() -> CmdResult<win_service::JsonResponse> {
|
||||
wrap_err!(win_service::check_service().await)
|
||||
pub async fn status_service<'a>() -> CmdResult<nyanpasu_ipc::types::StatusInfo<'a>> {
|
||||
wrap_err!(service::control::status().await)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_service() -> CmdResult {
|
||||
wrap_err!(win_service::install_service().await)
|
||||
wrap_err!(service::control::install_service().await)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn uninstall_service() -> CmdResult {
|
||||
wrap_err!(win_service::uninstall_service().await)
|
||||
}
|
||||
wrap_err!(service::control::uninstall_service().await)
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
pub mod service {
|
||||
use super::*;
|
||||
#[tauri::command]
|
||||
pub async fn start_service() -> CmdResult {
|
||||
wrap_err!(service::control::start_service().await)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn check_service() -> CmdResult {
|
||||
Ok(())
|
||||
pub async fn stop_service() -> CmdResult {
|
||||
wrap_err!(service::control::stop_service().await)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_service() -> CmdResult {
|
||||
Ok(())
|
||||
}
|
||||
#[tauri::command]
|
||||
pub async fn uninstall_service() -> CmdResult {
|
||||
Ok(())
|
||||
pub async fn restart_service() -> CmdResult {
|
||||
wrap_err!(service::control::restart_service().await)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -189,9 +189,12 @@ fn main() -> std::io::Result<()> {
|
||||
ipc::get_custom_app_dir,
|
||||
ipc::set_custom_app_dir,
|
||||
// service mode
|
||||
ipc::service::check_service,
|
||||
ipc::service::status_service,
|
||||
ipc::service::install_service,
|
||||
ipc::service::uninstall_service,
|
||||
ipc::service::start_service,
|
||||
ipc::service::stop_service,
|
||||
ipc::service::restart_service,
|
||||
ipc::is_portable,
|
||||
ipc::get_proxies,
|
||||
ipc::select_proxy,
|
||||
|
@@ -226,62 +226,37 @@ pub fn init_resources() -> Result<()> {
|
||||
|
||||
/// initialize service resources
|
||||
/// after tauri setup
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn init_service() -> Result<()> {
|
||||
let service_dir = dirs::service_dir()?;
|
||||
let res_dir = dirs::app_resources_dir()?;
|
||||
use nyanpasu_utils::runtime::block_on;
|
||||
|
||||
if !service_dir.exists() {
|
||||
let _ = fs::create_dir_all(&service_dir);
|
||||
}
|
||||
if !res_dir.exists() {
|
||||
let _ = fs::create_dir_all(&res_dir);
|
||||
}
|
||||
|
||||
let file_list = [
|
||||
"clash-verge-service.exe",
|
||||
"install-service.exe",
|
||||
"uninstall-service.exe",
|
||||
];
|
||||
|
||||
// copy the resource file
|
||||
// if the source file is newer than the destination file, copy it over
|
||||
for file in file_list.iter() {
|
||||
let src_path = res_dir.join(file);
|
||||
let dest_path = service_dir.join(file);
|
||||
|
||||
let handle_copy = || {
|
||||
match fs::copy(&src_path, &dest_path) {
|
||||
Ok(_) => log::debug!(target: "app", "resources copied '{file}'"),
|
||||
Err(err) => {
|
||||
log::error!(target: "app", "failed to copy resources '{file}', {err}")
|
||||
}
|
||||
block_on(async move {
|
||||
let enable_service = {
|
||||
*Config::verge()
|
||||
.latest()
|
||||
.enable_service_mode
|
||||
.as_ref()
|
||||
.unwrap_or(&false)
|
||||
};
|
||||
};
|
||||
|
||||
if src_path.exists() && !dest_path.exists() {
|
||||
handle_copy();
|
||||
continue;
|
||||
}
|
||||
|
||||
let src_modified = fs::metadata(&src_path).and_then(|m| m.modified());
|
||||
let dest_modified = fs::metadata(&dest_path).and_then(|m| m.modified());
|
||||
|
||||
match (src_modified, dest_modified) {
|
||||
(Ok(src_modified), Ok(dest_modified)) => {
|
||||
if src_modified > dest_modified {
|
||||
handle_copy();
|
||||
} else {
|
||||
log::debug!(target: "app", "skipping resource copy '{file}'");
|
||||
if enable_service {
|
||||
match crate::core::service::control::status().await {
|
||||
Ok(status) => {
|
||||
if let Some(info) = status.server {
|
||||
let server_ver = semver::Version::parse(info.version.as_ref()).unwrap();
|
||||
let app_ver = semver::Version::parse(status.version.as_ref()).unwrap();
|
||||
if app_ver > server_ver {
|
||||
if let Err(e) = crate::core::service::control::update_service().await {
|
||||
log::error!(target: "app", "failed to update service: {:?}", e);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
log::debug!(target: "app", "failed to get modified '{file}'");
|
||||
handle_copy();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Err(e) => {
|
||||
log::error!(target: "app", "failed to get service status: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
crate::core::service::init_service().await;
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@@ -76,7 +76,6 @@ pub fn resolve_setup(app: &mut App) {
|
||||
handle::Handle::global().init(app.app_handle());
|
||||
|
||||
log_err!(init::init_resources());
|
||||
#[cfg(target_os = "windows")]
|
||||
log_err!(init::init_service());
|
||||
|
||||
// 处理随机端口
|
||||
|
@@ -62,7 +62,7 @@ export const useNyanpasu = (options?: {
|
||||
|
||||
const getSystemProxy = useSWR("getSystemProxy", service.getSystemProxy);
|
||||
|
||||
const getServiceStatus = useSWR("getServiceStatus", service.checkService);
|
||||
const getServiceStatus = useSWR("getServiceStatus", service.statusService);
|
||||
|
||||
const setServiceStatus = async (type: "install" | "uninstall") => {
|
||||
if (type === "install") {
|
||||
|
@@ -120,19 +120,15 @@ export const getSystemProxy = async () => {
|
||||
return await invoke<SystemProxy>("get_sys_proxy");
|
||||
};
|
||||
|
||||
export const checkService = async () => {
|
||||
export const statusService = async () => {
|
||||
try {
|
||||
const result = await invoke<{ code: number }>("check_service");
|
||||
|
||||
if (result?.code === 0) {
|
||||
return "active";
|
||||
} else if (result?.code === 400) {
|
||||
return "installed";
|
||||
} else {
|
||||
return "unknown";
|
||||
}
|
||||
const result = await invoke<{
|
||||
status: "running" | "stopped" | "not_installed";
|
||||
}>("status_service");
|
||||
return result.status;
|
||||
} catch (e) {
|
||||
return "uninstall";
|
||||
console.error(e);
|
||||
return "not_installed";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -144,6 +140,18 @@ export const uninstallService = async () => {
|
||||
return await invoke<void>("uninstall_service");
|
||||
};
|
||||
|
||||
export const startService = async () => {
|
||||
return await invoke<void>("start_service");
|
||||
};
|
||||
|
||||
export const stopService = async () => {
|
||||
return await invoke<void>("stop_service");
|
||||
};
|
||||
|
||||
export const restartService = async () => {
|
||||
return await invoke<void>("restart_service");
|
||||
};
|
||||
|
||||
export const openAppConfigDir = async () => {
|
||||
return await invoke<void>("open_app_config_dir");
|
||||
};
|
||||
|
@@ -76,8 +76,8 @@ export const SideChain = ({ global, profile, onChainEdit }: SideChainProps) => {
|
||||
|
||||
const handleChainClick = useLockFn(async (uid: string) => {
|
||||
const chains = global
|
||||
? getProfiles.data?.chain ?? []
|
||||
: profile?.chains ?? [];
|
||||
? (getProfiles.data?.chain ?? [])
|
||||
: (profile?.chains ?? []);
|
||||
|
||||
const updatedChains = chains.includes(uid)
|
||||
? chains.filter((chain) => chain !== uid)
|
||||
|
@@ -2,7 +2,7 @@
|
||||
"manifest_version": 1,
|
||||
"latest": {
|
||||
"mihomo": "v1.18.6",
|
||||
"mihomo_alpha": "alpha-303f6e4",
|
||||
"mihomo_alpha": "alpha-1db3e45",
|
||||
"clash_rs": "v0.1.20",
|
||||
"clash_premium": "2023-09-05-gdcc8d87"
|
||||
},
|
||||
@@ -36,5 +36,5 @@
|
||||
"darwin-x64": "clash-darwin-amd64-n{}.gz"
|
||||
}
|
||||
},
|
||||
"updated_at": "2024-07-26T22:20:15.529Z"
|
||||
"updated_at": "2024-07-27T22:19:39.996Z"
|
||||
}
|
||||
|
@@ -55,7 +55,7 @@
|
||||
"@tauri-apps/cli": "1.6.0",
|
||||
"@types/fs-extra": "11.0.4",
|
||||
"@types/lodash-es": "4.17.12",
|
||||
"@types/node": "20.14.12",
|
||||
"@types/node": "20.14.13",
|
||||
"autoprefixer": "10.4.19",
|
||||
"conventional-changelog-conventionalcommits": "8.0.0",
|
||||
"cross-env": "7.0.3",
|
||||
|
86
clash-nyanpasu/pnpm-lock.yaml
generated
86
clash-nyanpasu/pnpm-lock.yaml
generated
@@ -24,7 +24,7 @@ importers:
|
||||
devDependencies:
|
||||
'@commitlint/cli':
|
||||
specifier: 19.3.0
|
||||
version: 19.3.0(@types/node@20.14.12)(typescript@5.5.4)
|
||||
version: 19.3.0(@types/node@20.14.13)(typescript@5.5.4)
|
||||
'@commitlint/config-conventional':
|
||||
specifier: 19.2.2
|
||||
version: 19.2.2
|
||||
@@ -41,8 +41,8 @@ importers:
|
||||
specifier: 4.17.12
|
||||
version: 4.17.12
|
||||
'@types/node':
|
||||
specifier: 20.14.12
|
||||
version: 20.14.12
|
||||
specifier: 20.14.13
|
||||
version: 20.14.13
|
||||
autoprefixer:
|
||||
specifier: 10.4.19
|
||||
version: 10.4.19(postcss@8.4.40)
|
||||
@@ -184,7 +184,7 @@ importers:
|
||||
version: 11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1))(react@19.0.0-rc-df783f9ea1-20240708)(types-react@19.0.0-rc.1)
|
||||
'@generouted/react-router':
|
||||
specifier: 1.19.6
|
||||
version: 1.19.6(react-router-dom@6.25.1(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
version: 1.19.6(react-router-dom@6.25.1(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(vite@5.3.5(@types/node@20.14.13)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
'@juggle/resize-observer':
|
||||
specifier: 3.4.0
|
||||
version: 3.4.0
|
||||
@@ -296,10 +296,10 @@ importers:
|
||||
version: 7.17.0(eslint@8.57.0)(typescript@5.5.4)
|
||||
'@vitejs/plugin-react':
|
||||
specifier: 4.3.1
|
||||
version: 4.3.1(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
version: 4.3.1(vite@5.3.5(@types/node@20.14.13)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
'@vitejs/plugin-react-swc':
|
||||
specifier: 3.7.0
|
||||
version: 3.7.0(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
version: 3.7.0(vite@5.3.5(@types/node@20.14.13)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
clsx:
|
||||
specifier: 2.1.1
|
||||
version: 2.1.1
|
||||
@@ -314,19 +314,19 @@ importers:
|
||||
version: 2.1.3
|
||||
vite:
|
||||
specifier: 5.3.5
|
||||
version: 5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
version: 5.3.5(@types/node@20.14.13)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
vite-plugin-monaco-editor:
|
||||
specifier: npm:vite-plugin-monaco-editor-new@1.1.3
|
||||
version: vite-plugin-monaco-editor-new@1.1.3(monaco-editor@0.50.0)
|
||||
vite-plugin-sass-dts:
|
||||
specifier: 1.3.25
|
||||
version: 1.3.25(postcss@8.4.40)(prettier@3.3.3)(sass@1.77.8)(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
version: 1.3.25(postcss@8.4.40)(prettier@3.3.3)(sass@1.77.8)(vite@5.3.5(@types/node@20.14.13)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
vite-plugin-svgr:
|
||||
specifier: 4.2.0
|
||||
version: 4.2.0(rollup@4.17.2)(typescript@5.5.4)(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
version: 4.2.0(rollup@4.17.2)(typescript@5.5.4)(vite@5.3.5(@types/node@20.14.13)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
vite-tsconfig-paths:
|
||||
specifier: 4.3.2
|
||||
version: 4.3.2(typescript@5.5.4)(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
version: 4.3.2(typescript@5.5.4)(vite@5.3.5(@types/node@20.14.13)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
|
||||
frontend/ui:
|
||||
dependencies:
|
||||
@@ -2053,8 +2053,8 @@ packages:
|
||||
'@types/node@20.12.10':
|
||||
resolution: {integrity: sha512-Eem5pH9pmWBHoGAT8Dr5fdc5rYA+4NAovdM4EktRPVAAiJhmWWfQrA0cFhAbOsQdSfIHjAud6YdkbL69+zSKjw==}
|
||||
|
||||
'@types/node@20.14.12':
|
||||
resolution: {integrity: sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ==}
|
||||
'@types/node@20.14.13':
|
||||
resolution: {integrity: sha512-+bHoGiZb8UiQ0+WEtmph2IWQCjIqg8MDZMAV+ppRRhUZnquF5mQkP/9vpSwJClEiSM/C7fZZExPzfU0vJTyp8w==}
|
||||
|
||||
'@types/parse-json@4.0.2':
|
||||
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
|
||||
@@ -6161,11 +6161,11 @@ snapshots:
|
||||
'@babel/helper-validator-identifier': 7.24.5
|
||||
to-fast-properties: 2.0.0
|
||||
|
||||
'@commitlint/cli@19.3.0(@types/node@20.14.12)(typescript@5.5.4)':
|
||||
'@commitlint/cli@19.3.0(@types/node@20.14.13)(typescript@5.5.4)':
|
||||
dependencies:
|
||||
'@commitlint/format': 19.3.0
|
||||
'@commitlint/lint': 19.2.2
|
||||
'@commitlint/load': 19.2.0(@types/node@20.14.12)(typescript@5.5.4)
|
||||
'@commitlint/load': 19.2.0(@types/node@20.14.13)(typescript@5.5.4)
|
||||
'@commitlint/read': 19.2.1
|
||||
'@commitlint/types': 19.0.3
|
||||
execa: 8.0.1
|
||||
@@ -6212,7 +6212,7 @@ snapshots:
|
||||
'@commitlint/rules': 19.0.3
|
||||
'@commitlint/types': 19.0.3
|
||||
|
||||
'@commitlint/load@19.2.0(@types/node@20.14.12)(typescript@5.5.4)':
|
||||
'@commitlint/load@19.2.0(@types/node@20.14.13)(typescript@5.5.4)':
|
||||
dependencies:
|
||||
'@commitlint/config-validator': 19.0.3
|
||||
'@commitlint/execute-rule': 19.0.0
|
||||
@@ -6220,7 +6220,7 @@ snapshots:
|
||||
'@commitlint/types': 19.0.3
|
||||
chalk: 5.3.0
|
||||
cosmiconfig: 9.0.0(typescript@5.5.4)
|
||||
cosmiconfig-typescript-loader: 5.0.0(@types/node@20.14.12)(cosmiconfig@9.0.0(typescript@5.5.4))(typescript@5.5.4)
|
||||
cosmiconfig-typescript-loader: 5.0.0(@types/node@20.14.13)(cosmiconfig@9.0.0(typescript@5.5.4))(typescript@5.5.4)
|
||||
lodash.isplainobject: 4.0.6
|
||||
lodash.merge: 4.6.2
|
||||
lodash.uniq: 4.5.0
|
||||
@@ -6594,13 +6594,13 @@ snapshots:
|
||||
postcss: 7.0.32
|
||||
purgecss: 2.3.0
|
||||
|
||||
'@generouted/react-router@1.19.6(react-router-dom@6.25.1(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))':
|
||||
'@generouted/react-router@1.19.6(react-router-dom@6.25.1(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)(vite@5.3.5(@types/node@20.14.13)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))':
|
||||
dependencies:
|
||||
fast-glob: 3.3.2
|
||||
generouted: 1.19.6(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
generouted: 1.19.6(vite@5.3.5(@types/node@20.14.13)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
react: 19.0.0-rc-df783f9ea1-20240708
|
||||
react-router-dom: 6.25.1(react-dom@19.0.0-rc-df783f9ea1-20240708(react@19.0.0-rc-df783f9ea1-20240708))(react@19.0.0-rc-df783f9ea1-20240708)
|
||||
vite: 5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
vite: 5.3.5(@types/node@20.14.13)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
|
||||
'@humanwhocodes/config-array@0.11.14':
|
||||
dependencies:
|
||||
@@ -7351,12 +7351,12 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/http-cache-semantics': 4.0.4
|
||||
'@types/keyv': 3.1.4
|
||||
'@types/node': 20.14.12
|
||||
'@types/node': 20.14.13
|
||||
'@types/responselike': 1.0.3
|
||||
|
||||
'@types/conventional-commits-parser@5.0.0':
|
||||
dependencies:
|
||||
'@types/node': 20.14.12
|
||||
'@types/node': 20.14.13
|
||||
|
||||
'@types/d3-array@3.2.1': {}
|
||||
|
||||
@@ -7492,7 +7492,7 @@ snapshots:
|
||||
'@types/fs-extra@11.0.4':
|
||||
dependencies:
|
||||
'@types/jsonfile': 6.1.4
|
||||
'@types/node': 20.14.12
|
||||
'@types/node': 20.14.13
|
||||
|
||||
'@types/geojson@7946.0.14': {}
|
||||
|
||||
@@ -7506,11 +7506,11 @@ snapshots:
|
||||
|
||||
'@types/jsonfile@6.1.4':
|
||||
dependencies:
|
||||
'@types/node': 20.14.12
|
||||
'@types/node': 20.14.13
|
||||
|
||||
'@types/keyv@3.1.4':
|
||||
dependencies:
|
||||
'@types/node': 20.14.12
|
||||
'@types/node': 20.14.13
|
||||
|
||||
'@types/lodash-es@4.17.12':
|
||||
dependencies:
|
||||
@@ -7530,7 +7530,7 @@ snapshots:
|
||||
dependencies:
|
||||
undici-types: 5.26.5
|
||||
|
||||
'@types/node@20.14.12':
|
||||
'@types/node@20.14.13':
|
||||
dependencies:
|
||||
undici-types: 5.26.5
|
||||
|
||||
@@ -7552,7 +7552,7 @@ snapshots:
|
||||
|
||||
'@types/responselike@1.0.3':
|
||||
dependencies:
|
||||
'@types/node': 20.14.12
|
||||
'@types/node': 20.14.13
|
||||
|
||||
'@types/unist@2.0.10': {}
|
||||
|
||||
@@ -7560,7 +7560,7 @@ snapshots:
|
||||
|
||||
'@types/yauzl@2.10.3':
|
||||
dependencies:
|
||||
'@types/node': 20.14.12
|
||||
'@types/node': 20.14.13
|
||||
optional: true
|
||||
|
||||
'@typescript-eslint/eslint-plugin@7.17.0(@typescript-eslint/parser@7.17.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4)':
|
||||
@@ -7646,21 +7646,21 @@ snapshots:
|
||||
|
||||
'@ungap/structured-clone@1.2.0': {}
|
||||
|
||||
'@vitejs/plugin-react-swc@3.7.0(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))':
|
||||
'@vitejs/plugin-react-swc@3.7.0(vite@5.3.5(@types/node@20.14.13)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))':
|
||||
dependencies:
|
||||
'@swc/core': 1.6.1
|
||||
vite: 5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
vite: 5.3.5(@types/node@20.14.13)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
transitivePeerDependencies:
|
||||
- '@swc/helpers'
|
||||
|
||||
'@vitejs/plugin-react@4.3.1(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))':
|
||||
'@vitejs/plugin-react@4.3.1(vite@5.3.5(@types/node@20.14.13)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))':
|
||||
dependencies:
|
||||
'@babel/core': 7.24.5
|
||||
'@babel/plugin-transform-react-jsx-self': 7.24.5(@babel/core@7.24.5)
|
||||
'@babel/plugin-transform-react-jsx-source': 7.24.1(@babel/core@7.24.5)
|
||||
'@types/babel__core': 7.20.5
|
||||
react-refresh: 0.14.2
|
||||
vite: 5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
vite: 5.3.5(@types/node@20.14.13)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -8143,9 +8143,9 @@ snapshots:
|
||||
dependencies:
|
||||
is-what: 3.14.1
|
||||
|
||||
cosmiconfig-typescript-loader@5.0.0(@types/node@20.14.12)(cosmiconfig@9.0.0(typescript@5.5.4))(typescript@5.5.4):
|
||||
cosmiconfig-typescript-loader@5.0.0(@types/node@20.14.13)(cosmiconfig@9.0.0(typescript@5.5.4))(typescript@5.5.4):
|
||||
dependencies:
|
||||
'@types/node': 20.14.12
|
||||
'@types/node': 20.14.13
|
||||
cosmiconfig: 9.0.0(typescript@5.5.4)
|
||||
jiti: 1.21.0
|
||||
typescript: 5.5.4
|
||||
@@ -9146,9 +9146,9 @@ snapshots:
|
||||
|
||||
functions-have-names@1.2.3: {}
|
||||
|
||||
generouted@1.19.6(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
|
||||
generouted@1.19.6(vite@5.3.5(@types/node@20.14.13)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
|
||||
dependencies:
|
||||
vite: 5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
vite: 5.3.5(@types/node@20.14.13)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
|
||||
gensync@1.0.0-beta.2: {}
|
||||
|
||||
@@ -11706,43 +11706,43 @@ snapshots:
|
||||
esbuild: 0.19.12
|
||||
monaco-editor: 0.50.0
|
||||
|
||||
vite-plugin-sass-dts@1.3.25(postcss@8.4.40)(prettier@3.3.3)(sass@1.77.8)(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
|
||||
vite-plugin-sass-dts@1.3.25(postcss@8.4.40)(prettier@3.3.3)(sass@1.77.8)(vite@5.3.5(@types/node@20.14.13)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
|
||||
dependencies:
|
||||
postcss: 8.4.40
|
||||
postcss-js: 4.0.1(postcss@8.4.40)
|
||||
prettier: 3.3.3
|
||||
sass: 1.77.8
|
||||
vite: 5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
vite: 5.3.5(@types/node@20.14.13)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
|
||||
vite-plugin-svgr@4.2.0(rollup@4.17.2)(typescript@5.5.4)(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
|
||||
vite-plugin-svgr@4.2.0(rollup@4.17.2)(typescript@5.5.4)(vite@5.3.5(@types/node@20.14.13)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 5.1.0(rollup@4.17.2)
|
||||
'@svgr/core': 8.1.0(typescript@5.5.4)
|
||||
'@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.5.4))
|
||||
vite: 5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
vite: 5.3.5(@types/node@20.14.13)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
transitivePeerDependencies:
|
||||
- rollup
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
vite-tsconfig-paths@4.3.2(typescript@5.5.4)(vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
|
||||
vite-tsconfig-paths@4.3.2(typescript@5.5.4)(vite@5.3.5(@types/node@20.14.13)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
|
||||
dependencies:
|
||||
debug: 4.3.4
|
||||
globrex: 0.1.2
|
||||
tsconfck: 3.0.3(typescript@5.5.4)
|
||||
optionalDependencies:
|
||||
vite: 5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
vite: 5.3.5(@types/node@20.14.13)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
vite@5.3.5(@types/node@20.14.12)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0):
|
||||
vite@5.3.5(@types/node@20.14.13)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0):
|
||||
dependencies:
|
||||
esbuild: 0.21.5
|
||||
postcss: 8.4.40
|
||||
rollup: 4.17.2
|
||||
optionalDependencies:
|
||||
'@types/node': 20.14.12
|
||||
'@types/node': 20.14.13
|
||||
fsevents: 2.3.3
|
||||
less: 4.2.0
|
||||
sass: 1.77.8
|
||||
|
@@ -1218,6 +1218,7 @@ define KernelPackage/nft-netdev
|
||||
DEPENDS:=+kmod-nft-core
|
||||
KCONFIG:= \
|
||||
CONFIG_NETFILTER_INGRESS=y \
|
||||
CONFIG_NETFILTER_EGRESS=y \
|
||||
CONFIG_NF_TABLES_NETDEV \
|
||||
CONFIG_NF_DUP_NETDEV \
|
||||
CONFIG_NFT_DUP_NETDEV \
|
||||
|
@@ -57,6 +57,16 @@ func (set *IpCidrSet) Merge() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (set *IpCidrSet) Foreach(f func(prefix netip.Prefix) bool) {
|
||||
for _, r := range set.rr {
|
||||
for _, prefix := range r.Prefixes() {
|
||||
if !f(prefix) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ToIPSet not safe convert to *netipx.IPSet
|
||||
// be careful, must be used after Merge
|
||||
func (set *IpCidrSet) ToIPSet() *netipx.IPSet {
|
||||
|
@@ -123,16 +123,18 @@ func (t *DomainTrie[T]) Optimize() {
|
||||
t.root.optimize()
|
||||
}
|
||||
|
||||
func (t *DomainTrie[T]) Foreach(print func(domain string, data T)) {
|
||||
func (t *DomainTrie[T]) Foreach(fn func(domain string, data T) bool) {
|
||||
for key, data := range t.root.getChildren() {
|
||||
recursion([]string{key}, data, print)
|
||||
recursion([]string{key}, data, fn)
|
||||
if data != nil && data.inited {
|
||||
print(joinDomain([]string{key}), data.data)
|
||||
if !fn(joinDomain([]string{key}), data.data) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func recursion[T any](items []string, node *Node[T], fn func(domain string, data T)) {
|
||||
func recursion[T any](items []string, node *Node[T], fn func(domain string, data T) bool) bool {
|
||||
for key, data := range node.getChildren() {
|
||||
newItems := append([]string{key}, items...)
|
||||
if data != nil && data.inited {
|
||||
@@ -140,10 +142,15 @@ func recursion[T any](items []string, node *Node[T], fn func(domain string, data
|
||||
if domain[0] == domainStepByte {
|
||||
domain = complexWildcard + domain
|
||||
}
|
||||
fn(domain, data.Data())
|
||||
if !fn(domain, data.Data()) {
|
||||
return false
|
||||
}
|
||||
recursion(newItems, data, fn)
|
||||
}
|
||||
if !recursion(newItems, data, fn) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func joinDomain(items []string) string {
|
||||
|
@@ -28,8 +28,9 @@ type qElt struct{ s, e, col int }
|
||||
// NewDomainSet creates a new *DomainSet struct, from a DomainTrie.
|
||||
func (t *DomainTrie[T]) NewDomainSet() *DomainSet {
|
||||
reserveDomains := make([]string, 0)
|
||||
t.Foreach(func(domain string, data T) {
|
||||
t.Foreach(func(domain string, data T) bool {
|
||||
reserveDomains = append(reserveDomains, utils.Reverse(domain))
|
||||
return true
|
||||
})
|
||||
// ensure that the same prefix is continuous
|
||||
// and according to the ascending sequence of length
|
||||
@@ -136,6 +137,41 @@ func (ss *DomainSet) Has(key string) bool {
|
||||
|
||||
}
|
||||
|
||||
func (ss *DomainSet) keys(f func(key string) bool) {
|
||||
var currentKey []byte
|
||||
var traverse func(int, int) bool
|
||||
traverse = func(nodeId, bmIdx int) bool {
|
||||
if getBit(ss.leaves, nodeId) != 0 {
|
||||
if !f(string(currentKey)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
for ; ; bmIdx++ {
|
||||
if getBit(ss.labelBitmap, bmIdx) != 0 {
|
||||
return true
|
||||
}
|
||||
nextLabel := ss.labels[bmIdx-nodeId]
|
||||
currentKey = append(currentKey, nextLabel)
|
||||
nextNodeId := countZeros(ss.labelBitmap, ss.ranks, bmIdx+1)
|
||||
nextBmIdx := selectIthOne(ss.labelBitmap, ss.ranks, ss.selects, nextNodeId-1) + 1
|
||||
if !traverse(nextNodeId, nextBmIdx) {
|
||||
return false
|
||||
}
|
||||
currentKey = currentKey[:len(currentKey)-1]
|
||||
}
|
||||
}
|
||||
|
||||
traverse(0, 0)
|
||||
return
|
||||
}
|
||||
|
||||
func (ss *DomainSet) Foreach(f func(key string) bool) {
|
||||
ss.keys(func(key string) bool {
|
||||
return f(utils.Reverse(key))
|
||||
})
|
||||
}
|
||||
|
||||
func setBit(bm *[]uint64, i int, v int) {
|
||||
for i>>6 >= len(*bm) {
|
||||
*bm = append(*bm, 0)
|
||||
|
@@ -1,12 +1,29 @@
|
||||
package trie_test
|
||||
|
||||
import (
|
||||
"golang.org/x/exp/slices"
|
||||
"testing"
|
||||
|
||||
"github.com/metacubex/mihomo/component/trie"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func testDump(t *testing.T, tree *trie.DomainTrie[struct{}], set *trie.DomainSet) {
|
||||
var dataSrc []string
|
||||
tree.Foreach(func(domain string, data struct{}) bool {
|
||||
dataSrc = append(dataSrc, domain)
|
||||
return true
|
||||
})
|
||||
slices.Sort(dataSrc)
|
||||
var dataSet []string
|
||||
set.Foreach(func(key string) bool {
|
||||
dataSet = append(dataSet, key)
|
||||
return true
|
||||
})
|
||||
slices.Sort(dataSet)
|
||||
assert.Equal(t, dataSrc, dataSet)
|
||||
}
|
||||
|
||||
func TestDomainSet(t *testing.T) {
|
||||
tree := trie.New[struct{}]()
|
||||
domainSet := []string{
|
||||
@@ -33,6 +50,7 @@ func TestDomainSet(t *testing.T) {
|
||||
assert.True(t, set.Has("google.com"))
|
||||
assert.False(t, set.Has("qq.com"))
|
||||
assert.False(t, set.Has("www.baidu.com"))
|
||||
testDump(t, tree, set)
|
||||
}
|
||||
|
||||
func TestDomainSetComplexWildcard(t *testing.T) {
|
||||
@@ -55,6 +73,7 @@ func TestDomainSetComplexWildcard(t *testing.T) {
|
||||
assert.False(t, set.Has("google.com"))
|
||||
assert.True(t, set.Has("www.baidu.com"))
|
||||
assert.True(t, set.Has("test.test.baidu.com"))
|
||||
testDump(t, tree, set)
|
||||
}
|
||||
|
||||
func TestDomainSetWildcard(t *testing.T) {
|
||||
@@ -82,4 +101,5 @@ func TestDomainSetWildcard(t *testing.T) {
|
||||
assert.False(t, set.Has("a.www.google.com"))
|
||||
assert.False(t, set.Has("test.qq.com"))
|
||||
assert.False(t, set.Has("test.test.test.qq.com"))
|
||||
testDump(t, tree, set)
|
||||
}
|
||||
|
@@ -121,8 +121,9 @@ func TestTrie_Foreach(t *testing.T) {
|
||||
assert.NoError(t, tree.Insert(domain, localIP))
|
||||
}
|
||||
count := 0
|
||||
tree.Foreach(func(domain string, data netip.Addr) {
|
||||
tree.Foreach(func(domain string, data netip.Addr) bool {
|
||||
count++
|
||||
return true
|
||||
})
|
||||
assert.Equal(t, 7, count)
|
||||
}
|
||||
|
@@ -944,10 +944,17 @@ rule-providers:
|
||||
type: file
|
||||
rule3:
|
||||
# mrs类型ruleset,目前仅支持domain和ipcidr(即不支持classical),
|
||||
# behavior=domain,format=yaml 可以通过“mihomo convert-ruleset domain yaml XXX.yaml XXX.mrs”转换得到
|
||||
# behavior=domain,format=text 可以通过“mihomo convert-ruleset domain text XXX.text XXX.mrs”转换得到
|
||||
# behavior=ipcidr,format=yaml 可以通过“mihomo convert-ruleset ipcidr yaml XXX.yaml XXX.mrs”转换得到
|
||||
# behavior=ipcidr,format=text 可以通过“mihomo convert-ruleset ipcidr text XXX.text XXX.mrs”转换得到
|
||||
#
|
||||
# 对于behavior=domain:
|
||||
# - format=yaml 可以通过“mihomo convert-ruleset domain yaml XXX.yaml XXX.mrs”转换到mrs格式
|
||||
# - format=text 可以通过“mihomo convert-ruleset domain text XXX.text XXX.mrs”转换到mrs格式
|
||||
# - XXX.mrs 可以通过"mihomo convert-ruleset domain mrs XXX.mrs XXX.text"转换回text格式(暂不支持转换回ymal格式)
|
||||
#
|
||||
# 对于behavior=ipcidr:
|
||||
# - format=yaml 可以通过“mihomo convert-ruleset ipcidr yaml XXX.yaml XXX.mrs”转换到mrs格式
|
||||
# - format=text 可以通过“mihomo convert-ruleset ipcidr text XXX.text XXX.mrs”转换到mrs格式
|
||||
# - XXX.mrs 可以通过"mihomo convert-ruleset ipcidr mrs XXX.mrs XXX.text"转换回text格式(暂不支持转换回ymal格式)
|
||||
#
|
||||
type: http
|
||||
url: "url"
|
||||
format: mrs
|
||||
|
@@ -9,6 +9,8 @@ import (
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
P "github.com/metacubex/mihomo/constant/provider"
|
||||
"github.com/metacubex/mihomo/log"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
type domainStrategy struct {
|
||||
@@ -78,6 +80,26 @@ func (d *domainStrategy) WriteMrs(w io.Writer) error {
|
||||
return d.domainSet.WriteBin(w)
|
||||
}
|
||||
|
||||
func (d *domainStrategy) DumpMrs(f func(key string) bool) {
|
||||
if d.domainSet != nil {
|
||||
var keys []string
|
||||
d.domainSet.Foreach(func(key string) bool {
|
||||
keys = append(keys, key)
|
||||
return true
|
||||
})
|
||||
slices.Sort(keys)
|
||||
|
||||
for _, key := range keys {
|
||||
if _, ok := slices.BinarySearch(keys, "+."+key); ok {
|
||||
continue // ignore the rules added by trie internal processing
|
||||
}
|
||||
if !f(key) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var _ mrsRuleStrategy = (*domainStrategy)(nil)
|
||||
|
||||
func NewDomainStrategy() *domainStrategy {
|
||||
|
@@ -3,6 +3,7 @@ package provider
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net/netip"
|
||||
|
||||
"github.com/metacubex/mihomo/component/cidr"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
@@ -82,6 +83,14 @@ func (i *ipcidrStrategy) WriteMrs(w io.Writer) error {
|
||||
return i.cidrSet.WriteBin(w)
|
||||
}
|
||||
|
||||
func (i *ipcidrStrategy) DumpMrs(f func(key string) bool) {
|
||||
if i.cidrSet != nil {
|
||||
i.cidrSet.Foreach(func(prefix netip.Prefix) bool {
|
||||
return f(prefix.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (i *ipcidrStrategy) ToIpCidr() *netipx.IPSet {
|
||||
return i.cidrSet.ToIPSet()
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package provider
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
@@ -21,6 +22,17 @@ func ConvertToMrs(buf []byte, behavior P.RuleBehavior, format P.RuleFormat, w io
|
||||
return errors.New("empty rule")
|
||||
}
|
||||
if _strategy, ok := strategy.(mrsRuleStrategy); ok {
|
||||
if format == P.MrsRule { // export to TextRule
|
||||
_strategy.DumpMrs(func(key string) bool {
|
||||
_, err = fmt.Fprintln(w, key)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
var encoder *zstd.Encoder
|
||||
encoder, err = zstd.NewWriter(w)
|
||||
if err != nil {
|
||||
|
@@ -58,6 +58,7 @@ type mrsRuleStrategy interface {
|
||||
ruleStrategy
|
||||
FromMrs(r io.Reader, count int) error
|
||||
WriteMrs(w io.Writer) error
|
||||
DumpMrs(f func(key string) bool)
|
||||
}
|
||||
|
||||
func (rp *ruleSetProvider) Type() P.ProviderType {
|
||||
|
@@ -85,6 +85,35 @@ local doh_validate = function(self, value, t)
|
||||
return nil, translate("DoH request address") .. " " .. translate("Format must be:") .. " URL,IP"
|
||||
end
|
||||
|
||||
local chinadns_dot_validate = function(self, value, t)
|
||||
if value ~= "" then
|
||||
value = api.trim(value)
|
||||
-- Define patterns for IPv4, IPv6, domain, and port
|
||||
local ipv4_pattern = "(%d+%.%d+%.%d+%.%d+)"
|
||||
local ipv6_pattern = "([%[%]a-fA-F0-9:]+)" -- IPv6 addresses are wrapped in []
|
||||
local domain_pattern = "([%w-_%.]+)"
|
||||
local port_pattern = "(%d+)"
|
||||
-- Define patterns for the different formats
|
||||
local patterns = {
|
||||
"^tls://" .. domain_pattern .. "@" .. ipv4_pattern .. "#" .. port_pattern .. "$", -- tls://域名@ip#端口
|
||||
"^tls://" .. ipv4_pattern .. "#" .. port_pattern .. "$", -- tls://ip#端口
|
||||
"^tls://" .. domain_pattern .. "@" .. ipv4_pattern .. "$", -- tls://域名@ip
|
||||
"^tls://" .. ipv4_pattern .. "$", -- tls://ip
|
||||
"^tls://" .. domain_pattern .. "@" .. ipv6_pattern .. "#" .. port_pattern .. "$", -- tls://域名@[IPv6]#端口
|
||||
"^tls://" .. ipv6_pattern .. "#" .. port_pattern .. "$", -- tls://[IPv6]#端口
|
||||
"^tls://" .. domain_pattern .. "@" .. ipv6_pattern .. "$", -- tls://域名@[IPv6]
|
||||
"^tls://" .. ipv6_pattern .. "$" -- tls://[IPv6]
|
||||
}
|
||||
-- Check if the string matches any of the patterns
|
||||
for _, pattern in ipairs(patterns) do
|
||||
if value:match(pattern) then
|
||||
return value
|
||||
end
|
||||
end
|
||||
return nil, translate("Direct DNS") .. " DoT " .. translate("Format must be:") .. " tls://Domain@IP(#Port) or tls://IP(#Port)"
|
||||
end
|
||||
end
|
||||
|
||||
m:append(Template(appname .. "/global/status"))
|
||||
|
||||
s = m:section(TypedSection, "global")
|
||||
@@ -266,20 +295,48 @@ dns_shunt = s:taboption("DNS", ListValue, "dns_shunt", "DNS " .. translate("Shun
|
||||
dns_shunt:value("dnsmasq", "Dnsmasq")
|
||||
dns_shunt:value("chinadns-ng", "Dnsmasq + ChinaDNS-NG")
|
||||
|
||||
o = s:taboption("DNS", Value, "direct_dns", translate("Direct DNS"))
|
||||
o.datatype = "or(ipaddr,ipaddrport)"
|
||||
o = s:taboption("DNS", ListValue, "direct_dns_mode", translate("Direct DNS") .. " " .. translate("Request protocol"))
|
||||
o.default = ""
|
||||
o:value("", translate("Auto"))
|
||||
o:value("223.5.5.5")
|
||||
o:value("223.6.6.6")
|
||||
o:value("114.114.114.114")
|
||||
o:value("119.29.29.29")
|
||||
o:value("180.76.76.76")
|
||||
o:value("1.12.12.12")
|
||||
o:value("120.53.53.53")
|
||||
o:value("udp", "UDP")
|
||||
o:value("tcp", "TCP")
|
||||
if os.execute("chinadns-ng -V | grep -i wolfssl >/dev/null") == 0 then
|
||||
o:value("dot", "DoT")
|
||||
end
|
||||
--TO DO
|
||||
--o:value("doh", "DoH")
|
||||
o:depends({dns_shunt = "dnsmasq"})
|
||||
o:depends({dns_shunt = "chinadns-ng"})
|
||||
|
||||
o = s:taboption("DNS", Value, "direct_dns_udp", translate("Direct DNS"))
|
||||
o.datatype = "or(ipaddr,ipaddrport)"
|
||||
o.default = "223.5.5.5"
|
||||
o:value("223.5.5.5")
|
||||
o:value("223.6.6.6")
|
||||
o:value("119.29.29.29")
|
||||
o:value("180.184.1.1")
|
||||
o:value("180.184.2.2")
|
||||
o:value("114.114.114.114")
|
||||
o:depends("direct_dns_mode", "udp")
|
||||
|
||||
o = s:taboption("DNS", Value, "direct_dns_tcp", translate("Direct DNS"))
|
||||
o.datatype = "or(ipaddr,ipaddrport)"
|
||||
o.default = "223.5.5.5"
|
||||
o:value("223.5.5.5")
|
||||
o:value("223.6.6.6")
|
||||
o:value("180.184.1.1")
|
||||
o:value("180.184.2.2")
|
||||
o:depends("direct_dns_mode", "tcp")
|
||||
|
||||
o = s:taboption("DNS", Value, "direct_dns_dot", translate("Direct DNS"))
|
||||
o.default = "tls://dot.pub@1.12.12.12"
|
||||
o:value("tls://dot.pub@1.12.12.12")
|
||||
o:value("tls://dot.pub@120.53.53.53")
|
||||
o:value("tls://dot.360.cn@36.99.170.86")
|
||||
o:value("tls://dot.360.cn@101.198.191.4")
|
||||
o.validate = chinadns_dot_validate
|
||||
o:depends("direct_dns_mode", "dot")
|
||||
|
||||
o = s:taboption("DNS", Flag, "filter_proxy_ipv6", translate("Filter Proxy Host IPv6"), translate("Experimental feature."))
|
||||
o.default = "0"
|
||||
|
||||
|
@@ -1298,6 +1298,38 @@ stop_crontab() {
|
||||
start_dns() {
|
||||
echolog "DNS域名解析:"
|
||||
|
||||
local direct_dns_mode=$(config_t_get global direct_dns_mode "auto")
|
||||
case "$direct_dns_mode" in
|
||||
udp)
|
||||
LOCAL_DNS=$(config_t_get global direct_dns_udp 223.5.5.5 | sed 's/:/#/g')
|
||||
;;
|
||||
tcp)
|
||||
LOCAL_DNS="127.0.0.1#${dns_listen_port}"
|
||||
dns_listen_port=$(expr $dns_listen_port + 1)
|
||||
local DIRECT_DNS=$(config_t_get global direct_dns_tcp 223.5.5.5 | sed 's/:/#/g')
|
||||
ln_run "$(first_type dns2tcp)" dns2tcp "/dev/null" -L "${LOCAL_DNS}" -R "$(get_first_dns DIRECT_DNS 53)" -v
|
||||
echolog " - dns2tcp(${LOCAL_DNS}) -> tcp://$(get_first_dns DIRECT_DNS 53 | sed 's/#/:/g')"
|
||||
echolog " * 请确保上游直连 DNS 支持 TCP 查询。"
|
||||
;;
|
||||
dot)
|
||||
if [ "$(chinadns-ng -V | grep -i wolfssl)" != "nil" ]; then
|
||||
LOCAL_DNS="127.0.0.1#${dns_listen_port}"
|
||||
local cdns_listen_port=${dns_listen_port}
|
||||
dns_listen_port=$(expr $dns_listen_port + 1)
|
||||
local DIRECT_DNS=$(config_t_get global direct_dns_dot "tls://dot.pub@1.12.12.12")
|
||||
ln_run "$(first_type chinadns-ng)" chinadns-ng "/dev/null" -b 127.0.0.1 -l ${cdns_listen_port}@udp -c ${DIRECT_DNS} -d chn
|
||||
echolog " - ChinaDNS-NG(${LOCAL_DNS}) -> ${DIRECT_DNS}"
|
||||
echolog " * 请确保上游直连 DNS 支持 DoT 查询。"
|
||||
else
|
||||
echolog " - 你的ChinaDNS-NG版本不支持DoT,直连DNS将使用默认UDP地址。"
|
||||
fi
|
||||
;;
|
||||
auto)
|
||||
#Automatic logic is already done by default
|
||||
:
|
||||
;;
|
||||
esac
|
||||
|
||||
TUN_DNS="127.0.0.1#${dns_listen_port}"
|
||||
[ "${resolve_dns}" == "1" ] && TUN_DNS="127.0.0.1#${resolve_dns_port}"
|
||||
|
||||
@@ -1880,9 +1912,6 @@ DEFAULT_DNSMASQ_CFGID=$(uci show dhcp.@dnsmasq[0] | awk -F '.' '{print $2}' | a
|
||||
DEFAULT_DNS=$(uci show dhcp.@dnsmasq[0] | grep "\.server=" | awk -F '=' '{print $2}' | sed "s/'//g" | tr ' ' '\n' | grep -v "\/" | head -2 | sed ':label;N;s/\n/,/;b label')
|
||||
[ -z "${DEFAULT_DNS}" ] && [ "$(echo $ISP_DNS | tr ' ' '\n' | wc -l)" -le 2 ] && DEFAULT_DNS=$(echo -n $ISP_DNS | tr ' ' '\n' | head -2 | tr '\n' ',')
|
||||
LOCAL_DNS="${DEFAULT_DNS:-119.29.29.29,223.5.5.5}"
|
||||
DIRECT_DNS=$(config_t_get global direct_dns "auto")
|
||||
#Automatic logic is already done by default
|
||||
[ "${DIRECT_DNS}" != "auto" ] && LOCAL_DNS=$(echo ${DIRECT_DNS} | sed 's/:/#/g')
|
||||
|
||||
DNS_QUERY_STRATEGY="UseIP"
|
||||
[ "$FILTER_PROXY_IPV6" = "1" ] && DNS_QUERY_STRATEGY="UseIPv4"
|
||||
|
@@ -6,3 +6,5 @@
|
||||
180.76.76.76
|
||||
1.12.12.12
|
||||
120.53.53.53
|
||||
180.184.1.1
|
||||
180.184.2.2
|
||||
|
221
shadowsocks-rust/Cargo.lock
generated
221
shadowsocks-rust/Cargo.lock
generated
@@ -121,9 +121,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.14"
|
||||
version = "0.6.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
|
||||
checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
@@ -136,33 +136,33 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.7"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
|
||||
checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.4"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
|
||||
checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.0"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
|
||||
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
|
||||
dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.3"
|
||||
version = "3.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
|
||||
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys 0.52.0",
|
||||
@@ -182,9 +182,9 @@ checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.7"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545"
|
||||
checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
@@ -194,9 +194,9 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
|
||||
|
||||
[[package]]
|
||||
name = "async-compression"
|
||||
version = "0.4.11"
|
||||
version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd066d0b4ef8ecb03a55319dc13aa6910616d0f44008a045bb1835af830abff5"
|
||||
checksum = "fec134f64e2bc57411226dfc4e52dec859ddfc7e711fc5e07b612584f000e4aa"
|
||||
dependencies = [
|
||||
"brotli",
|
||||
"flate2",
|
||||
@@ -216,7 +216,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.71",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -391,7 +391,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.71",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -450,13 +450,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.1.4"
|
||||
version = "1.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9711f33475c22aab363b05564a17d7b789bf3dfec5ebabb586adee56f0e271b5"
|
||||
checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -532,18 +531,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.9"
|
||||
version = "4.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462"
|
||||
checksum = "35723e6a11662c2afb578bcf0b88bf6ea8e21282a953428f240574fcc3a2b5b3"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.9"
|
||||
version = "4.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942"
|
||||
checksum = "49eb96cbfa7cfa35017b7cd548c75b14c3118c98b423041d70562665e07fb0fa"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -554,9 +553,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.1"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
|
||||
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
@@ -569,9 +568,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.1"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
|
||||
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
|
||||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
@@ -710,7 +709,7 @@ dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.71",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -798,7 +797,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.71",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -858,14 +857,14 @@ dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.71",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_filter"
|
||||
version = "0.1.0"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea"
|
||||
checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab"
|
||||
dependencies = [
|
||||
"log",
|
||||
"regex",
|
||||
@@ -873,9 +872,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.11.3"
|
||||
version = "0.11.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9"
|
||||
checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -1067,7 +1066,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.71",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1457,7 +1456,7 @@ dependencies = [
|
||||
"http 1.1.0",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"rustls 0.23.11",
|
||||
"rustls 0.23.12",
|
||||
"rustls-native-certs 0.7.1",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
@@ -1640,7 +1639,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.71",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1752,9 +1751,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.0"
|
||||
version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
@@ -1784,9 +1783,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.31"
|
||||
version = "0.1.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e"
|
||||
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -1845,9 +1844,9 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.4"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d"
|
||||
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets 0.52.6",
|
||||
@@ -2032,6 +2031,18 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"wasi",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.12"
|
||||
@@ -2075,7 +2086,7 @@ dependencies = [
|
||||
"kqueue",
|
||||
"libc",
|
||||
"log",
|
||||
"mio",
|
||||
"mio 0.8.11",
|
||||
"walkdir",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
@@ -2105,16 +2116,6 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_threads"
|
||||
version = "0.1.7"
|
||||
@@ -2126,9 +2127,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.1"
|
||||
version = "0.36.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce"
|
||||
checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -2168,7 +2169,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.71",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2284,7 +2285,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall 0.5.2",
|
||||
"redox_syscall 0.5.3",
|
||||
"smallvec",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
@@ -2326,7 +2327,7 @@ dependencies = [
|
||||
"pest_meta",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.71",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2357,7 +2358,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.71",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2503,9 +2504,9 @@ dependencies = [
|
||||
"bytes",
|
||||
"pin-project-lite",
|
||||
"quinn-proto 0.11.3",
|
||||
"quinn-udp 0.5.2",
|
||||
"quinn-udp 0.5.4",
|
||||
"rustc-hash",
|
||||
"rustls 0.23.11",
|
||||
"rustls 0.23.12",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tracing",
|
||||
@@ -2538,7 +2539,7 @@ dependencies = [
|
||||
"rand",
|
||||
"ring 0.17.8",
|
||||
"rustc-hash",
|
||||
"rustls 0.23.11",
|
||||
"rustls 0.23.12",
|
||||
"slab",
|
||||
"thiserror",
|
||||
"tinyvec",
|
||||
@@ -2560,14 +2561,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quinn-udp"
|
||||
version = "0.5.2"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9096629c45860fc7fb143e125eb826b5e721e10be3263160c7d60ca832cf8c46"
|
||||
checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"once_cell",
|
||||
"socket2",
|
||||
"tracing",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
@@ -2636,9 +2636,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.2"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd"
|
||||
checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
]
|
||||
@@ -2728,7 +2728,7 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"quinn 0.11.2",
|
||||
"rustls 0.23.11",
|
||||
"rustls 0.23.12",
|
||||
"rustls-native-certs 0.7.1",
|
||||
"rustls-pemfile 2.1.2",
|
||||
"rustls-pki-types",
|
||||
@@ -2889,15 +2889,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.11"
|
||||
version = "0.23.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4828ea528154ae444e5a642dbb7d5623354030dc9822b83fd9bb79683c7399d0"
|
||||
checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"ring 0.17.8",
|
||||
"rustls-pki-types",
|
||||
"rustls-webpki 0.102.5",
|
||||
"rustls-webpki 0.102.6",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
@@ -2964,9 +2964,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.102.5"
|
||||
version = "0.102.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9a6fccd794a42c2c105b513a2f62bc3fd8f3ba57a4593677ceb0bd035164d78"
|
||||
checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e"
|
||||
dependencies = [
|
||||
"ring 0.17.8",
|
||||
"rustls-pki-types",
|
||||
@@ -3095,7 +3095,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.71",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3225,7 +3225,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "shadowsocks-rust"
|
||||
version = "1.20.2"
|
||||
version = "1.20.3"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"build-time",
|
||||
@@ -3266,7 +3266,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "shadowsocks-service"
|
||||
version = "1.20.2"
|
||||
version = "1.20.3"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"async-trait",
|
||||
@@ -3488,9 +3488,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.71"
|
||||
version = "2.0.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462"
|
||||
checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -3511,7 +3511,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.71",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3601,14 +3601,14 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.71",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread-id"
|
||||
version = "4.2.1"
|
||||
version = "4.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0ec81c46e9eb50deaa257be2f148adf052d1fb7701cfd55ccfab2525280b70b"
|
||||
checksum = "cfe8f25bbdd100db7e1d34acf7fd2dc59c4bf8f7483f505eaa7d4f12f76cc0ea"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
@@ -3684,32 +3684,31 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.38.0"
|
||||
version = "1.39.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
|
||||
checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
"libc",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"mio 1.0.1",
|
||||
"parking_lot 0.12.3",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.3.0"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
|
||||
checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.71",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3738,7 +3737,7 @@ version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
|
||||
dependencies = [
|
||||
"rustls 0.23.11",
|
||||
"rustls 0.23.12",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
]
|
||||
@@ -3820,7 +3819,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.71",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3871,9 +3870,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||
|
||||
[[package]]
|
||||
name = "tun2"
|
||||
version = "2.0.2"
|
||||
version = "2.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa06f8128a534de505cae0a1d394ca3f7acb8504580b24d23ba774c48baaa98e"
|
||||
checksum = "50ff242bea1c5ceb9b6aa4918cf340a6c157e1328a2389c5353cf91049d8cf17"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"cfg-if",
|
||||
@@ -4023,9 +4022,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
@@ -4073,7 +4072,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.71",
|
||||
"syn 2.0.72",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@@ -4107,7 +4106,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.71",
|
||||
"syn 2.0.72",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
@@ -4180,16 +4179,6 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
|
||||
dependencies = [
|
||||
"windows-core",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
@@ -4371,15 +4360,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wintun"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b3c8c8876c686f8a2d6376999ac1c9a24c74d2968551c9394f7e89127783685"
|
||||
checksum = "b196f9328341b035820c54beebca487823e2e20a5977f284f2af2a0ee8f04400"
|
||||
dependencies = [
|
||||
"c2rust-bitfields",
|
||||
"libloading",
|
||||
"log",
|
||||
"thiserror",
|
||||
"windows",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4429,7 +4418,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.71",
|
||||
"syn 2.0.72",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@@ -4450,7 +4439,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.71",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4470,7 +4459,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.71",
|
||||
"syn 2.0.72",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@@ -4499,7 +4488,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.71",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "shadowsocks-rust"
|
||||
version = "1.20.2"
|
||||
version = "1.20.3"
|
||||
authors = ["Shadowsocks Contributors"]
|
||||
description = "shadowsocks is a fast tunnel proxy that helps you bypass firewalls."
|
||||
repository = "https://github.com/shadowsocks/shadowsocks-rust"
|
||||
@@ -248,7 +248,7 @@ jemallocator = { version = "0.5", optional = true }
|
||||
snmalloc-rs = { version = "0.3", optional = true }
|
||||
rpmalloc = { version = "0.2", optional = true }
|
||||
|
||||
shadowsocks-service = { version = "1.20.2", path = "./crates/shadowsocks-service" }
|
||||
shadowsocks-service = { version = "1.20.3", path = "./crates/shadowsocks-service" }
|
||||
|
||||
windows-service = { version = "0.7", optional = true }
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user