Compare commits
55 Commits
Author | SHA1 | Date | |
---|---|---|---|
002163f07b | |||
9c5b184db6 | |||
7550067fde | |||
076a0840bf | |||
5ebcc526de | |||
46dc262e8e | |||
d70cfefde7 | |||
52c37f7140 | |||
180bce2940 | |||
d7f5e8d3de | |||
0a180eeb40 | |||
7ff48ea42d | |||
a0e44f4041 | |||
2f6f9ebc2e | |||
90e6ed4612 | |||
ae5a790510 | |||
a732e1a603 | |||
b1a639feae | |||
76dccebbf6 | |||
cd5b735973 | |||
a5ce62db33 | |||
2f8e575308 | |||
62b70725ef | |||
8595d6c2e9 | |||
03b956b7a3 | |||
e5c99cbee7 | |||
58a47e1835 | |||
daf83eb6f7 | |||
bb68b59c9a | |||
c3cfa3d6cd | |||
b15344ec78 | |||
cfe7354c07 | |||
9732efe938 | |||
ee6c1871a9 | |||
8f3385bbb6 | |||
00e44cd141 | |||
4ab986cccb | |||
64869d0f17 | |||
7f0368da66 | |||
4f1b227ca2 | |||
16abba385a | |||
75b5f633cd | |||
8ae68552a6 | |||
d35d6c9ac9 | |||
a832cfdb65 | |||
951a5a0eb5 | |||
89609cc4a2 | |||
bfb976bbdc | |||
d237b041b3 | |||
a15d2535f1 | |||
610c79570a | |||
051c81518c | |||
0209efd423 | |||
ba6fdd2962 | |||
9475799615 |
44
.github/workflows/Dev.yml
vendored
Normal file
44
.github/workflows/Dev.yml
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
name: Dev
|
||||||
|
on: [push]
|
||||||
|
jobs:
|
||||||
|
dev-build:
|
||||||
|
if: ${{ !contains(github.event.head_commit.message, '[Skip CI]') }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Get latest go version
|
||||||
|
id: version
|
||||||
|
run: |
|
||||||
|
echo ::set-output name=go_version::$(curl -s https://raw.githubusercontent.com/actions/go-versions/main/versions-manifest.json | grep -oE '"version": "[0-9]{1}.[0-9]{1,}(.[0-9]{1,})?"' | head -1 | cut -d':' -f2 | sed 's/ //g; s/"//g')
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: ${{ steps.version.outputs.go_version }}
|
||||||
|
|
||||||
|
- name: Check out code into the Go module directory
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Cache go module
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: ~/go/pkg/mod
|
||||||
|
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-go-
|
||||||
|
# - name: Get dependencies, run test
|
||||||
|
# run: |
|
||||||
|
# go test ./...
|
||||||
|
- name: Build
|
||||||
|
if: success()
|
||||||
|
env:
|
||||||
|
NAME: Clash.Meta
|
||||||
|
BINDIR: bin
|
||||||
|
run: make -j releases
|
||||||
|
|
||||||
|
- name: Upload Release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
if: ${{ env.GIT_BRANCH != 'Meta' && success() }}
|
||||||
|
with:
|
||||||
|
tag_name: Dev
|
||||||
|
files: bin/*
|
||||||
|
prerelease: true
|
||||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -23,3 +23,5 @@ vendor
|
|||||||
|
|
||||||
# test suite
|
# test suite
|
||||||
test/config/cache*
|
test/config/cache*
|
||||||
|
/output
|
||||||
|
/.vscode
|
37
Makefile
37
Makefile
@ -1,6 +1,10 @@
|
|||||||
NAME=Clash.Meta
|
NAME=Clash.Meta
|
||||||
BINDIR=bin
|
BINDIR=bin
|
||||||
VERSION=$(shell git describe --tags || echo "unknown version")
|
BRANCH=$(shell git rev-parse --abbrev-ref HEAD)
|
||||||
|
VERSION=$(shell git describe --tags || echo "unknown version" )
|
||||||
|
ifeq ($(BRANCH),Dev)
|
||||||
|
VERSION=develop-$(shell git rev-parse --short HEAD)
|
||||||
|
endif
|
||||||
BUILDTIME=$(shell date -u)
|
BUILDTIME=$(shell date -u)
|
||||||
AUTOIPTABLES=Enable
|
AUTOIPTABLES=Enable
|
||||||
GOBUILD=CGO_ENABLED=0 go build -trimpath -ldflags '-X "github.com/Dreamacro/clash/constant.Version=$(VERSION)" \
|
GOBUILD=CGO_ENABLED=0 go build -trimpath -ldflags '-X "github.com/Dreamacro/clash/constant.Version=$(VERSION)" \
|
||||||
@ -15,18 +19,34 @@ GOBUILDOP=CGO_ENABLED=0 go build -trimpath -ldflags '-X "github.com/Dreamacro/cl
|
|||||||
PLATFORM_LIST = \
|
PLATFORM_LIST = \
|
||||||
darwin-amd64 \
|
darwin-amd64 \
|
||||||
darwin-arm64 \
|
darwin-arm64 \
|
||||||
linux-arm64 \
|
|
||||||
linux-amd64 \
|
linux-amd64 \
|
||||||
linux-arm64-AutoIptables\
|
linux-armv5 \
|
||||||
linux-amd64-AutoIptables
|
linux-armv6 \
|
||||||
|
linux-armv7 \
|
||||||
|
linux-armv8 \
|
||||||
|
linux-mips64 \
|
||||||
|
linux-mips64le \
|
||||||
|
linux-mips-softfloat \
|
||||||
|
linux-mips-hardfloat \
|
||||||
|
linux-mipsle-softfloat \
|
||||||
|
linux-mipsle-hardfloat \
|
||||||
|
freebsd-386 \
|
||||||
|
freebsd-amd64 \
|
||||||
|
freebsd-arm64
|
||||||
|
|
||||||
|
|
||||||
WINDOWS_ARCH_LIST = \
|
WINDOWS_ARCH_LIST = \
|
||||||
windows-386 \
|
windows-386 \
|
||||||
windows-amd64
|
windows-amd64 \
|
||||||
|
windows-arm64 \
|
||||||
|
windows-arm32v7
|
||||||
|
|
||||||
|
|
||||||
all: linux-arm64-AutoIptables linux-amd64-AutoIptables linux-arm64 linux-amd64 darwin-amd64 darwin-arm64 windows-amd64 windows-386 # Most used
|
all:linux-amd64-AutoIptables linux-amd64\
|
||||||
|
linux-arm64 linux-arm64-AutoIptables linux-armv7\
|
||||||
|
darwin-amd64 darwin-arm64\
|
||||||
|
windows-amd64 windows-386 \
|
||||||
|
linux-mips-hardfloat linux-mips-softfloat linux-mips64 linux-mips64le linux-mipsle-hardfloat linux-mipsle-softfloat# Most used
|
||||||
|
|
||||||
docker:
|
docker:
|
||||||
$(GOBUILD) -o $(BINDIR)/$(NAME)-$@
|
$(GOBUILD) -o $(BINDIR)/$(NAME)-$@
|
||||||
@ -109,6 +129,9 @@ windows-386:
|
|||||||
windows-amd64:
|
windows-amd64:
|
||||||
GOARCH=amd64 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
|
GOARCH=amd64 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
|
||||||
|
|
||||||
|
windows-arm64:
|
||||||
|
GOARCH=arm64 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
|
||||||
|
|
||||||
windows-arm32v7:
|
windows-arm32v7:
|
||||||
GOARCH=arm GOOS=windows GOARM=7 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
|
GOARCH=arm GOOS=windows GOARM=7 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
|
||||||
|
|
||||||
@ -126,4 +149,4 @@ all-arch: $(PLATFORM_LIST) $(WINDOWS_ARCH_LIST)
|
|||||||
|
|
||||||
releases: $(gz_releases) $(zip_releases)
|
releases: $(gz_releases) $(zip_releases)
|
||||||
clean:
|
clean:
|
||||||
rm $(BINDIR)/*
|
rm $(BINDIR)/*
|
||||||
|
96
README.md
96
README.md
@ -1,9 +1,9 @@
|
|||||||
<h1 align="center">
|
<h1 align="center">
|
||||||
<img src="Meta.png" alt="Meta Kennel" width="200">
|
<img src="Meta.png" alt="Meta Kennel" width="200">
|
||||||
<br>Meta Kennel<br>
|
<br>Meta Kernel<br>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<h3 align="center">Another Clash Kennel.</h3>
|
<h3 align="center">Another Clash Kernel.</h3>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://goreportcard.com/report/github.com/Clash-Mini/Clash.Meta">
|
<a href="https://goreportcard.com/report/github.com/Clash-Mini/Clash.Meta">
|
||||||
@ -33,16 +33,32 @@
|
|||||||
Documentations are now moved to [GitHub Wiki](https://github.com/Dreamacro/clash/wiki).
|
Documentations are now moved to [GitHub Wiki](https://github.com/Dreamacro/clash/wiki).
|
||||||
|
|
||||||
## Advanced usage for this branch
|
## Advanced usage for this branch
|
||||||
|
|
||||||
### DNS configuration
|
### DNS configuration
|
||||||
Support resolve ip with a proxy tunnel.
|
|
||||||
|
|
||||||
Support `geosite` with `fallback-filter`.
|
Support `geosite` with `fallback-filter`.
|
||||||
|
|
||||||
|
Restore `Redir remote resolution`.
|
||||||
|
|
||||||
|
Support resolve ip with a `Proxy Tunnel`.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
proxy-groups:
|
||||||
|
|
||||||
|
- name: DNS
|
||||||
|
type: url-test
|
||||||
|
use:
|
||||||
|
- HK
|
||||||
|
url: http://cp.cloudflare.com
|
||||||
|
interval: 180
|
||||||
|
lazy: true
|
||||||
|
```
|
||||||
```yaml
|
```yaml
|
||||||
dns:
|
dns:
|
||||||
enable: true
|
enable: true
|
||||||
use-hosts: true
|
use-hosts: true
|
||||||
ipv6: false
|
ipv6: false
|
||||||
enhanced-mode: fake-ip
|
enhanced-mode: redir-host
|
||||||
fake-ip-range: 198.18.0.1/16
|
fake-ip-range: 198.18.0.1/16
|
||||||
listen: 127.0.0.1:6868
|
listen: 127.0.0.1:6868
|
||||||
default-nameserver:
|
default-nameserver:
|
||||||
@ -52,8 +68,8 @@ dns:
|
|||||||
- https://doh.pub/dns-query
|
- https://doh.pub/dns-query
|
||||||
- tls://223.5.5.5:853
|
- tls://223.5.5.5:853
|
||||||
fallback:
|
fallback:
|
||||||
- 'https://1.0.0.1/dns-query#Proxy' # append the proxy adapter name to the end of DNS URL with '#' prefix.
|
- 'https://1.0.0.1/dns-query#DNS' # append the proxy adapter name or group name to the end of DNS URL with '#' prefix.
|
||||||
- 'tls://8.8.4.4:853#Proxy'
|
- 'tls://8.8.4.4:853#DNS'
|
||||||
fallback-filter:
|
fallback-filter:
|
||||||
geoip: false
|
geoip: false
|
||||||
geosite:
|
geosite:
|
||||||
@ -74,8 +90,9 @@ Built-in [Wintun](https://www.wintun.net) driver.
|
|||||||
# Enable the TUN listener
|
# Enable the TUN listener
|
||||||
tun:
|
tun:
|
||||||
enable: true
|
enable: true
|
||||||
stack: gvisor # system or gvisor
|
stack: gvisor # only gvisor
|
||||||
dns-listen: 0.0.0.0:53 # additional dns server listen on TUN
|
dns-hijack:
|
||||||
|
- 0.0.0.0:53 # additional dns server listen on TUN
|
||||||
auto-route: true # auto set global route
|
auto-route: true # auto set global route
|
||||||
```
|
```
|
||||||
### Rules configuration
|
### Rules configuration
|
||||||
@ -118,11 +135,47 @@ rules:
|
|||||||
|
|
||||||
|
|
||||||
### Proxies configuration
|
### Proxies configuration
|
||||||
|
|
||||||
|
Active health detection `urltest / fallback` (based on tcp handshake, multiple failures within a limited time will actively trigger health detection to use the node)
|
||||||
|
|
||||||
|
Support `Policy Group Filter`
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
proxy-groups:
|
||||||
|
|
||||||
|
- name: 🚀 HK Group
|
||||||
|
type: select
|
||||||
|
use:
|
||||||
|
- ALL
|
||||||
|
filter: 'HK'
|
||||||
|
|
||||||
|
- name: 🚀 US Group
|
||||||
|
type: select
|
||||||
|
use:
|
||||||
|
- ALL
|
||||||
|
filter: 'US'
|
||||||
|
|
||||||
|
proxy-providers:
|
||||||
|
ALL:
|
||||||
|
type: http
|
||||||
|
url: "xxxxx"
|
||||||
|
interval: 3600
|
||||||
|
path: "xxxxx"
|
||||||
|
health-check:
|
||||||
|
enable: true
|
||||||
|
interval: 600
|
||||||
|
url: http://www.gstatic.com/generate_204
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Support outbound transport protocol `VLESS`.
|
Support outbound transport protocol `VLESS`.
|
||||||
|
|
||||||
The XTLS only support TCP transport by the XRAY-CORE.
|
The XTLS support TCP/UDP by the XRAY-CORE.
|
||||||
```yaml
|
```yaml
|
||||||
proxies:
|
proxies:
|
||||||
|
# Vless + TCP Sample
|
||||||
- name: "vless-tcp"
|
- name: "vless-tcp"
|
||||||
type: vless
|
type: vless
|
||||||
server: server
|
server: server
|
||||||
@ -132,7 +185,8 @@ proxies:
|
|||||||
servername: example.com # AKA SNI
|
servername: example.com # AKA SNI
|
||||||
# flow: xtls-rprx-direct # xtls-rprx-origin # enable XTLS
|
# flow: xtls-rprx-direct # xtls-rprx-origin # enable XTLS
|
||||||
# skip-cert-verify: true
|
# skip-cert-verify: true
|
||||||
|
|
||||||
|
# Vless + WS Sample
|
||||||
- name: "vless-ws"
|
- name: "vless-ws"
|
||||||
type: vless
|
type: vless
|
||||||
server: server
|
server: server
|
||||||
@ -145,6 +199,17 @@ proxies:
|
|||||||
ws-path: /path
|
ws-path: /path
|
||||||
ws-headers:
|
ws-headers:
|
||||||
Host: example.com
|
Host: example.com
|
||||||
|
|
||||||
|
# Trojan + XTLS Sample
|
||||||
|
- name: "proxy name"
|
||||||
|
type: trojan
|
||||||
|
server: server name
|
||||||
|
port: 443
|
||||||
|
password: password
|
||||||
|
udp: true
|
||||||
|
servername: server name # AKA SNI
|
||||||
|
flow: xtls-rprx-direct # Enable XTLS: xtls-rprx-direct | xtls-rprx-origin
|
||||||
|
skip-cert-verify: false
|
||||||
```
|
```
|
||||||
|
|
||||||
### IPTABLES auto-configuration
|
### IPTABLES auto-configuration
|
||||||
@ -160,13 +225,13 @@ tun:
|
|||||||
```
|
```
|
||||||
Create user given name `Clash.Meta`.
|
Create user given name `Clash.Meta`.
|
||||||
|
|
||||||
Run Meta Kennel by user `Clash.Meta` as a daemon.
|
Run Meta Kernel by user `Clash.Meta` as a daemon.
|
||||||
|
|
||||||
Create the systemd configuration file at /etc/systemd/system/clash.service:
|
Create the systemd configuration file at /etc/systemd/system/clash.service:
|
||||||
|
|
||||||
```
|
```
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Clash.Meta Daemon, Another Clash Kennel.
|
Description=Clash.Meta Daemon, Another Clash Kernel.
|
||||||
After=network.target
|
After=network.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
@ -201,6 +266,13 @@ To display process name in GUI please use [Dashboard For Meta](https://github.co
|
|||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
|
Build the Clash.Meta locally
|
||||||
|
```shell
|
||||||
|
$ git clone https://github.com/MetaCubeX/Clash.Meta.git
|
||||||
|
$ cd Clash.Meta
|
||||||
|
$ make # build for all platform or 'make darwin-amd64' for specific platform, darwin-amd64
|
||||||
|
```
|
||||||
|
|
||||||
If you want to build an application that uses clash as a library, check out the
|
If you want to build an application that uses clash as a library, check out the
|
||||||
the [GitHub Wiki](https://github.com/Dreamacro/clash/wiki/use-clash-as-a-library)
|
the [GitHub Wiki](https://github.com/Dreamacro/clash/wiki/use-clash-as-a-library)
|
||||||
|
|
||||||
|
@ -20,3 +20,26 @@ func NewSocket(target socks5.Addr, conn net.Conn, source C.Type) *context.ConnCo
|
|||||||
|
|
||||||
return context.NewConnContext(conn, metadata)
|
return context.NewConnContext(conn, metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewInner(conn net.Conn, dst string, host string) *context.ConnContext {
|
||||||
|
metadata := &C.Metadata{}
|
||||||
|
metadata.NetWork = C.TCP
|
||||||
|
metadata.Type = C.INNER
|
||||||
|
metadata.DNSMode = C.DNSMapping
|
||||||
|
metadata.Host = host
|
||||||
|
metadata.AddrType = C.AtypDomainName
|
||||||
|
metadata.Process = C.ClashName
|
||||||
|
if ip, port, err := parseAddr(dst); err == nil {
|
||||||
|
metadata.DstPort = port
|
||||||
|
if host == "" {
|
||||||
|
metadata.DstIP = ip
|
||||||
|
if ip.To4() == nil {
|
||||||
|
metadata.AddrType = C.AtypIPv6
|
||||||
|
} else {
|
||||||
|
metadata.AddrType = C.AtypIPv4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.NewConnContext(conn, metadata)
|
||||||
|
}
|
||||||
|
@ -44,3 +44,13 @@ func NewDirect() *Direct {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewCompatible() *Direct {
|
||||||
|
return &Direct{
|
||||||
|
Base: &Base{
|
||||||
|
name: "COMPATIBLE",
|
||||||
|
tp: C.Compatible,
|
||||||
|
udp: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -27,6 +27,7 @@ type SnellOption struct {
|
|||||||
Server string `proxy:"server"`
|
Server string `proxy:"server"`
|
||||||
Port int `proxy:"port"`
|
Port int `proxy:"port"`
|
||||||
Psk string `proxy:"psk"`
|
Psk string `proxy:"psk"`
|
||||||
|
UDP bool `proxy:"udp,omitempty"`
|
||||||
Version int `proxy:"version,omitempty"`
|
Version int `proxy:"version,omitempty"`
|
||||||
ObfsOpts map[string]interface{} `proxy:"obfs-opts,omitempty"`
|
ObfsOpts map[string]interface{} `proxy:"obfs-opts,omitempty"`
|
||||||
}
|
}
|
||||||
@ -85,6 +86,24 @@ func (s *Snell) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d
|
|||||||
return NewConn(c, s), err
|
return NewConn(c, s), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListenPacketContext implements C.ProxyAdapter
|
||||||
|
func (s *Snell) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
|
||||||
|
c, err := dialer.DialContext(ctx, "tcp", s.addr, s.Base.DialOptions(opts...)...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tcpKeepAlive(c)
|
||||||
|
c = streamConn(c, streamOption{s.psk, s.version, s.addr, s.obfsOption})
|
||||||
|
|
||||||
|
err = snell.WriteUDPHeader(c, s.version)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pc := snell.PacketConn(c)
|
||||||
|
return newPacketConn(pc, s), nil
|
||||||
|
}
|
||||||
|
|
||||||
func NewSnell(option SnellOption) (*Snell, error) {
|
func NewSnell(option SnellOption) (*Snell, error) {
|
||||||
addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
|
addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
|
||||||
psk := []byte(option.Psk)
|
psk := []byte(option.Psk)
|
||||||
@ -106,7 +125,13 @@ func NewSnell(option SnellOption) (*Snell, error) {
|
|||||||
if option.Version == 0 {
|
if option.Version == 0 {
|
||||||
option.Version = snell.DefaultSnellVersion
|
option.Version = snell.DefaultSnellVersion
|
||||||
}
|
}
|
||||||
if option.Version != snell.Version1 && option.Version != snell.Version2 {
|
switch option.Version {
|
||||||
|
case snell.Version1, snell.Version2:
|
||||||
|
if option.UDP {
|
||||||
|
return nil, fmt.Errorf("snell version %d not support UDP", option.Version)
|
||||||
|
}
|
||||||
|
case snell.Version3:
|
||||||
|
default:
|
||||||
return nil, fmt.Errorf("snell version error: %d", option.Version)
|
return nil, fmt.Errorf("snell version error: %d", option.Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,6 +140,7 @@ func NewSnell(option SnellOption) (*Snell, error) {
|
|||||||
name: option.Name,
|
name: option.Name,
|
||||||
addr: addr,
|
addr: addr,
|
||||||
tp: C.Snell,
|
tp: C.Snell,
|
||||||
|
udp: option.UDP,
|
||||||
iface: option.Interface,
|
iface: option.Interface,
|
||||||
},
|
},
|
||||||
psk: psk,
|
psk: psk,
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
xtls "github.com/xtls/go"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -33,6 +34,7 @@ type TrojanOption struct {
|
|||||||
Server string `proxy:"server"`
|
Server string `proxy:"server"`
|
||||||
Port int `proxy:"port"`
|
Port int `proxy:"port"`
|
||||||
Password string `proxy:"password"`
|
Password string `proxy:"password"`
|
||||||
|
Flow string `proxy:"flow,omitempty"`
|
||||||
ALPN []string `proxy:"alpn,omitempty"`
|
ALPN []string `proxy:"alpn,omitempty"`
|
||||||
SNI string `proxy:"sni,omitempty"`
|
SNI string `proxy:"sni,omitempty"`
|
||||||
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
|
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
|
||||||
@ -82,7 +84,19 @@ func (t *Trojan) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error)
|
|||||||
return nil, fmt.Errorf("%s connect error: %w", t.addr, err)
|
return nil, fmt.Errorf("%s connect error: %w", t.addr, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = t.instance.WriteHeader(c, trojan.CommandTCP, serializesSocksAddr(metadata))
|
var tc trojan.Command
|
||||||
|
if xtlsConn, ok := c.(*xtls.Conn); ok {
|
||||||
|
xtlsConn.RPRX = true
|
||||||
|
if t.instance.GetFlow() == trojan.XRD {
|
||||||
|
xtlsConn.DirectMode = true
|
||||||
|
tc = trojan.CommandXRD
|
||||||
|
} else {
|
||||||
|
tc = trojan.CommandXRO
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tc = trojan.CommandTCP
|
||||||
|
}
|
||||||
|
err = t.instance.WriteHeader(c, tc, serializesSocksAddr(metadata))
|
||||||
return c, err
|
return c, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,10 +170,13 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
|
|||||||
addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
|
addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
|
||||||
|
|
||||||
tOption := &trojan.Option{
|
tOption := &trojan.Option{
|
||||||
Password: option.Password,
|
Password: option.Password,
|
||||||
ALPN: option.ALPN,
|
Flow: option.Flow,
|
||||||
ServerName: option.Server,
|
ALPN: option.ALPN,
|
||||||
SkipCertVerify: option.SkipCertVerify,
|
ServerName: option.Server,
|
||||||
|
SkipCertVerify: option.SkipCertVerify,
|
||||||
|
ClientSessionCache: getClientSessionCache(),
|
||||||
|
ClientXSessionCache: getClientXSessionCache(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if option.SNI != "" {
|
if option.SNI != "" {
|
||||||
|
@ -2,8 +2,11 @@ package outbound
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/tls"
|
||||||
|
xtls "github.com/xtls/go"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/component/resolver"
|
"github.com/Dreamacro/clash/component/resolver"
|
||||||
@ -11,6 +14,26 @@ import (
|
|||||||
"github.com/Dreamacro/clash/transport/socks5"
|
"github.com/Dreamacro/clash/transport/socks5"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
globalClientSessionCache tls.ClientSessionCache
|
||||||
|
globalClientXSessionCache xtls.ClientSessionCache
|
||||||
|
once sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
|
func getClientSessionCache() tls.ClientSessionCache {
|
||||||
|
once.Do(func() {
|
||||||
|
globalClientSessionCache = tls.NewLRUClientSessionCache(128)
|
||||||
|
})
|
||||||
|
return globalClientSessionCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func getClientXSessionCache() xtls.ClientSessionCache {
|
||||||
|
once.Do(func() {
|
||||||
|
globalClientXSessionCache = xtls.NewLRUClientSessionCache(128)
|
||||||
|
})
|
||||||
|
return globalClientXSessionCache
|
||||||
|
}
|
||||||
|
|
||||||
func tcpKeepAlive(c net.Conn) {
|
func tcpKeepAlive(c net.Conn) {
|
||||||
if tcp, ok := c.(*net.TCPConn); ok {
|
if tcp, ok := c.(*net.TCPConn); ok {
|
||||||
tcp.SetKeepAlive(true)
|
tcp.SetKeepAlive(true)
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package outboundgroup
|
package outboundgroup
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/Dreamacro/clash/tunnel"
|
||||||
|
"regexp"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
@ -11,7 +13,7 @@ const (
|
|||||||
defaultGetProxiesDuration = time.Second * 5
|
defaultGetProxiesDuration = time.Second * 5
|
||||||
)
|
)
|
||||||
|
|
||||||
func getProvidersProxies(providers []provider.ProxyProvider, touch bool) []C.Proxy {
|
func getProvidersProxies(providers []provider.ProxyProvider, touch bool, filter string) []C.Proxy {
|
||||||
proxies := []C.Proxy{}
|
proxies := []C.Proxy{}
|
||||||
for _, provider := range providers {
|
for _, provider := range providers {
|
||||||
if touch {
|
if touch {
|
||||||
@ -20,5 +22,28 @@ func getProvidersProxies(providers []provider.ProxyProvider, touch bool) []C.Pro
|
|||||||
proxies = append(proxies, provider.Proxies()...)
|
proxies = append(proxies, provider.Proxies()...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return proxies
|
|
||||||
|
var filterReg *regexp.Regexp = nil
|
||||||
|
matchedProxies := []C.Proxy{}
|
||||||
|
if len(filter) > 0 {
|
||||||
|
filterReg = regexp.MustCompile(filter)
|
||||||
|
for _, p := range proxies {
|
||||||
|
if filterReg.MatchString(p.Name()) {
|
||||||
|
matchedProxies = append(matchedProxies, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(matchedProxies) > 0 {
|
||||||
|
return matchedProxies
|
||||||
|
} else {
|
||||||
|
return append([]C.Proxy{}, tunnel.Proxies()["COMPATIBLE"])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if len(proxies) == 0 {
|
||||||
|
return append(proxies, tunnel.Proxies()["COMPATIBLE"])
|
||||||
|
} else {
|
||||||
|
return proxies
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import (
|
|||||||
type Fallback struct {
|
type Fallback struct {
|
||||||
*outbound.Base
|
*outbound.Base
|
||||||
disableUDP bool
|
disableUDP bool
|
||||||
|
filter string
|
||||||
single *singledo.Single
|
single *singledo.Single
|
||||||
providers []provider.ProxyProvider
|
providers []provider.ProxyProvider
|
||||||
failedTimes *atomic.Int32
|
failedTimes *atomic.Int32
|
||||||
@ -65,18 +66,20 @@ func (f *Fallback) onDialFailed() {
|
|||||||
f.failedTime.Store(now)
|
f.failedTime.Store(now)
|
||||||
f.failedTimes.Store(1)
|
f.failedTimes.Store(1)
|
||||||
} else {
|
} else {
|
||||||
if f.failedTime.Load()-time.Now().UnixMilli() > 5*1000 {
|
if f.failedTime.Load()-time.Now().UnixMilli() > 5*time.Second.Milliseconds() {
|
||||||
f.failedTimes.Store(-1)
|
f.failedTimes.Store(-1)
|
||||||
f.failedTime.Store(-1)
|
f.failedTime.Store(-1)
|
||||||
} else {
|
} else {
|
||||||
f.failedTimes.Inc()
|
failedCount := f.failedTimes.Inc()
|
||||||
failedCount := f.failedTimes.Load()
|
|
||||||
log.Warnln("%s failed count: %d", f.Name(), failedCount)
|
log.Warnln("%s failed count: %d", f.Name(), failedCount)
|
||||||
if failedCount > 5 {
|
if failedCount >= 5 {
|
||||||
log.Debugln("%s failed multiple times.", f.Name())
|
log.Warnln("because %s failed multiple times, active health check", f.Name())
|
||||||
for _, proxyProvider := range f.providers {
|
for _, proxyProvider := range f.providers {
|
||||||
go proxyProvider.HealthCheck()
|
go proxyProvider.HealthCheck()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f.failedTimes.Store(-1)
|
||||||
|
f.failedTime.Store(-1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,10 +97,11 @@ func (f *Fallback) SupportUDP() bool {
|
|||||||
|
|
||||||
// MarshalJSON implements C.ProxyAdapter
|
// MarshalJSON implements C.ProxyAdapter
|
||||||
func (f *Fallback) MarshalJSON() ([]byte, error) {
|
func (f *Fallback) MarshalJSON() ([]byte, error) {
|
||||||
var all []string
|
all := make([]string, 0)
|
||||||
for _, proxy := range f.proxies(false) {
|
for _, proxy := range f.proxies(false) {
|
||||||
all = append(all, proxy.Name())
|
all = append(all, proxy.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
return json.Marshal(map[string]interface{}{
|
return json.Marshal(map[string]interface{}{
|
||||||
"type": f.Type().String(),
|
"type": f.Type().String(),
|
||||||
"now": f.Now(),
|
"now": f.Now(),
|
||||||
@ -113,7 +117,7 @@ func (f *Fallback) Unwrap(metadata *C.Metadata) C.Proxy {
|
|||||||
|
|
||||||
func (f *Fallback) proxies(touch bool) []C.Proxy {
|
func (f *Fallback) proxies(touch bool) []C.Proxy {
|
||||||
elm, _, _ := f.single.Do(func() (interface{}, error) {
|
elm, _, _ := f.single.Do(func() (interface{}, error) {
|
||||||
return getProvidersProxies(f.providers, touch), nil
|
return getProvidersProxies(f.providers, touch, f.filter), nil
|
||||||
})
|
})
|
||||||
|
|
||||||
return elm.([]C.Proxy)
|
return elm.([]C.Proxy)
|
||||||
@ -141,6 +145,7 @@ func NewFallback(option *GroupCommonOption, providers []provider.ProxyProvider)
|
|||||||
single: singledo.NewSingle(defaultGetProxiesDuration),
|
single: singledo.NewSingle(defaultGetProxiesDuration),
|
||||||
providers: providers,
|
providers: providers,
|
||||||
disableUDP: option.DisableUDP,
|
disableUDP: option.DisableUDP,
|
||||||
|
filter: option.Filter,
|
||||||
failedTimes: atomic.NewInt32(-1),
|
failedTimes: atomic.NewInt32(-1),
|
||||||
failedTime: atomic.NewInt64(-1),
|
failedTime: atomic.NewInt64(-1),
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ type LoadBalance struct {
|
|||||||
*outbound.Base
|
*outbound.Base
|
||||||
disableUDP bool
|
disableUDP bool
|
||||||
single *singledo.Single
|
single *singledo.Single
|
||||||
|
filter string
|
||||||
providers []provider.ProxyProvider
|
providers []provider.ProxyProvider
|
||||||
strategyFn strategyFn
|
strategyFn strategyFn
|
||||||
}
|
}
|
||||||
@ -141,7 +142,7 @@ func (lb *LoadBalance) Unwrap(metadata *C.Metadata) C.Proxy {
|
|||||||
|
|
||||||
func (lb *LoadBalance) proxies(touch bool) []C.Proxy {
|
func (lb *LoadBalance) proxies(touch bool) []C.Proxy {
|
||||||
elm, _, _ := lb.single.Do(func() (interface{}, error) {
|
elm, _, _ := lb.single.Do(func() (interface{}, error) {
|
||||||
return getProvidersProxies(lb.providers, touch), nil
|
return getProvidersProxies(lb.providers, touch, lb.filter), nil
|
||||||
})
|
})
|
||||||
|
|
||||||
return elm.([]C.Proxy)
|
return elm.([]C.Proxy)
|
||||||
@ -149,10 +150,12 @@ func (lb *LoadBalance) proxies(touch bool) []C.Proxy {
|
|||||||
|
|
||||||
// MarshalJSON implements C.ProxyAdapter
|
// MarshalJSON implements C.ProxyAdapter
|
||||||
func (lb *LoadBalance) MarshalJSON() ([]byte, error) {
|
func (lb *LoadBalance) MarshalJSON() ([]byte, error) {
|
||||||
var all []string
|
all := make([]string, 0)
|
||||||
|
|
||||||
for _, proxy := range lb.proxies(false) {
|
for _, proxy := range lb.proxies(false) {
|
||||||
all = append(all, proxy.Name())
|
all = append(all, proxy.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
return json.Marshal(map[string]interface{}{
|
return json.Marshal(map[string]interface{}{
|
||||||
"type": lb.Type().String(),
|
"type": lb.Type().String(),
|
||||||
"all": all,
|
"all": all,
|
||||||
@ -180,5 +183,6 @@ func NewLoadBalance(option *GroupCommonOption, providers []provider.ProxyProvide
|
|||||||
providers: providers,
|
providers: providers,
|
||||||
strategyFn: strategyFn,
|
strategyFn: strategyFn,
|
||||||
disableUDP: option.DisableUDP,
|
disableUDP: option.DisableUDP,
|
||||||
|
filter: option.Filter,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ type GroupCommonOption struct {
|
|||||||
Interval int `group:"interval,omitempty"`
|
Interval int `group:"interval,omitempty"`
|
||||||
Lazy bool `group:"lazy,omitempty"`
|
Lazy bool `group:"lazy,omitempty"`
|
||||||
DisableUDP bool `group:"disable-udp,omitempty"`
|
DisableUDP bool `group:"disable-udp,omitempty"`
|
||||||
|
Filter string `group:"filter,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseProxyGroup(config map[string]interface{}, proxyMap map[string]C.Proxy, providersMap map[string]types.ProxyProvider) (C.ProxyAdapter, error) {
|
func ParseProxyGroup(config map[string]interface{}, proxyMap map[string]C.Proxy, providersMap map[string]types.ProxyProvider) (C.ProxyAdapter, error) {
|
||||||
@ -95,6 +96,8 @@ func ParseProxyGroup(config map[string]interface{}, proxyMap map[string]C.Proxy,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
providers = append(providers, list...)
|
providers = append(providers, list...)
|
||||||
|
} else {
|
||||||
|
groupOption.Filter = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
var group C.ProxyAdapter
|
var group C.ProxyAdapter
|
||||||
|
@ -16,13 +16,14 @@ type Relay struct {
|
|||||||
*outbound.Base
|
*outbound.Base
|
||||||
single *singledo.Single
|
single *singledo.Single
|
||||||
providers []provider.ProxyProvider
|
providers []provider.ProxyProvider
|
||||||
|
filter string
|
||||||
}
|
}
|
||||||
|
|
||||||
// DialContext implements C.ProxyAdapter
|
// DialContext implements C.ProxyAdapter
|
||||||
func (r *Relay) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
|
func (r *Relay) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
|
||||||
var proxies []C.Proxy
|
var proxies []C.Proxy
|
||||||
for _, proxy := range r.proxies(metadata, true) {
|
for _, proxy := range r.proxies(metadata, true) {
|
||||||
if proxy.Type() != C.Direct {
|
if proxy.Type() != C.Direct && proxy.Type() != C.Compatible {
|
||||||
proxies = append(proxies, proxy)
|
proxies = append(proxies, proxy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -68,10 +69,12 @@ func (r *Relay) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d
|
|||||||
|
|
||||||
// MarshalJSON implements C.ProxyAdapter
|
// MarshalJSON implements C.ProxyAdapter
|
||||||
func (r *Relay) MarshalJSON() ([]byte, error) {
|
func (r *Relay) MarshalJSON() ([]byte, error) {
|
||||||
var all []string
|
all := make([]string, 0)
|
||||||
|
|
||||||
for _, proxy := range r.rawProxies(false) {
|
for _, proxy := range r.rawProxies(false) {
|
||||||
all = append(all, proxy.Name())
|
all = append(all, proxy.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
return json.Marshal(map[string]interface{}{
|
return json.Marshal(map[string]interface{}{
|
||||||
"type": r.Type().String(),
|
"type": r.Type().String(),
|
||||||
"all": all,
|
"all": all,
|
||||||
@ -80,7 +83,7 @@ func (r *Relay) MarshalJSON() ([]byte, error) {
|
|||||||
|
|
||||||
func (r *Relay) rawProxies(touch bool) []C.Proxy {
|
func (r *Relay) rawProxies(touch bool) []C.Proxy {
|
||||||
elm, _, _ := r.single.Do(func() (interface{}, error) {
|
elm, _, _ := r.single.Do(func() (interface{}, error) {
|
||||||
return getProvidersProxies(r.providers, touch), nil
|
return getProvidersProxies(r.providers, touch, r.filter), nil
|
||||||
})
|
})
|
||||||
|
|
||||||
return elm.([]C.Proxy)
|
return elm.([]C.Proxy)
|
||||||
@ -110,5 +113,6 @@ func NewRelay(option *GroupCommonOption, providers []provider.ProxyProvider) *Re
|
|||||||
}),
|
}),
|
||||||
single: singledo.NewSingle(defaultGetProxiesDuration),
|
single: singledo.NewSingle(defaultGetProxiesDuration),
|
||||||
providers: providers,
|
providers: providers,
|
||||||
|
filter: option.Filter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ type Selector struct {
|
|||||||
disableUDP bool
|
disableUDP bool
|
||||||
single *singledo.Single
|
single *singledo.Single
|
||||||
selected string
|
selected string
|
||||||
|
filter string
|
||||||
providers []provider.ProxyProvider
|
providers []provider.ProxyProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,8 +50,9 @@ func (s *Selector) SupportUDP() bool {
|
|||||||
|
|
||||||
// MarshalJSON implements C.ProxyAdapter
|
// MarshalJSON implements C.ProxyAdapter
|
||||||
func (s *Selector) MarshalJSON() ([]byte, error) {
|
func (s *Selector) MarshalJSON() ([]byte, error) {
|
||||||
var all []string
|
all := make([]string, 0)
|
||||||
for _, proxy := range getProvidersProxies(s.providers, false) {
|
|
||||||
|
for _, proxy := range getProvidersProxies(s.providers, false, s.filter) {
|
||||||
all = append(all, proxy.Name())
|
all = append(all, proxy.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +68,7 @@ func (s *Selector) Now() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Selector) Set(name string) error {
|
func (s *Selector) Set(name string) error {
|
||||||
for _, proxy := range getProvidersProxies(s.providers, false) {
|
for _, proxy := range getProvidersProxies(s.providers, false, s.filter) {
|
||||||
if proxy.Name() == name {
|
if proxy.Name() == name {
|
||||||
s.selected = name
|
s.selected = name
|
||||||
s.single.Reset()
|
s.single.Reset()
|
||||||
@ -84,7 +86,7 @@ func (s *Selector) Unwrap(metadata *C.Metadata) C.Proxy {
|
|||||||
|
|
||||||
func (s *Selector) selectedProxy(touch bool) C.Proxy {
|
func (s *Selector) selectedProxy(touch bool) C.Proxy {
|
||||||
elm, _, _ := s.single.Do(func() (interface{}, error) {
|
elm, _, _ := s.single.Do(func() (interface{}, error) {
|
||||||
proxies := getProvidersProxies(s.providers, touch)
|
proxies := getProvidersProxies(s.providers, touch, s.filter)
|
||||||
for _, proxy := range proxies {
|
for _, proxy := range proxies {
|
||||||
if proxy.Name() == s.selected {
|
if proxy.Name() == s.selected {
|
||||||
return proxy, nil
|
return proxy, nil
|
||||||
@ -98,7 +100,6 @@ func (s *Selector) selectedProxy(touch bool) C.Proxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewSelector(option *GroupCommonOption, providers []provider.ProxyProvider) *Selector {
|
func NewSelector(option *GroupCommonOption, providers []provider.ProxyProvider) *Selector {
|
||||||
selected := providers[0].Proxies()[0].Name()
|
|
||||||
return &Selector{
|
return &Selector{
|
||||||
Base: outbound.NewBase(outbound.BaseOption{
|
Base: outbound.NewBase(outbound.BaseOption{
|
||||||
Name: option.Name,
|
Name: option.Name,
|
||||||
@ -108,7 +109,8 @@ func NewSelector(option *GroupCommonOption, providers []provider.ProxyProvider)
|
|||||||
}),
|
}),
|
||||||
single: singledo.NewSingle(defaultGetProxiesDuration),
|
single: singledo.NewSingle(defaultGetProxiesDuration),
|
||||||
providers: providers,
|
providers: providers,
|
||||||
selected: selected,
|
selected: "COMPATIBLE",
|
||||||
disableUDP: option.DisableUDP,
|
disableUDP: option.DisableUDP,
|
||||||
|
filter: option.Filter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ type URLTest struct {
|
|||||||
tolerance uint16
|
tolerance uint16
|
||||||
disableUDP bool
|
disableUDP bool
|
||||||
fastNode C.Proxy
|
fastNode C.Proxy
|
||||||
|
filter string
|
||||||
single *singledo.Single
|
single *singledo.Single
|
||||||
fastSingle *singledo.Single
|
fastSingle *singledo.Single
|
||||||
providers []provider.ProxyProvider
|
providers []provider.ProxyProvider
|
||||||
@ -73,7 +74,7 @@ func (u *URLTest) Unwrap(metadata *C.Metadata) C.Proxy {
|
|||||||
|
|
||||||
func (u *URLTest) proxies(touch bool) []C.Proxy {
|
func (u *URLTest) proxies(touch bool) []C.Proxy {
|
||||||
elm, _, _ := u.single.Do(func() (interface{}, error) {
|
elm, _, _ := u.single.Do(func() (interface{}, error) {
|
||||||
return getProvidersProxies(u.providers, touch), nil
|
return getProvidersProxies(u.providers, touch, u.filter), nil
|
||||||
})
|
})
|
||||||
|
|
||||||
return elm.([]C.Proxy)
|
return elm.([]C.Proxy)
|
||||||
@ -124,10 +125,12 @@ func (u *URLTest) SupportUDP() bool {
|
|||||||
|
|
||||||
// MarshalJSON implements C.ProxyAdapter
|
// MarshalJSON implements C.ProxyAdapter
|
||||||
func (u *URLTest) MarshalJSON() ([]byte, error) {
|
func (u *URLTest) MarshalJSON() ([]byte, error) {
|
||||||
var all []string
|
all := make([]string, 0)
|
||||||
|
|
||||||
for _, proxy := range u.proxies(false) {
|
for _, proxy := range u.proxies(false) {
|
||||||
all = append(all, proxy.Name())
|
all = append(all, proxy.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
return json.Marshal(map[string]interface{}{
|
return json.Marshal(map[string]interface{}{
|
||||||
"type": u.Type().String(),
|
"type": u.Type().String(),
|
||||||
"now": u.Now(),
|
"now": u.Now(),
|
||||||
@ -146,14 +149,16 @@ func (u *URLTest) onDialFailed() {
|
|||||||
u.failedTimes.Store(-1)
|
u.failedTimes.Store(-1)
|
||||||
u.failedTime.Store(-1)
|
u.failedTime.Store(-1)
|
||||||
} else {
|
} else {
|
||||||
u.failedTimes.Inc()
|
failedCount := u.failedTimes.Inc()
|
||||||
failedCount := u.failedTimes.Load()
|
|
||||||
log.Warnln("%s failed count: %d", u.Name(), failedCount)
|
log.Warnln("%s failed count: %d", u.Name(), failedCount)
|
||||||
if failedCount > 5 {
|
if failedCount >= 5 {
|
||||||
log.Debugln("%s failed multiple times.", u.Name())
|
log.Warnln("because %s failed multiple times, active health check", u.Name())
|
||||||
for _, proxyProvider := range u.providers {
|
for _, proxyProvider := range u.providers {
|
||||||
go proxyProvider.HealthCheck()
|
go proxyProvider.HealthCheck()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u.failedTimes.Store(-1)
|
||||||
|
u.failedTime.Store(-1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -184,6 +189,7 @@ func NewURLTest(option *GroupCommonOption, providers []provider.ProxyProvider, o
|
|||||||
fastSingle: singledo.NewSingle(time.Second * 10),
|
fastSingle: singledo.NewSingle(time.Second * 10),
|
||||||
providers: providers,
|
providers: providers,
|
||||||
disableUDP: option.DisableUDP,
|
disableUDP: option.DisableUDP,
|
||||||
|
filter: option.Filter,
|
||||||
failedTimes: atomic.NewInt32(-1),
|
failedTimes: atomic.NewInt32(-1),
|
||||||
failedTime: atomic.NewInt64(-1),
|
failedTime: atomic.NewInt64(-1),
|
||||||
}
|
}
|
||||||
|
@ -102,6 +102,7 @@ func (f *fetcher) Update() (interface{}, bool, error) {
|
|||||||
hash := md5.Sum(buf)
|
hash := md5.Sum(buf)
|
||||||
if bytes.Equal(f.hash[:], hash[:]) {
|
if bytes.Equal(f.hash[:], hash[:]) {
|
||||||
f.updatedAt = &now
|
f.updatedAt = &now
|
||||||
|
os.Chtimes(f.vehicle.Path(), now, now)
|
||||||
return nil, true, nil
|
return nil, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +67,10 @@ func (pp *proxySetProvider) Initial() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pp.onUpdate(elm)
|
pp.onUpdate(elm)
|
||||||
|
if pp.healthCheck.auto() {
|
||||||
|
go pp.healthCheck.process()
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,10 +106,6 @@ func NewProxySetProvider(name string, interval time.Duration, filter string, veh
|
|||||||
return nil, fmt.Errorf("invalid filter regex: %w", err)
|
return nil, fmt.Errorf("invalid filter regex: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if hc.auto() {
|
|
||||||
go hc.process()
|
|
||||||
}
|
|
||||||
|
|
||||||
pd := &proxySetProvider{
|
pd := &proxySetProvider{
|
||||||
proxies: []C.Proxy{},
|
proxies: []C.Proxy{},
|
||||||
healthCheck: hc,
|
healthCheck: hc,
|
||||||
@ -190,6 +190,10 @@ func (cp *compatibleProvider) Update() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cp *compatibleProvider) Initial() error {
|
func (cp *compatibleProvider) Initial() error {
|
||||||
|
if cp.healthCheck.auto() {
|
||||||
|
go cp.healthCheck.process()
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,10 +223,6 @@ func NewCompatibleProvider(name string, proxies []C.Proxy, hc *HealthCheck) (*Co
|
|||||||
return nil, errors.New("provider need one proxy at least")
|
return nil, errors.New("provider need one proxy at least")
|
||||||
}
|
}
|
||||||
|
|
||||||
if hc.auto() {
|
|
||||||
go hc.process()
|
|
||||||
}
|
|
||||||
|
|
||||||
pd := &compatibleProvider{
|
pd := &compatibleProvider{
|
||||||
name: name,
|
name: name,
|
||||||
proxies: proxies,
|
proxies: proxies,
|
||||||
|
@ -2,6 +2,7 @@ package provider
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/Dreamacro/clash/listener/inner"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -10,7 +11,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
netHttp "github.com/Dreamacro/clash/common/net"
|
netHttp "github.com/Dreamacro/clash/common/net"
|
||||||
"github.com/Dreamacro/clash/component/dialer"
|
|
||||||
types "github.com/Dreamacro/clash/constant/provider"
|
types "github.com/Dreamacro/clash/constant/provider"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -77,7 +77,8 @@ func (h *HTTPVehicle) Read() ([]byte, error) {
|
|||||||
TLSHandshakeTimeout: 10 * time.Second,
|
TLSHandshakeTimeout: 10 * time.Second,
|
||||||
ExpectContinueTimeout: 1 * time.Second,
|
ExpectContinueTimeout: 1 * time.Second,
|
||||||
DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
|
DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||||
return dialer.DialContext(ctx, network, address)
|
conn := inner.HandleTcp(address, uri.Hostname())
|
||||||
|
return conn, nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
56
common/collections/stack.go
Normal file
56
common/collections/stack.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package collections
|
||||||
|
|
||||||
|
import "sync"
|
||||||
|
|
||||||
|
type (
|
||||||
|
stack struct {
|
||||||
|
top *node
|
||||||
|
length int
|
||||||
|
lock *sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
node struct {
|
||||||
|
value interface{}
|
||||||
|
prev *node
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewStack Create a new stack
|
||||||
|
func NewStack() *stack {
|
||||||
|
return &stack{nil, 0, &sync.RWMutex{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len Return the number of items in the stack
|
||||||
|
func (this *stack) Len() int {
|
||||||
|
return this.length
|
||||||
|
}
|
||||||
|
|
||||||
|
// Peek View the top item on the stack
|
||||||
|
func (this *stack) Peek() interface{} {
|
||||||
|
if this.length == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return this.top.value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pop the top item of the stack and return it
|
||||||
|
func (this *stack) Pop() interface{} {
|
||||||
|
this.lock.Lock()
|
||||||
|
defer this.lock.Unlock()
|
||||||
|
if this.length == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
n := this.top
|
||||||
|
this.top = n.prev
|
||||||
|
this.length--
|
||||||
|
return n.value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push a value onto the top of the stack
|
||||||
|
func (this *stack) Push(value interface{}) {
|
||||||
|
this.lock.Lock()
|
||||||
|
defer this.lock.Unlock()
|
||||||
|
n := &node{value, this.top}
|
||||||
|
this.top = n
|
||||||
|
this.length++
|
||||||
|
}
|
46
common/net/tcpip.go
Normal file
46
common/net/tcpip.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SplitNetworkType(s string) (string, string, error) {
|
||||||
|
var (
|
||||||
|
shecme string
|
||||||
|
hostPort string
|
||||||
|
)
|
||||||
|
result := strings.Split(s, "://")
|
||||||
|
if len(result) == 2 {
|
||||||
|
shecme = result[0]
|
||||||
|
hostPort = result[1]
|
||||||
|
} else if len(result) == 1 {
|
||||||
|
hostPort = result[0]
|
||||||
|
} else {
|
||||||
|
return "", "", fmt.Errorf("tcp/udp style error")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(shecme) == 0 {
|
||||||
|
shecme = "udp"
|
||||||
|
}
|
||||||
|
|
||||||
|
if shecme != "tcp" && shecme != "udp" {
|
||||||
|
return "", "", fmt.Errorf("scheme should be tcp:// or udp://")
|
||||||
|
} else {
|
||||||
|
return shecme, hostPort, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SplitHostPort(s string) (host, port string, hasPort bool, err error) {
|
||||||
|
temp := s
|
||||||
|
hasPort = true
|
||||||
|
|
||||||
|
if !strings.Contains(s, ":") && !strings.Contains(s, "]:") {
|
||||||
|
temp += ":0"
|
||||||
|
hasPort = false
|
||||||
|
}
|
||||||
|
|
||||||
|
host, port, err = net.SplitHostPort(temp)
|
||||||
|
return
|
||||||
|
}
|
@ -11,6 +11,7 @@ import (
|
|||||||
func DialContext(ctx context.Context, network, address string, options ...Option) (net.Conn, error) {
|
func DialContext(ctx context.Context, network, address string, options ...Option) (net.Conn, error) {
|
||||||
opt := &option{
|
opt := &option{
|
||||||
interfaceName: DefaultInterface.Load(),
|
interfaceName: DefaultInterface.Load(),
|
||||||
|
routingMark: int(DefaultRoutingMark.Load()),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, o := range DefaultOptions {
|
for _, o := range DefaultOptions {
|
||||||
@ -58,6 +59,7 @@ func DialContext(ctx context.Context, network, address string, options ...Option
|
|||||||
func ListenPacket(ctx context.Context, network, address string, options ...Option) (net.PacketConn, error) {
|
func ListenPacket(ctx context.Context, network, address string, options ...Option) (net.PacketConn, error) {
|
||||||
cfg := &option{
|
cfg := &option{
|
||||||
interfaceName: DefaultInterface.Load(),
|
interfaceName: DefaultInterface.Load(),
|
||||||
|
routingMark: int(DefaultRoutingMark.Load()),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, o := range DefaultOptions {
|
for _, o := range DefaultOptions {
|
||||||
|
@ -3,8 +3,9 @@ package dialer
|
|||||||
import "go.uber.org/atomic"
|
import "go.uber.org/atomic"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
DefaultOptions []Option
|
DefaultOptions []Option
|
||||||
DefaultInterface = atomic.NewString("")
|
DefaultInterface = atomic.NewString("")
|
||||||
|
DefaultRoutingMark = atomic.NewInt32(0)
|
||||||
)
|
)
|
||||||
|
|
||||||
type option struct {
|
type option struct {
|
||||||
|
@ -3,6 +3,7 @@ package geodata
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/component/geodata/router"
|
"github.com/Dreamacro/clash/component/geodata/router"
|
||||||
@ -14,7 +15,7 @@ type loader struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *loader) LoadGeoSite(list string) ([]*router.Domain, error) {
|
func (l *loader) LoadGeoSite(list string) ([]*router.Domain, error) {
|
||||||
return l.LoadGeoSiteWithAttr("geosite.dat", list)
|
return l.LoadGeoSiteWithAttr(C.GeositeName, list)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *loader) LoadGeoSiteWithAttr(file string, siteWithAttr string) ([]*router.Domain, error) {
|
func (l *loader) LoadGeoSiteWithAttr(file string, siteWithAttr string) ([]*router.Domain, error) {
|
||||||
@ -58,7 +59,7 @@ func (l *loader) LoadGeoSiteWithAttr(file string, siteWithAttr string) ([]*route
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *loader) LoadGeoIP(country string) ([]*router.CIDR, error) {
|
func (l *loader) LoadGeoIP(country string) ([]*router.CIDR, error) {
|
||||||
return l.LoadIP("geoip.dat", country)
|
return l.LoadIP(C.GeoipName, country)
|
||||||
}
|
}
|
||||||
|
|
||||||
var loaders map[string]func() LoaderImplementation
|
var loaders map[string]func() LoaderImplementation
|
||||||
|
@ -4,8 +4,19 @@ import (
|
|||||||
"github.com/Dreamacro/clash/component/geodata/router"
|
"github.com/Dreamacro/clash/component/geodata/router"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var geoLoaderName = "memconservative"
|
||||||
|
|
||||||
|
// geoLoaderName = "standard"
|
||||||
|
|
||||||
|
func LoaderName() string {
|
||||||
|
return geoLoaderName
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetLoader(newLoader string) {
|
||||||
|
geoLoaderName = newLoader
|
||||||
|
}
|
||||||
|
|
||||||
func LoadGeoSiteMatcher(countryCode string) (*router.DomainMatcher, int, error) {
|
func LoadGeoSiteMatcher(countryCode string) (*router.DomainMatcher, int, error) {
|
||||||
geoLoaderName := "standard"
|
|
||||||
geoLoader, err := GetGeoDataLoader(geoLoaderName)
|
geoLoader, err := GetGeoDataLoader(geoLoaderName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
|
@ -109,13 +109,13 @@ func (t *DomainTrie) search(node *Node, parts []string) *Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if c := node.getChild(parts[len(parts)-1]); c != nil {
|
if c := node.getChild(parts[len(parts)-1]); c != nil {
|
||||||
if n := t.search(c, parts[:len(parts)-1]); n != nil {
|
if n := t.search(c, parts[:len(parts)-1]); n != nil && n.Data != nil {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c := node.getChild(wildcard); c != nil {
|
if c := node.getChild(wildcard); c != nil {
|
||||||
if n := t.search(c, parts[:len(parts)-1]); n != nil {
|
if n := t.search(c, parts[:len(parts)-1]); n != nil && n.Data != nil {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,3 +97,11 @@ func TestTrie_Boundary(t *testing.T) {
|
|||||||
assert.NotNil(t, tree.Insert("..dev", localIP))
|
assert.NotNil(t, tree.Insert("..dev", localIP))
|
||||||
assert.Nil(t, tree.Search("dev"))
|
assert.Nil(t, tree.Search("dev"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTrie_WildcardBoundary(t *testing.T) {
|
||||||
|
tree := New()
|
||||||
|
tree.Insert("+.*", localIP)
|
||||||
|
tree.Insert("stun.*.*.*", localIP)
|
||||||
|
|
||||||
|
assert.NotNil(t, tree.Search("example.com"))
|
||||||
|
}
|
||||||
|
@ -103,7 +103,7 @@ func subIpCidr(ip net.IP, maskSize int, isIpv4 bool) ([]net.IP, int, error) {
|
|||||||
lastByteMaskSize := maskSize % 8
|
lastByteMaskSize := maskSize % 8
|
||||||
lastByteMaskIndex := maskSize / 8
|
lastByteMaskIndex := maskSize / 8
|
||||||
subIpCidrNum := 0xFF >> lastByteMaskSize
|
subIpCidrNum := 0xFF >> lastByteMaskSize
|
||||||
for i := 0; i < subIpCidrNum; i++ {
|
for i := 0; i <= subIpCidrNum; i++ {
|
||||||
subIpCidr := make([]byte, len(ip))
|
subIpCidr := make([]byte, len(ip))
|
||||||
copy(subIpCidr, ip)
|
copy(subIpCidr, ip)
|
||||||
subIpCidr[lastByteMaskIndex] += byte(i)
|
subIpCidr[lastByteMaskIndex] += byte(i)
|
||||||
|
@ -2,8 +2,8 @@ package trie
|
|||||||
|
|
||||||
// Node is the trie's node
|
// Node is the trie's node
|
||||||
type Node struct {
|
type Node struct {
|
||||||
Data interface{}
|
|
||||||
children map[string]*Node
|
children map[string]*Node
|
||||||
|
Data interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) getChild(s string) *Node {
|
func (n *Node) getChild(s string) *Node {
|
||||||
|
@ -26,12 +26,20 @@ func TestIpv4AddFail(t *testing.T) {
|
|||||||
|
|
||||||
func TestIpv4Search(t *testing.T) {
|
func TestIpv4Search(t *testing.T) {
|
||||||
trie := NewIpCidrTrie()
|
trie := NewIpCidrTrie()
|
||||||
|
// Boundary testing
|
||||||
|
assert.NoError(t, trie.AddIpCidrForString("149.154.160.0/20"))
|
||||||
|
assert.Equal(t, true, trie.IsContainForString("149.154.160.0"))
|
||||||
|
assert.Equal(t, true, trie.IsContainForString("149.154.175.255"))
|
||||||
|
assert.Equal(t, false, trie.IsContainForString("149.154.176.0"))
|
||||||
|
assert.Equal(t, false, trie.IsContainForString("149.154.159.255"))
|
||||||
|
|
||||||
assert.NoError(t, trie.AddIpCidrForString("129.2.36.0/16"))
|
assert.NoError(t, trie.AddIpCidrForString("129.2.36.0/16"))
|
||||||
assert.NoError(t, trie.AddIpCidrForString("10.2.36.0/18"))
|
assert.NoError(t, trie.AddIpCidrForString("10.2.36.0/18"))
|
||||||
assert.NoError(t, trie.AddIpCidrForString("16.2.23.0/24"))
|
assert.NoError(t, trie.AddIpCidrForString("16.2.23.0/24"))
|
||||||
assert.NoError(t, trie.AddIpCidrForString("11.2.13.2/26"))
|
assert.NoError(t, trie.AddIpCidrForString("11.2.13.2/26"))
|
||||||
assert.NoError(t, trie.AddIpCidrForString("55.5.6.3/8"))
|
assert.NoError(t, trie.AddIpCidrForString("55.5.6.3/8"))
|
||||||
assert.NoError(t, trie.AddIpCidrForString("66.23.25.4/6"))
|
assert.NoError(t, trie.AddIpCidrForString("66.23.25.4/6"))
|
||||||
|
|
||||||
assert.Equal(t, true, trie.IsContainForString("129.2.3.65"))
|
assert.Equal(t, true, trie.IsContainForString("129.2.3.65"))
|
||||||
assert.Equal(t, false, trie.IsContainForString("15.2.3.1"))
|
assert.Equal(t, false, trie.IsContainForString("15.2.3.1"))
|
||||||
assert.Equal(t, true, trie.IsContainForString("11.2.13.1"))
|
assert.Equal(t, true, trie.IsContainForString("11.2.13.1"))
|
||||||
@ -41,6 +49,7 @@ func TestIpv4Search(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(t, false, trie.IsContain(net.ParseIP("22")))
|
assert.Equal(t, false, trie.IsContain(net.ParseIP("22")))
|
||||||
assert.Equal(t, false, trie.IsContain(net.ParseIP("")))
|
assert.Equal(t, false, trie.IsContain(net.ParseIP("")))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIpv6AddSuccess(t *testing.T) {
|
func TestIpv6AddSuccess(t *testing.T) {
|
||||||
@ -66,6 +75,14 @@ func TestIpv6AddFail(t *testing.T) {
|
|||||||
|
|
||||||
func TestIpv6Search(t *testing.T) {
|
func TestIpv6Search(t *testing.T) {
|
||||||
trie := NewIpCidrTrie()
|
trie := NewIpCidrTrie()
|
||||||
|
|
||||||
|
// Boundary testing
|
||||||
|
assert.NoError(t, trie.AddIpCidrForString("2a0a:f280::/32"))
|
||||||
|
assert.Equal(t, true, trie.IsContainForString("2a0a:f280:0000:0000:0000:0000:0000:0000"))
|
||||||
|
assert.Equal(t, true, trie.IsContainForString("2a0a:f280:ffff:ffff:ffff:ffff:ffff:ffff"))
|
||||||
|
assert.Equal(t, false, trie.IsContainForString("2a0a:f279:ffff:ffff:ffff:ffff:ffff:ffff"))
|
||||||
|
assert.Equal(t, false, trie.IsContainForString("2a0a:f281:0000:0000:0000:0000:0000:0000"))
|
||||||
|
|
||||||
assert.NoError(t, trie.AddIpCidrForString("2001:b28:f23d:f001::e/128"))
|
assert.NoError(t, trie.AddIpCidrForString("2001:b28:f23d:f001::e/128"))
|
||||||
assert.NoError(t, trie.AddIpCidrForString("2001:67c:4e8:f002::e/12"))
|
assert.NoError(t, trie.AddIpCidrForString("2001:67c:4e8:f002::e/12"))
|
||||||
assert.NoError(t, trie.AddIpCidrForString("2001:b28:f23d:f003::e/96"))
|
assert.NoError(t, trie.AddIpCidrForString("2001:b28:f23d:f003::e/96"))
|
||||||
@ -79,4 +96,5 @@ func TestIpv6Search(t *testing.T) {
|
|||||||
assert.Equal(t, true, trie.IsContainForString("2001:67c:4e8:9666::1213"))
|
assert.Equal(t, true, trie.IsContainForString("2001:67c:4e8:9666::1213"))
|
||||||
|
|
||||||
assert.Equal(t, false, trie.IsContain(net.ParseIP("22233:22")))
|
assert.Equal(t, false, trie.IsContain(net.ParseIP("22233:22")))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
160
config/config.go
160
config/config.go
@ -4,12 +4,15 @@ import (
|
|||||||
"container/list"
|
"container/list"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
R "github.com/Dreamacro/clash/rule"
|
||||||
|
RP "github.com/Dreamacro/clash/rule/provider"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/adapter"
|
"github.com/Dreamacro/clash/adapter"
|
||||||
"github.com/Dreamacro/clash/adapter/outbound"
|
"github.com/Dreamacro/clash/adapter/outbound"
|
||||||
@ -24,7 +27,6 @@ import (
|
|||||||
providerTypes "github.com/Dreamacro/clash/constant/provider"
|
providerTypes "github.com/Dreamacro/clash/constant/provider"
|
||||||
"github.com/Dreamacro/clash/dns"
|
"github.com/Dreamacro/clash/dns"
|
||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
R "github.com/Dreamacro/clash/rule"
|
|
||||||
T "github.com/Dreamacro/clash/tunnel"
|
T "github.com/Dreamacro/clash/tunnel"
|
||||||
|
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
@ -34,11 +36,13 @@ import (
|
|||||||
type General struct {
|
type General struct {
|
||||||
Inbound
|
Inbound
|
||||||
Controller
|
Controller
|
||||||
Mode T.TunnelMode `json:"mode"`
|
Mode T.TunnelMode `json:"mode"`
|
||||||
UnifiedDelay bool
|
UnifiedDelay bool
|
||||||
LogLevel log.LogLevel `json:"log-level"`
|
LogLevel log.LogLevel `json:"log-level"`
|
||||||
IPv6 bool `json:"ipv6"`
|
IPv6 bool `json:"ipv6"`
|
||||||
Interface string `json:"-"`
|
Interface string `json:"-"`
|
||||||
|
GeodataLoader string `json:"geodata-loader"`
|
||||||
|
AutoIptables bool `json:"auto-iptables"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inbound
|
// Inbound
|
||||||
@ -48,7 +52,6 @@ type Inbound struct {
|
|||||||
RedirPort int `json:"redir-port"`
|
RedirPort int `json:"redir-port"`
|
||||||
TProxyPort int `json:"tproxy-port"`
|
TProxyPort int `json:"tproxy-port"`
|
||||||
MixedPort int `json:"mixed-port"`
|
MixedPort int `json:"mixed-port"`
|
||||||
Tun Tun `json:"tun"`
|
|
||||||
Authentication []string `json:"authentication"`
|
Authentication []string `json:"authentication"`
|
||||||
AllowLan bool `json:"allow-lan"`
|
AllowLan bool `json:"allow-lan"`
|
||||||
BindAddress string `json:"bind-address"`
|
BindAddress string `json:"bind-address"`
|
||||||
@ -99,10 +102,10 @@ type Profile struct {
|
|||||||
|
|
||||||
// Tun config
|
// Tun config
|
||||||
type Tun struct {
|
type Tun struct {
|
||||||
Enable bool `yaml:"enable" json:"enable"`
|
Enable bool `yaml:"enable" json:"enable"`
|
||||||
Stack string `yaml:"stack" json:"stack"`
|
Stack string `yaml:"stack" json:"stack"`
|
||||||
DNSListen string `yaml:"dns-listen" json:"dns-listen"`
|
DnsHijack []string `yaml:"dns-hijack" json:"dns-hijack"`
|
||||||
AutoRoute bool `yaml:"auto-route" json:"auto-route"`
|
AutoRoute bool `yaml:"auto-route" json:"auto-route"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Script config
|
// Script config
|
||||||
@ -169,6 +172,8 @@ type RawConfig struct {
|
|||||||
ExternalUI string `yaml:"external-ui"`
|
ExternalUI string `yaml:"external-ui"`
|
||||||
Secret string `yaml:"secret"`
|
Secret string `yaml:"secret"`
|
||||||
Interface string `yaml:"interface-name"`
|
Interface string `yaml:"interface-name"`
|
||||||
|
GeodataLoader string `yaml:"geodata-loader"`
|
||||||
|
AutoIptables bool `yaml:"auto-iptables"`
|
||||||
|
|
||||||
ProxyProvider map[string]map[string]interface{} `yaml:"proxy-providers"`
|
ProxyProvider map[string]map[string]interface{} `yaml:"proxy-providers"`
|
||||||
RuleProvider map[string]map[string]interface{} `yaml:"rule-providers"`
|
RuleProvider map[string]map[string]interface{} `yaml:"rule-providers"`
|
||||||
@ -199,6 +204,8 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
|
|||||||
AllowLan: false,
|
AllowLan: false,
|
||||||
BindAddress: "*",
|
BindAddress: "*",
|
||||||
Mode: T.Rule,
|
Mode: T.Rule,
|
||||||
|
GeodataLoader: "memconservative",
|
||||||
|
AutoIptables: false,
|
||||||
UnifiedDelay: false,
|
UnifiedDelay: false,
|
||||||
Authentication: []string{},
|
Authentication: []string{},
|
||||||
LogLevel: log.INFO,
|
LogLevel: log.INFO,
|
||||||
@ -209,8 +216,8 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
|
|||||||
Tun: Tun{
|
Tun: Tun{
|
||||||
Enable: false,
|
Enable: false,
|
||||||
Stack: "gvisor",
|
Stack: "gvisor",
|
||||||
DNSListen: "0.0.0.0:53",
|
DnsHijack: []string{"198.18.0.2:53"},
|
||||||
AutoRoute: true,
|
AutoRoute: false,
|
||||||
},
|
},
|
||||||
DNS: RawDNS{
|
DNS: RawDNS{
|
||||||
Enable: false,
|
Enable: false,
|
||||||
@ -225,6 +232,17 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
|
|||||||
DefaultNameserver: []string{
|
DefaultNameserver: []string{
|
||||||
"114.114.114.114",
|
"114.114.114.114",
|
||||||
"223.5.5.5",
|
"223.5.5.5",
|
||||||
|
"8.8.8.8",
|
||||||
|
"1.0.0.1",
|
||||||
|
},
|
||||||
|
NameServer: []string{
|
||||||
|
"223.5.5.5",
|
||||||
|
"119.29.29",
|
||||||
|
},
|
||||||
|
FakeIPFilter: []string{
|
||||||
|
"dns.msftnsci.com",
|
||||||
|
"www.msftnsci.com",
|
||||||
|
"www.msftconnecttest.com",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Profile: Profile{
|
Profile: Profile{
|
||||||
@ -254,7 +272,7 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
config.General = general
|
config.General = general
|
||||||
//TODO 暂未使用
|
|
||||||
config.Tun = &rawCfg.Tun
|
config.Tun = &rawCfg.Tun
|
||||||
|
|
||||||
proxies, providers, err := parseProxies(rawCfg)
|
proxies, providers, err := parseProxies(rawCfg)
|
||||||
@ -295,7 +313,7 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
|
|||||||
|
|
||||||
func parseGeneral(cfg *RawConfig) (*General, error) {
|
func parseGeneral(cfg *RawConfig) (*General, error) {
|
||||||
externalUI := cfg.ExternalUI
|
externalUI := cfg.ExternalUI
|
||||||
|
geodata.SetLoader(cfg.GeodataLoader)
|
||||||
// checkout externalUI exist
|
// checkout externalUI exist
|
||||||
if externalUI != "" {
|
if externalUI != "" {
|
||||||
externalUI = C.Path.Resolve(externalUI)
|
externalUI = C.Path.Resolve(externalUI)
|
||||||
@ -312,7 +330,6 @@ func parseGeneral(cfg *RawConfig) (*General, error) {
|
|||||||
RedirPort: cfg.RedirPort,
|
RedirPort: cfg.RedirPort,
|
||||||
TProxyPort: cfg.TProxyPort,
|
TProxyPort: cfg.TProxyPort,
|
||||||
MixedPort: cfg.MixedPort,
|
MixedPort: cfg.MixedPort,
|
||||||
Tun: cfg.Tun,
|
|
||||||
AllowLan: cfg.AllowLan,
|
AllowLan: cfg.AllowLan,
|
||||||
BindAddress: cfg.BindAddress,
|
BindAddress: cfg.BindAddress,
|
||||||
},
|
},
|
||||||
@ -321,18 +338,20 @@ func parseGeneral(cfg *RawConfig) (*General, error) {
|
|||||||
ExternalUI: cfg.ExternalUI,
|
ExternalUI: cfg.ExternalUI,
|
||||||
Secret: cfg.Secret,
|
Secret: cfg.Secret,
|
||||||
},
|
},
|
||||||
UnifiedDelay: cfg.UnifiedDelay,
|
UnifiedDelay: cfg.UnifiedDelay,
|
||||||
Mode: cfg.Mode,
|
Mode: cfg.Mode,
|
||||||
LogLevel: cfg.LogLevel,
|
LogLevel: cfg.LogLevel,
|
||||||
IPv6: cfg.IPv6,
|
IPv6: cfg.IPv6,
|
||||||
Interface: cfg.Interface,
|
Interface: cfg.Interface,
|
||||||
|
GeodataLoader: cfg.GeodataLoader,
|
||||||
|
AutoIptables: cfg.AutoIptables,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[string]providerTypes.ProxyProvider, err error) {
|
func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[string]providerTypes.ProxyProvider, err error) {
|
||||||
proxies = make(map[string]C.Proxy)
|
proxies = make(map[string]C.Proxy)
|
||||||
providersMap = make(map[string]providerTypes.ProxyProvider)
|
providersMap = make(map[string]providerTypes.ProxyProvider)
|
||||||
proxyList := []string{}
|
var proxyList []string
|
||||||
_proxiesList := list.New()
|
_proxiesList := list.New()
|
||||||
_groupsList := list.New()
|
_groupsList := list.New()
|
||||||
proxiesConfig := cfg.Proxy
|
proxiesConfig := cfg.Proxy
|
||||||
@ -341,6 +360,7 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
|
|||||||
|
|
||||||
proxies["DIRECT"] = adapter.NewProxy(outbound.NewDirect())
|
proxies["DIRECT"] = adapter.NewProxy(outbound.NewDirect())
|
||||||
proxies["REJECT"] = adapter.NewProxy(outbound.NewReject())
|
proxies["REJECT"] = adapter.NewProxy(outbound.NewReject())
|
||||||
|
proxies["COMPATIBLE"] = adapter.NewProxy(outbound.NewCompatible())
|
||||||
proxyList = append(proxyList, "DIRECT", "REJECT")
|
proxyList = append(proxyList, "DIRECT", "REJECT")
|
||||||
|
|
||||||
// parse proxy
|
// parse proxy
|
||||||
@ -387,13 +407,6 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
|
|||||||
providersMap[name] = pd
|
providersMap[name] = pd
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, rp := range providersMap {
|
|
||||||
log.Infoln("Start initial provider %s", rp.Name())
|
|
||||||
if err := rp.Initial(); err != nil {
|
|
||||||
return nil, nil, fmt.Errorf("initial proxy provider %s error: %w", rp.Name(), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse proxy group
|
// parse proxy group
|
||||||
for idx, mapping := range groupsConfig {
|
for idx, mapping := range groupsConfig {
|
||||||
group, err := outboundgroup.ParseProxyGroup(mapping, proxies, providersMap)
|
group, err := outboundgroup.ParseProxyGroup(mapping, proxies, providersMap)
|
||||||
@ -409,19 +422,7 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
|
|||||||
proxies[groupName] = adapter.NewProxy(group)
|
proxies[groupName] = adapter.NewProxy(group)
|
||||||
}
|
}
|
||||||
|
|
||||||
// initial compatible provider
|
var ps []C.Proxy
|
||||||
for _, pd := range providersMap {
|
|
||||||
if pd.VehicleType() != providerTypes.Compatible {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Infoln("Start initial compatible provider %s", pd.Name())
|
|
||||||
if err := pd.Initial(); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ps := []C.Proxy{}
|
|
||||||
for _, v := range proxyList {
|
for _, v := range proxyList {
|
||||||
ps = append(ps, proxies[v])
|
ps = append(ps, proxies[v])
|
||||||
}
|
}
|
||||||
@ -491,25 +492,19 @@ time = ClashTime()
|
|||||||
func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[string]*providerTypes.RuleProvider, error) {
|
func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[string]*providerTypes.RuleProvider, error) {
|
||||||
ruleProviders := map[string]*providerTypes.RuleProvider{}
|
ruleProviders := map[string]*providerTypes.RuleProvider{}
|
||||||
|
|
||||||
|
startTime := time.Now()
|
||||||
// parse rule provider
|
// parse rule provider
|
||||||
for name, mapping := range cfg.RuleProvider {
|
for name, mapping := range cfg.RuleProvider {
|
||||||
rp, err := R.ParseRuleProvider(name, mapping)
|
rp, err := RP.ParseRuleProvider(name, mapping)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ruleProviders[name] = &rp
|
ruleProviders[name] = &rp
|
||||||
R.SetRuleProvider(rp)
|
RP.SetRuleProvider(rp)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, provider := range ruleProviders {
|
var rules []C.Rule
|
||||||
log.Infoln("Start initial provider %s", (*provider).Name())
|
|
||||||
if err := (*provider).Initial(); err != nil {
|
|
||||||
return nil, nil, fmt.Errorf("initial rule provider %s error: %w", (*provider).Name(), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rules := []C.Rule{}
|
|
||||||
rulesConfig := cfg.Rule
|
rulesConfig := cfg.Rule
|
||||||
mode := cfg.Mode
|
mode := cfg.Mode
|
||||||
|
|
||||||
@ -519,7 +514,7 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[strin
|
|||||||
var (
|
var (
|
||||||
payload string
|
payload string
|
||||||
target string
|
target string
|
||||||
params = []string{}
|
params []string
|
||||||
ruleName = strings.ToUpper(rule[0])
|
ruleName = strings.ToUpper(rule[0])
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -527,24 +522,29 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[strin
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
switch l := len(rule); {
|
if ruleName == "NOT" || ruleName == "OR" || ruleName == "AND" {
|
||||||
case l == 2:
|
payload = strings.Join(rule[1:len(rule)-1], ",")
|
||||||
target = rule[1]
|
target = rule[len(rule)-1]
|
||||||
case l == 3:
|
} else {
|
||||||
if ruleName == "MATCH" {
|
switch l := len(rule); {
|
||||||
payload = ""
|
case l == 2:
|
||||||
target = rule[1]
|
target = rule[1]
|
||||||
params = rule[2:]
|
case l == 3:
|
||||||
break
|
if ruleName == "MATCH" {
|
||||||
|
payload = ""
|
||||||
|
target = rule[1]
|
||||||
|
params = rule[2:]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
payload = rule[1]
|
||||||
|
target = rule[2]
|
||||||
|
case l >= 4:
|
||||||
|
payload = rule[1]
|
||||||
|
target = rule[2]
|
||||||
|
params = rule[3:]
|
||||||
|
default:
|
||||||
|
return nil, nil, fmt.Errorf("rules[%d] [%s] error: format invalid", idx, line)
|
||||||
}
|
}
|
||||||
payload = rule[1]
|
|
||||||
target = rule[2]
|
|
||||||
case l >= 4:
|
|
||||||
payload = rule[1]
|
|
||||||
target = rule[2]
|
|
||||||
params = rule[3:]
|
|
||||||
default:
|
|
||||||
return nil, nil, fmt.Errorf("rules[%d] [%s] error: format invalid", idx, line)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := proxies[target]; mode != T.Script && !ok {
|
if _, ok := proxies[target]; mode != T.Script && !ok {
|
||||||
@ -553,6 +553,11 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[strin
|
|||||||
|
|
||||||
params = trimArr(params)
|
params = trimArr(params)
|
||||||
|
|
||||||
|
if ruleName == "GEOSITE" {
|
||||||
|
if err := initGeoSite(); err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("can't initial GeoSite: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
parsed, parseErr := R.ParseRule(ruleName, payload, target, params)
|
parsed, parseErr := R.ParseRule(ruleName, payload, target, params)
|
||||||
if parseErr != nil {
|
if parseErr != nil {
|
||||||
return nil, nil, fmt.Errorf("rules[%d] [%s] error: %s", idx, line, parseErr.Error())
|
return nil, nil, fmt.Errorf("rules[%d] [%s] error: %s", idx, line, parseErr.Error())
|
||||||
@ -562,7 +567,9 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[strin
|
|||||||
rules = append(rules, parsed)
|
rules = append(rules, parsed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
elapsedTime := time.Since(startTime) / time.Millisecond // duration in ms
|
||||||
|
log.Infoln("Initialization time consuming %dms", elapsedTime) //Segment finished in xxm
|
||||||
|
log.Infoln("Geodata Loader mode: %s", geodata.LoaderName())
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
|
|
||||||
return rules, ruleProviders, nil
|
return rules, ruleProviders, nil
|
||||||
@ -607,7 +614,7 @@ func hostWithDefaultPort(host string, defPort string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parseNameServer(servers []string) ([]dns.NameServer, error) {
|
func parseNameServer(servers []string) ([]dns.NameServer, error) {
|
||||||
nameservers := []dns.NameServer{}
|
var nameservers []dns.NameServer
|
||||||
|
|
||||||
for idx, server := range servers {
|
for idx, server := range servers {
|
||||||
// parse without scheme .e.g 8.8.8.8:53
|
// parse without scheme .e.g 8.8.8.8:53
|
||||||
@ -675,7 +682,7 @@ func parseNameServerPolicy(nsPolicy map[string]string) (map[string]dns.NameServe
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parseFallbackIPCIDR(ips []string) ([]*net.IPNet, error) {
|
func parseFallbackIPCIDR(ips []string) ([]*net.IPNet, error) {
|
||||||
ipNets := []*net.IPNet{}
|
var ipNets []*net.IPNet
|
||||||
|
|
||||||
for idx, ip := range ips {
|
for idx, ip := range ips {
|
||||||
_, ipnet, err := net.ParseCIDR(ip)
|
_, ipnet, err := net.ParseCIDR(ip)
|
||||||
@ -689,7 +696,12 @@ func parseFallbackIPCIDR(ips []string) ([]*net.IPNet, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parseFallbackGeoSite(countries []string, rules []C.Rule) ([]*router.DomainMatcher, error) {
|
func parseFallbackGeoSite(countries []string, rules []C.Rule) ([]*router.DomainMatcher, error) {
|
||||||
sites := []*router.DomainMatcher{}
|
var sites []*router.DomainMatcher
|
||||||
|
if len(countries) > 0 {
|
||||||
|
if err := initGeoSite(); err != nil {
|
||||||
|
return nil, fmt.Errorf("can't initial GeoSite: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, country := range countries {
|
for _, country := range countries {
|
||||||
found := false
|
found := false
|
||||||
@ -784,7 +796,7 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie, rules []C.Rule) (*DNS,
|
|||||||
if net.ParseIP(fb.Addr) != nil {
|
if net.ParseIP(fb.Addr) != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
host.Insert(fb.Addr, true)
|
_ = host.Insert(fb.Addr, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,23 +50,6 @@ func initMMDB() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//func downloadGeoIP(path string) (err error) {
|
|
||||||
// resp, err := http.Get("https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geoip.dat")
|
|
||||||
// if err != nil {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// defer resp.Body.Close()
|
|
||||||
//
|
|
||||||
// f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0644)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// defer f.Close()
|
|
||||||
// _, err = io.Copy(f, resp.Body)
|
|
||||||
//
|
|
||||||
// return err
|
|
||||||
//}
|
|
||||||
|
|
||||||
func downloadGeoSite(path string) (err error) {
|
func downloadGeoSite(path string) (err error) {
|
||||||
resp, err := http.Get("https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat")
|
resp, err := http.Get("https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -84,22 +67,9 @@ func downloadGeoSite(path string) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
//func initGeoIP() error {
|
|
||||||
// if _, err := os.Stat(C.Path.GeoIP()); os.IsNotExist(err) {
|
|
||||||
// log.Infoln("Can't find GeoIP.dat, start download")
|
|
||||||
// if err := downloadGeoIP(C.Path.GeoIP()); err != nil {
|
|
||||||
// return fmt.Errorf("can't download GeoIP.dat: %s", err.Error())
|
|
||||||
// }
|
|
||||||
// log.Infoln("Download GeoIP.dat finish")
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return nil
|
|
||||||
//}
|
|
||||||
|
|
||||||
func initGeoSite() error {
|
func initGeoSite() error {
|
||||||
if _, err := os.Stat(C.Path.GeoSite()); os.IsNotExist(err) {
|
if _, err := os.Stat(C.Path.GeoSite()); os.IsNotExist(err) {
|
||||||
log.Infoln("Can't find GeoSite.dat, start download")
|
log.Infoln("Need GeoSite but can't find GeoSite.dat, start download")
|
||||||
if err := downloadGeoSite(C.Path.GeoSite()); err != nil {
|
if err := downloadGeoSite(C.Path.GeoSite()); err != nil {
|
||||||
return fmt.Errorf("can't download GeoSite.dat: %s", err.Error())
|
return fmt.Errorf("can't download GeoSite.dat: %s", err.Error())
|
||||||
}
|
}
|
||||||
@ -139,9 +109,5 @@ func Init(dir string) error {
|
|||||||
return fmt.Errorf("can't initial MMDB: %w", err)
|
return fmt.Errorf("can't initial MMDB: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// initial GeoSite
|
|
||||||
if err := initGeoSite(); err != nil {
|
|
||||||
return fmt.Errorf("can't initial GeoSite: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ import (
|
|||||||
const (
|
const (
|
||||||
Direct AdapterType = iota
|
Direct AdapterType = iota
|
||||||
Reject
|
Reject
|
||||||
|
Compatible
|
||||||
Shadowsocks
|
Shadowsocks
|
||||||
ShadowsocksR
|
ShadowsocksR
|
||||||
Snell
|
Snell
|
||||||
@ -33,6 +33,7 @@ const (
|
|||||||
const (
|
const (
|
||||||
DefaultTCPTimeout = 5 * time.Second
|
DefaultTCPTimeout = 5 * time.Second
|
||||||
DefaultUDPTimeout = DefaultTCPTimeout
|
DefaultUDPTimeout = DefaultTCPTimeout
|
||||||
|
DefaultTLSTimeout = DefaultTCPTimeout
|
||||||
)
|
)
|
||||||
|
|
||||||
type Connection interface {
|
type Connection interface {
|
||||||
@ -128,7 +129,8 @@ func (at AdapterType) String() string {
|
|||||||
return "Direct"
|
return "Direct"
|
||||||
case Reject:
|
case Reject:
|
||||||
return "Reject"
|
return "Reject"
|
||||||
|
case Compatible:
|
||||||
|
return "Compatible"
|
||||||
case Shadowsocks:
|
case Shadowsocks:
|
||||||
return "Shadowsocks"
|
return "Shadowsocks"
|
||||||
case ShadowsocksR:
|
case ShadowsocksR:
|
||||||
|
@ -2,6 +2,7 @@ package constant
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
@ -23,6 +24,7 @@ const (
|
|||||||
REDIR
|
REDIR
|
||||||
TPROXY
|
TPROXY
|
||||||
TUN
|
TUN
|
||||||
|
INNER
|
||||||
)
|
)
|
||||||
|
|
||||||
type NetWork int
|
type NetWork int
|
||||||
@ -58,6 +60,8 @@ func (t Type) String() string {
|
|||||||
return "TProxy"
|
return "TProxy"
|
||||||
case TUN:
|
case TUN:
|
||||||
return "Tun"
|
return "Tun"
|
||||||
|
case INNER:
|
||||||
|
return "Inner"
|
||||||
default:
|
default:
|
||||||
return "Unknown"
|
return "Unknown"
|
||||||
}
|
}
|
||||||
@ -89,6 +93,18 @@ func (m *Metadata) SourceAddress() string {
|
|||||||
return net.JoinHostPort(m.SrcIP.String(), m.SrcPort)
|
return net.JoinHostPort(m.SrcIP.String(), m.SrcPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Metadata) SourceDetail() string {
|
||||||
|
if m.Process != "" {
|
||||||
|
return fmt.Sprintf("%s(%s)", m.SourceAddress(), m.Process)
|
||||||
|
} else {
|
||||||
|
if m.Type == INNER {
|
||||||
|
return fmt.Sprintf("[Clash]")
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%s", m.SourceAddress())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Metadata) Resolved() bool {
|
func (m *Metadata) Resolved() bool {
|
||||||
return m.DstIP != nil
|
return m.DstIP != nil
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,20 @@
|
|||||||
package constant
|
package constant
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
P "path"
|
P "path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const Name = "clash"
|
const Name = "clash"
|
||||||
|
|
||||||
|
var (
|
||||||
|
GeositeName = "GeoSite.dat"
|
||||||
|
GeoipName = "GeoIP.dat"
|
||||||
|
)
|
||||||
|
|
||||||
// Path is used to get the configuration path
|
// Path is used to get the configuration path
|
||||||
var Path = func() *path {
|
var Path = func() *path {
|
||||||
homeDir, err := os.UserHomeDir()
|
homeDir, err := os.UserHomeDir()
|
||||||
@ -48,7 +55,6 @@ func (p *path) Resolve(path string) string {
|
|||||||
if !filepath.IsAbs(path) {
|
if !filepath.IsAbs(path) {
|
||||||
return filepath.Join(p.HomeDir(), path)
|
return filepath.Join(p.HomeDir(), path)
|
||||||
}
|
}
|
||||||
|
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,11 +71,41 @@ func (p *path) Cache() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *path) GeoIP() string {
|
func (p *path) GeoIP() string {
|
||||||
return P.Join(p.homeDir, "geoip.dat")
|
files, err := ioutil.ReadDir(p.homeDir)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
for _, fi := range files {
|
||||||
|
if fi.IsDir() {
|
||||||
|
// 目录则直接跳过
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
if strings.EqualFold(fi.Name(), "GeoIP.dat") {
|
||||||
|
GeoipName = fi.Name()
|
||||||
|
return P.Join(p.homeDir, fi.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return P.Join(p.homeDir, "GeoIP.dat")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *path) GeoSite() string {
|
func (p *path) GeoSite() string {
|
||||||
return P.Join(p.homeDir, "geosite.dat")
|
files, err := ioutil.ReadDir(p.homeDir)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
for _, fi := range files {
|
||||||
|
if fi.IsDir() {
|
||||||
|
// 目录则直接跳过
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
if strings.EqualFold(fi.Name(), "GeoSite.dat") {
|
||||||
|
GeositeName = fi.Name()
|
||||||
|
return P.Join(p.homeDir, fi.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return P.Join(p.homeDir, "GeoSite.dat")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *path) ScriptDir() string {
|
func (p *path) ScriptDir() string {
|
||||||
|
@ -14,7 +14,12 @@ const (
|
|||||||
Process
|
Process
|
||||||
Script
|
Script
|
||||||
RuleSet
|
RuleSet
|
||||||
|
Network
|
||||||
|
Combination
|
||||||
MATCH
|
MATCH
|
||||||
|
AND
|
||||||
|
OR
|
||||||
|
NOT
|
||||||
)
|
)
|
||||||
|
|
||||||
type RuleType int
|
type RuleType int
|
||||||
@ -47,6 +52,14 @@ func (rt RuleType) String() string {
|
|||||||
return "Match"
|
return "Match"
|
||||||
case RuleSet:
|
case RuleSet:
|
||||||
return "RuleSet"
|
return "RuleSet"
|
||||||
|
case Network:
|
||||||
|
return "Network"
|
||||||
|
case AND:
|
||||||
|
return "AND"
|
||||||
|
case OR:
|
||||||
|
return "OR"
|
||||||
|
case NOT:
|
||||||
|
return "NOT"
|
||||||
default:
|
default:
|
||||||
return "Unknown"
|
return "Unknown"
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,8 @@ package constant
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
Meta = true
|
Meta = true
|
||||||
Version = "1.8.0"
|
Version = "1.9.0"
|
||||||
BuildTime = "unknown time"
|
BuildTime = "unknown time"
|
||||||
AutoIptables string
|
AutoIptables string
|
||||||
|
ClashName = "Clash.Meta"
|
||||||
)
|
)
|
||||||
|
@ -60,6 +60,10 @@ func ReCreateServer(addr string, resolver *Resolver, mapper *ResolverEnhancer) {
|
|||||||
address = ""
|
address = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if addr == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
9
go.mod
9
go.mod
@ -15,7 +15,7 @@ require (
|
|||||||
github.com/oschwald/geoip2-golang v1.5.0
|
github.com/oschwald/geoip2-golang v1.5.0
|
||||||
github.com/sirupsen/logrus v1.8.1
|
github.com/sirupsen/logrus v1.8.1
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499
|
github.com/xtls/go v0.0.0-20210920065950-d4af136d3672
|
||||||
go.etcd.io/bbolt v1.3.6
|
go.etcd.io/bbolt v1.3.6
|
||||||
go.uber.org/atomic v1.9.0
|
go.uber.org/atomic v1.9.0
|
||||||
go.uber.org/automaxprocs v1.4.0
|
go.uber.org/automaxprocs v1.4.0
|
||||||
@ -26,7 +26,7 @@ require (
|
|||||||
golang.zx2c4.com/wireguard/windows v0.5.1
|
golang.zx2c4.com/wireguard/windows v0.5.1
|
||||||
google.golang.org/protobuf v1.27.1
|
google.golang.org/protobuf v1.27.1
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
gvisor.dev/gvisor v0.0.0-20211104052249-2de3450f76d6
|
gvisor.dev/gvisor v0.0.0-20220129032118-ed00636ef990
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@ -36,10 +36,11 @@ require (
|
|||||||
github.com/oschwald/maxminddb-golang v1.8.0 // indirect
|
github.com/oschwald/maxminddb-golang v1.8.0 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect
|
github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect
|
||||||
golang.org/x/mod v0.4.2 // indirect
|
golang.org/x/mod v0.5.1 // indirect
|
||||||
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b // indirect
|
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b // indirect
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
|
||||||
golang.org/x/tools v0.1.7 // indirect
|
golang.org/x/tools v0.1.9 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
|
||||||
|
|
||||||
)
|
)
|
||||||
|
135
go.sum
135
go.sum
@ -14,14 +14,6 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV
|
|||||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
|
||||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
|
||||||
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
|
|
||||||
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
|
|
||||||
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
|
|
||||||
cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
|
|
||||||
cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
|
|
||||||
cloud.google.com/go v0.88.0/go.mod h1:dnKwfYbP9hQhefiUvpbcAyoGSHUrOxR20JVElLiUvEY=
|
|
||||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||||
@ -76,7 +68,6 @@ github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmE
|
|||||||
github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
|
github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
|
||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
@ -114,10 +105,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
|||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||||
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
|
||||||
github.com/docker/docker v1.4.2-0.20191028175130-9e7d5ac5ea55/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
|
||||||
github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
|
||||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
|
|
||||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||||
@ -127,9 +114,7 @@ github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb
|
|||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
@ -161,7 +146,6 @@ github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x
|
|||||||
github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||||
github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
|
github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
|
||||||
github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4=
|
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||||
@ -180,8 +164,6 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
|
|||||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
|
||||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
|
||||||
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
@ -198,9 +180,7 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
|||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
||||||
@ -218,14 +198,10 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-github/v35 v35.1.0/go.mod h1:s0515YVTI+IMrDoy9Y4pHt9ShGpzHvHO8rZ7L7acgvs=
|
|
||||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
|
||||||
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
|
||||||
github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
|
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
@ -233,16 +209,8 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
|
|||||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
|
||||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
|
||||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
|
||||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
|
||||||
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
|
||||||
github.com/google/pprof v0.0.0-20210715191844-86eeefc3e471/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
|
||||||
github.com/google/pprof v0.0.0-20211008130755-947d60d73cc0/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
|
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/subcommands v1.0.2-0.20190508160503-636abe8753b8/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
github.com/google/subcommands v1.0.2-0.20190508160503-636abe8753b8/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
@ -267,8 +235,6 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T
|
|||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
|
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
|
|
||||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/insomniacslk/dhcp v0.0.0-20211214070828-5297eed8f489 h1:jhdHqd7DxBrzfuFSoPxjD6nUVaV/1RIn9aHA0WCf/as=
|
github.com/insomniacslk/dhcp v0.0.0-20211214070828-5297eed8f489 h1:jhdHqd7DxBrzfuFSoPxjD6nUVaV/1RIn9aHA0WCf/as=
|
||||||
@ -334,15 +300,14 @@ github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGV
|
|||||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
|
||||||
github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||||
github.com/opencontainers/runc v1.0.0-rc90/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
github.com/opencontainers/runc v1.0.0-rc90/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||||
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||||
|
github.com/opencontainers/runtime-spec v1.0.3-0.20211123151946-c2389c3cb60a/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||||
github.com/oschwald/geoip2-golang v1.5.0 h1:igg2yQIrrcRccB1ytFXqBfOHCjXWIoMv85lVJ1ONZzw=
|
github.com/oschwald/geoip2-golang v1.5.0 h1:igg2yQIrrcRccB1ytFXqBfOHCjXWIoMv85lVJ1ONZzw=
|
||||||
github.com/oschwald/geoip2-golang v1.5.0/go.mod h1:xdvYt5xQzB8ORWFqPnqMwZpCpgNagttWdoZLlJQzg7s=
|
github.com/oschwald/geoip2-golang v1.5.0/go.mod h1:xdvYt5xQzB8ORWFqPnqMwZpCpgNagttWdoZLlJQzg7s=
|
||||||
github.com/oschwald/maxminddb-golang v1.8.0 h1:Uh/DSnGoxsyp/KYbY1AuP0tYEwfs0sCph9p/UMXK/Hk=
|
github.com/oschwald/maxminddb-golang v1.8.0 h1:Uh/DSnGoxsyp/KYbY1AuP0tYEwfs0sCph9p/UMXK/Hk=
|
||||||
github.com/oschwald/maxminddb-golang v1.8.0/go.mod h1:RXZtst0N6+FY/3qCNmZMBApR19cdQj43/NM9VkrNAis=
|
github.com/oschwald/maxminddb-golang v1.8.0/go.mod h1:RXZtst0N6+FY/3qCNmZMBApR19cdQj43/NM9VkrNAis=
|
||||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
@ -405,14 +370,11 @@ github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF
|
|||||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||||
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
github.com/vishvananda/netlink v1.0.1-0.20190930145447-2ec5bdc52b86/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
|
github.com/vishvananda/netlink v1.0.1-0.20190930145447-2ec5bdc52b86/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
|
||||||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499 h1:QHESTXtfgc1ABV+ArlbPVqUx9Ht5I0dDkYhxYoXFxNo=
|
github.com/xtls/go v0.0.0-20210920065950-d4af136d3672 h1:4mkzGhKqt3JO1BWYjtD3iRFyAx4ow67hmSqOcGjuxqQ=
|
||||||
github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499/go.mod h1:5TB2+k58gx4A4g2Nf5miSHNDF6CuAzHKpWBooLAshTs=
|
github.com/xtls/go v0.0.0-20210920065950-d4af136d3672/go.mod h1:YGGVbz9cOxyKFUmhW7LGaLZaMA0cPlHJinvAmVxEMSU=
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
@ -420,6 +382,7 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
|
|||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
|
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
||||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||||
@ -428,17 +391,14 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
|||||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
|
||||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
|
||||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go.uber.org/automaxprocs v1.4.0 h1:CpDZl6aOlLhReez+8S3eEotD7Jx0Os++lemPlMULQP0=
|
go.uber.org/automaxprocs v1.4.0 h1:CpDZl6aOlLhReez+8S3eEotD7Jx0Os++lemPlMULQP0=
|
||||||
go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q=
|
go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q=
|
||||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
@ -450,6 +410,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
|||||||
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
|
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
|
||||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
@ -475,7 +436,6 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl
|
|||||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
|
||||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||||
@ -485,11 +445,10 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
|||||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
|
||||||
|
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||||
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@ -528,17 +487,14 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R
|
|||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
|
||||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM=
|
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM=
|
||||||
@ -548,14 +504,6 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr
|
|||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@ -615,7 +563,6 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@ -624,27 +571,20 @@ golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@ -655,9 +595,9 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b h1:NXqSWXSRUSCaFuvitrWtU169I3876zRTalMRbfd6LL0=
|
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b h1:NXqSWXSRUSCaFuvitrWtU169I3876zRTalMRbfd6LL0=
|
||||||
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
|
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
@ -710,21 +650,12 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY
|
|||||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
|
||||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
|
||||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|
||||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|
||||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|
||||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|
||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
|
|
||||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||||
|
golang.org/x/tools v0.1.9 h1:j9KsMiaP1c3B0OTQGth0/k+miLGTgLsAFUCrF2vLcF8=
|
||||||
|
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@ -752,15 +683,6 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M
|
|||||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
|
||||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
|
||||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
|
||||||
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
|
|
||||||
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
|
|
||||||
google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
|
|
||||||
google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
|
|
||||||
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
|
|
||||||
google.golang.org/api v0.52.0/go.mod h1:Him/adpjt0sxtkWViy0b6xyKW/SD71CwdJ7HqJo7SrU=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
@ -799,22 +721,6 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc
|
|||||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
|
||||||
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
|
|
||||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
|
||||||
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
|
||||||
google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
|
||||||
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
|
|
||||||
google.golang.org/genproto v0.0.0-20210721163202-f1cecdd8b78a/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
|
||||||
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
@ -830,19 +736,11 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa
|
|||||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
|
||||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
|
||||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
|
||||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
|
||||||
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
|
||||||
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
|
||||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
|
||||||
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||||
google.golang.org/grpc v1.42.0-dev.0.20211020220737-f00baa6c3c84/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
google.golang.org/grpc v1.42.0-dev.0.20211020220737-f00baa6c3c84/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
@ -876,8 +774,8 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
|||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||||
gvisor.dev/gvisor v0.0.0-20211104052249-2de3450f76d6 h1:ZqN8yQG1UONNe/u1LJvvTg80BDevYvaRgmWPBlCT+0g=
|
gvisor.dev/gvisor v0.0.0-20220129032118-ed00636ef990 h1:fTgWAYpliP19U3FX8+tI2TZGXnnk45g18frOuZxKay4=
|
||||||
gvisor.dev/gvisor v0.0.0-20211104052249-2de3450f76d6/go.mod h1:btyTBPTxT8AFMvW7yctFJ2nPCEDWZLpmKQEZ0gG+bbQ=
|
gvisor.dev/gvisor v0.0.0-20220129032118-ed00636ef990/go.mod h1:vmN0Pug/s8TJmpnt30DvrEfZ5vDl52psGLU04tFuK2U=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
@ -885,7 +783,6 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
|||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
honnef.co/go/tools v0.2.1/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=
|
|
||||||
k8s.io/api v0.16.13/go.mod h1:QWu8UWSTiuQZMMeYjwLs6ILu5O74qKSJ0c+4vrchDxs=
|
k8s.io/api v0.16.13/go.mod h1:QWu8UWSTiuQZMMeYjwLs6ILu5O74qKSJ0c+4vrchDxs=
|
||||||
k8s.io/apimachinery v0.16.13/go.mod h1:4HMHS3mDHtVttspuuhrJ1GGr/0S9B6iWYWZ57KnnZqQ=
|
k8s.io/apimachinery v0.16.13/go.mod h1:4HMHS3mDHtVttspuuhrJ1GGr/0S9B6iWYWZ57KnnZqQ=
|
||||||
k8s.io/apimachinery v0.16.14-rc.0/go.mod h1:4HMHS3mDHtVttspuuhrJ1GGr/0S9B6iWYWZ57KnnZqQ=
|
k8s.io/apimachinery v0.16.14-rc.0/go.mod h1:4HMHS3mDHtVttspuuhrJ1GGr/0S9B6iWYWZ57KnnZqQ=
|
||||||
|
@ -2,7 +2,7 @@ package executor
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Dreamacro/clash/listener/tproxy"
|
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -10,10 +10,13 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/clash/listener/tproxy"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/adapter"
|
"github.com/Dreamacro/clash/adapter"
|
||||||
"github.com/Dreamacro/clash/adapter/outboundgroup"
|
"github.com/Dreamacro/clash/adapter/outboundgroup"
|
||||||
"github.com/Dreamacro/clash/component/auth"
|
"github.com/Dreamacro/clash/component/auth"
|
||||||
"github.com/Dreamacro/clash/component/dialer"
|
"github.com/Dreamacro/clash/component/dialer"
|
||||||
|
G "github.com/Dreamacro/clash/component/geodata"
|
||||||
"github.com/Dreamacro/clash/component/iface"
|
"github.com/Dreamacro/clash/component/iface"
|
||||||
"github.com/Dreamacro/clash/component/profile"
|
"github.com/Dreamacro/clash/component/profile"
|
||||||
"github.com/Dreamacro/clash/component/profile/cachefile"
|
"github.com/Dreamacro/clash/component/profile/cachefile"
|
||||||
@ -74,14 +77,17 @@ func ApplyConfig(cfg *config.Config, force bool) {
|
|||||||
defer mux.Unlock()
|
defer mux.Unlock()
|
||||||
|
|
||||||
updateUsers(cfg.Users)
|
updateUsers(cfg.Users)
|
||||||
|
updateHosts(cfg.Hosts)
|
||||||
updateProxies(cfg.Proxies, cfg.Providers)
|
updateProxies(cfg.Proxies, cfg.Providers)
|
||||||
updateRules(cfg.Rules, cfg.RuleProviders)
|
updateRules(cfg.Rules, cfg.RuleProviders)
|
||||||
updateHosts(cfg.Hosts)
|
updateIPTables(cfg.DNS, cfg.General, cfg.Tun)
|
||||||
updateProfile(cfg)
|
updateDNS(cfg.DNS, cfg.Tun)
|
||||||
updateIPTables(cfg.DNS, cfg.General)
|
updateGeneral(cfg.General, cfg.Tun, force)
|
||||||
updateDNS(cfg.DNS, cfg.General)
|
updateTun(cfg.Tun)
|
||||||
updateGeneral(cfg.General, force)
|
|
||||||
updateExperimental(cfg)
|
updateExperimental(cfg)
|
||||||
|
loadProvider(cfg.RuleProviders, cfg.Providers)
|
||||||
|
updateProfile(cfg)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetGeneral() *config.General {
|
func GetGeneral() *config.General {
|
||||||
@ -98,14 +104,14 @@ func GetGeneral() *config.General {
|
|||||||
RedirPort: ports.RedirPort,
|
RedirPort: ports.RedirPort,
|
||||||
TProxyPort: ports.TProxyPort,
|
TProxyPort: ports.TProxyPort,
|
||||||
MixedPort: ports.MixedPort,
|
MixedPort: ports.MixedPort,
|
||||||
Tun: P.Tun(),
|
|
||||||
Authentication: authenticator,
|
Authentication: authenticator,
|
||||||
AllowLan: P.AllowLan(),
|
AllowLan: P.AllowLan(),
|
||||||
BindAddress: P.BindAddress(),
|
BindAddress: P.BindAddress(),
|
||||||
},
|
},
|
||||||
Mode: tunnel.Mode(),
|
Mode: tunnel.Mode(),
|
||||||
LogLevel: log.Level(),
|
LogLevel: log.Level(),
|
||||||
IPv6: !resolver.DisableIPv6,
|
IPv6: !resolver.DisableIPv6,
|
||||||
|
GeodataLoader: G.LoaderName(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return general
|
return general
|
||||||
@ -113,8 +119,8 @@ func GetGeneral() *config.General {
|
|||||||
|
|
||||||
func updateExperimental(c *config.Config) {}
|
func updateExperimental(c *config.Config) {}
|
||||||
|
|
||||||
func updateDNS(c *config.DNS, general *config.General) {
|
func updateDNS(c *config.DNS, Tun *config.Tun) {
|
||||||
if !c.Enable && !general.Tun.Enable {
|
if !c.Enable && !Tun.Enable {
|
||||||
resolver.DefaultResolver = nil
|
resolver.DefaultResolver = nil
|
||||||
resolver.MainResolver = nil
|
resolver.MainResolver = nil
|
||||||
resolver.DefaultHostMapper = nil
|
resolver.DefaultHostMapper = nil
|
||||||
@ -152,7 +158,7 @@ func updateDNS(c *config.DNS, general *config.General) {
|
|||||||
resolver.DefaultResolver = r
|
resolver.DefaultResolver = r
|
||||||
resolver.MainResolver = mr
|
resolver.MainResolver = mr
|
||||||
resolver.DefaultHostMapper = m
|
resolver.DefaultHostMapper = m
|
||||||
if general.Tun.Enable && !strings.EqualFold(general.Tun.Stack, "gvisor") {
|
if Tun.Enable && !strings.EqualFold(Tun.Stack, "gVisor") {
|
||||||
resolver.DefaultLocalServer = dns.NewLocalServer(r, m)
|
resolver.DefaultLocalServer = dns.NewLocalServer(r, m)
|
||||||
} else {
|
} else {
|
||||||
resolver.DefaultLocalServer = nil
|
resolver.DefaultLocalServer = nil
|
||||||
@ -175,12 +181,44 @@ func updateRules(rules []C.Rule, ruleProviders map[string]*provider.RuleProvider
|
|||||||
tunnel.UpdateRules(rules, ruleProviders)
|
tunnel.UpdateRules(rules, ruleProviders)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateGeneral(general *config.General, force bool) {
|
func loadProvider(ruleProviders map[string]*provider.RuleProvider, proxyProviders map[string]provider.ProxyProvider) {
|
||||||
|
load := func(pv provider.Provider) {
|
||||||
|
if pv.VehicleType() == provider.Compatible {
|
||||||
|
log.Infoln("Start initial compatible provider %s", pv.Name())
|
||||||
|
} else {
|
||||||
|
log.Infoln("Start initial provider %s", (pv).Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := (pv).Initial(); err != nil {
|
||||||
|
switch pv.Type() {
|
||||||
|
case provider.Proxy:
|
||||||
|
{
|
||||||
|
log.Warnln("initial proxy provider %s error: %v", (pv).Name(), err)
|
||||||
|
}
|
||||||
|
case provider.Rule:
|
||||||
|
{
|
||||||
|
log.Warnln("initial rule provider %s error: %v", (pv).Name(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, proxyProvider := range proxyProviders {
|
||||||
|
load(proxyProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ruleProvider := range ruleProviders {
|
||||||
|
load(*ruleProvider)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateGeneral(general *config.General, Tun *config.Tun, force bool) {
|
||||||
tunnel.SetMode(general.Mode)
|
tunnel.SetMode(general.Mode)
|
||||||
resolver.DisableIPv6 = !general.IPv6
|
resolver.DisableIPv6 = !general.IPv6
|
||||||
adapter.UnifiedDelay.Store(general.UnifiedDelay)
|
adapter.UnifiedDelay.Store(general.UnifiedDelay)
|
||||||
|
|
||||||
if (general.Tun.Enable || general.TProxyPort != 0) && general.Interface == "" {
|
if (Tun.Enable || general.TProxyPort != 0) && general.Interface == "" {
|
||||||
autoDetectInterfaceName, err := dev.GetAutoDetectInterface()
|
autoDetectInterfaceName, err := dev.GetAutoDetectInterface()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if autoDetectInterfaceName != "" && autoDetectInterfaceName != "<nil>" {
|
if autoDetectInterfaceName != "" && autoDetectInterfaceName != "<nil>" {
|
||||||
@ -204,6 +242,9 @@ func updateGeneral(general *config.General, force bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geodataLoader := general.GeodataLoader
|
||||||
|
G.SetLoader(geodataLoader)
|
||||||
|
|
||||||
allowLan := general.AllowLan
|
allowLan := general.AllowLan
|
||||||
P.SetAllowLan(allowLan)
|
P.SetAllowLan(allowLan)
|
||||||
|
|
||||||
@ -219,12 +260,21 @@ func updateGeneral(general *config.General, force bool) {
|
|||||||
P.ReCreateTProxy(general.TProxyPort, tcpIn, udpIn)
|
P.ReCreateTProxy(general.TProxyPort, tcpIn, udpIn)
|
||||||
P.ReCreateMixed(general.MixedPort, tcpIn, udpIn)
|
P.ReCreateMixed(general.MixedPort, tcpIn, udpIn)
|
||||||
|
|
||||||
if err := P.ReCreateTun(general.Tun, tcpIn, udpIn); err != nil {
|
log.SetLevel(general.LogLevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateTun(Tun *config.Tun) {
|
||||||
|
if Tun == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tcpIn := tunnel.TCPIn()
|
||||||
|
udpIn := tunnel.UDPIn()
|
||||||
|
|
||||||
|
if err := P.ReCreateTun(*Tun, tcpIn, udpIn); err != nil {
|
||||||
log.Errorln("Start Tun interface error: %s", err.Error())
|
log.Errorln("Start Tun interface error: %s", err.Error())
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.SetLevel(general.LogLevel)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateUsers(users []auth.AuthUser) {
|
func updateUsers(users []auth.AuthUser) {
|
||||||
@ -270,9 +320,8 @@ func patchSelectGroup(proxies map[string]C.Proxy) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateIPTables(dns *config.DNS, general *config.General) {
|
func updateIPTables(dns *config.DNS, general *config.General, tun *config.Tun) {
|
||||||
AutoIptables := C.AutoIptables
|
if runtime.GOOS != "linux" || dns.Listen == "" || general.TProxyPort == 0 || tun.Enable || !general.AutoIptables {
|
||||||
if runtime.GOOS != "linux" || dns.Listen == "" || general.TProxyPort == 0 || general.Tun.Enable || AutoIptables != "Enable" {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,8 +347,7 @@ func updateIPTables(dns *config.DNS, general *config.General) {
|
|||||||
|
|
||||||
func CleanUp() {
|
func CleanUp() {
|
||||||
P.CleanUp()
|
P.CleanUp()
|
||||||
AutoIptables := C.AutoIptables
|
if runtime.GOOS == "linux" {
|
||||||
if runtime.GOOS == "linux" && AutoIptables == "Enable" {
|
|
||||||
tproxy.CleanUpTProxyLinuxIPTables()
|
tproxy.CleanUpTProxyLinuxIPTables()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,6 @@ type Rule struct {
|
|||||||
|
|
||||||
func getRules(w http.ResponseWriter, r *http.Request) {
|
func getRules(w http.ResponseWriter, r *http.Request) {
|
||||||
rawRules := tunnel.Rules()
|
rawRules := tunnel.Rules()
|
||||||
|
|
||||||
rules := []Rule{}
|
rules := []Rule{}
|
||||||
for _, rule := range rawRules {
|
for _, rule := range rawRules {
|
||||||
rules = append(rules, Rule{
|
rules = append(rules, Rule{
|
||||||
@ -31,6 +30,7 @@ func getRules(w http.ResponseWriter, r *http.Request) {
|
|||||||
Payload: rule.Payload(),
|
Payload: rule.Payload(),
|
||||||
Proxy: rule.Adapter(),
|
Proxy: rule.Adapter(),
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render.JSON(w, r, render.M{
|
render.JSON(w, r, render.M{
|
||||||
|
16
hub/route/script.go
Normal file
16
hub/route/script.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package route
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-chi/chi/v5"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func scriptRouter() http.Handler {
|
||||||
|
r := chi.NewRouter()
|
||||||
|
r.Get("/", getScript)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func getScript(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
writer.WriteHeader(http.StatusMethodNotAllowed)
|
||||||
|
}
|
@ -72,6 +72,7 @@ func Start(addr string, secret string) {
|
|||||||
r.Mount("/connections", connectionRouter())
|
r.Mount("/connections", connectionRouter())
|
||||||
r.Mount("/providers/proxies", proxyProviderRouter())
|
r.Mount("/providers/proxies", proxyProviderRouter())
|
||||||
r.Mount("/providers/rules", ruleProviderRouter())
|
r.Mount("/providers/rules", ruleProviderRouter())
|
||||||
|
r.Mount("/script", scriptRouter())
|
||||||
})
|
})
|
||||||
|
|
||||||
if uiPath != "" {
|
if uiPath != "" {
|
||||||
|
20
listener/inner/tcp.go
Normal file
20
listener/inner/tcp.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package inner
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Dreamacro/clash/adapter/inbound"
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
var tcpIn chan<- C.ConnContext
|
||||||
|
|
||||||
|
func New(in chan<- C.ConnContext) {
|
||||||
|
tcpIn = in
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleTcp(dst string, host string) net.Conn {
|
||||||
|
conn1, conn2 := net.Pipe()
|
||||||
|
context := inbound.NewInner(conn2, dst, host)
|
||||||
|
tcpIn <- context
|
||||||
|
return conn1
|
||||||
|
}
|
@ -2,6 +2,7 @@ package proxy
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/Dreamacro/clash/listener/inner"
|
||||||
"net"
|
"net"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -71,7 +72,7 @@ func Tun() config.Tun {
|
|||||||
return config.Tun{
|
return config.Tun{
|
||||||
Enable: true,
|
Enable: true,
|
||||||
Stack: tunAdapter.Stack(),
|
Stack: tunAdapter.Stack(),
|
||||||
DNSListen: tunAdapter.DNSListen(),
|
DnsHijack: tunAdapter.DnsHijack(),
|
||||||
AutoRoute: tunAdapter.AutoRoute(),
|
AutoRoute: tunAdapter.AutoRoute(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -124,6 +125,7 @@ func ReCreateSocks(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.P
|
|||||||
log.Errorln("Start SOCKS server error: %s", err.Error())
|
log.Errorln("Start SOCKS server error: %s", err.Error())
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
inner.New(tcpIn)
|
||||||
|
|
||||||
addr := genAddr(bindAddress, port, allowLan)
|
addr := genAddr(bindAddress, port, allowLan)
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@ package tproxy
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/Dreamacro/clash/component/dialer"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
U "os/user"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -20,7 +20,6 @@ var (
|
|||||||
const (
|
const (
|
||||||
PROXY_FWMARK = "0x2d0"
|
PROXY_FWMARK = "0x2d0"
|
||||||
PROXY_ROUTE_TABLE = "0x2d0"
|
PROXY_ROUTE_TABLE = "0x2d0"
|
||||||
USERNAME = "root"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func SetTProxyLinuxIPTables(ifname string, tport int, dport int) error {
|
func SetTProxyLinuxIPTables(ifname string, tport int, dport int) error {
|
||||||
@ -29,17 +28,10 @@ func SetTProxyLinuxIPTables(ifname string, tport int, dport int) error {
|
|||||||
return fmt.Errorf("current operations system [%s] are not support iptables or command iptables does not exist", runtime.GOOS)
|
return fmt.Errorf("current operations system [%s] are not support iptables or command iptables does not exist", runtime.GOOS)
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := U.Lookup(USERNAME)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("the user \" %s\" does not exist, please create it", USERNAME)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ifname == "" {
|
if ifname == "" {
|
||||||
return errors.New("the 'interface-name' can not be empty")
|
return errors.New("the 'interface-name' can not be empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
ownerUid := user.Uid
|
|
||||||
|
|
||||||
interfaceName = ifname
|
interfaceName = ifname
|
||||||
tproxyPort = tport
|
tproxyPort = tport
|
||||||
dnsPort = dport
|
dnsPort = dport
|
||||||
@ -84,7 +76,7 @@ func SetTProxyLinuxIPTables(ifname string, tport int, dport int) error {
|
|||||||
// set output
|
// set output
|
||||||
execCmd("iptables -t mangle -N clash_output")
|
execCmd("iptables -t mangle -N clash_output")
|
||||||
execCmd("iptables -t mangle -F clash_output")
|
execCmd("iptables -t mangle -F clash_output")
|
||||||
execCmd(fmt.Sprintf("iptables -t mangle -A clash_output -m owner --uid-owner %s -j RETURN", ownerUid))
|
execCmd(fmt.Sprintf("iptables -t mangle -A clash_output -m mark --mark %#x -j RETURN", dialer.DefaultRoutingMark.Load()))
|
||||||
execCmd("iptables -t mangle -A clash_output -p udp -m multiport --dports 53,123,137 -j ACCEPT")
|
execCmd("iptables -t mangle -A clash_output -p udp -m multiport --dports 53,123,137 -j ACCEPT")
|
||||||
execCmd("iptables -t mangle -A clash_output -p tcp --dport 53 -j ACCEPT")
|
execCmd("iptables -t mangle -A clash_output -p tcp --dport 53 -j ACCEPT")
|
||||||
execCmd("iptables -t mangle -A clash_output -m addrtype --dst-type LOCAL -j RETURN")
|
execCmd("iptables -t mangle -A clash_output -m addrtype --dst-type LOCAL -j RETURN")
|
||||||
@ -97,7 +89,7 @@ func SetTProxyLinuxIPTables(ifname string, tport int, dport int) error {
|
|||||||
// set dns output
|
// set dns output
|
||||||
execCmd("iptables -t nat -N clash_dns_output")
|
execCmd("iptables -t nat -N clash_dns_output")
|
||||||
execCmd("iptables -t nat -F clash_dns_output")
|
execCmd("iptables -t nat -F clash_dns_output")
|
||||||
execCmd(fmt.Sprintf("iptables -t nat -A clash_dns_output -m owner --uid-owner %s -j RETURN", ownerUid))
|
execCmd(fmt.Sprintf("iptables -t nat -A clash_dns_output -m mark --mark %#x -j RETURN", dialer.DefaultRoutingMark.Load()))
|
||||||
execCmd("iptables -t nat -A clash_dns_output -s 172.17.0.0/16 -j RETURN")
|
execCmd("iptables -t nat -A clash_dns_output -s 172.17.0.0/16 -j RETURN")
|
||||||
execCmd(fmt.Sprintf("iptables -t nat -A clash_dns_output -p udp -j REDIRECT --to-ports %d", dnsPort))
|
execCmd(fmt.Sprintf("iptables -t nat -A clash_dns_output -p udp -j REDIRECT --to-ports %d", dnsPort))
|
||||||
execCmd(fmt.Sprintf("iptables -t nat -A clash_dns_output -p tcp -j REDIRECT --to-ports %d", dnsPort))
|
execCmd(fmt.Sprintf("iptables -t nat -A clash_dns_output -p tcp -j REDIRECT --to-ports %d", dnsPort))
|
||||||
@ -115,6 +107,8 @@ func CleanUpTProxyLinuxIPTables() {
|
|||||||
|
|
||||||
log.Warnln("Clean up tproxy linux iptables")
|
log.Warnln("Clean up tproxy linux iptables")
|
||||||
|
|
||||||
|
dialer.DefaultRoutingMark.Store(0)
|
||||||
|
|
||||||
if _, err := execCmd("iptables -t mangle -L clash_divert"); err != nil {
|
if _, err := execCmd("iptables -t mangle -L clash_divert"); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,5 @@
|
|||||||
package dev
|
package dev
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"os/exec"
|
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TunDevice is cross-platform tun interface
|
// TunDevice is cross-platform tun interface
|
||||||
type TunDevice interface {
|
type TunDevice interface {
|
||||||
Name() string
|
Name() string
|
||||||
@ -18,54 +10,3 @@ type TunDevice interface {
|
|||||||
Read(buff []byte) (int, error)
|
Read(buff []byte) (int, error)
|
||||||
Write(buff []byte) (int, error)
|
Write(buff []byte) (int, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetLinuxAutoRoute() {
|
|
||||||
log.Infoln("Tun adapter auto setting global route")
|
|
||||||
addLinuxSystemRoute("0")
|
|
||||||
//addLinuxSystemRoute("1")
|
|
||||||
//addLinuxSystemRoute("2/7")
|
|
||||||
//addLinuxSystemRoute("4/6")
|
|
||||||
//addLinuxSystemRoute("8/5")
|
|
||||||
//addLinuxSystemRoute("16/4")
|
|
||||||
//addLinuxSystemRoute("32/3")
|
|
||||||
//addLinuxSystemRoute("64/2")
|
|
||||||
//addLinuxSystemRoute("128.0/1")
|
|
||||||
//addLinuxSystemRoute("198.18.0/16")
|
|
||||||
}
|
|
||||||
|
|
||||||
func RemoveLinuxAutoRoute() {
|
|
||||||
log.Infoln("Tun adapter removing global route")
|
|
||||||
delLinuxSystemRoute("0")
|
|
||||||
//delLinuxSystemRoute("1")
|
|
||||||
//delLinuxSystemRoute("2/7")
|
|
||||||
//delLinuxSystemRoute("4/6")
|
|
||||||
//delLinuxSystemRoute("8/5")
|
|
||||||
//delLinuxSystemRoute("16/4")
|
|
||||||
//delLinuxSystemRoute("32/3")
|
|
||||||
//delLinuxSystemRoute("64/2")
|
|
||||||
//delLinuxSystemRoute("128.0/1")
|
|
||||||
//delLinuxSystemRoute("198.18.0/16")
|
|
||||||
}
|
|
||||||
|
|
||||||
func addLinuxSystemRoute(net string) {
|
|
||||||
if runtime.GOOS != "darwin" && runtime.GOOS != "linux" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cmd := exec.Command("route", "add", "-net", net, "meta")
|
|
||||||
var stderr bytes.Buffer
|
|
||||||
cmd.Stderr = &stderr
|
|
||||||
if err := cmd.Run(); err != nil {
|
|
||||||
log.Errorln("[auto route] Failed to add system route: %s: %s , cmd: %s", err.Error(), stderr.String(), cmd.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func delLinuxSystemRoute(net string) {
|
|
||||||
if runtime.GOOS != "darwin" && runtime.GOOS != "linux" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cmd := exec.Command("route", "delete", "-net", net, "meta")
|
|
||||||
_ = cmd.Run()
|
|
||||||
//if err := cmd.Run(); err != nil {
|
|
||||||
// log.Errorln("[auto route]Failed to delete system route: %s, cmd: %s", err.Error(), cmd.String())
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
@ -5,11 +5,13 @@ package dev
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/Dreamacro/clash/log"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
@ -176,7 +178,7 @@ func OpenTunDevice(tunAddress string, autoRoute bool) (TunDevice, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if autoRoute {
|
if autoRoute {
|
||||||
SetLinuxAutoRoute()
|
setAutoRoute(tunAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
return tun, nil
|
return tun, nil
|
||||||
@ -280,7 +282,7 @@ func (t *tunDarwin) IsClose() bool {
|
|||||||
func (t *tunDarwin) Close() error {
|
func (t *tunDarwin) Close() error {
|
||||||
t.stopOnce.Do(func() {
|
t.stopOnce.Do(func() {
|
||||||
if t.autoRoute {
|
if t.autoRoute {
|
||||||
RemoveLinuxAutoRoute()
|
resetAutoRoute(t.tunAddress)
|
||||||
}
|
}
|
||||||
t.closed = true
|
t.closed = true
|
||||||
t.tunFile.Close()
|
t.tunFile.Close()
|
||||||
@ -480,15 +482,60 @@ func (t *tunDarwin) attachLinkLocal() error {
|
|||||||
|
|
||||||
// GetAutoDetectInterface get ethernet interface
|
// GetAutoDetectInterface get ethernet interface
|
||||||
func GetAutoDetectInterface() (string, error) {
|
func GetAutoDetectInterface() (string, error) {
|
||||||
cmd := exec.Command("bash", "-c", "netstat -rnf inet | grep 'default' | awk -F ' ' 'NR==1{print $6}' | xargs echo -n")
|
cmd := exec.Command("route", "-n", "get", "default")
|
||||||
var out bytes.Buffer
|
if result, err := cmd.Output(); err != nil {
|
||||||
cmd.Stdout = &out
|
|
||||||
err := cmd.Run()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
return "", err
|
||||||
|
} else {
|
||||||
|
resultString := string(result)
|
||||||
|
reg, err := regexp.Compile("(interface:)(.*)")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
matchResult := reg.FindStringSubmatch(resultString)
|
||||||
|
interfaceName := strings.TrimSpace(matchResult[len(matchResult)-1])
|
||||||
|
return interfaceName, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func setAutoRoute(tunGateway string) {
|
||||||
|
addRoute("1", tunGateway)
|
||||||
|
addRoute("2/7", tunGateway)
|
||||||
|
addRoute("4/6", tunGateway)
|
||||||
|
addRoute("8/5", tunGateway)
|
||||||
|
addRoute("16/4", tunGateway)
|
||||||
|
addRoute("32/3", tunGateway)
|
||||||
|
addRoute("64/2", tunGateway)
|
||||||
|
addRoute("128.0/1", tunGateway)
|
||||||
|
addRoute("198.18.0/16", tunGateway)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resetAutoRoute(tunGateway string) {
|
||||||
|
delRoute("1", tunGateway)
|
||||||
|
delRoute("2/7", tunGateway)
|
||||||
|
delRoute("4/6", tunGateway)
|
||||||
|
delRoute("8/5", tunGateway)
|
||||||
|
delRoute("16/4", tunGateway)
|
||||||
|
delRoute("32/3", tunGateway)
|
||||||
|
delRoute("64/2", tunGateway)
|
||||||
|
delRoute("128.0/1", tunGateway)
|
||||||
|
delRoute("198.18.0/16", tunGateway)
|
||||||
|
}
|
||||||
|
|
||||||
|
func addRoute(net, name string) {
|
||||||
|
cmd := exec.Command("route", "add", "-net", net, name)
|
||||||
|
var stderr bytes.Buffer
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
log.Errorln("[auto route] Failed to add system route: %s: %s , cmd: %s", err.Error(), stderr.String(), cmd.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func delRoute(net, name string) {
|
||||||
|
cmd := exec.Command("route", "delete", "-net", net, name)
|
||||||
|
var stderr bytes.Buffer
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
log.Errorln("[auto route] Failed to delete system route: %s: %s , cmd: %s", err.Error(), stderr.String(), cmd.String())
|
||||||
}
|
}
|
||||||
if out.Len() == 0 {
|
|
||||||
return "", errors.New("interface not found by default route")
|
|
||||||
}
|
|
||||||
return out.String(), nil
|
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/Dreamacro/clash/log"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@ -38,7 +39,7 @@ type tunLinux struct {
|
|||||||
|
|
||||||
// OpenTunDevice return a TunDevice according a URL
|
// OpenTunDevice return a TunDevice according a URL
|
||||||
func OpenTunDevice(tunAddress string, autoRoute bool) (TunDevice, error) {
|
func OpenTunDevice(tunAddress string, autoRoute bool) (TunDevice, error) {
|
||||||
deviceURL, _ := url.Parse("dev://meta")
|
deviceURL, _ := url.Parse("dev://utun")
|
||||||
mtu, _ := strconv.ParseInt(deviceURL.Query().Get("mtu"), 0, 32)
|
mtu, _ := strconv.ParseInt(deviceURL.Query().Get("mtu"), 0, 32)
|
||||||
|
|
||||||
t := &tunLinux{
|
t := &tunLinux{
|
||||||
@ -62,8 +63,9 @@ func OpenTunDevice(tunAddress string, autoRoute bool) (TunDevice, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if autoRoute {
|
if autoRoute {
|
||||||
SetLinuxAutoRoute()
|
addRoute(tunAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
return dev, nil
|
return dev, nil
|
||||||
case "fd":
|
case "fd":
|
||||||
fd, err := strconv.ParseInt(deviceURL.Host, 10, 32)
|
fd, err := strconv.ParseInt(deviceURL.Host, 10, 32)
|
||||||
@ -76,7 +78,7 @@ func OpenTunDevice(tunAddress string, autoRoute bool) (TunDevice, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if autoRoute {
|
if autoRoute {
|
||||||
SetLinuxAutoRoute()
|
log.Warnln("linux unsupported automatic route")
|
||||||
}
|
}
|
||||||
return dev, nil
|
return dev, nil
|
||||||
}
|
}
|
||||||
@ -105,9 +107,6 @@ func (t *tunLinux) IsClose() bool {
|
|||||||
|
|
||||||
func (t *tunLinux) Close() error {
|
func (t *tunLinux) Close() error {
|
||||||
t.stopOnce.Do(func() {
|
t.stopOnce.Do(func() {
|
||||||
if t.autoRoute {
|
|
||||||
RemoveLinuxAutoRoute()
|
|
||||||
}
|
|
||||||
t.closed = true
|
t.closed = true
|
||||||
t.tunFile.Close()
|
t.tunFile.Close()
|
||||||
})
|
})
|
||||||
@ -330,3 +329,21 @@ func GetAutoDetectInterface() (string, error) {
|
|||||||
}
|
}
|
||||||
return out.String(), nil
|
return out.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addRoute(gateway string) {
|
||||||
|
cmd := exec.Command("route", "add", "default", "gw", gateway)
|
||||||
|
var stderr bytes.Buffer
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
log.Errorln("[auto route] Failed to add system route: %s: %s , cmd: %s", err.Error(), stderr.String(), cmd.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func delRoute(gateway string) {
|
||||||
|
cmd := exec.Command("ip", "route", "delete", "gw")
|
||||||
|
var stderr bytes.Buffer
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
log.Errorln("[auto route] Failed to delete system route: %s: %s , cmd: %s", err.Error(), stderr.String(), cmd.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -36,7 +36,7 @@ const nicID tcpip.NICID = 1
|
|||||||
type gvisorAdapter struct {
|
type gvisorAdapter struct {
|
||||||
device dev.TunDevice
|
device dev.TunDevice
|
||||||
ipstack *stack.Stack
|
ipstack *stack.Stack
|
||||||
dnsserver *DNSServer
|
dnsServer *DNSServer
|
||||||
udpIn chan<- *inbound.PacketAdapter
|
udpIn chan<- *inbound.PacketAdapter
|
||||||
|
|
||||||
stackName string
|
stackName string
|
||||||
@ -47,7 +47,7 @@ type gvisorAdapter struct {
|
|||||||
writeHandle *channel.NotificationHandle
|
writeHandle *channel.NotificationHandle
|
||||||
}
|
}
|
||||||
|
|
||||||
// GvisorAdapter create GvisorAdapter
|
// NewAdapter GvisorAdapter create GvisorAdapter
|
||||||
func NewAdapter(device dev.TunDevice, conf config.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) (ipstack.TunAdapter, error) {
|
func NewAdapter(device dev.TunDevice, conf config.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) (ipstack.TunAdapter, error) {
|
||||||
ipstack := stack.New(stack.Options{
|
ipstack := stack.New(stack.Options{
|
||||||
NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol},
|
NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol},
|
||||||
@ -92,7 +92,8 @@ func NewAdapter(device dev.TunDevice, conf config.Tun, tcpIn chan<- C.ConnContex
|
|||||||
r.Complete(true)
|
r.Complete(true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r.Complete(false)
|
|
||||||
|
defer r.Complete(false)
|
||||||
|
|
||||||
conn := gonet.NewTCPConn(&wq, ep)
|
conn := gonet.NewTCPConn(&wq, ep)
|
||||||
|
|
||||||
@ -107,13 +108,14 @@ func NewAdapter(device dev.TunDevice, conf config.Tun, tcpIn chan<- C.ConnContex
|
|||||||
target := getAddr(ep.Info().(*stack.TransportEndpointInfo).ID)
|
target := getAddr(ep.Info().(*stack.TransportEndpointInfo).ID)
|
||||||
tcpIn <- inbound.NewSocket(target, conn, C.TUN)
|
tcpIn <- inbound.NewSocket(target, conn, C.TUN)
|
||||||
})
|
})
|
||||||
|
|
||||||
ipstack.SetTransportProtocolHandler(tcp.ProtocolNumber, tcpFwd.HandlePacket)
|
ipstack.SetTransportProtocolHandler(tcp.ProtocolNumber, tcpFwd.HandlePacket)
|
||||||
|
|
||||||
// UDP handler
|
// UDP handler
|
||||||
ipstack.SetTransportProtocolHandler(udp.ProtocolNumber, adapter.udpHandlePacket)
|
ipstack.SetTransportProtocolHandler(udp.ProtocolNumber, adapter.udpHandlePacket)
|
||||||
|
|
||||||
if resolver.DefaultResolver != nil {
|
if resolver.DefaultResolver != nil {
|
||||||
err = adapter.ReCreateDNSServer(resolver.DefaultResolver.(*dns.Resolver), resolver.DefaultHostMapper.(*dns.ResolverEnhancer), conf.DNSListen)
|
err = adapter.ReCreateDNSServer(resolver.DefaultResolver.(*dns.Resolver), resolver.DefaultHostMapper.(*dns.ResolverEnhancer), conf.DnsHijack)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -132,9 +134,7 @@ func (t *gvisorAdapter) AutoRoute() bool {
|
|||||||
|
|
||||||
// Close close the TunAdapter
|
// Close close the TunAdapter
|
||||||
func (t *gvisorAdapter) Close() {
|
func (t *gvisorAdapter) Close() {
|
||||||
if t.dnsserver != nil {
|
t.StopDNSServer()
|
||||||
t.dnsserver.Stop()
|
|
||||||
}
|
|
||||||
if t.ipstack != nil {
|
if t.ipstack != nil {
|
||||||
t.ipstack.Close()
|
t.ipstack.Close()
|
||||||
}
|
}
|
||||||
@ -196,21 +196,31 @@ func (t *gvisorAdapter) AsLinkEndpoint() (result stack.LinkEndpoint, err error)
|
|||||||
log.Errorln("can not read from tun: %v", err)
|
log.Errorln("can not read from tun: %v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var p tcpip.NetworkProtocolNumber
|
var p tcpip.NetworkProtocolNumber
|
||||||
switch header.IPVersion(packet) {
|
switch header.IPVersion(packet) {
|
||||||
case header.IPv4Version:
|
case header.IPv4Version:
|
||||||
p = header.IPv4ProtocolNumber
|
p = header.IPv4ProtocolNumber
|
||||||
case header.IPv6Version:
|
case header.IPv6Version:
|
||||||
p = header.IPv6ProtocolNumber
|
p = header.IPv6ProtocolNumber
|
||||||
|
default:
|
||||||
|
log.Warnln("invalid IP version:%d", header.IPVersion(packet))
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if linkEP.IsAttached() {
|
if linkEP.IsAttached() {
|
||||||
linkEP.InjectInbound(p, stack.NewPacketBuffer(stack.PacketBufferOptions{
|
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||||
Data: buffer.View(packet[:n]).ToVectorisedView(),
|
Data: buffer.View(packet[:n]).ToVectorisedView(),
|
||||||
}))
|
})
|
||||||
|
|
||||||
|
linkEP.InjectInbound(p, pkt)
|
||||||
|
// release memory
|
||||||
|
pkt.DecRef()
|
||||||
} else {
|
} else {
|
||||||
log.Debugln("received packet from tun when %s is not attached to any dispatcher.", t.device.Name())
|
log.Debugln("received packet from tun when %s is not attached to any dispatcher.", t.device.Name())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
t.wg.Done()
|
t.wg.Done()
|
||||||
t.Close()
|
t.Close()
|
||||||
log.Debugln("%v stop read loop", t.device.Name())
|
log.Debugln("%v stop read loop", t.device.Name())
|
||||||
@ -224,14 +234,14 @@ func (t *gvisorAdapter) AsLinkEndpoint() (result stack.LinkEndpoint, err error)
|
|||||||
|
|
||||||
// WriteNotify implements channel.Notification.WriteNotify.
|
// WriteNotify implements channel.Notification.WriteNotify.
|
||||||
func (t *gvisorAdapter) WriteNotify() {
|
func (t *gvisorAdapter) WriteNotify() {
|
||||||
packet, ok := t.linkCache.Read()
|
packetBuffer := t.linkCache.Read()
|
||||||
if ok {
|
if packetBuffer != nil {
|
||||||
var vv buffer.VectorisedView
|
var vv buffer.VectorisedView
|
||||||
// Append upper headers.
|
// Append upper headers.
|
||||||
vv.AppendView(packet.Pkt.NetworkHeader().View())
|
vv.AppendView(packetBuffer.NetworkHeader().View())
|
||||||
vv.AppendView(packet.Pkt.TransportHeader().View())
|
vv.AppendView(packetBuffer.TransportHeader().View())
|
||||||
// Append data payload.
|
// Append data payload.
|
||||||
vv.Append(packet.Pkt.Data().ExtractVV())
|
vv.Append(packetBuffer.Data().ExtractVV())
|
||||||
|
|
||||||
_, err := t.device.Write(vv.ToView())
|
_, err := t.device.Write(vv.ToView())
|
||||||
if err != nil && !t.device.IsClose() {
|
if err != nil && !t.device.IsClose() {
|
||||||
|
@ -2,13 +2,14 @@ package gvisor
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
|
Common "github.com/Dreamacro/clash/common/net"
|
||||||
"github.com/Dreamacro/clash/dns"
|
"github.com/Dreamacro/clash/dns"
|
||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
D "github.com/miekg/dns"
|
D "github.com/miekg/dns"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip"
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
|
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
|
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
|
||||||
@ -23,15 +24,33 @@ var (
|
|||||||
ipv6Zero = tcpip.Address(net.IPv6zero.To16())
|
ipv6Zero = tcpip.Address(net.IPv6zero.To16())
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ListenerWrap struct {
|
||||||
|
net.Listener
|
||||||
|
listener net.Listener
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ListenerWrap) Accept() (conn net.Conn, err error) {
|
||||||
|
conn, err = l.listener.Accept()
|
||||||
|
log.Debugln("[DNS] hijack tcp:%s", l.Addr())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ListenerWrap) Close() error {
|
||||||
|
return l.listener.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ListenerWrap) Addr() net.Addr {
|
||||||
|
return l.listener.Addr()
|
||||||
|
}
|
||||||
|
|
||||||
// DNSServer is DNS Server listening on tun devcice
|
// DNSServer is DNS Server listening on tun devcice
|
||||||
type DNSServer struct {
|
type DNSServer struct {
|
||||||
*dns.Server
|
dnsServers []*dns.Server
|
||||||
resolver *dns.Resolver
|
tcpListeners []net.Listener
|
||||||
|
resolver *dns.Resolver
|
||||||
stack *stack.Stack
|
stack *stack.Stack
|
||||||
tcpListener net.Listener
|
udpEndpoints []*dnsEndpoint
|
||||||
udpEndpoint *dnsEndpoint
|
udpEndpointIDs []*stack.TransportEndpointID
|
||||||
udpEndpointID *stack.TransportEndpointID
|
|
||||||
tcpip.NICID
|
tcpip.NICID
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,6 +85,8 @@ func (e *dnsEndpoint) HandlePacket(id stack.TransportEndpointID, pkt *stack.Pack
|
|||||||
var msg D.Msg
|
var msg D.Msg
|
||||||
msg.Unpack(pkt.Data().AsRange().ToOwnedView())
|
msg.Unpack(pkt.Data().AsRange().ToOwnedView())
|
||||||
writer := dnsResponseWriter{s: e.stack, pkt: pkt, id: id}
|
writer := dnsResponseWriter{s: e.stack, pkt: pkt, id: id}
|
||||||
|
log.Debugln("[DNS] hijack udp:%s:%d from %s:%d", id.LocalAddress.String(), id.LocalPort,
|
||||||
|
id.RemoteAddress.String(), id.RemotePort)
|
||||||
go e.server.ServeDNS(&writer, &msg)
|
go e.server.ServeDNS(&writer, &msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,9 +140,17 @@ func (w *dnsResponseWriter) Write(b []byte) (int, error) {
|
|||||||
v := buffer.NewView(len(b))
|
v := buffer.NewView(len(b))
|
||||||
copy(v, b)
|
copy(v, b)
|
||||||
data := v.ToVectorisedView()
|
data := v.ToVectorisedView()
|
||||||
|
|
||||||
// w.id.LocalAddress is the source ip of DNS response
|
// w.id.LocalAddress is the source ip of DNS response
|
||||||
r, _ := w.s.FindRoute(w.pkt.NICID, w.id.LocalAddress, w.id.RemoteAddress, w.pkt.NetworkProtocolNumber, false /* multicastLoop */)
|
if !w.pkt.NetworkHeader().View().IsEmpty() &&
|
||||||
return writeUDP(r, data, w.id.LocalPort, w.id.RemotePort)
|
(w.pkt.NetworkProtocolNumber == ipv4.ProtocolNumber ||
|
||||||
|
w.pkt.NetworkProtocolNumber == ipv6.ProtocolNumber) {
|
||||||
|
r, _ := w.s.FindRoute(w.pkt.NICID, w.id.LocalAddress, w.id.RemoteAddress, w.pkt.NetworkProtocolNumber, false /* multicastLoop */)
|
||||||
|
return writeUDP(r, data, w.id.LocalPort, w.id.RemotePort)
|
||||||
|
} else {
|
||||||
|
log.Debugln("the network protocl[%d] is not available", w.pkt.NetworkProtocolNumber)
|
||||||
|
return 0, fmt.Errorf("the network protocl[%d] is not available", w.pkt.NetworkProtocolNumber)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *dnsResponseWriter) Close() error {
|
func (w *dnsResponseWriter) Close() error {
|
||||||
@ -129,163 +158,276 @@ func (w *dnsResponseWriter) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateDNSServer create a dns server on given netstack
|
// CreateDNSServer create a dns server on given netstack
|
||||||
func CreateDNSServer(s *stack.Stack, resolver *dns.Resolver, mapper *dns.ResolverEnhancer, ip net.IP, port int, nicID tcpip.NICID) (*DNSServer, error) {
|
func CreateDNSServer(s *stack.Stack, resolver *dns.Resolver, mapper *dns.ResolverEnhancer, dnsHijack []net.Addr, nicID tcpip.NICID) (*DNSServer, error) {
|
||||||
var v4 bool
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
address := tcpip.FullAddress{NIC: nicID, Port: uint16(port)}
|
|
||||||
var protocol tcpip.NetworkProtocolNumber
|
|
||||||
if ip.To4() != nil {
|
|
||||||
v4 = true
|
|
||||||
address.Addr = tcpip.Address(ip.To4())
|
|
||||||
protocol = ipv4.ProtocolNumber
|
|
||||||
|
|
||||||
} else {
|
|
||||||
v4 = false
|
|
||||||
address.Addr = tcpip.Address(ip.To16())
|
|
||||||
protocol = ipv6.ProtocolNumber
|
|
||||||
}
|
|
||||||
protocolAddr := tcpip.ProtocolAddress{
|
|
||||||
Protocol: protocol,
|
|
||||||
AddressWithPrefix: address.Addr.WithPrefix(),
|
|
||||||
}
|
|
||||||
// netstack will only reassemble IP fragments when its' dest ip address is registered in NIC.endpoints
|
|
||||||
if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil {
|
|
||||||
log.Errorln("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if address.Addr == ipv4Zero || address.Addr == ipv6Zero {
|
|
||||||
address.Addr = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
handler := dns.NewHandler(resolver, mapper)
|
handler := dns.NewHandler(resolver, mapper)
|
||||||
serverIn := &dns.Server{}
|
serverIn := &dns.Server{}
|
||||||
serverIn.SetHandler(handler)
|
serverIn.SetHandler(handler)
|
||||||
|
tcpDnsArr := make([]net.TCPAddr, 0, len(dnsHijack))
|
||||||
// UDP DNS
|
udpDnsArr := make([]net.UDPAddr, 0, len(dnsHijack))
|
||||||
id := &stack.TransportEndpointID{
|
for _, d := range dnsHijack {
|
||||||
LocalAddress: address.Addr,
|
switch d.(type) {
|
||||||
LocalPort: uint16(port),
|
case *net.TCPAddr:
|
||||||
RemotePort: 0,
|
{
|
||||||
RemoteAddress: "",
|
tcpDnsArr = append(tcpDnsArr, *d.(*net.TCPAddr))
|
||||||
}
|
break
|
||||||
|
}
|
||||||
// TransportEndpoint for DNS
|
case *net.UDPAddr:
|
||||||
endpoint := &dnsEndpoint{
|
{
|
||||||
stack: s,
|
udpDnsArr = append(udpDnsArr, *d.(*net.UDPAddr))
|
||||||
uniqueID: s.UniqueID(),
|
break
|
||||||
server: serverIn,
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if tcpiperr := s.RegisterTransportEndpoint(
|
|
||||||
[]tcpip.NetworkProtocolNumber{
|
|
||||||
ipv4.ProtocolNumber,
|
|
||||||
ipv6.ProtocolNumber,
|
|
||||||
},
|
|
||||||
udp.ProtocolNumber,
|
|
||||||
*id,
|
|
||||||
endpoint,
|
|
||||||
ports.Flags{LoadBalanced: true}, // it's actually the SO_REUSEPORT. Not sure it take effect.
|
|
||||||
nicID); tcpiperr != nil {
|
|
||||||
log.Errorln("Unable to start UDP DNS on tun: %v", tcpiperr.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
// TCP DNS
|
|
||||||
var tcpListener net.Listener
|
|
||||||
if v4 {
|
|
||||||
tcpListener, err = gonet.ListenTCP(s, address, ipv4.ProtocolNumber)
|
|
||||||
} else {
|
|
||||||
tcpListener, err = gonet.ListenTCP(s, address, ipv6.ProtocolNumber)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("can not listen on tun: %v", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
endpoints, ids := hijackUdpDns(udpDnsArr, s, serverIn)
|
||||||
|
tcpListeners, dnsServers := hijackTcpDns(tcpDnsArr, s, serverIn)
|
||||||
server := &DNSServer{
|
server := &DNSServer{
|
||||||
Server: serverIn,
|
resolver: resolver,
|
||||||
resolver: resolver,
|
stack: s,
|
||||||
stack: s,
|
udpEndpoints: endpoints,
|
||||||
tcpListener: tcpListener,
|
udpEndpointIDs: ids,
|
||||||
udpEndpoint: endpoint,
|
NICID: nicID,
|
||||||
udpEndpointID: id,
|
tcpListeners: tcpListeners,
|
||||||
NICID: nicID,
|
|
||||||
}
|
}
|
||||||
server.SetHandler(handler)
|
|
||||||
server.Server.Server = &D.Server{Listener: tcpListener, Handler: server}
|
|
||||||
|
|
||||||
go func() {
|
server.dnsServers = dnsServers
|
||||||
server.ActivateAndServe()
|
|
||||||
}()
|
|
||||||
|
|
||||||
return server, err
|
return server, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hijackUdpDns(dnsArr []net.UDPAddr, s *stack.Stack, serverIn *dns.Server) ([]*dnsEndpoint, []*stack.TransportEndpointID) {
|
||||||
|
endpoints := make([]*dnsEndpoint, len(dnsArr))
|
||||||
|
ids := make([]*stack.TransportEndpointID, len(dnsArr))
|
||||||
|
for i, dns := range dnsArr {
|
||||||
|
port := dns.Port
|
||||||
|
ip := dns.IP
|
||||||
|
address := tcpip.FullAddress{NIC: nicID, Port: uint16(port)}
|
||||||
|
var protocol tcpip.NetworkProtocolNumber
|
||||||
|
if ip.To4() != nil {
|
||||||
|
address.Addr = tcpip.Address(ip.To4())
|
||||||
|
protocol = ipv4.ProtocolNumber
|
||||||
|
|
||||||
|
} else {
|
||||||
|
address.Addr = tcpip.Address(ip.To16())
|
||||||
|
protocol = ipv6.ProtocolNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
protocolAddr := tcpip.ProtocolAddress{
|
||||||
|
Protocol: protocol,
|
||||||
|
AddressWithPrefix: address.Addr.WithPrefix(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// netstack will only reassemble IP fragments when its' dest ip address is registered in NIC.endpoints
|
||||||
|
if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil {
|
||||||
|
log.Errorln("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if address.Addr == ipv4Zero || address.Addr == ipv6Zero {
|
||||||
|
address.Addr = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// UDP DNS
|
||||||
|
id := &stack.TransportEndpointID{
|
||||||
|
LocalAddress: address.Addr,
|
||||||
|
LocalPort: uint16(port),
|
||||||
|
RemotePort: 0,
|
||||||
|
RemoteAddress: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
// TransportEndpoint for DNS
|
||||||
|
endpoint := &dnsEndpoint{
|
||||||
|
stack: s,
|
||||||
|
uniqueID: s.UniqueID(),
|
||||||
|
server: serverIn,
|
||||||
|
}
|
||||||
|
|
||||||
|
if tcpiperr := s.RegisterTransportEndpoint(
|
||||||
|
[]tcpip.NetworkProtocolNumber{
|
||||||
|
ipv4.ProtocolNumber,
|
||||||
|
ipv6.ProtocolNumber,
|
||||||
|
},
|
||||||
|
udp.ProtocolNumber,
|
||||||
|
*id,
|
||||||
|
endpoint,
|
||||||
|
ports.Flags{LoadBalanced: true}, // it's actually the SO_REUSEPORT. Not sure it take effect.
|
||||||
|
nicID); tcpiperr != nil {
|
||||||
|
log.Errorln("Unable to start UDP DNS on tun: %v", tcpiperr.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
ids[i] = id
|
||||||
|
endpoints[i] = endpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
return endpoints, ids
|
||||||
|
}
|
||||||
|
|
||||||
|
func hijackTcpDns(dnsArr []net.TCPAddr, s *stack.Stack, serverIn *dns.Server) ([]net.Listener, []*dns.Server) {
|
||||||
|
tcpListeners := make([]net.Listener, len(dnsArr))
|
||||||
|
dnsServers := make([]*dns.Server, len(dnsArr))
|
||||||
|
|
||||||
|
for i, dnsAddr := range dnsArr {
|
||||||
|
var tcpListener net.Listener
|
||||||
|
var v4 bool
|
||||||
|
var err error
|
||||||
|
port := dnsAddr.Port
|
||||||
|
ip := dnsAddr.IP
|
||||||
|
address := tcpip.FullAddress{NIC: nicID, Port: uint16(port)}
|
||||||
|
if ip.To4() != nil {
|
||||||
|
address.Addr = tcpip.Address(ip.To4())
|
||||||
|
v4 = true
|
||||||
|
} else {
|
||||||
|
address.Addr = tcpip.Address(ip.To16())
|
||||||
|
v4 = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if v4 {
|
||||||
|
tcpListener, err = gonet.ListenTCP(s, address, ipv4.ProtocolNumber)
|
||||||
|
} else {
|
||||||
|
tcpListener, err = gonet.ListenTCP(s, address, ipv6.ProtocolNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Errorln("can not listen on tun: %v, hijack tcp[%s] failed", err, dnsAddr)
|
||||||
|
} else {
|
||||||
|
tcpListeners[i] = tcpListener
|
||||||
|
server := &D.Server{Listener: &ListenerWrap{
|
||||||
|
listener: tcpListener,
|
||||||
|
}, Handler: serverIn}
|
||||||
|
dnsServer := dns.Server{}
|
||||||
|
dnsServer.Server = server
|
||||||
|
go dnsServer.ActivateAndServe()
|
||||||
|
dnsServers[i] = &dnsServer
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
//
|
||||||
|
//for _, listener := range tcpListeners {
|
||||||
|
// server := &D.Server{Listener: listener, Handler: serverIn}
|
||||||
|
//
|
||||||
|
// dnsServers = append(dnsServers, &dnsServer)
|
||||||
|
// go dnsServer.ActivateAndServe()
|
||||||
|
//}
|
||||||
|
|
||||||
|
return tcpListeners, dnsServers
|
||||||
|
}
|
||||||
|
|
||||||
// Stop stop the DNS Server on tun
|
// Stop stop the DNS Server on tun
|
||||||
func (s *DNSServer) Stop() {
|
func (s *DNSServer) Stop() {
|
||||||
// shutdown TCP DNS Server
|
if s == nil {
|
||||||
s.Server.Shutdown()
|
return
|
||||||
// remove TCP endpoint from stack
|
}
|
||||||
if s.Listener != nil {
|
|
||||||
s.Listener.Close()
|
for i := 0; i < len(s.udpEndpointIDs); i++ {
|
||||||
|
ep := s.udpEndpoints[i]
|
||||||
|
id := s.udpEndpointIDs[i]
|
||||||
|
// remove udp endpoint from stack
|
||||||
|
s.stack.UnregisterTransportEndpoint(
|
||||||
|
[]tcpip.NetworkProtocolNumber{
|
||||||
|
ipv4.ProtocolNumber,
|
||||||
|
ipv6.ProtocolNumber,
|
||||||
|
},
|
||||||
|
udp.ProtocolNumber,
|
||||||
|
*id,
|
||||||
|
ep,
|
||||||
|
ports.Flags{LoadBalanced: true}, // should match the RegisterTransportEndpoint
|
||||||
|
s.NICID)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, server := range s.dnsServers {
|
||||||
|
server.Shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, listener := range s.tcpListeners {
|
||||||
|
listener.Close()
|
||||||
}
|
}
|
||||||
// remove udp endpoint from stack
|
|
||||||
s.stack.UnregisterTransportEndpoint(
|
|
||||||
[]tcpip.NetworkProtocolNumber{
|
|
||||||
ipv4.ProtocolNumber,
|
|
||||||
ipv6.ProtocolNumber,
|
|
||||||
},
|
|
||||||
udp.ProtocolNumber,
|
|
||||||
*s.udpEndpointID,
|
|
||||||
s.udpEndpoint,
|
|
||||||
ports.Flags{LoadBalanced: true}, // should match the RegisterTransportEndpoint
|
|
||||||
s.NICID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DNSListen return the listening address of DNS Server
|
// DnsHijack return the listening address of DNS Server
|
||||||
func (t *gvisorAdapter) DNSListen() string {
|
func (t *gvisorAdapter) DnsHijack() []string {
|
||||||
if t.dnsserver != nil {
|
dnsHijackArr := make([]string, len(t.dnsServer.udpEndpoints))
|
||||||
id := t.dnsserver.udpEndpointID
|
for _, id := range t.dnsServer.udpEndpointIDs {
|
||||||
return fmt.Sprintf("%s:%d", id.LocalAddress.String(), id.LocalPort)
|
dnsHijackArr = append(dnsHijackArr, fmt.Sprintf("%s:%d", id.LocalAddress.String(), id.LocalPort))
|
||||||
}
|
}
|
||||||
return ""
|
|
||||||
|
return dnsHijackArr
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop stop the DNS Server on tun
|
func (t *gvisorAdapter) StopDNSServer() {
|
||||||
func (t *gvisorAdapter) ReCreateDNSServer(resolver *dns.Resolver, mapper *dns.ResolverEnhancer, addr string) error {
|
t.dnsServer.Stop()
|
||||||
if addr == "" && t.dnsserver == nil {
|
log.Debugln("tun DNS server stoped")
|
||||||
return nil
|
t.dnsServer = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if addr == t.DNSListen() && t.dnsserver != nil && t.dnsserver.resolver == resolver {
|
// ReCreateDNSServer recreate the DNS Server on tun
|
||||||
return nil
|
func (t *gvisorAdapter) ReCreateDNSServer(resolver *dns.Resolver, mapper *dns.ResolverEnhancer, dnsHijackArr []string) error {
|
||||||
}
|
t.StopDNSServer()
|
||||||
|
|
||||||
if t.dnsserver != nil {
|
|
||||||
t.dnsserver.Stop()
|
|
||||||
t.dnsserver = nil
|
|
||||||
log.Debugln("tun DNS server stoped")
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
_, port, err := net.SplitHostPort(addr)
|
|
||||||
if port == "0" || port == "" || err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if resolver == nil {
|
if resolver == nil {
|
||||||
return fmt.Errorf("failed to create DNS server on tun: resolver not provided")
|
return fmt.Errorf("failed to create DNS server on tun: resolver not provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
udpAddr, err := net.ResolveUDPAddr("udp", addr)
|
if len(dnsHijackArr) == 0 {
|
||||||
|
return fmt.Errorf("failed to create DNS server on tun: len(addrs) == 0")
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
var addrs []net.Addr
|
||||||
|
for _, addr := range dnsHijackArr {
|
||||||
|
var (
|
||||||
|
addrType string
|
||||||
|
hostPort string
|
||||||
|
)
|
||||||
|
|
||||||
|
addrType, hostPort, err = Common.SplitNetworkType(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
host, port string
|
||||||
|
hasPort bool
|
||||||
|
)
|
||||||
|
|
||||||
|
host, port, hasPort, err = Common.SplitHostPort(hostPort)
|
||||||
|
if !hasPort {
|
||||||
|
port = "53"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch addrType {
|
||||||
|
case "udp", "":
|
||||||
|
{
|
||||||
|
var udpDNS *net.UDPAddr
|
||||||
|
udpDNS, err = net.ResolveUDPAddr("udp", net.JoinHostPort(host, port))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
addrs = append(addrs, udpDNS)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case "tcp":
|
||||||
|
{
|
||||||
|
var tcpDNS *net.TCPAddr
|
||||||
|
tcpDNS, err = net.ResolveTCPAddr("tcp", net.JoinHostPort(host, port))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
addrs = append(addrs, tcpDNS)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("unspported dns scheme:%s", addrType)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
server, err := CreateDNSServer(t.ipstack, resolver, mapper, addrs, nicID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
server, err := CreateDNSServer(t.ipstack, resolver, mapper, udpAddr.IP, udpAddr.Port, nicID)
|
t.dnsServer = server
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
t.dnsserver = server
|
|
||||||
log.Infoln("Tun DNS server listening at: %s, fake ip enabled: %v", addr, mapper.FakeIPEnabled())
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,9 @@ package gvisor
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/Dreamacro/clash/log"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/component/resolver"
|
"github.com/Dreamacro/clash/component/resolver"
|
||||||
@ -40,8 +43,15 @@ func (c *fakeConn) WriteBack(b []byte, addr net.Addr) (n int, err error) {
|
|||||||
localPort = uint16(udpaddr.Port)
|
localPort = uint16(udpaddr.Port)
|
||||||
}
|
}
|
||||||
|
|
||||||
r, _ := c.s.FindRoute(c.pkt.NICID, localAddress, c.id.RemoteAddress, c.pkt.NetworkProtocolNumber, false /* multicastLoop */)
|
if !c.pkt.NetworkHeader().View().IsEmpty() &&
|
||||||
return writeUDP(r, data, localPort, c.id.RemotePort)
|
(c.pkt.NetworkProtocolNumber == ipv4.ProtocolNumber ||
|
||||||
|
c.pkt.NetworkProtocolNumber == ipv6.ProtocolNumber) {
|
||||||
|
r, _ := c.s.FindRoute(c.pkt.NICID, localAddress, c.id.RemoteAddress, c.pkt.NetworkProtocolNumber, false /* multicastLoop */)
|
||||||
|
return writeUDP(r, data, localPort, c.id.RemotePort)
|
||||||
|
} else {
|
||||||
|
log.Debugln("the network protocl[%d] is not available", c.pkt.NetworkProtocolNumber)
|
||||||
|
return 0, fmt.Errorf("the network protocl[%d] is not available", c.pkt.NetworkProtocolNumber)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeConn) LocalAddr() net.Addr {
|
func (c *fakeConn) LocalAddr() net.Addr {
|
||||||
|
@ -4,6 +4,6 @@ package ipstack
|
|||||||
type TunAdapter interface {
|
type TunAdapter interface {
|
||||||
Close()
|
Close()
|
||||||
Stack() string
|
Stack() string
|
||||||
DNSListen() string
|
DnsHijack() []string
|
||||||
AutoRoute() bool
|
AutoRoute() bool
|
||||||
}
|
}
|
||||||
|
@ -17,26 +17,26 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type systemAdapter struct {
|
type systemAdapter struct {
|
||||||
device dev.TunDevice
|
device dev.TunDevice
|
||||||
tun *tun2socket.Tun2Socket
|
tun *tun2socket.Tun2Socket
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
stackName string
|
stackName string
|
||||||
dnsListen string
|
dnsHackjack []string
|
||||||
autoRoute bool
|
autoRoute bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAdapter(device dev.TunDevice, conf config.Tun, mtu int, gateway, mirror string, onStop func(), tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) (ipstack.TunAdapter, error) {
|
func NewAdapter(device dev.TunDevice, conf config.Tun, mtu int, gateway, mirror string, onStop func(), tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) (ipstack.TunAdapter, error) {
|
||||||
adapter := &systemAdapter{
|
adapter := &systemAdapter{
|
||||||
device: device,
|
device: device,
|
||||||
stackName: conf.Stack,
|
stackName: conf.Stack,
|
||||||
dnsListen: conf.DNSListen,
|
dnsHackjack: conf.DnsHijack,
|
||||||
autoRoute: conf.AutoRoute,
|
autoRoute: conf.AutoRoute,
|
||||||
}
|
}
|
||||||
|
|
||||||
adapter.lock.Lock()
|
adapter.lock.Lock()
|
||||||
defer adapter.lock.Unlock()
|
defer adapter.lock.Unlock()
|
||||||
|
|
||||||
dnsHost, dnsPort, err := net.SplitHostPort(conf.DNSListen)
|
dnsHost, dnsPort, err := net.SplitHostPort(conf.DnsHijack[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -91,8 +91,8 @@ func (t *systemAdapter) AutoRoute() bool {
|
|||||||
return t.autoRoute
|
return t.autoRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *systemAdapter) DNSListen() string {
|
func (t *systemAdapter) DnsHijack() []string {
|
||||||
return t.dnsListen
|
return t.dnsHackjack
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *systemAdapter) Close() {
|
func (t *systemAdapter) Close() {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package rules
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
@ -22,7 +22,7 @@ func HasNoResolve(params []string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func findNetwork(params []string) C.NetWork {
|
func FindNetwork(params []string) C.NetWork {
|
||||||
for _, p := range params {
|
for _, p := range params {
|
||||||
if p == "tcp" {
|
if p == "tcp" {
|
||||||
return C.TCP
|
return C.TCP
|
||||||
@ -33,7 +33,7 @@ func findNetwork(params []string) C.NetWork {
|
|||||||
return C.ALLNet
|
return C.ALLNet
|
||||||
}
|
}
|
||||||
|
|
||||||
func findSourceIPs(params []string) []*net.IPNet {
|
func FindSourceIPs(params []string) []*net.IPNet {
|
||||||
var ips []*net.IPNet
|
var ips []*net.IPNet
|
||||||
for _, p := range params {
|
for _, p := range params {
|
||||||
if p == noResolve || len(p) < 7 {
|
if p == noResolve || len(p) < 7 {
|
@ -1,4 +1,4 @@
|
|||||||
package rules
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
@ -1,4 +1,4 @@
|
|||||||
package rules
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
@ -1,4 +1,4 @@
|
|||||||
package rules
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
@ -1,4 +1,4 @@
|
|||||||
package rules
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
@ -1,4 +1,4 @@
|
|||||||
package rules
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
@ -1,4 +1,4 @@
|
|||||||
package rules
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -8,6 +8,7 @@ import (
|
|||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
|
|
||||||
|
_ "github.com/Dreamacro/clash/component/geodata/memconservative"
|
||||||
_ "github.com/Dreamacro/clash/component/geodata/standard"
|
_ "github.com/Dreamacro/clash/component/geodata/standard"
|
||||||
)
|
)
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package rules
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
53
rule/common/network_type.go
Normal file
53
rule/common/network_type.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NetworkType struct {
|
||||||
|
network C.NetWork
|
||||||
|
adapter string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNetworkType(network, adapter string) (*NetworkType, error) {
|
||||||
|
ntType := new(NetworkType)
|
||||||
|
ntType.adapter = adapter
|
||||||
|
switch strings.ToUpper(network) {
|
||||||
|
case "TCP":
|
||||||
|
ntType.network = C.TCP
|
||||||
|
break
|
||||||
|
case "UDP":
|
||||||
|
ntType.network = C.UDP
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported network type, only TCP/UDP")
|
||||||
|
}
|
||||||
|
|
||||||
|
return ntType, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkType) RuleType() C.RuleType {
|
||||||
|
return C.Network
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkType) Match(metadata *C.Metadata) bool {
|
||||||
|
return n.network == metadata.NetWork
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkType) Adapter() string {
|
||||||
|
return n.adapter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkType) Payload() string {
|
||||||
|
return n.network.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkType) ShouldResolveIP() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkType) RuleExtra() *C.RuleExtra {
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package rules
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
@ -1,4 +1,4 @@
|
|||||||
package rules
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -30,31 +30,33 @@ func (ps *Process) Match(metadata *C.Metadata) bool {
|
|||||||
// ignore match in proxy type "tproxy"
|
// ignore match in proxy type "tproxy"
|
||||||
//if metadata.Type == C.TPROXY || !C.AutoIptables {
|
//if metadata.Type == C.TPROXY || !C.AutoIptables {
|
||||||
|
|
||||||
if C.AutoIptables == "Enable" {
|
//if C.AutoIptables == "Enable" {
|
||||||
return false
|
// return false
|
||||||
}
|
//}
|
||||||
|
|
||||||
key := fmt.Sprintf("%s:%s:%s", metadata.NetWork.String(), metadata.SrcIP.String(), metadata.SrcPort)
|
key := fmt.Sprintf("%s:%s:%s", metadata.NetWork.String(), metadata.SrcIP.String(), metadata.SrcPort)
|
||||||
cached, hit := processCache.Get(key)
|
if strings.TrimSpace(metadata.Process) == "" {
|
||||||
if !hit {
|
cached, hit := processCache.Get(key)
|
||||||
srcPort, err := strconv.Atoi(metadata.SrcPort)
|
if !hit {
|
||||||
if err != nil {
|
srcPort, err := strconv.Atoi(metadata.SrcPort)
|
||||||
processCache.Set(key, "")
|
if err != nil {
|
||||||
return false
|
processCache.Set(key, "")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
name, err := process.FindProcessName(metadata.NetWork.String(), metadata.SrcIP, srcPort)
|
||||||
|
if err != nil {
|
||||||
|
log.Debugln("[Rule] find process name %s error: %s", C.Process.String(), err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
processCache.Set(key, name)
|
||||||
|
|
||||||
|
cached = name
|
||||||
}
|
}
|
||||||
|
|
||||||
name, err := process.FindProcessName(metadata.NetWork.String(), metadata.SrcIP, srcPort)
|
metadata.Process = cached.(string)
|
||||||
if err != nil {
|
|
||||||
log.Debugln("[Rule] find process name %s error: %s", C.Process.String(), err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
processCache.Set(key, name)
|
|
||||||
|
|
||||||
cached = name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata.Process = cached.(string)
|
|
||||||
|
|
||||||
return strings.EqualFold(metadata.Process, ps.process)
|
return strings.EqualFold(metadata.Process, ps.process)
|
||||||
}
|
}
|
||||||
|
|
58
rule/logic/and.go
Normal file
58
rule/logic/and.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package logic
|
||||||
|
|
||||||
|
import C "github.com/Dreamacro/clash/constant"
|
||||||
|
|
||||||
|
type AND struct {
|
||||||
|
rules []C.Rule
|
||||||
|
payload string
|
||||||
|
adapter string
|
||||||
|
needIP bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAND(payload string, adapter string) (*AND, error) {
|
||||||
|
and := &AND{payload: payload, adapter: adapter}
|
||||||
|
rules, err := parseRuleByPayload(payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
and.rules = rules
|
||||||
|
for _, rule := range rules {
|
||||||
|
if rule.ShouldResolveIP() {
|
||||||
|
and.needIP = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return and, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (A *AND) RuleType() C.RuleType {
|
||||||
|
return C.AND
|
||||||
|
}
|
||||||
|
|
||||||
|
func (A *AND) Match(metadata *C.Metadata) bool {
|
||||||
|
for _, rule := range A.rules {
|
||||||
|
if !rule.Match(metadata) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (A *AND) Adapter() string {
|
||||||
|
return A.adapter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (A *AND) Payload() string {
|
||||||
|
return A.payload
|
||||||
|
}
|
||||||
|
|
||||||
|
func (A *AND) ShouldResolveIP() bool {
|
||||||
|
return A.needIP
|
||||||
|
}
|
||||||
|
|
||||||
|
func (A *AND) RuleExtra() *C.RuleExtra {
|
||||||
|
return nil
|
||||||
|
}
|
168
rule/logic/common.go
Normal file
168
rule/logic/common.go
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
package logic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/Dreamacro/clash/common/collections"
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
RC "github.com/Dreamacro/clash/rule/common"
|
||||||
|
"github.com/Dreamacro/clash/rule/provider"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func parseRuleByPayload(payload string) ([]C.Rule, error) {
|
||||||
|
regex, err := regexp.Compile("\\(.*\\)")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if regex.MatchString(payload) {
|
||||||
|
subAllRanges, err := format(payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rules := make([]C.Rule, 0, len(subAllRanges))
|
||||||
|
|
||||||
|
subRanges := findSubRuleRange(payload, subAllRanges)
|
||||||
|
for _, subRange := range subRanges {
|
||||||
|
subPayload := payload[subRange.start+1 : subRange.end]
|
||||||
|
|
||||||
|
rule, err := payloadToRule(subPayload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rules = append(rules, rule)
|
||||||
|
}
|
||||||
|
|
||||||
|
return rules, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("payload format error")
|
||||||
|
}
|
||||||
|
|
||||||
|
func containRange(r Range, preStart, preEnd int) bool {
|
||||||
|
return preStart < r.start && preEnd > r.end
|
||||||
|
}
|
||||||
|
|
||||||
|
func payloadToRule(subPayload string) (C.Rule, error) {
|
||||||
|
splitStr := strings.SplitN(subPayload, ",", 2)
|
||||||
|
tp := splitStr[0]
|
||||||
|
payload := splitStr[1]
|
||||||
|
if tp == "NOT" || tp == "OR" || tp == "AND" {
|
||||||
|
return parseRule(tp, payload, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
param := strings.Split(payload, ",")
|
||||||
|
return parseRule(tp, param[0], param[1:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseRule(tp, payload string, params []string) (C.Rule, error) {
|
||||||
|
var (
|
||||||
|
parseErr error
|
||||||
|
parsed C.Rule
|
||||||
|
)
|
||||||
|
|
||||||
|
switch tp {
|
||||||
|
case "DOMAIN":
|
||||||
|
parsed = RC.NewDomain(payload, "", nil)
|
||||||
|
case "DOMAIN-SUFFIX":
|
||||||
|
parsed = RC.NewDomainSuffix(payload, "", nil)
|
||||||
|
case "DOMAIN-KEYWORD":
|
||||||
|
parsed = RC.NewDomainKeyword(payload, "", nil)
|
||||||
|
case "GEOSITE":
|
||||||
|
parsed, parseErr = RC.NewGEOSITE(payload, "", nil)
|
||||||
|
case "GEOIP":
|
||||||
|
noResolve := RC.HasNoResolve(params)
|
||||||
|
parsed, parseErr = RC.NewGEOIP(payload, "", noResolve, nil)
|
||||||
|
case "IP-CIDR", "IP-CIDR6":
|
||||||
|
noResolve := RC.HasNoResolve(params)
|
||||||
|
parsed, parseErr = RC.NewIPCIDR(payload, "", nil, RC.WithIPCIDRNoResolve(noResolve))
|
||||||
|
case "SRC-IP-CIDR":
|
||||||
|
parsed, parseErr = RC.NewIPCIDR(payload, "", nil, RC.WithIPCIDRSourceIP(true), RC.WithIPCIDRNoResolve(true))
|
||||||
|
case "SRC-PORT":
|
||||||
|
parsed, parseErr = RC.NewPort(payload, "", true, nil)
|
||||||
|
case "DST-PORT":
|
||||||
|
parsed, parseErr = RC.NewPort(payload, "", false, nil)
|
||||||
|
case "PROCESS-NAME":
|
||||||
|
parsed, parseErr = RC.NewProcess(payload, "", nil)
|
||||||
|
case "RULE-SET":
|
||||||
|
parsed, parseErr = provider.NewRuleSet(payload, "", nil)
|
||||||
|
case "NOT":
|
||||||
|
parsed, parseErr = NewNOT(payload, "")
|
||||||
|
case "AND":
|
||||||
|
parsed, parseErr = NewAND(payload, "")
|
||||||
|
case "OR":
|
||||||
|
parsed, parseErr = NewOR(payload, "")
|
||||||
|
case "NETWORK":
|
||||||
|
parsed, parseErr = RC.NewNetworkType(payload, "")
|
||||||
|
default:
|
||||||
|
parseErr = fmt.Errorf("unsupported rule type %s", tp)
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed, parseErr
|
||||||
|
}
|
||||||
|
|
||||||
|
type Range struct {
|
||||||
|
start int
|
||||||
|
end int
|
||||||
|
index int
|
||||||
|
}
|
||||||
|
|
||||||
|
func format(payload string) ([]Range, error) {
|
||||||
|
stack := collections.NewStack()
|
||||||
|
num := 0
|
||||||
|
subRanges := make([]Range, 0)
|
||||||
|
for i, c := range payload {
|
||||||
|
if c == '(' {
|
||||||
|
sr := Range{
|
||||||
|
start: i,
|
||||||
|
index: num,
|
||||||
|
}
|
||||||
|
|
||||||
|
num++
|
||||||
|
stack.Push(sr)
|
||||||
|
} else if c == ')' {
|
||||||
|
sr := stack.Pop().(Range)
|
||||||
|
sr.end = i
|
||||||
|
subRanges = append(subRanges, sr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if stack.Len() != 0 {
|
||||||
|
return nil, fmt.Errorf("format error is missing )")
|
||||||
|
}
|
||||||
|
|
||||||
|
sortResult := make([]Range, len(subRanges))
|
||||||
|
for _, sr := range subRanges {
|
||||||
|
sortResult[sr.index] = sr
|
||||||
|
}
|
||||||
|
|
||||||
|
return sortResult, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func findSubRuleRange(payload string, ruleRanges []Range) []Range {
|
||||||
|
payloadLen := len(payload)
|
||||||
|
subRuleRange := make([]Range, 0)
|
||||||
|
for _, rr := range ruleRanges {
|
||||||
|
if rr.start == 0 && rr.end == payloadLen-1 {
|
||||||
|
// 最大范围跳过
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
containInSub := false
|
||||||
|
for _, r := range subRuleRange {
|
||||||
|
if containRange(rr, r.start, r.end) {
|
||||||
|
// The subRuleRange contains a range of rr, which is the next level node of the tree
|
||||||
|
containInSub = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !containInSub {
|
||||||
|
subRuleRange = append(subRuleRange, rr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return subRuleRange
|
||||||
|
}
|
51
rule/logic/not.go
Normal file
51
rule/logic/not.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package logic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NOT struct {
|
||||||
|
rule C.Rule
|
||||||
|
payload string
|
||||||
|
adapter string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNOT(payload string, adapter string) (*NOT, error) {
|
||||||
|
not := &NOT{payload: payload, adapter: adapter}
|
||||||
|
rule, err := parseRuleByPayload(payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rule) < 1 {
|
||||||
|
return nil, fmt.Errorf("the parsed rule is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
not.rule = rule[0]
|
||||||
|
return not, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (not *NOT) RuleType() C.RuleType {
|
||||||
|
return C.NOT
|
||||||
|
}
|
||||||
|
|
||||||
|
func (not *NOT) Match(metadata *C.Metadata) bool {
|
||||||
|
return !not.rule.Match(metadata)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (not *NOT) Adapter() string {
|
||||||
|
return not.adapter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (not *NOT) Payload() string {
|
||||||
|
return not.payload
|
||||||
|
}
|
||||||
|
|
||||||
|
func (not *NOT) ShouldResolveIP() bool {
|
||||||
|
return not.rule.ShouldResolveIP()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (not *NOT) RuleExtra() *C.RuleExtra {
|
||||||
|
return nil
|
||||||
|
}
|
58
rule/logic/or.go
Normal file
58
rule/logic/or.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package logic
|
||||||
|
|
||||||
|
import C "github.com/Dreamacro/clash/constant"
|
||||||
|
|
||||||
|
type OR struct {
|
||||||
|
rules []C.Rule
|
||||||
|
payload string
|
||||||
|
adapter string
|
||||||
|
needIP bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (or *OR) RuleType() C.RuleType {
|
||||||
|
return C.OR
|
||||||
|
}
|
||||||
|
|
||||||
|
func (or *OR) Match(metadata *C.Metadata) bool {
|
||||||
|
for _, rule := range or.rules {
|
||||||
|
if rule.Match(metadata) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (or *OR) Adapter() string {
|
||||||
|
return or.adapter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (or *OR) Payload() string {
|
||||||
|
return or.payload
|
||||||
|
}
|
||||||
|
|
||||||
|
func (or *OR) ShouldResolveIP() bool {
|
||||||
|
return or.needIP
|
||||||
|
}
|
||||||
|
|
||||||
|
func (or *OR) RuleExtra() *C.RuleExtra {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOR(payload string, adapter string) (*OR, error) {
|
||||||
|
or := &OR{payload: payload, adapter: adapter}
|
||||||
|
rules, err := parseRuleByPayload(payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
or.rules = rules
|
||||||
|
for _, rule := range rules {
|
||||||
|
if rule.ShouldResolveIP() {
|
||||||
|
or.needIP = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return or, nil
|
||||||
|
}
|
@ -1,12 +1,11 @@
|
|||||||
package rules
|
package rule
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Dreamacro/clash/adapter/provider"
|
|
||||||
"github.com/Dreamacro/clash/common/structure"
|
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
P "github.com/Dreamacro/clash/constant/provider"
|
RC "github.com/Dreamacro/clash/rule/common"
|
||||||
"time"
|
"github.com/Dreamacro/clash/rule/logic"
|
||||||
|
RP "github.com/Dreamacro/clash/rule/provider"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParseRule(tp, payload, target string, params []string) (C.Rule, error) {
|
func ParseRule(tp, payload, target string, params []string) (C.Rule, error) {
|
||||||
@ -16,81 +15,48 @@ func ParseRule(tp, payload, target string, params []string) (C.Rule, error) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
ruleExtra := &C.RuleExtra{
|
ruleExtra := &C.RuleExtra{
|
||||||
Network: findNetwork(params),
|
Network: RC.FindNetwork(params),
|
||||||
SourceIPs: findSourceIPs(params),
|
SourceIPs: RC.FindSourceIPs(params),
|
||||||
}
|
}
|
||||||
|
|
||||||
switch tp {
|
switch tp {
|
||||||
case "DOMAIN":
|
case "DOMAIN":
|
||||||
parsed = NewDomain(payload, target, ruleExtra)
|
parsed = RC.NewDomain(payload, target, ruleExtra)
|
||||||
case "DOMAIN-SUFFIX":
|
case "DOMAIN-SUFFIX":
|
||||||
parsed = NewDomainSuffix(payload, target, ruleExtra)
|
parsed = RC.NewDomainSuffix(payload, target, ruleExtra)
|
||||||
case "DOMAIN-KEYWORD":
|
case "DOMAIN-KEYWORD":
|
||||||
parsed = NewDomainKeyword(payload, target, ruleExtra)
|
parsed = RC.NewDomainKeyword(payload, target, ruleExtra)
|
||||||
case "GEOSITE":
|
case "GEOSITE":
|
||||||
parsed, parseErr = NewGEOSITE(payload, target, ruleExtra)
|
parsed, parseErr = RC.NewGEOSITE(payload, target, ruleExtra)
|
||||||
case "GEOIP":
|
case "GEOIP":
|
||||||
noResolve := HasNoResolve(params)
|
noResolve := RC.HasNoResolve(params)
|
||||||
parsed, parseErr = NewGEOIP(payload, target, noResolve, ruleExtra)
|
parsed, parseErr = RC.NewGEOIP(payload, target, noResolve, ruleExtra)
|
||||||
case "IP-CIDR", "IP-CIDR6":
|
case "IP-CIDR", "IP-CIDR6":
|
||||||
noResolve := HasNoResolve(params)
|
noResolve := RC.HasNoResolve(params)
|
||||||
parsed, parseErr = NewIPCIDR(payload, target, ruleExtra, WithIPCIDRNoResolve(noResolve))
|
parsed, parseErr = RC.NewIPCIDR(payload, target, ruleExtra, RC.WithIPCIDRNoResolve(noResolve))
|
||||||
case "SRC-IP-CIDR":
|
case "SRC-IP-CIDR":
|
||||||
parsed, parseErr = NewIPCIDR(payload, target, ruleExtra, WithIPCIDRSourceIP(true), WithIPCIDRNoResolve(true))
|
parsed, parseErr = RC.NewIPCIDR(payload, target, ruleExtra, RC.WithIPCIDRSourceIP(true), RC.WithIPCIDRNoResolve(true))
|
||||||
case "SRC-PORT":
|
case "SRC-PORT":
|
||||||
parsed, parseErr = NewPort(payload, target, true, ruleExtra)
|
parsed, parseErr = RC.NewPort(payload, target, true, ruleExtra)
|
||||||
case "DST-PORT":
|
case "DST-PORT":
|
||||||
parsed, parseErr = NewPort(payload, target, false, ruleExtra)
|
parsed, parseErr = RC.NewPort(payload, target, false, ruleExtra)
|
||||||
case "PROCESS-NAME":
|
case "PROCESS-NAME":
|
||||||
parsed, parseErr = NewProcess(payload, target, ruleExtra)
|
parsed, parseErr = RC.NewProcess(payload, target, ruleExtra)
|
||||||
case "MATCH":
|
case "MATCH":
|
||||||
parsed = NewMatch(target, ruleExtra)
|
parsed = RC.NewMatch(target, ruleExtra)
|
||||||
case "RULE-SET":
|
case "RULE-SET":
|
||||||
parsed, parseErr = NewRuleSet(payload, target, ruleExtra)
|
parsed, parseErr = RP.NewRuleSet(payload, target, ruleExtra)
|
||||||
|
case "NETWORK":
|
||||||
|
parsed, parseErr = RC.NewNetworkType(payload, target)
|
||||||
|
case "AND":
|
||||||
|
parsed, parseErr = logic.NewAND(payload, target)
|
||||||
|
case "OR":
|
||||||
|
parsed, parseErr = logic.NewOR(payload, target)
|
||||||
|
case "NOT":
|
||||||
|
parsed, parseErr = logic.NewNOT(payload, target)
|
||||||
default:
|
default:
|
||||||
parseErr = fmt.Errorf("unsupported rule type %s", tp)
|
parseErr = fmt.Errorf("unsupported rule type %s", tp)
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsed, parseErr
|
return parsed, parseErr
|
||||||
}
|
}
|
||||||
|
|
||||||
type ruleProviderSchema struct {
|
|
||||||
Type string `provider:"type"`
|
|
||||||
Behavior string `provider:"behavior"`
|
|
||||||
Path string `provider:"path"`
|
|
||||||
URL string `provider:"url,omitempty"`
|
|
||||||
Interval int `provider:"interval,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseRuleProvider(name string, mapping map[string]interface{}) (P.RuleProvider, error) {
|
|
||||||
schema := &ruleProviderSchema{}
|
|
||||||
decoder := structure.NewDecoder(structure.Option{TagName: "provider", WeaklyTypedInput: true})
|
|
||||||
if err := decoder.Decode(mapping, schema); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var behavior P.RuleType
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
path := C.Path.Resolve(schema.Path)
|
|
||||||
var vehicle P.Vehicle
|
|
||||||
switch schema.Type {
|
|
||||||
case "file":
|
|
||||||
vehicle = provider.NewFileVehicle(path)
|
|
||||||
case "http":
|
|
||||||
vehicle = provider.NewHTTPVehicle(schema.URL, path)
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unsupported vehicle type: %s", schema.Type)
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewRuleSetProvider(name, behavior, time.Duration(uint(schema.Interval))*time.Second, vehicle), nil
|
|
||||||
}
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package rules
|
package provider
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
90
rule/provider/parse.go
Normal file
90
rule/provider/parse.go
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
package provider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/Dreamacro/clash/adapter/provider"
|
||||||
|
"github.com/Dreamacro/clash/common/structure"
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
P "github.com/Dreamacro/clash/constant/provider"
|
||||||
|
RC "github.com/Dreamacro/clash/rule/common"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ruleProviderSchema struct {
|
||||||
|
Type string `provider:"type"`
|
||||||
|
Behavior string `provider:"behavior"`
|
||||||
|
Path string `provider:"path"`
|
||||||
|
URL string `provider:"url,omitempty"`
|
||||||
|
Interval int `provider:"interval,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseRuleProvider(name string, mapping map[string]interface{}) (P.RuleProvider, error) {
|
||||||
|
schema := &ruleProviderSchema{}
|
||||||
|
decoder := structure.NewDecoder(structure.Option{TagName: "provider", WeaklyTypedInput: true})
|
||||||
|
if err := decoder.Decode(mapping, schema); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var behavior P.RuleType
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
path := C.Path.Resolve(schema.Path)
|
||||||
|
var vehicle P.Vehicle
|
||||||
|
switch schema.Type {
|
||||||
|
case "file":
|
||||||
|
vehicle = provider.NewFileVehicle(path)
|
||||||
|
case "http":
|
||||||
|
vehicle = provider.NewHTTPVehicle(schema.URL, path)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported vehicle type: %s", schema.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewRuleSetProvider(name, behavior, time.Duration(uint(schema.Interval))*time.Second, vehicle), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseRule(tp, payload, target string, params []string) (C.Rule, error) {
|
||||||
|
var (
|
||||||
|
parseErr error
|
||||||
|
parsed C.Rule
|
||||||
|
)
|
||||||
|
|
||||||
|
ruleExtra := &C.RuleExtra{
|
||||||
|
Network: RC.FindNetwork(params),
|
||||||
|
SourceIPs: RC.FindSourceIPs(params),
|
||||||
|
}
|
||||||
|
|
||||||
|
switch tp {
|
||||||
|
case "DOMAIN":
|
||||||
|
parsed = RC.NewDomain(payload, target, ruleExtra)
|
||||||
|
case "DOMAIN-SUFFIX":
|
||||||
|
parsed = RC.NewDomainSuffix(payload, target, ruleExtra)
|
||||||
|
case "DOMAIN-KEYWORD":
|
||||||
|
parsed = RC.NewDomainKeyword(payload, target, ruleExtra)
|
||||||
|
case "GEOSITE":
|
||||||
|
parsed, parseErr = RC.NewGEOSITE(payload, target, ruleExtra)
|
||||||
|
case "IP-CIDR", "IP-CIDR6":
|
||||||
|
noResolve := RC.HasNoResolve(params)
|
||||||
|
parsed, parseErr = RC.NewIPCIDR(payload, target, ruleExtra, RC.WithIPCIDRNoResolve(noResolve))
|
||||||
|
case "SRC-IP-CIDR":
|
||||||
|
parsed, parseErr = RC.NewIPCIDR(payload, target, ruleExtra, RC.WithIPCIDRSourceIP(true), RC.WithIPCIDRNoResolve(true))
|
||||||
|
case "SRC-PORT":
|
||||||
|
parsed, parseErr = RC.NewPort(payload, target, true, ruleExtra)
|
||||||
|
case "DST-PORT":
|
||||||
|
parsed, parseErr = RC.NewPort(payload, target, false, ruleExtra)
|
||||||
|
case "PROCESS-NAME":
|
||||||
|
parsed, parseErr = RC.NewProcess(payload, target, ruleExtra)
|
||||||
|
default:
|
||||||
|
parseErr = fmt.Errorf("unsupported rule type %s", tp)
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed, parseErr
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package rules
|
package provider
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -75,11 +75,15 @@ func (rp *ruleSetProvider) Behavior() P.RuleType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (rp *ruleSetProvider) Match(metadata *C.Metadata) bool {
|
func (rp *ruleSetProvider) Match(metadata *C.Metadata) bool {
|
||||||
|
if rp.count == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
switch rp.behavior {
|
switch rp.behavior {
|
||||||
case P.Domain:
|
case P.Domain:
|
||||||
return rp.DomainRules.Search(metadata.Host) != nil
|
return rp.DomainRules != nil && rp.DomainRules.Search(metadata.Host) != nil
|
||||||
case P.IPCIDR:
|
case P.IPCIDR:
|
||||||
return rp.IPCIDRRules.IsContain(metadata.DstIP)
|
return rp.IPCIDRRules != nil && rp.IPCIDRRules.IsContain(metadata.DstIP)
|
||||||
case P.Classical:
|
case P.Classical:
|
||||||
for _, rule := range rp.ClassicalRules {
|
for _, rule := range rp.ClassicalRules {
|
||||||
if rule.Match(metadata) {
|
if rule.Match(metadata) {
|
||||||
@ -201,7 +205,7 @@ func handleClassicalRules(rules []string) (interface{}, error) {
|
|||||||
return nil, errors.New("error rule type")
|
return nil, errors.New("error rule type")
|
||||||
}
|
}
|
||||||
|
|
||||||
r, err := ParseRule(ruleType, rule, "", params)
|
r, err := parseRule(ruleType, rule, "", params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package rules
|
package provider
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
@ -32,7 +32,7 @@ const (
|
|||||||
ImageVmess = "v2fly/v2fly-core:latest"
|
ImageVmess = "v2fly/v2fly-core:latest"
|
||||||
ImageTrojan = "trojangfw/trojan:latest"
|
ImageTrojan = "trojangfw/trojan:latest"
|
||||||
ImageTrojanGo = "p4gefau1t/trojan-go:latest"
|
ImageTrojanGo = "p4gefau1t/trojan-go:latest"
|
||||||
ImageSnell = "icpz/snell-server:latest"
|
ImageSnell = "ghcr.io/icpz/snell-server:latest"
|
||||||
ImageXray = "teddysun/xray:latest"
|
ImageXray = "teddysun/xray:latest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -120,6 +120,42 @@ func TestClash_Snell(t *testing.T) {
|
|||||||
testSuit(t, proxy)
|
testSuit(t, proxy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestClash_Snellv3(t *testing.T) {
|
||||||
|
cfg := &container.Config{
|
||||||
|
Image: ImageSnell,
|
||||||
|
ExposedPorts: defaultExposedPorts,
|
||||||
|
Cmd: []string{"-c", "/config.conf"},
|
||||||
|
}
|
||||||
|
hostCfg := &container.HostConfig{
|
||||||
|
PortBindings: defaultPortBindings,
|
||||||
|
Binds: []string{fmt.Sprintf("%s:/config.conf", C.Path.Resolve("snell.conf"))},
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := startContainer(cfg, hostCfg, "snell")
|
||||||
|
if err != nil {
|
||||||
|
assert.FailNow(t, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
cleanContainer(id)
|
||||||
|
})
|
||||||
|
|
||||||
|
proxy, err := outbound.NewSnell(outbound.SnellOption{
|
||||||
|
Name: "snell",
|
||||||
|
Server: localIP.String(),
|
||||||
|
Port: 10002,
|
||||||
|
Psk: "password",
|
||||||
|
UDP: true,
|
||||||
|
Version: 3,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
assert.FailNow(t, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(waitTime)
|
||||||
|
testSuit(t, proxy)
|
||||||
|
}
|
||||||
|
|
||||||
func Benchmark_Snell(b *testing.B) {
|
func Benchmark_Snell(b *testing.B) {
|
||||||
cfg := &container.Config{
|
cfg := &container.Config{
|
||||||
Image: ImageSnell,
|
Image: ImageSnell,
|
||||||
|
@ -5,6 +5,7 @@ package gun
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
@ -17,6 +18,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/pool"
|
"github.com/Dreamacro/clash/common/pool"
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
|
||||||
"go.uber.org/atomic"
|
"go.uber.org/atomic"
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
@ -173,7 +175,11 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config) *http2.Transport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cn := tls.Client(pconn, cfg)
|
cn := tls.Client(pconn, cfg)
|
||||||
if err := cn.Handshake(); err != nil {
|
|
||||||
|
// fix tls handshake not timeout
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout)
|
||||||
|
defer cancel()
|
||||||
|
if err := cn.HandshakeContext(ctx); err != nil {
|
||||||
pconn.Close()
|
pconn.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/pool"
|
"github.com/Dreamacro/clash/common/pool"
|
||||||
|
"github.com/Dreamacro/clash/transport/socks5"
|
||||||
|
|
||||||
"github.com/Dreamacro/go-shadowsocks2/shadowaead"
|
"github.com/Dreamacro/go-shadowsocks2/shadowaead"
|
||||||
)
|
)
|
||||||
@ -15,13 +17,19 @@ import (
|
|||||||
const (
|
const (
|
||||||
Version1 = 1
|
Version1 = 1
|
||||||
Version2 = 2
|
Version2 = 2
|
||||||
|
Version3 = 3
|
||||||
DefaultSnellVersion = Version1
|
DefaultSnellVersion = Version1
|
||||||
|
|
||||||
|
// max packet length
|
||||||
|
maxLength = 0x3FFF
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
CommandPing byte = 0
|
CommandPing byte = 0
|
||||||
CommandConnect byte = 1
|
CommandConnect byte = 1
|
||||||
CommandConnectV2 byte = 5
|
CommandConnectV2 byte = 5
|
||||||
|
CommandUDP byte = 6
|
||||||
|
CommondUDPForward byte = 1
|
||||||
|
|
||||||
CommandTunnel byte = 0
|
CommandTunnel byte = 0
|
||||||
CommandPong byte = 1
|
CommandPong byte = 1
|
||||||
@ -100,6 +108,16 @@ func WriteHeader(conn net.Conn, host string, port uint, version int) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WriteUDPHeader(conn net.Conn, version int) error {
|
||||||
|
if version < Version3 {
|
||||||
|
return errors.New("unsupport UDP version")
|
||||||
|
}
|
||||||
|
|
||||||
|
// version, command, clientID length
|
||||||
|
_, err := conn.Write([]byte{Version, CommandUDP, 0x00})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// HalfClose works only on version2
|
// HalfClose works only on version2
|
||||||
func HalfClose(conn net.Conn) error {
|
func HalfClose(conn net.Conn) error {
|
||||||
if _, err := conn.Write(endSignal); err != nil {
|
if _, err := conn.Write(endSignal); err != nil {
|
||||||
@ -114,10 +132,147 @@ func HalfClose(conn net.Conn) error {
|
|||||||
|
|
||||||
func StreamConn(conn net.Conn, psk []byte, version int) *Snell {
|
func StreamConn(conn net.Conn, psk []byte, version int) *Snell {
|
||||||
var cipher shadowaead.Cipher
|
var cipher shadowaead.Cipher
|
||||||
if version == Version2 {
|
if version != Version1 {
|
||||||
cipher = NewAES128GCM(psk)
|
cipher = NewAES128GCM(psk)
|
||||||
} else {
|
} else {
|
||||||
cipher = NewChacha20Poly1305(psk)
|
cipher = NewChacha20Poly1305(psk)
|
||||||
}
|
}
|
||||||
return &Snell{Conn: shadowaead.NewConn(conn, cipher)}
|
return &Snell{Conn: shadowaead.NewConn(conn, cipher)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PacketConn(conn net.Conn) net.PacketConn {
|
||||||
|
return &packetConn{
|
||||||
|
Conn: conn,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func writePacket(w io.Writer, socks5Addr, payload []byte) (int, error) {
|
||||||
|
buf := pool.GetBuffer()
|
||||||
|
defer pool.PutBuffer(buf)
|
||||||
|
|
||||||
|
// compose snell UDP address format (refer: icpz/snell-server-reversed)
|
||||||
|
// a brand new wheel to replace socks5 address format, well done Yachen
|
||||||
|
buf.WriteByte(CommondUDPForward)
|
||||||
|
switch socks5Addr[0] {
|
||||||
|
case socks5.AtypDomainName:
|
||||||
|
hostLen := socks5Addr[1]
|
||||||
|
buf.Write(socks5Addr[1 : 1+1+hostLen+2])
|
||||||
|
case socks5.AtypIPv4:
|
||||||
|
buf.Write([]byte{0x00, 0x04})
|
||||||
|
buf.Write(socks5Addr[1 : 1+net.IPv4len+2])
|
||||||
|
case socks5.AtypIPv6:
|
||||||
|
buf.Write([]byte{0x00, 0x06})
|
||||||
|
buf.Write(socks5Addr[1 : 1+net.IPv6len+2])
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.Write(payload)
|
||||||
|
_, err := w.Write(buf.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return len(payload), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func WritePacket(w io.Writer, socks5Addr, payload []byte) (int, error) {
|
||||||
|
if len(payload) <= maxLength {
|
||||||
|
return writePacket(w, socks5Addr, payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
offset := 0
|
||||||
|
total := len(payload)
|
||||||
|
for {
|
||||||
|
cursor := offset + maxLength
|
||||||
|
if cursor > total {
|
||||||
|
cursor = total
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err := writePacket(w, socks5Addr, payload[offset:cursor])
|
||||||
|
if err != nil {
|
||||||
|
return offset + n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = cursor
|
||||||
|
if offset == total {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return total, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadPacket(r io.Reader, payload []byte) (net.Addr, int, error) {
|
||||||
|
buf := pool.Get(pool.UDPBufferSize)
|
||||||
|
defer pool.Put(buf)
|
||||||
|
|
||||||
|
n, err := r.Read(buf)
|
||||||
|
headLen := 1
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
if n < headLen {
|
||||||
|
return nil, 0, errors.New("insufficient UDP length")
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse snell UDP response address format
|
||||||
|
switch buf[0] {
|
||||||
|
case 0x04:
|
||||||
|
headLen += net.IPv4len + 2
|
||||||
|
if n < headLen {
|
||||||
|
err = errors.New("insufficient UDP length")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
buf[0] = socks5.AtypIPv4
|
||||||
|
case 0x06:
|
||||||
|
headLen += net.IPv6len + 2
|
||||||
|
if n < headLen {
|
||||||
|
err = errors.New("insufficient UDP length")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
buf[0] = socks5.AtypIPv6
|
||||||
|
default:
|
||||||
|
err = errors.New("ip version invalid")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
addr := socks5.SplitAddr(buf[0:])
|
||||||
|
if addr == nil {
|
||||||
|
return nil, 0, errors.New("remote address invalid")
|
||||||
|
}
|
||||||
|
uAddr := addr.UDPAddr()
|
||||||
|
|
||||||
|
length := len(payload)
|
||||||
|
if n-headLen < length {
|
||||||
|
length = n - headLen
|
||||||
|
}
|
||||||
|
copy(payload[:], buf[headLen:headLen+length])
|
||||||
|
|
||||||
|
return uAddr, length, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type packetConn struct {
|
||||||
|
net.Conn
|
||||||
|
rMux sync.Mutex
|
||||||
|
wMux sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pc *packetConn) WriteTo(b []byte, addr net.Addr) (int, error) {
|
||||||
|
pc.wMux.Lock()
|
||||||
|
defer pc.wMux.Unlock()
|
||||||
|
|
||||||
|
return WritePacket(pc, socks5.ParseAddr(addr.String()), b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pc *packetConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
||||||
|
pc.rMux.Lock()
|
||||||
|
defer pc.rMux.Unlock()
|
||||||
|
|
||||||
|
addr, n, err := ReadPacket(pc.Conn, b)
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return n, addr, nil
|
||||||
|
}
|
||||||
|
@ -1,17 +1,20 @@
|
|||||||
package trojan
|
package trojan
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
|
xtls "github.com/xtls/go"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/pool"
|
"github.com/Dreamacro/clash/common/pool"
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/transport/socks5"
|
"github.com/Dreamacro/clash/transport/socks5"
|
||||||
"github.com/Dreamacro/clash/transport/vmess"
|
"github.com/Dreamacro/clash/transport/vmess"
|
||||||
)
|
)
|
||||||
@ -19,6 +22,9 @@ import (
|
|||||||
const (
|
const (
|
||||||
// max packet length
|
// max packet length
|
||||||
maxLength = 8192
|
maxLength = 8192
|
||||||
|
|
||||||
|
XRD = "xtls-rprx-direct"
|
||||||
|
XRO = "xtls-rprx-origin"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -33,13 +39,18 @@ type Command = byte
|
|||||||
var (
|
var (
|
||||||
CommandTCP byte = 1
|
CommandTCP byte = 1
|
||||||
CommandUDP byte = 3
|
CommandUDP byte = 3
|
||||||
|
CommandXRD byte = 0xf0
|
||||||
|
CommandXRO byte = 0xf1
|
||||||
)
|
)
|
||||||
|
|
||||||
type Option struct {
|
type Option struct {
|
||||||
Password string
|
Password string
|
||||||
ALPN []string
|
Flow string
|
||||||
ServerName string
|
ALPN []string
|
||||||
SkipCertVerify bool
|
ServerName string
|
||||||
|
SkipCertVerify bool
|
||||||
|
ClientSessionCache tls.ClientSessionCache
|
||||||
|
ClientXSessionCache xtls.ClientSessionCache
|
||||||
}
|
}
|
||||||
|
|
||||||
type WebsocketOption struct {
|
type WebsocketOption struct {
|
||||||
@ -54,25 +65,54 @@ type Trojan struct {
|
|||||||
hexPassword []byte
|
hexPassword []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Trojan) GetFlow() string {
|
||||||
|
return t.option.Flow
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Trojan) StreamConn(conn net.Conn) (net.Conn, error) {
|
func (t *Trojan) StreamConn(conn net.Conn) (net.Conn, error) {
|
||||||
alpn := defaultALPN
|
alpn := defaultALPN
|
||||||
if len(t.option.ALPN) != 0 {
|
if len(t.option.ALPN) != 0 {
|
||||||
alpn = t.option.ALPN
|
alpn = t.option.ALPN
|
||||||
}
|
}
|
||||||
|
switch t.option.Flow {
|
||||||
tlsConfig := &tls.Config{
|
case XRD, XRO:
|
||||||
NextProtos: alpn,
|
xtlsConfig := &xtls.Config{
|
||||||
MinVersion: tls.VersionTLS12,
|
NextProtos: alpn,
|
||||||
InsecureSkipVerify: t.option.SkipCertVerify,
|
MinVersion: xtls.VersionTLS12,
|
||||||
ServerName: t.option.ServerName,
|
InsecureSkipVerify: t.option.SkipCertVerify,
|
||||||
|
ServerName: t.option.ServerName,
|
||||||
|
ClientSessionCache: t.option.ClientXSessionCache,
|
||||||
|
}
|
||||||
|
xtlsConn := xtls.Client(conn, xtlsConfig)
|
||||||
|
if err := xtlsConn.Handshake(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout)
|
||||||
|
defer cancel()
|
||||||
|
if err := xtlsConn.HandshakeContext(ctx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return xtlsConn, nil
|
||||||
|
default:
|
||||||
|
tlsConfig := &tls.Config{
|
||||||
|
NextProtos: alpn,
|
||||||
|
MinVersion: tls.VersionTLS12,
|
||||||
|
InsecureSkipVerify: t.option.SkipCertVerify,
|
||||||
|
ServerName: t.option.ServerName,
|
||||||
|
ClientSessionCache: t.option.ClientSessionCache,
|
||||||
|
}
|
||||||
|
tlsConn := tls.Client(conn, tlsConfig)
|
||||||
|
if err := tlsConn.Handshake(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// fix tls handshake not timeout
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout)
|
||||||
|
defer cancel()
|
||||||
|
if err := tlsConn.HandshakeContext(ctx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return tlsConn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsConn := tls.Client(conn, tlsConfig)
|
|
||||||
if err := tlsConn.Handshake(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return tlsConn, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Trojan) StreamWebsocketConn(conn net.Conn, wsOptions *WebsocketOption) (net.Conn, error) {
|
func (t *Trojan) StreamWebsocketConn(conn net.Conn, wsOptions *WebsocketOption) (net.Conn, error) {
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
package vmess
|
package vmess
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TLSConfig struct {
|
type TLSConfig struct {
|
||||||
@ -19,6 +22,10 @@ func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tlsConn := tls.Client(conn, tlsConfig)
|
tlsConn := tls.Client(conn, tlsConfig)
|
||||||
err := tlsConn.Handshake()
|
|
||||||
|
// fix tls handshake not timeout
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout)
|
||||||
|
defer cancel()
|
||||||
|
err := tlsConn.HandshakeContext(ctx)
|
||||||
return tlsConn, err
|
return tlsConn, err
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package tunnel
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
R "github.com/Dreamacro/clash/rule/common"
|
||||||
"net"
|
"net"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
@ -15,7 +16,6 @@ import (
|
|||||||
"github.com/Dreamacro/clash/constant/provider"
|
"github.com/Dreamacro/clash/constant/provider"
|
||||||
icontext "github.com/Dreamacro/clash/context"
|
icontext "github.com/Dreamacro/clash/context"
|
||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
R "github.com/Dreamacro/clash/rule"
|
|
||||||
"github.com/Dreamacro/clash/tunnel/statistic"
|
"github.com/Dreamacro/clash/tunnel/statistic"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -158,7 +158,7 @@ func preHandleMetadata(metadata *C.Metadata) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolveMetadata(ctx C.PlainContext, metadata *C.Metadata) (proxy C.Proxy, rule C.Rule, err error) {
|
func resolveMetadata(metadata *C.Metadata) (proxy C.Proxy, rule C.Rule, err error) {
|
||||||
switch mode {
|
switch mode {
|
||||||
case Direct:
|
case Direct:
|
||||||
proxy = proxies["DIRECT"]
|
proxy = proxies["DIRECT"]
|
||||||
@ -222,7 +222,7 @@ func handleUDPConn(packet *inbound.PacketAdapter) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
pCtx := icontext.NewPacketConnContext(metadata)
|
pCtx := icontext.NewPacketConnContext(metadata)
|
||||||
proxy, rule, err := resolveMetadata(pCtx, metadata)
|
proxy, rule, err := resolveMetadata(metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnln("[UDP] Parse metadata failed: %s", err.Error())
|
log.Warnln("[UDP] Parse metadata failed: %s", err.Error())
|
||||||
return
|
return
|
||||||
@ -244,15 +244,19 @@ func handleUDPConn(packet *inbound.PacketAdapter) {
|
|||||||
|
|
||||||
switch true {
|
switch true {
|
||||||
case rule != nil:
|
case rule != nil:
|
||||||
log.Infoln("[UDP] %s(%s) --> %s match %s(%s) using %s", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress(), rule.RuleType().String(), rule.Payload(), rawPc.Chains().String())
|
if rule.Payload() != "" {
|
||||||
|
log.Infoln("[UDP] %s --> %s match %s using %s", metadata.SourceDetail(), metadata.RemoteAddress(), fmt.Sprintf("%s(%s)", rule.RuleType().String(), rule.Payload()), rawPc.Chains().String())
|
||||||
|
} else {
|
||||||
|
log.Infoln("[UDP] %s --> %s match %s using %s", metadata.SourceDetail(), metadata.RemoteAddress(), rule.Payload(), rawPc.Chains().String())
|
||||||
|
}
|
||||||
case mode == Script:
|
case mode == Script:
|
||||||
log.Infoln("[UDP] %s --> %s using SCRIPT %s", metadata.SourceAddress(), metadata.RemoteAddress(), rawPc.Chains().String())
|
log.Infoln("[UDP] %s --> %s using SCRIPT %s", metadata.SourceDetail(), metadata.RemoteAddress(), rawPc.Chains().String())
|
||||||
case mode == Global:
|
case mode == Global:
|
||||||
log.Infoln("[UDP] %s(%s) --> %s using GLOBAL", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress())
|
log.Infoln("[UDP] %s --> %s using GLOBAL", metadata.SourceDetail(), metadata.RemoteAddress())
|
||||||
case mode == Direct:
|
case mode == Direct:
|
||||||
log.Infoln("[UDP] %s(%s) --> %s using DIRECT", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress())
|
log.Infoln("[UDP] %s --> %s using DIRECT", metadata.SourceDetail(), metadata.RemoteAddress())
|
||||||
default:
|
default:
|
||||||
log.Infoln("[UDP] %s(%s) --> %s doesn't match any rule using DIRECT", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress())
|
log.Infoln("[UDP] %s --> %s doesn't match any rule using DIRECT", metadata.SourceDetail(), metadata.RemoteAddress())
|
||||||
}
|
}
|
||||||
|
|
||||||
go handleUDPToLocal(packet.UDPPacket, pc, key, fAddr)
|
go handleUDPToLocal(packet.UDPPacket, pc, key, fAddr)
|
||||||
@ -276,7 +280,7 @@ func handleTCPConn(connCtx C.ConnContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
proxy, rule, err := resolveMetadata(connCtx, metadata)
|
proxy, rule, err := resolveMetadata(metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnln("[Metadata] parse failed: %s", err.Error())
|
log.Warnln("[Metadata] parse failed: %s", err.Error())
|
||||||
return
|
return
|
||||||
@ -298,15 +302,19 @@ func handleTCPConn(connCtx C.ConnContext) {
|
|||||||
|
|
||||||
switch true {
|
switch true {
|
||||||
case rule != nil:
|
case rule != nil:
|
||||||
log.Infoln("[TCP] %s(%s) --> %s match %s(%s) using %s", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress(), rule.RuleType().String(), rule.Payload(), remoteConn.Chains().String())
|
if rule.Payload() != "" {
|
||||||
|
log.Infoln("[TCP] %s --> %s match %s using %s", metadata.SourceDetail(), metadata.RemoteAddress(), fmt.Sprintf("%s(%s)", rule.RuleType().String(), rule.Payload()), remoteConn.Chains().String())
|
||||||
|
} else {
|
||||||
|
log.Infoln("[TCP] %s --> %s match %s using %s", metadata.SourceDetail(), metadata.RemoteAddress(), rule.RuleType().String(), remoteConn.Chains().String())
|
||||||
|
}
|
||||||
case mode == Script:
|
case mode == Script:
|
||||||
log.Infoln("[TCP] %s(%s) --> %s using SCRIPT %s", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress(), remoteConn.Chains().String())
|
log.Infoln("[TCP] %s --> %s using SCRIPT %s", metadata.SourceDetail(), metadata.RemoteAddress(), remoteConn.Chains().String())
|
||||||
case mode == Global:
|
case mode == Global:
|
||||||
log.Infoln("[TCP] %s(%s) --> %s using GLOBAL", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress())
|
log.Infoln("[TCP] %s --> %s using GLOBAL", metadata.SourceDetail(), metadata.RemoteAddress())
|
||||||
case mode == Direct:
|
case mode == Direct:
|
||||||
log.Infoln("[TCP] %s(%s) --> %s using DIRECT", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress())
|
log.Infoln("[TCP] %s --> %s using DIRECT", metadata.SourceDetail(), metadata.RemoteAddress())
|
||||||
default:
|
default:
|
||||||
log.Infoln("[TCP] %s(%s) --> %s doesn't match any rule using DIRECT", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress())
|
log.Infoln("[TCP] %s --> %s doesn't match any rule using DIRECT", metadata.SourceAddress(), metadata.RemoteAddress())
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSocket(connCtx, remoteConn)
|
handleSocket(connCtx, remoteConn)
|
||||||
|
Reference in New Issue
Block a user