Compare commits

...

91 Commits

Author SHA1 Message Date
2f6f9ebc2e Merge branch 'Dev' into Meta
# Conflicts:
#	config/config.go
2022-02-05 19:30:12 +08:00
90e6ed4612 [Fixed] Fixed clash process name is Clash.Meta 2022-02-04 17:38:06 +08:00
ae5a790510 [Fixed] Abnormal rule when host is ip addr 2022-02-04 17:38:06 +08:00
a732e1a603 Merge remote-tracking branch 'clash/dev' into Dev 2022-02-04 02:40:15 +08:00
b1a639feae Fix: domain trie search 2022-01-26 22:28:13 +08:00
76dccebbf6 github action build config 2022-01-26 21:35:18 +08:00
cd5b735973 [Refactor] logic rule parse 2022-01-26 21:34:49 +08:00
a5ce62db33 Merge branch 'clash-dev' into Dev 2022-01-25 15:05:24 +08:00
2f8e575308 [Fixed] modified RULE-SET supported rule 2022-01-23 18:35:48 +08:00
62b70725ef [Fixed] GEOSITE rule load fail 2022-01-23 18:27:44 +08:00
8595d6c2e9 [Feature]
1.Add Network rule, match network type(TCP/UDP)
2.Add logic rules(NOT,OR,AND)
-AND,((DOMAIN,baidu.com),(NETWORK,UDP)),REJECT

(cherry picked from commit d7092e2e37f2c48282c878edea1b2ebc2912b09a)
2022-01-22 22:37:07 +08:00
03b956b7a3 [Fixed] auto-route support use ip route 2022-01-22 13:24:31 +08:00
e5c99cbee7 modify gitignore 2022-01-21 22:39:00 +08:00
58a47e1835 [Style] clear unless notes 2022-01-21 22:38:28 +08:00
daf83eb6f7 [Fixed] select group crash 2022-01-21 22:38:02 +08:00
bb68b59c9a Merge pull request #7 from CHIZI-0618/DnsHijack
Fix DnsHijack default value bug.
2022-01-21 18:27:26 +08:00
c3cfa3d6cd Fix DnsHijack default value bug. 2022-01-21 18:11:21 +08:00
b15344ec78 [Refactor]
1.allow maybe empty group
2.use COMPATIBLE(DIRECT alias) when proxy group is empty
3.http provider pass through tunnel
2022-01-18 21:09:36 +08:00
cfe7354c07 Improve: change provider file modify time when updated (#1918) 2022-01-18 13:32:47 +08:00
9732efe938 Fix: tls handshake requires a timeout (#1893) 2022-01-15 19:33:21 +08:00
ee6c1871a9 [Refactor] lazy loading geosite.bat 2022-01-11 22:17:24 +08:00
8f3385bbb6 Feature: support snell v3 (#1884) 2022-01-10 20:24:20 +08:00
00e44cd141 [Style] Modify the default configuration, tun config delete default hijack dns and modify auto-route to false. modify NameServer to 223.5.5.5 and 119.29.29.29 by Skyxim 2022-01-09 00:36:05 +08:00
4ab986cccb [Refactor] gvisor support hijack dns list
dns-hijack:
 - 1.1.1.1
 - 8.8.8.8:53
 - tcp://1.1.1.1:53
 - udp://223.5.5.5
 - 10.0.0.1:5353
2022-01-09 00:35:45 +08:00
64869d0f17 [Fixed] Remove the Linux automatic routing configuration Change the name of the Linux network card to utun 2022-01-08 16:57:59 +08:00
7f0368da66 [Style] Adjust delete routes on macos 2022-01-08 16:55:02 +08:00
4f1b227ca2 [Style] Positive health check 2022-01-08 09:23:49 +08:00
16abba385a [Style] Adjust the routing table of tun on mac 2022-01-07 22:40:05 +08:00
75b5f633cd [Fixed] Positive health check multithreading is not safe 2022-01-07 12:58:40 +08:00
8ae68552a6 [Fixed] Stupid mistakes 2022-01-06 10:49:50 +08:00
d35d6c9ac9 [Fixed] Stupid mistakes 2022-01-06 10:49:26 +08:00
a832cfdb65 [Fixed] compatible cfw 2022-01-05 19:28:54 +08:00
951a5a0eb5 [update]readme 2022-01-05 18:45:32 +08:00
89609cc4a2 [update]readme 2022-01-05 17:04:56 +08:00
bfb976bbdc [test]Add name filter to proxy group 2022-01-05 12:19:49 +08:00
d237b041b3 Fix: ignore empty dns server error 2022-01-05 11:41:31 +08:00
a15d2535f1 升级版本号 2022-01-05 11:41:17 +08:00
610c79570a make tun config compatible with premium 2022-01-05 11:24:00 +08:00
051c81518c make tun config compatible with premium 2022-01-05 01:56:35 +08:00
0209efd423 Revert "make tun config compatible with premium"
This reverts commit ba6fdd2962.
2022-01-05 01:56:05 +08:00
ba6fdd2962 make tun config compatible with premium 2022-01-05 01:50:43 +08:00
9475799615 make tun config compatible with premium 2022-01-05 00:33:42 +08:00
14917c8af1 merge clash 1.9.0 2022-01-04 17:58:50 +08:00
3bb32d12e0 Merge remote-tracking branch 'clash/dev' into Meta
# Conflicts:
#	.github/workflows/docker.yml
#	dns/server.go
#	go.mod
#	go.sum
#	hub/executor/executor.go
#	test/go.mod
#	test/go.sum
2022-01-04 17:31:07 +08:00
3cb87e083c Fix: duplicate provider err typo 2022-01-03 17:21:27 +08:00
8c6d0c6757 Chore: fix docker dependencies security warning 2022-01-02 11:15:40 +08:00
cb95326aca Chore: update dependencies 2022-01-02 01:15:49 +08:00
8679968ab0 Fix: multiple port string parsing overflow (#1868)
Ports in TCP and UDP should be parsed as an unsigned integer,
otherwise ports > 32767 get truncated to 32767. As this is
the case with Metadata.UDPAddr(), this fundamentally breaks
UDP connections where demand for high port numbers is high.

This commit fixes all known cases where ParseInt is used for ports,
and has been verified to fix Discord voice connections on port
50001~50004.

Fixes: d40e5e4fe6

Co-authored-by: Hamster Tian <haotia@gmail.com>
2022-01-02 01:09:29 +08:00
204a72bbd3 Chore: remove forward compatible code 2022-01-02 00:48:57 +08:00
013b839678 [Fix] Linux Tun 2021-12-27 07:09:45 +08:00
a06382cebc [test] 2021-12-27 06:44:17 +08:00
ebc3f36236 [fix]autoIptables 2021-12-27 03:29:14 +08:00
e2a0437685 [fix] 2021-12-27 03:16:48 +08:00
82c8e02d02 [Style] Add User-Agent for provider request 2021-12-26 22:26:53 +08:00
7267c58913 Chore: ReCreate* do side effect job (#1849) 2021-12-26 22:08:53 +08:00
a210ec4197 [Feature] 添加unified-delay boolean 控制延迟测试,默认为false,当设置true时忽略握手延迟,将统一延迟结果,从而利于不同协议的url-test 2021-12-26 21:20:41 +08:00
14ae87fcd0 Chore: remove reduce regex compile (#1855) 2021-12-26 20:47:12 +08:00
0b72395704 Merge pull request #5 from xsxun/patch-1
Update vless.go, fix udp blocked
2021-12-20 18:13:43 +08:00
8955107d6b Update vless.go 2021-12-20 12:59:06 +08:00
Fan
ee6fc12709 Fix: when both providers and proxies are present, use the health check configuration for proxies (#1821)
Co-authored-by: Ho <ho@fluidex.com>
2021-12-12 20:37:30 +08:00
69aef9cec0 [Fixed] Configure tun interface on linux 2021-12-11 22:34:45 +08:00
9e44e21406 [Fixed] launch resolver an enhancer when tun mode 2021-12-09 23:00:54 +08:00
b0fdd8dc47 [Fixed] Add retry to open tun 2021-12-09 22:52:32 +08:00
e92ef587bb [Fixed] The array may be sent out of bounds 2021-12-09 22:52:32 +08:00
7d17d53a8f [readme] 2021-12-09 17:54:53 +08:00
78e105f3b2 Chore: builtin right mime of .js (#1808) 2021-12-08 13:38:25 +08:00
58ef4ddbba [Fixed]Meaningless pointer 2021-12-07 20:49:39 +08:00
a78b89d16e Revert: Revert Redir-Host, please add fallback dns and append proxy adapter
DNS pass proxy use:
- protocol://ip:port#AdapterName
- protocol://ip:port/query#AdapterName

sure as:
- tls://1.1.1.1:853#DNS
2021-12-06 22:45:59 +08:00
833b43a538 Fixed: Does RuleSet resolve ip logic modification 2021-12-06 21:47:22 +08:00
8df3efe932 [Fix] 修正因xray服务端alpn参数为http/1.1而导致无法连接的问题 2021-12-06 00:19:03 +08:00
645c3154d6 [Fix] 修正因xray服务端alpn参数为http/1.1而导致无法连接的问题 2021-12-05 03:51:26 +08:00
a847d7b58d [Fix] 修正因xray服务端alpn参数为http/1.1而导致无法连接的问题 2021-12-05 02:18:58 +08:00
37ea8aff5c README 2021-12-05 00:48:35 +08:00
cb4ce8be6a Makefile 2021-12-04 21:43:33 +08:00
a85395e777 readme 2021-12-04 20:50:57 +08:00
819b29956b readme 2021-12-04 20:40:09 +08:00
eb999b3bf1 fix AutoIptables 2021-12-04 19:59:41 +08:00
8580ee8898 [style] 2021-12-04 17:41:13 +08:00
58552447ef [fix]Linux TProxy 2021-12-04 14:34:01 +08:00
23ca356447 Fixed: Modify the trigger condition, only if it fails successively 2021-12-04 00:16:39 +08:00
fae65b97ec fix Makefile 2021-12-03 22:13:05 +08:00
99f0231a9b style 2021-12-03 21:54:45 +08:00
edf1bb476d test 2021-12-03 20:38:40 +08:00
08607fb6b4 Feature: add linux/arm/v6 for the container image (#1771) 2021-12-02 21:12:45 +08:00
075d8ed094 Fix: fakeip pool cycle used 2021-11-23 22:01:49 +08:00
b1bed7623d Fix: provider filter potential panic 2021-11-21 17:44:03 +08:00
1401a82bb0 Feature: add filter on proxy provider (#1511) 2021-11-20 23:38:49 +08:00
4524cf4418 Fix: should return io.EOF immediately 2021-11-20 12:44:31 +08:00
0db15d46c3 Change: use nop packet conn for reject 2021-11-20 12:34:14 +08:00
08c43b8876 Fix: revert ssr udp fix 2021-11-14 14:48:00 +08:00
499beb7344 Fix: bind iface should throw control error 2021-11-10 22:19:11 +08:00
98 changed files with 2544 additions and 1122 deletions

44
.github/workflows/dev.yml vendored Normal file
View 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 Dev
uses: softprops/action-gh-release@v1
if: ${{ env.GIT_BRANCH != 'Meta' && success() }}
with:
tag_name: develop
files: bin/*
prerelease: true

76
.github/workflows/docker.yml vendored Normal file
View File

@ -0,0 +1,76 @@
name: Publish Docker Image
on:
push:
branches:
- dev
tags:
- '*'
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
with:
platforms: all
- name: Set up docker buildx
id: buildx
uses: docker/setup-buildx-action@v1
with:
version: latest
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to Github Package
uses: docker/login-action@v1
with:
registry: ghcr.io
username: Dreamacro
password: ${{ secrets.PACKAGE_TOKEN }}
- name: Build dev branch and push
if: github.ref == 'refs/heads/dev'
uses: docker/build-push-action@v2
with:
context: .
platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64
push: true
tags: 'dreamacro/clash:dev,ghcr.io/dreamacro/clash:dev'
- name: Get all docker tags
if: startsWith(github.ref, 'refs/tags/')
uses: actions/github-script@v4
id: tags
with:
script: |
const ref = `${context.payload.ref.replace(/\/?refs\/tags\//, '')}`
const tags = [
'dreamacro/clash:latest',
`dreamacro/clash:${ref}`,
'ghcr.io/dreamacro/clash:latest',
`ghcr.io/dreamacro/clash:${ref}`
]
return tags.join(',')
result-encoding: string
- name: Build release and push
if: startsWith(github.ref, 'refs/tags/')
uses: docker/build-push-action@v2
with:
context: .
platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64
push: true
tags: ${{steps.tags.outputs.result}}

2
.gitignore vendored
View File

@ -23,3 +23,5 @@ vendor
# test suite # test suite
test/config/cache* test/config/cache*
/output
/.vscode

158
Makefile
View File

@ -1,67 +1,139 @@
GOCMD=go NAME=Clash.Meta
XGOCMD=xgo -go=go-1.17.x BINDIR=bin
GOBUILD=CGO_ENABLED=1 $(GOCMD) build -trimpath BRANCH=$(shell git rev-parse --abbrev-ref HEAD)
GOCLEAN=$(GOCMD) clean VERSION=$(shell git describe --tags || echo "unknown version" )
NAME=clash ifeq ($(BRANCH),Dev)
BINDIR=$(shell pwd)/bin VERSION=develop-$(shell git rev-parse --short HEAD)
VERSION=$(shell git describe --tags --always 2>/dev/null || date +%F) endif
BUILDTIME=$(shell date -u) BUILDTIME=$(shell date -u)
BUILD_PACKAGE=. AUTOIPTABLES=Enable
RELEASE_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)" \
-X "github.com/Dreamacro/clash/constant.BuildTime=$(BUILDTIME)" \ -X "github.com/Dreamacro/clash/constant.BuildTime=$(BUILDTIME)" \
-w -s -buildid=' -w -s -buildid='
STATIC_LDFLAGS='-X "github.com/Dreamacro/clash/constant.Version=$(VERSION)" \
GOBUILDOP=CGO_ENABLED=0 go build -trimpath -ldflags '-X "github.com/Dreamacro/clash/constant.Version=$(VERSION)" \
-X "github.com/Dreamacro/clash/constant.BuildTime=$(BUILDTIME)" \ -X "github.com/Dreamacro/clash/constant.BuildTime=$(BUILDTIME)" \
-extldflags "-static" \ -X "github.com/Dreamacro/clash/constant.AutoIptables=$(AUTOIPTABLES)" \
-w -s -buildid=' -w -s -buildid='
PLATFORM_LIST = \ PLATFORM_LIST = \
darwin-amd64 \ darwin-amd64 \
darwin-arm64 \ darwin-arm64 \
linux-amd64 linux-amd64 \
# linux-arm64 linux-armv5 \
# linux-386 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-amd64 \ windows-amd64 \
windows-386 windows-arm64 \
# windows-arm64 windows-arm32v7
all: linux-amd64 darwin-amd64 windows-amd64 # Most used
build: all:linux-amd64-AutoIptables linux-amd64\
$(GOBUILD) -ldflags $(RELEASE_LDFLAGS) -tags build_local -o $(BINDIR)/$(NAME)-$@ 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:
$(GOBUILD) -o $(BINDIR)/$(NAME)-$@
darwin-amd64: darwin-amd64:
$(XGOCMD) -dest=$(BINDIR) -out=$(NAME) -trimpath=true -ldflags=$(RELEASE_LDFLAGS) -targets=darwin-10.12/amd64 $(BUILD_PACKAGE) && \ GOARCH=amd64 GOOS=darwin $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
mv $(BINDIR)/$(NAME)-darwin-10.12-amd64 $(BINDIR)/$(NAME)-darwin-amd64
darwin-arm64: darwin-arm64:
$(XGOCMD) -dest=$(BINDIR) -out=$(NAME) -trimpath=true -ldflags=$(RELEASE_LDFLAGS) -targets=darwin-11.1/arm64 $(BUILD_PACKAGE) && \ GOARCH=arm64 GOOS=darwin $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
mv $(BINDIR)/$(NAME)-darwin-11.1-arm64 $(BINDIR)/$(NAME)-darwin-arm64
linux-386: linux-386:
$(XGOCMD) -dest=$(BINDIR) -out=$(NAME) -trimpath=true -ldflags=$(STATIC_LDFLAGS) -targets=linux/386 $(BUILD_PACKAGE) GOARCH=386 GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
linux-amd64: linux-amd64:
$(GOBUILD) -ldflags $(RELEASE_LDFLAGS) -o $(BINDIR)/$(NAME)-$@ GOARCH=amd64 GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
#GOARCH=amd64 GOOS=linux $(GOBUILD) -ldflags $(RELEASE_LDFLAGS) -o $(BINDIR)/$(NAME)-$@
#$(XGOCMD) -dest=$(BINDIR) -out=$(NAME) -trimpath=true -ldflags=$(STATIC_LDFLAGS) -targets=linux/amd64 $(BUILD_PACKAGE) linux-amd64-AutoIptables:
GOARCH=amd64 GOOS=linux $(GOBUILDOP) -o $(BINDIR)/$(NAME)-$@
linux-arm64: linux-arm64:
$(XGOCMD) -dest=$(BINDIR) -out=$(NAME) -trimpath=true -ldflags=$(STATIC_LDFLAGS) -targets=linux/arm64 $(BUILD_PACKAGE) GOARCH=arm64 GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
linux-arm64-AutoIptables:
GOARCH=arm64 GOOS=linux $(GOBUILDOP) -o $(BINDIR)/$(NAME)-$@
linux-armv5:
GOARCH=arm GOOS=linux GOARM=5 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
linux-armv5-AutoIptables:
GOARCH=arm GOOS=linux GOARM=5 $(GOBUILDOP) -o $(BINDIR)/$(NAME)-$@
linux-armv6:
GOARCH=arm GOOS=linux GOARM=6 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
linux-armv6-AutoIptables:
GOARCH=arm GOOS=linux GOARM=6 $(GOBUILDOP) -o $(BINDIR)/$(NAME)-$@
linux-armv7:
GOARCH=arm GOOS=linux GOARM=7 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
linux-armv7-AutoIptables:
GOARCH=arm GOOS=linux GOARM=7 $(GOBUILDOP) -o $(BINDIR)/$(NAME)-$@
linux-armv8:
GOARCH=arm64 GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
linux-armv8-AutoIptables:
GOARCH=arm64 GOOS=linux $(GOBUILDOP) -o $(BINDIR)/$(NAME)-$@
linux-mips-softfloat:
GOARCH=mips GOMIPS=softfloat GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
linux-mips-hardfloat:
GOARCH=mips GOMIPS=hardfloat GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
linux-mipsle-softfloat:
GOARCH=mipsle GOMIPS=softfloat GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
linux-mipsle-hardfloat:
GOARCH=mipsle GOMIPS=hardfloat GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
linux-mips64:
GOARCH=mips64 GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
linux-mips64le:
GOARCH=mips64le GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
freebsd-386:
GOARCH=386 GOOS=freebsd $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
freebsd-amd64:
GOARCH=amd64 GOOS=freebsd $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
freebsd-arm64:
GOARCH=arm64 GOOS=freebsd $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
windows-386: windows-386:
$(XGOCMD) -dest=$(BINDIR) -out=$(NAME) -trimpath=true -ldflags=$(RELEASE_LDFLAGS) -targets=windows-4.0/386 $(BUILD_PACKAGE) && \ GOARCH=386 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
mv $(BINDIR)/$(NAME)-windows-4.0-386.exe $(BINDIR)/$(NAME)-windows-386.exe
windows-amd64: windows-amd64:
$(XGOCMD) -dest=$(BINDIR) -out=$(NAME) -trimpath=true -ldflags=$(RELEASE_LDFLAGS) -targets=windows-4.0/amd64 $(BUILD_PACKAGE) && \ GOARCH=amd64 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
mv $(BINDIR)/$(NAME)-windows-4.0-amd64.exe $(BINDIR)/$(NAME)-windows-amd64.exe
#windows-arm64: windows-arm64:
# $(XGOCMD) -dest=$(BINDIR) -out=$(NAME) -trimpath=true -ldflags=$(RELEASE_LDFLAGS) -targets=windows/arm64 $(BUILD_PACKAGE) GOARCH=arm64 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
# mv $(NAME)-windows-4.0-arm64.exe $(NAME)-windows-arm64.exe
windows-arm32v7:
GOARCH=arm GOOS=windows GOARM=7 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
gz_releases=$(addsuffix .gz, $(PLATFORM_LIST)) gz_releases=$(addsuffix .gz, $(PLATFORM_LIST))
zip_releases=$(addsuffix .zip, $(WINDOWS_ARCH_LIST)) zip_releases=$(addsuffix .zip, $(WINDOWS_ARCH_LIST))
@ -76,19 +148,5 @@ $(zip_releases): %.zip : %
all-arch: $(PLATFORM_LIST) $(WINDOWS_ARCH_LIST) all-arch: $(PLATFORM_LIST) $(WINDOWS_ARCH_LIST)
releases: $(gz_releases) $(zip_releases) releases: $(gz_releases) $(zip_releases)
vet:
$(GOCMD) vet -tags build_local ./...
lint:
golangci-lint run --build-tags=build_local --disable-all -E govet -E gofumpt -E megacheck ./...
clean: clean:
rm -rf $(BINDIR)/ rm $(BINDIR)/*
mkdir -p $(BINDIR)
cleancache:
# go build cache may need to cleanup if changing C source code
$(GOCLEAN) -cache
rm -rf $(BINDIR)/
mkdir -p $(BINDIR)

BIN
Meta.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

207
README.md
View File

@ -1,23 +1,20 @@
<h1 align="center"> <h1 align="center">
<img src="https://github.com/Dreamacro/clash/raw/master/docs/logo.png" alt="Clash" width="200"> <img src="Meta.png" alt="Meta Kennel" width="200">
<br>Clash<br> <br>Meta Kernel<br>
</h1> </h1>
<h4 align="center">A rule-based tunnel in Go.</h4> <h3 align="center">Another Clash Kernel.</h3>
<p align="center"> <p align="center">
<a href="https://github.com/Dreamacro/clash/actions"> <a href="https://goreportcard.com/report/github.com/Clash-Mini/Clash.Meta">
<img src="https://img.shields.io/github/workflow/status/Dreamacro/clash/Go?style=flat-square" alt="Github Actions"> <img src="https://goreportcard.com/badge/github.com/Clash-Mini/Clash.Meta?style=flat-square">
</a>
<a href="https://goreportcard.com/report/github.com/Dreamacro/clash">
<img src="https://goreportcard.com/badge/github.com/Dreamacro/clash?style=flat-square">
</a> </a>
<img src="https://img.shields.io/github/go-mod/go-version/Dreamacro/clash?style=flat-square"> <img src="https://img.shields.io/github/go-mod/go-version/Dreamacro/clash?style=flat-square">
<a href="https://github.com/Dreamacro/clash/releases"> <a href="https://github.com/Clash-Mini/Clash.Meta/releases">
<img src="https://img.shields.io/github/release/Dreamacro/clash/all.svg?style=flat-square"> <img src="https://img.shields.io/github/release/Clash-Mini/Clash.Meta/all.svg?style=flat-square">
</a> </a>
<a href="https://github.com/Dreamacro/clash/releases/tag/premium"> <a href="https://github.com/Clash-Mini/Clash.Meta">
<img src="https://img.shields.io/badge/release-Premium-00b4f0?style=flat-square"> <img src="https://img.shields.io/badge/release-Meta-00b4f0?style=flat-square">
</a> </a>
</p> </p>
@ -36,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:
@ -55,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:
@ -68,39 +81,29 @@ dns:
``` ```
### TUN configuration ### TUN configuration
Supports macOS, Linux and Windows. Supports macOS, Linux and Windows.
Support lwIP stack, a lightweight TCP/IP stack, it's recommended set to tun. Built-in [Wintun](https://www.wintun.net) driver.
On Windows, you should download the [Wintun](https://www.wintun.net) driver and copy `wintun.dll` into Clash home directory.
```yaml ```yaml
# Enable the TUN listener # Enable the TUN listener
tun: tun:
enable: true enable: true
stack: lwip # lwip(recommended), 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
- Support rule `GEOSITE`. - Support rule `GEOSITE`.
- Support rule `SCRIPT`. - Support rule-providers `RULE-SET`.
- Support `multiport` condition for rule `SRC-PORT` and `DST-PORT`. - Support `multiport` condition for rule `SRC-PORT` and `DST-PORT`.
- Support `network` condition for all rules. - Support `network` condition for all rules.
- Support source IPCIDR condition for all rules, just append to the end. - Support source IPCIDR condition for all rules, just append to the end.
- The `GEOSITE` databases via https://github.com/Loyalsoldier/v2ray-rules-dat.
The `GEOSITE` databases via https://github.com/Loyalsoldier/v2ray-rules-dat.
```yaml ```yaml
mode: rule
script:
shortcuts:
quic: 'network == "udp" and dst_port == 443'
privacy: '"analytics" in host or "adservice" in host or "firebase" in host or "safebrowsing" in host or "doubleclick" in host'
rules: rules:
# rule SCRIPT
- SCRIPT,quic,REJECT # Disable QUIC, same as rule "DST-PORT,443,REJECT,udp"
- SCRIPT,privacy,REJECT
# network(tcp/udp) condition for all rules # network(tcp/udp) condition for all rules
- DOMAIN-SUFFIX,bilibili.com,DIRECT,tcp - DOMAIN-SUFFIX,bilibili.com,DIRECT,tcp
@ -130,84 +133,46 @@ rules:
- MATCH,PROXY - MATCH,PROXY
``` ```
### Script configuration
Script enables users to programmatically select a policy for the packets with more flexibility.
```yaml
mode: script
rules:
# the rule GEOSITE just as a rule provider in mode script
- GEOSITE,category-ads-all,Whatever
- GEOSITE,youtube,Whatever
- GEOSITE,geolocation-cn,Whatever
script:
code: |
def main(ctx, metadata):
if metadata["process_name"] == 'apsd':
return "DIRECT"
if metadata["network"] == 'udp' and metadata["dst_port"] == 443:
return "REJECT"
host = metadata["host"]
for kw in ['analytics', 'adservice', 'firebase', 'bugly', 'safebrowsing', 'doubleclick']:
if kw in host:
return "REJECT"
now = time.now()
if (now.hour < 8 or now.hour > 17) and metadata["src_ip"] == '192.168.1.99':
return "REJECT"
if ctx.rule_providers["geosite:category-ads-all"].match(metadata):
return "REJECT"
if ctx.rule_providers["geosite:youtube"].match(metadata):
ctx.log('[Script] domain %s matched youtube' % host)
return "Proxy"
if ctx.rule_providers["geosite:geolocation-cn"].match(metadata):
ctx.log('[Script] domain %s matched geolocation-cn' % host)
return "DIRECT"
ip = metadata["dst_ip"]
if host != "":
ip = ctx.resolve_ip(host)
if ip == "":
return "Proxy"
code = ctx.geoip(ip)
if code == "LAN" or code == "CN":
return "DIRECT"
return "Proxy" # default policy for requests which are not matched by any other script
```
the context and metadata
```ts
interface Metadata {
type: string // socks5、http
network: string // tcp
host: string
process_name: string
src_ip: string
src_port: int
dst_ip: string
dst_port: int
}
interface Context {
resolve_ip: (host: string) => string // ip string
geoip: (ip: string) => string // country code
log: (log: string) => void
rule_providers: Record<string, { match: (metadata: Metadata) => boolean }>
}
```
### 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:
- name: "vless-tcp" - name: "vless-tcp"
@ -245,47 +210,55 @@ tproxy-port: 9898
tun: tun:
enable: false enable: false
``` ```
Create user given name `clash`. Create user given name `Clash.Meta`.
Run Clash by user `clash` 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 daemon, A rule-based proxy in Go. Description=Clash.Meta Daemon, Another Clash Kernel.
After=network.target After=network.target
[Service] [Service]
Type=simple Type=simple
User=clash User=Clash.Meta
Group=clash Group=Clash.Meta
CapabilityBoundingSet=cap_net_admin CapabilityBoundingSet=cap_net_admin
AmbientCapabilities=cap_net_admin AmbientCapabilities=cap_net_admin
Restart=always Restart=always
ExecStart=/usr/local/bin/clash -d /etc/clash ExecStart=/usr/local/bin/Clash.Meta -d /etc/Clash.Meta
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
``` ```
Launch clashd on system startup with: Launch clashd on system startup with:
```shell ```shell
$ systemctl enable clash $ systemctl enable Clash.Meta
``` ```
Launch clashd immediately with: Launch clashd immediately with:
```shell ```shell
$ systemctl start clash $ systemctl start Clash.Meta
``` ```
### Display Process name ### Display Process name
Clash add field `Process` to `Metadata` and prepare to get process name for Restful API `GET /connections`. Clash add field `Process` to `Metadata` and prepare to get process name for Restful API `GET /connections`.
To display process name in GUI please use https://yaling888.github.io/yacd/. To display process name in GUI please use [Dashboard For Meta](https://github.com/Clash-Mini/Dashboard).
![img.png](https://github.com/Clash-Mini/Dashboard/raw/master/View/Dashboard-Process.png)
## Development ## Development
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)
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)
## Credits ## Credits
* [Dreamacro/clash](https://github.com/Dreamacro/clash)
* [riobard/go-shadowsocks2](https://github.com/riobard/go-shadowsocks2) * [riobard/go-shadowsocks2](https://github.com/riobard/go-shadowsocks2)
* [v2ray/v2ray-core](https://github.com/v2ray/v2ray-core) * [v2ray/v2ray-core](https://github.com/v2ray/v2ray-core)
* [WireGuard/wireguard-go](https://github.com/WireGuard/wireguard-go) * [WireGuard/wireguard-go](https://github.com/WireGuard/wireguard-go)

View File

@ -16,6 +16,8 @@ import (
"go.uber.org/atomic" "go.uber.org/atomic"
) )
var UnifiedDelay = atomic.NewBool(false)
type Proxy struct { type Proxy struct {
C.ProxyAdapter C.ProxyAdapter
history *queue.Queue history *queue.Queue
@ -114,6 +116,8 @@ func (p *Proxy) URLTest(ctx context.Context, url string) (t uint16, err error) {
} }
}() }()
unifiedDelay := UnifiedDelay.Load()
addr, err := urlToMetadata(url) addr, err := urlToMetadata(url)
if err != nil { if err != nil {
return return
@ -150,11 +154,19 @@ func (p *Proxy) URLTest(ctx context.Context, url string) (t uint16, err error) {
}, },
} }
defer client.CloseIdleConnections() defer client.CloseIdleConnections()
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
return return
} }
if unifiedDelay {
start = time.Now()
resp, err = client.Do(req)
if err != nil {
return
}
}
resp.Body.Close() resp.Body.Close()
t = uint16(time.Since(start) / time.Millisecond) t = uint16(time.Since(start) / time.Millisecond)
return return

View File

@ -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)
}

View File

@ -44,3 +44,13 @@ func NewDirect() *Direct {
}, },
} }
} }
func NewCompatible() *Direct {
return &Direct{
Base: &Base{
name: "COMPATIBLE",
tp: C.Compatible,
udp: true,
},
}
}

View File

@ -2,7 +2,6 @@ package outbound
import ( import (
"context" "context"
"errors"
"io" "io"
"net" "net"
"time" "time"
@ -17,12 +16,12 @@ type Reject struct {
// DialContext implements C.ProxyAdapter // DialContext implements C.ProxyAdapter
func (r *Reject) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) { func (r *Reject) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
return NewConn(&NopConn{}, r), nil return NewConn(&nopConn{}, r), nil
} }
// ListenPacketContext implements C.ProxyAdapter // ListenPacketContext implements C.ProxyAdapter
func (r *Reject) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) { func (r *Reject) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
return nil, errors.New("match reject rule") return newPacketConn(&nopPacketConn{}, r), nil
} }
func NewReject() *Reject { func NewReject() *Reject {
@ -35,30 +34,29 @@ func NewReject() *Reject {
} }
} }
type NopConn struct{} type nopConn struct{}
func (rw *NopConn) Read(b []byte) (int, error) { func (rw *nopConn) Read(b []byte) (int, error) {
return 0, io.EOF return 0, io.EOF
} }
func (rw *NopConn) Write(b []byte) (int, error) { func (rw *nopConn) Write(b []byte) (int, error) {
return 0, io.EOF return 0, io.EOF
} }
// Close is fake function for net.Conn func (rw *nopConn) Close() error { return nil }
func (rw *NopConn) Close() error { return nil } func (rw *nopConn) LocalAddr() net.Addr { return nil }
func (rw *nopConn) RemoteAddr() net.Addr { return nil }
func (rw *nopConn) SetDeadline(time.Time) error { return nil }
func (rw *nopConn) SetReadDeadline(time.Time) error { return nil }
func (rw *nopConn) SetWriteDeadline(time.Time) error { return nil }
// LocalAddr is fake function for net.Conn type nopPacketConn struct{}
func (rw *NopConn) LocalAddr() net.Addr { return nil }
// RemoteAddr is fake function for net.Conn func (npc *nopPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { return len(b), nil }
func (rw *NopConn) RemoteAddr() net.Addr { return nil } func (npc *nopPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { return 0, nil, io.EOF }
func (npc *nopPacketConn) Close() error { return nil }
// SetDeadline is fake function for net.Conn func (npc *nopPacketConn) LocalAddr() net.Addr { return &net.UDPAddr{IP: net.IPv4zero, Port: 0} }
func (rw *NopConn) SetDeadline(time.Time) error { return nil } func (npc *nopPacketConn) SetDeadline(time.Time) error { return nil }
func (npc *nopPacketConn) SetReadDeadline(time.Time) error { return nil }
// SetReadDeadline is fake function for net.Conn func (npc *nopPacketConn) SetWriteDeadline(time.Time) error { return nil }
func (rw *NopConn) SetReadDeadline(time.Time) error { return nil }
// SetWriteDeadline is fake function for net.Conn
func (rw *NopConn) SetWriteDeadline(time.Time) error { return nil }

View File

@ -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"`
} }
@ -52,7 +53,7 @@ func streamConn(c net.Conn, option streamOption) *snell.Snell {
// StreamConn implements C.ProxyAdapter // StreamConn implements C.ProxyAdapter
func (s *Snell) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { func (s *Snell) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
c = streamConn(c, streamOption{s.psk, s.version, s.addr, s.obfsOption}) c = streamConn(c, streamOption{s.psk, s.version, s.addr, s.obfsOption})
port, _ := strconv.ParseInt(metadata.DstPort, 10, 16) port, _ := strconv.ParseUint(metadata.DstPort, 10, 16)
err := snell.WriteHeader(c, metadata.String(), uint(port), s.version) err := snell.WriteHeader(c, metadata.String(), uint(port), s.version)
return c, err return c, err
} }
@ -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,

View File

@ -3,11 +3,13 @@ package outbound
import ( import (
"context" "context"
"crypto/tls" "crypto/tls"
"encoding/binary"
"errors" "errors"
"fmt" "fmt"
"net" "net"
"net/http" "net/http"
"strconv" "strconv"
"sync"
"github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/resolver" "github.com/Dreamacro/clash/component/resolver"
@ -18,6 +20,11 @@ import (
"golang.org/x/net/http2" "golang.org/x/net/http2"
) )
const (
// max packet length
maxLength = 8192
)
type Vless struct { type Vless struct {
*Base *Base
client *vless.Client client *vless.Client
@ -128,7 +135,7 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
} }
default: default:
// handle TLS And XTLS // handle TLS And XTLS
c, err = v.streamTLSOrXTLSConn(c, true) c, err = v.streamTLSOrXTLSConn(c, false)
} }
if err != nil { if err != nil {
@ -280,17 +287,85 @@ func parseVlessAddr(metadata *C.Metadata) *vless.DstAddr {
type vlessPacketConn struct { type vlessPacketConn struct {
net.Conn net.Conn
rAddr net.Addr rAddr net.Addr
remain int
mux sync.Mutex
cache []byte
} }
func (uc *vlessPacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { func (c *vlessPacketConn) writePacket(b []byte, addr net.Addr) (int, error) {
return uc.Conn.Write(b) length := len(b)
defer func() {
c.cache = c.cache[:0]
}()
c.cache = append(c.cache, byte(length>>8), byte(length))
c.cache = append(c.cache, b...)
n, err := c.Conn.Write(c.cache)
if n > 2 {
return n - 2, err
} }
func (uc *vlessPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { return 0, err
n, err := uc.Conn.Read(b)
return n, uc.rAddr, err
} }
func (c *vlessPacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
if len(b) <= maxLength {
return c.writePacket(b, addr)
}
offset := 0
total := len(b)
for offset < total {
cursor := offset + maxLength
if cursor > total {
cursor = total
}
n, err := c.writePacket(b[offset:cursor], addr)
if err != nil {
return offset + n, err
}
offset = cursor
}
return total, nil
}
func (c *vlessPacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
c.mux.Lock()
defer c.mux.Unlock()
length := len(b)
if c.remain > 0 {
if c.remain < length {
length = c.remain
}
n, err := c.Conn.Read(b[:length])
if err != nil {
return 0, nil, err
}
c.remain -= n
return n, c.rAddr, nil
}
var packetLength uint16
if err := binary.Read(c.Conn, binary.BigEndian, &packetLength); err != nil {
return 0, nil, err
}
remain := int(packetLength)
n, err := c.Conn.Read(b[:length])
remain -= n
if remain > 0 {
c.remain = remain
}
return n, c.rAddr, err
}
func NewVless(option VlessOption) (*Vless, error) { func NewVless(option VlessOption) (*Vless, error) {
if !option.TLS && option.Network == "grpc" { if !option.TLS && option.Network == "grpc" {
return nil, fmt.Errorf("TLS must be true with vless-grpc") return nil, fmt.Errorf("TLS must be true with vless-grpc")

View File

@ -47,10 +47,6 @@ type VmessOption struct {
HTTP2Opts HTTP2Options `proxy:"h2-opts,omitempty"` HTTP2Opts HTTP2Options `proxy:"h2-opts,omitempty"`
GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"` GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"`
WSOpts WSOptions `proxy:"ws-opts,omitempty"` WSOpts WSOptions `proxy:"ws-opts,omitempty"`
// TODO: remove these until 2022
WSHeaders map[string]string `proxy:"ws-headers,omitempty"`
WSPath string `proxy:"ws-path,omitempty"`
} }
type HTTPOptions struct { type HTTPOptions struct {
@ -80,13 +76,6 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
var err error var err error
switch v.option.Network { switch v.option.Network {
case "ws": case "ws":
if v.option.WSOpts.Path == "" {
v.option.WSOpts.Path = v.option.WSPath
}
if len(v.option.WSOpts.Headers) == 0 {
v.option.WSOpts.Headers = v.option.WSHeaders
}
host, port, _ := net.SplitHostPort(v.addr) host, port, _ := net.SplitHostPort(v.addr)
wsOpts := &vmess.WebsocketConfig{ wsOpts := &vmess.WebsocketConfig{
Host: host, Host: host,

View File

@ -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()...)
} }
} }
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 return proxies
} }
}
}

View File

@ -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
@ -34,9 +35,12 @@ func (f *Fallback) DialContext(ctx context.Context, metadata *C.Metadata, opts .
c, err := proxy.DialContext(ctx, metadata, f.Base.DialOptions(opts...)...) c, err := proxy.DialContext(ctx, metadata, f.Base.DialOptions(opts...)...)
if err == nil { if err == nil {
c.AppendToChains(f) c.AppendToChains(f)
f.failedTimes.Store(-1)
f.failedTime.Store(-1)
} else { } else {
f.onDialFailed() f.onDialFailed()
} }
return c, err return c, err
} }
@ -46,9 +50,12 @@ func (f *Fallback) ListenPacketContext(ctx context.Context, metadata *C.Metadata
pc, err := proxy.ListenPacketContext(ctx, metadata, f.Base.DialOptions(opts...)...) pc, err := proxy.ListenPacketContext(ctx, metadata, f.Base.DialOptions(opts...)...)
if err == nil { if err == nil {
pc.AppendToChains(f) pc.AppendToChains(f)
f.failedTimes.Store(-1)
f.failedTime.Store(-1)
} else { } else {
f.onDialFailed() f.onDialFailed()
} }
return pc, err return pc, err
} }
@ -59,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)
} }
} }
} }
@ -88,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(),
@ -107,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)
@ -135,5 +145,8 @@ 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),
failedTime: atomic.NewInt64(-1),
} }
} }

View File

@ -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
} }

View File

@ -16,7 +16,7 @@ var (
errType = errors.New("unsupport type") errType = errors.New("unsupport type")
errMissProxy = errors.New("`use` or `proxies` missing") errMissProxy = errors.New("`use` or `proxies` missing")
errMissHealthCheck = errors.New("`url` or `interval` missing") errMissHealthCheck = errors.New("`url` or `interval` missing")
errDuplicateProvider = errors.New("`duplicate provider name") errDuplicateProvider = errors.New("duplicate provider name")
) )
type GroupCommonOption struct { type GroupCommonOption struct {
@ -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) {
@ -59,16 +60,6 @@ func ParseProxyGroup(config map[string]interface{}, proxyMap map[string]C.Proxy,
return nil, err return nil, err
} }
// if Use not empty, drop health check options
if len(groupOption.Use) != 0 {
hc := provider.NewHealthCheck(ps, "", 0, true)
pd, err := provider.NewCompatibleProvider(groupName, ps, hc)
if err != nil {
return nil, err
}
providers = append(providers, pd)
} else {
if _, ok := providersMap[groupName]; ok { if _, ok := providersMap[groupName]; ok {
return nil, errDuplicateProvider return nil, errDuplicateProvider
} }
@ -98,7 +89,6 @@ func ParseProxyGroup(config map[string]interface{}, proxyMap map[string]C.Proxy,
providersMap[groupName] = pd providersMap[groupName] = pd
} }
} }
}
if len(groupOption.Use) != 0 { if len(groupOption.Use) != 0 {
list, err := getProviders(providersMap, groupOption.Use) list, err := getProviders(providersMap, groupOption.Use)
@ -106,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

View File

@ -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,
} }
} }

View File

@ -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,
} }
} }

View File

@ -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
@ -43,6 +44,8 @@ func (u *URLTest) DialContext(ctx context.Context, metadata *C.Metadata, opts ..
c, err = u.fast(true).DialContext(ctx, metadata, u.Base.DialOptions(opts...)...) c, err = u.fast(true).DialContext(ctx, metadata, u.Base.DialOptions(opts...)...)
if err == nil { if err == nil {
c.AppendToChains(u) c.AppendToChains(u)
u.failedTimes.Store(-1)
u.failedTime.Store(-1)
} else { } else {
u.onDialFailed() u.onDialFailed()
} }
@ -55,6 +58,8 @@ func (u *URLTest) ListenPacketContext(ctx context.Context, metadata *C.Metadata,
pc, err := u.fast(true).ListenPacketContext(ctx, metadata, u.Base.DialOptions(opts...)...) pc, err := u.fast(true).ListenPacketContext(ctx, metadata, u.Base.DialOptions(opts...)...)
if err == nil { if err == nil {
pc.AppendToChains(u) pc.AppendToChains(u)
u.failedTimes.Store(-1)
u.failedTime.Store(-1)
} else { } else {
u.onDialFailed() u.onDialFailed()
} }
@ -69,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)
@ -120,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(),
@ -142,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)
} }
} }
} }
@ -180,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),
} }

View File

@ -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
} }

View File

@ -24,6 +24,7 @@ type proxyProviderSchema struct {
Path string `provider:"path"` Path string `provider:"path"`
URL string `provider:"url,omitempty"` URL string `provider:"url,omitempty"`
Interval int `provider:"interval,omitempty"` Interval int `provider:"interval,omitempty"`
Filter string `provider:"filter,omitempty"`
HealthCheck healthCheckSchema `provider:"health-check,omitempty"` HealthCheck healthCheckSchema `provider:"health-check,omitempty"`
} }
@ -58,5 +59,6 @@ func ParseProxyProvider(name string, mapping map[string]interface{}) (types.Prox
} }
interval := time.Duration(uint(schema.Interval)) * time.Second interval := time.Duration(uint(schema.Interval)) * time.Second
return NewProxySetProvider(name, interval, vehicle, hc), nil filter := schema.Filter
return NewProxySetProvider(name, interval, filter, vehicle, hc)
} }

View File

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"regexp"
"runtime" "runtime"
"time" "time"
@ -66,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
} }
@ -82,33 +87,6 @@ func (pp *proxySetProvider) ProxiesWithTouch() []C.Proxy {
return pp.Proxies() return pp.Proxies()
} }
func proxiesParse(buf []byte) (interface{}, error) {
schema := &ProxySchema{}
if err := yaml.Unmarshal(buf, schema); err != nil {
return nil, err
}
if schema.Proxies == nil {
return nil, errors.New("file must have a `proxies` field")
}
proxies := []C.Proxy{}
for idx, mapping := range schema.Proxies {
proxy, err := adapter.ParseProxy(mapping)
if err != nil {
return nil, fmt.Errorf("proxy %d error: %w", idx, err)
}
proxies = append(proxies, proxy)
}
if len(proxies) == 0 {
return nil, errors.New("file doesn't have any valid proxy")
}
return proxies, nil
}
func (pp *proxySetProvider) setProxies(proxies []C.Proxy) { func (pp *proxySetProvider) setProxies(proxies []C.Proxy) {
pp.proxies = proxies pp.proxies = proxies
pp.healthCheck.setProxy(proxies) pp.healthCheck.setProxy(proxies)
@ -122,9 +100,10 @@ func stopProxyProvider(pd *ProxySetProvider) {
pd.fetcher.Destroy() pd.fetcher.Destroy()
} }
func NewProxySetProvider(name string, interval time.Duration, vehicle types.Vehicle, hc *HealthCheck) *ProxySetProvider { func NewProxySetProvider(name string, interval time.Duration, filter string, vehicle types.Vehicle, hc *HealthCheck) (*ProxySetProvider, error) {
if hc.auto() { filterReg, err := regexp.Compile(filter)
go hc.process() if err != nil {
return nil, fmt.Errorf("invalid filter regex: %w", err)
} }
pd := &proxySetProvider{ pd := &proxySetProvider{
@ -137,12 +116,45 @@ func NewProxySetProvider(name string, interval time.Duration, vehicle types.Vehi
pd.setProxies(ret) pd.setProxies(ret)
} }
fetcher := newFetcher(name, interval, vehicle, proxiesParse, onUpdate) proxiesParseAndFilter := func(buf []byte) (interface{}, error) {
schema := &ProxySchema{}
if err := yaml.Unmarshal(buf, schema); err != nil {
return nil, err
}
if schema.Proxies == nil {
return nil, errors.New("file must have a `proxies` field")
}
proxies := []C.Proxy{}
for idx, mapping := range schema.Proxies {
if name, ok := mapping["name"]; ok && len(filter) > 0 && !filterReg.MatchString(name.(string)) {
continue
}
proxy, err := adapter.ParseProxy(mapping)
if err != nil {
return nil, fmt.Errorf("proxy %d error: %w", idx, err)
}
proxies = append(proxies, proxy)
}
if len(proxies) == 0 {
if len(filter) > 0 {
return nil, errors.New("doesn't match any proxy, please check your filter")
}
return nil, errors.New("file doesn't have any proxy")
}
return proxies, nil
}
fetcher := newFetcher(name, interval, vehicle, proxiesParseAndFilter, onUpdate)
pd.fetcher = fetcher pd.fetcher = fetcher
wrapper := &ProxySetProvider{pd} wrapper := &ProxySetProvider{pd}
runtime.SetFinalizer(wrapper, stopProxyProvider) runtime.SetFinalizer(wrapper, stopProxyProvider)
return wrapper return wrapper, nil
} }
// for auto gc // for auto gc
@ -178,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
} }
@ -207,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,

View File

@ -2,6 +2,7 @@ package provider
import ( import (
"context" "context"
"github.com/Dreamacro/clash/listener/inner"
"io" "io"
"net" "net"
"net/http" "net/http"
@ -9,7 +10,7 @@ import (
"os" "os"
"time" "time"
"github.com/Dreamacro/clash/component/dialer" netHttp "github.com/Dreamacro/clash/common/net"
types "github.com/Dreamacro/clash/constant/provider" types "github.com/Dreamacro/clash/constant/provider"
) )
@ -56,6 +57,8 @@ func (h *HTTPVehicle) Read() ([]byte, error) {
} }
req, err := http.NewRequest(http.MethodGet, uri.String(), nil) req, err := http.NewRequest(http.MethodGet, uri.String(), nil)
req.Header.Set("user-agent", netHttp.UA)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -74,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
}, },
} }

View 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++
}

5
common/net/http.go Normal file
View File

@ -0,0 +1,5 @@
package net
const (
UA = "Clash"
)

46
common/net/tcpip.go Normal file
View 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
}

View File

@ -58,11 +58,11 @@ func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, des
return nil return nil
} }
local := int64(0) local := uint64(0)
if dialer.LocalAddr != nil { if dialer.LocalAddr != nil {
_, port, err := net.SplitHostPort(dialer.LocalAddr.String()) _, port, err := net.SplitHostPort(dialer.LocalAddr.String())
if err == nil { if err == nil {
local, _ = strconv.ParseInt(port, 10, 16) local, _ = strconv.ParseUint(port, 10, 16)
} }
} }
@ -82,7 +82,7 @@ func bindIfaceToListenConfig(ifaceName string, _ *net.ListenConfig, network, add
port = "0" port = "0"
} }
local, _ := strconv.ParseInt(port, 10, 16) local, _ := strconv.ParseUint(port, 10, 16)
addr, err := lookupLocalAddr(ifaceName, network, nil, int(local)) addr, err := lookupLocalAddr(ifaceName, network, nil, int(local))
if err != nil { if err != nil {

View File

@ -38,6 +38,12 @@ func (c *cachefileStore) PutByIP(ip net.IP, host string) {
c.cache.PutFakeip(ip.To4(), []byte(host)) c.cache.PutFakeip(ip.To4(), []byte(host))
} }
// DelByIP implements store.DelByIP
func (c *cachefileStore) DelByIP(ip net.IP) {
ip = ip.To4()
c.cache.DelFakeipPair(ip, c.cache.GetFakeip(ip.To4()))
}
// Exist implements store.Exist // Exist implements store.Exist
func (c *cachefileStore) Exist(ip net.IP) bool { func (c *cachefileStore) Exist(ip net.IP) bool {
_, exist := c.GetByIP(ip) _, exist := c.GetByIP(ip)

View File

@ -46,6 +46,15 @@ func (m *memoryStore) PutByIP(ip net.IP, host string) {
m.cache.Set(ipToUint(ip.To4()), host) m.cache.Set(ipToUint(ip.To4()), host)
} }
// DelByIP implements store.DelByIP
func (m *memoryStore) DelByIP(ip net.IP) {
ipNum := ipToUint(ip.To4())
if elm, exist := m.cache.Get(ipNum); exist {
m.cache.Delete(elm.(string))
}
m.cache.Delete(ipNum)
}
// Exist implements store.Exist // Exist implements store.Exist
func (m *memoryStore) Exist(ip net.IP) bool { func (m *memoryStore) Exist(ip net.IP) bool {
return m.cache.Exist(ipToUint(ip.To4())) return m.cache.Exist(ipToUint(ip.To4()))

View File

@ -15,6 +15,7 @@ type store interface {
PutByHost(host string, ip net.IP) PutByHost(host string, ip net.IP)
GetByIP(ip net.IP) (string, bool) GetByIP(ip net.IP) (string, bool)
PutByIP(ip net.IP, host string) PutByIP(ip net.IP, host string)
DelByIP(ip net.IP)
Exist(ip net.IP) bool Exist(ip net.IP) bool
CloneTo(store) CloneTo(store)
} }
@ -97,6 +98,9 @@ func (p *Pool) get(host string) net.IP {
p.offset = (p.offset + 1) % (p.max - p.min) p.offset = (p.offset + 1) % (p.max - p.min)
// Avoid infinite loops // Avoid infinite loops
if p.offset == current { if p.offset == current {
p.offset = (p.offset + 1) % (p.max - p.min)
ip := uintToIP(p.min + p.offset - 1)
p.store.DelByIP(ip)
break break
} }

View File

@ -1,6 +1,7 @@
package fakeip package fakeip
import ( import (
"fmt"
"net" "net"
"os" "os"
"testing" "testing"
@ -75,7 +76,7 @@ func TestPool_Basic(t *testing.T) {
} }
func TestPool_CycleUsed(t *testing.T) { func TestPool_CycleUsed(t *testing.T) {
_, ipnet, _ := net.ParseCIDR("192.168.0.1/30") _, ipnet, _ := net.ParseCIDR("192.168.0.1/29")
pools, tempfile, err := createPools(Options{ pools, tempfile, err := createPools(Options{
IPNet: ipnet, IPNet: ipnet,
Size: 10, Size: 10,
@ -84,9 +85,15 @@ func TestPool_CycleUsed(t *testing.T) {
defer os.Remove(tempfile) defer os.Remove(tempfile)
for _, pool := range pools { for _, pool := range pools {
first := pool.Lookup("foo.com") foo := pool.Lookup("foo.com")
same := pool.Lookup("baz.com") bar := pool.Lookup("bar.com")
assert.True(t, first.Equal(same)) for i := 0; i < 3; i++ {
pool.Lookup(fmt.Sprintf("%d.com", i))
}
baz := pool.Lookup("baz.com")
next := pool.Lookup("foo.com")
assert.True(t, foo.Equal(baz))
assert.True(t, next.Equal(bar))
} }
} }

View File

@ -1,8 +1,6 @@
package cachefile package cachefile
import ( import (
"bytes"
"encoding/gob"
"os" "os"
"sync" "sync"
"time" "time"
@ -90,6 +88,31 @@ func (c *CacheFile) PutFakeip(key, value []byte) error {
return err return err
} }
func (c *CacheFile) DelFakeipPair(ip, host []byte) error {
if c.DB == nil {
return nil
}
err := c.DB.Batch(func(t *bbolt.Tx) error {
bucket, err := t.CreateBucketIfNotExists(bucketFakeip)
if err != nil {
return err
}
err = bucket.Delete(ip)
if len(host) > 0 {
if err := bucket.Delete(host); err != nil {
return err
}
}
return err
})
if err != nil {
log.Warnln("[CacheFile] write cache to %s failed: %s", c.DB.Path(), err.Error())
}
return err
}
func (c *CacheFile) GetFakeip(key []byte) []byte { func (c *CacheFile) GetFakeip(key []byte) []byte {
if c.DB == nil { if c.DB == nil {
return nil return nil
@ -113,9 +136,7 @@ func (c *CacheFile) Close() error {
return c.DB.Close() return c.DB.Close()
} }
// TODO: remove migrateCache until 2022 func initCache() {
func migrateCache() {
defer func() {
options := bbolt.Options{Timeout: time.Second} options := bbolt.Options{Timeout: time.Second}
db, err := bbolt.Open(C.Path.Cache(), fileMode, &options) db, err := bbolt.Open(C.Path.Cache(), fileMode, &options)
switch err { switch err {
@ -134,48 +155,11 @@ func migrateCache() {
defaultCache = &CacheFile{ defaultCache = &CacheFile{
DB: db, DB: db,
} }
}()
buf, err := os.ReadFile(C.Path.OldCache())
if err != nil {
return
}
defer os.Remove(C.Path.OldCache())
// read old cache file
type cache struct {
Selected map[string]string
}
model := &cache{
Selected: map[string]string{},
}
bufReader := bytes.NewBuffer(buf)
gob.NewDecoder(bufReader).Decode(model)
// write to new cache file
db, err := bbolt.Open(C.Path.Cache(), fileMode, nil)
if err != nil {
return
}
defer db.Close()
db.Batch(func(t *bbolt.Tx) error {
bucket, err := t.CreateBucketIfNotExists(bucketSelected)
if err != nil {
return err
}
for group, selected := range model.Selected {
if err := bucket.Put([]byte(group), []byte(selected)); err != nil {
return err
}
}
return nil
})
} }
// Cache return singleton of CacheFile // Cache return singleton of CacheFile
func Cache() *CacheFile { func Cache() *CacheFile {
initOnce.Do(migrateCache) initOnce.Do(initCache)
return defaultCache return defaultCache
} }

View File

@ -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
} }
} }

View File

@ -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"))
}

View File

@ -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 {

View File

@ -4,6 +4,8 @@ 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"
@ -24,7 +26,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"
@ -35,6 +36,7 @@ type General struct {
Inbound Inbound
Controller Controller
Mode T.TunnelMode `json:"mode"` Mode T.TunnelMode `json:"mode"`
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:"-"`
@ -47,7 +49,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"`
@ -100,7 +101,7 @@ type Profile struct {
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"`
} }
@ -161,6 +162,7 @@ type RawConfig struct {
AllowLan bool `yaml:"allow-lan"` AllowLan bool `yaml:"allow-lan"`
BindAddress string `yaml:"bind-address"` BindAddress string `yaml:"bind-address"`
Mode T.TunnelMode `yaml:"mode"` Mode T.TunnelMode `yaml:"mode"`
UnifiedDelay bool `yaml:"unified-delay"`
LogLevel log.LogLevel `yaml:"log-level"` LogLevel log.LogLevel `yaml:"log-level"`
IPv6 bool `yaml:"ipv6"` IPv6 bool `yaml:"ipv6"`
ExternalController string `yaml:"external-controller"` ExternalController string `yaml:"external-controller"`
@ -197,6 +199,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
AllowLan: false, AllowLan: false,
BindAddress: "*", BindAddress: "*",
Mode: T.Rule, Mode: T.Rule,
UnifiedDelay: false,
Authentication: []string{}, Authentication: []string{},
LogLevel: log.INFO, LogLevel: log.INFO,
Hosts: map[string]string{}, Hosts: map[string]string{},
@ -205,9 +208,9 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
ProxyGroup: []map[string]interface{}{}, ProxyGroup: []map[string]interface{}{},
Tun: Tun{ Tun: Tun{
Enable: false, Enable: false,
Stack: "lwip", 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,
@ -222,6 +225,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{
@ -252,6 +266,8 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
} }
config.General = general config.General = general
config.Tun = &rawCfg.Tun
proxies, providers, err := parseProxies(rawCfg) proxies, providers, err := parseProxies(rawCfg)
if err != nil { if err != nil {
return nil, err return nil, err
@ -307,7 +323,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,
}, },
@ -316,6 +331,7 @@ func parseGeneral(cfg *RawConfig) (*General, error) {
ExternalUI: cfg.ExternalUI, ExternalUI: cfg.ExternalUI,
Secret: cfg.Secret, Secret: cfg.Secret,
}, },
UnifiedDelay: cfg.UnifiedDelay,
Mode: cfg.Mode, Mode: cfg.Mode,
LogLevel: cfg.LogLevel, LogLevel: cfg.LogLevel,
IPv6: cfg.IPv6, IPv6: cfg.IPv6,
@ -326,7 +342,7 @@ func parseGeneral(cfg *RawConfig) (*General, error) {
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
@ -335,6 +351,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
@ -381,13 +398,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)
@ -403,19 +413,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])
} }
@ -487,23 +485,16 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[strin
// 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
@ -513,7 +504,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])
) )
@ -521,6 +512,10 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[strin
continue continue
} }
if ruleName == "NOT" || ruleName == "OR" || ruleName == "AND" {
payload = strings.Join(rule[1:len(rule)-1], ",")
target = rule[len(rule)-1]
} else {
switch l := len(rule); { switch l := len(rule); {
case l == 2: case l == 2:
target = rule[1] target = rule[1]
@ -540,6 +535,7 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[strin
default: default:
return nil, nil, fmt.Errorf("rules[%d] [%s] error: format invalid", idx, line) return nil, nil, fmt.Errorf("rules[%d] [%s] error: format invalid", idx, line)
} }
}
if _, ok := proxies[target]; mode != T.Script && !ok { if _, ok := proxies[target]; mode != T.Script && !ok {
return nil, nil, fmt.Errorf("rules[%d] [%s] error: proxy [%s] not found", idx, line, target) return nil, nil, fmt.Errorf("rules[%d] [%s] error: proxy [%s] not found", idx, line, target)
@ -547,6 +543,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())
@ -601,7 +602,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
@ -669,7 +670,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)
@ -683,7 +684,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
@ -778,7 +784,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)
} }
} }

View File

@ -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
} }

View File

@ -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 {
@ -94,7 +95,6 @@ type ProxyAdapter interface {
// DialContext return a C.Conn with protocol which // DialContext return a C.Conn with protocol which
// contains multiplexing-related reuse logic (if any) // contains multiplexing-related reuse logic (if any)
DialContext(ctx context.Context, metadata *Metadata, opts ...dialer.Option) (Conn, error) DialContext(ctx context.Context, metadata *Metadata, opts ...dialer.Option) (Conn, error)
ListenPacketContext(ctx context.Context, metadata *Metadata, opts ...dialer.Option) (PacketConn, error) ListenPacketContext(ctx context.Context, metadata *Metadata, opts ...dialer.Option) (PacketConn, error)
// Unwrap extracts the proxy from a proxy-group. It returns nil when nothing to extract. // Unwrap extracts the proxy from a proxy-group. It returns nil when nothing to extract.
@ -129,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:

View File

@ -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
} }
@ -114,7 +130,7 @@ func (m *Metadata) UDPAddr() *net.UDPAddr {
if m.NetWork != UDP || m.DstIP == nil { if m.NetWork != UDP || m.DstIP == nil {
return nil return nil
} }
port, _ := strconv.ParseInt(m.DstPort, 10, 16) port, _ := strconv.ParseUint(m.DstPort, 10, 16)
return &net.UDPAddr{ return &net.UDPAddr{
IP: m.DstIP, IP: m.DstIP,
Port: int(port), Port: int(port),

16
constant/mime/mime.go Normal file
View File

@ -0,0 +1,16 @@
package mime
import (
"mime"
)
var consensusMimes = map[string]string{
// rfc4329: text/javascript is obsolete, so we need to overwrite mime's builtin
".js": "application/javascript; charset=utf-8",
}
func init() {
for ext, typ := range consensusMimes {
mime.AddExtensionType(ext, typ)
}
}

View File

@ -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"
} }

View File

@ -1,6 +1,9 @@
package constant package constant
var ( var (
Version = "1.8.0 - Meta" Meta = true
Version = "1.9.0"
BuildTime = "unknown time" BuildTime = "unknown time"
AutoIptables string
ClashName = "Clash.Meta"
) )

View File

@ -47,11 +47,11 @@ func (s *Server) SetHandler(handler handler) {
s.handler = handler s.handler = handler
} }
func ReCreateServer(addr string, resolver *Resolver, mapper *ResolverEnhancer) error { func ReCreateServer(addr string, resolver *Resolver, mapper *ResolverEnhancer) {
if addr == address && resolver != nil { if addr == address && resolver != nil {
handler := NewHandler(resolver, mapper) handler := NewHandler(resolver, mapper)
server.SetHandler(handler) server.SetHandler(handler)
return nil return
} }
if server.Server != nil { if server.Server != nil {
@ -60,24 +60,37 @@ func ReCreateServer(addr string, resolver *Resolver, mapper *ResolverEnhancer) e
address = "" address = ""
} }
if addr == "" {
return
}
var err error
defer func() {
if err != nil {
log.Errorln("Start DNS server error: %s", err.Error())
}
}()
_, port, err := net.SplitHostPort(addr) _, port, err := net.SplitHostPort(addr)
if port == "0" || port == "" || err != nil { if port == "0" || port == "" || err != nil {
return nil return
} }
udpAddr, err := net.ResolveUDPAddr("udp", addr) udpAddr, err := net.ResolveUDPAddr("udp", addr)
if err != nil { if err != nil {
return err return
} }
p, err := net.ListenUDP("udp", udpAddr) p, err := net.ListenUDP("udp", udpAddr)
if err != nil { if err != nil {
return err return
} }
err = sockopt.UDPReuseaddr(p) err = sockopt.UDPReuseaddr(p)
if err != nil { if err != nil {
log.Warnln("Failed to Reuse UDP Address: %s", err) log.Warnln("Failed to Reuse UDP Address: %s", err)
err = nil
} }
address = addr address = addr
@ -88,5 +101,6 @@ func ReCreateServer(addr string, resolver *Resolver, mapper *ResolverEnhancer) e
go func() { go func() {
server.ActivateAndServe() server.ActivateAndServe()
}() }()
return nil
log.Infoln("DNS server listening at: %s", p.LocalAddr().String())
} }

18
go.mod
View File

@ -4,26 +4,25 @@ go 1.17
require ( require (
github.com/Dreamacro/go-shadowsocks2 v0.1.7 github.com/Dreamacro/go-shadowsocks2 v0.1.7
github.com/go-chi/chi/v5 v5.0.5 github.com/go-chi/chi/v5 v5.0.7
github.com/go-chi/cors v1.2.0 github.com/go-chi/cors v1.2.0
github.com/go-chi/render v1.0.1 github.com/go-chi/render v1.0.1
github.com/gofrs/uuid v4.1.0+incompatible github.com/gofrs/uuid v4.2.0+incompatible
github.com/gorilla/websocket v1.4.2 github.com/gorilla/websocket v1.4.2
github.com/insomniacslk/dhcp v0.0.0-20211026125128-ad197bcd36fd github.com/insomniacslk/dhcp v0.0.0-20211214070828-5297eed8f489
github.com/kr328/tun2socket v0.0.0-20210412191540-3d56c47e2d99 github.com/kr328/tun2socket v0.0.0-20210412191540-3d56c47e2d99
github.com/miekg/dns v1.1.43 github.com/miekg/dns v1.1.45
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-20201118062508-3632bf3b7499
github.com/yaling888/go-lwip v0.0.0-20211103185822-c9d650538091
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
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
golang.org/x/net v0.0.0-20211105192438-b53810dc28af golang.org/x/net v0.0.0-20211216030914-fe4d6282115f
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20211107104306-e0b2ad06fe42 golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
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
@ -37,7 +36,10 @@ 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/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/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
) )

49
go.sum
View File

@ -139,8 +139,8 @@ github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-chi/chi/v5 v5.0.5 h1:l3RJ8T8TAqLsXFfah+RA6N4pydMbPwSdvNM+AFWvLUM= github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
github.com/go-chi/chi/v5 v5.0.5/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.0 h1:tV1g1XENQ8ku4Bq3K9ub2AtgG+p16SmzeMSGTwrOKdE= github.com/go-chi/cors v1.2.0 h1:tV1g1XENQ8ku4Bq3K9ub2AtgG+p16SmzeMSGTwrOKdE=
github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-chi/render v1.0.1 h1:4/5tis2cKaNdnv9zFLfXzcquC9HbeZgCnxGnKrltBS8= github.com/go-chi/render v1.0.1 h1:4/5tis2cKaNdnv9zFLfXzcquC9HbeZgCnxGnKrltBS8=
@ -159,8 +159,8 @@ github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dp
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
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.1.0+incompatible h1:sIa2eCvUTwgjbqXrPLfNwUf9S3i3mpH1O1atV+iL/Wk= github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
github.com/gofrs/uuid v4.1.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/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=
@ -271,8 +271,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= 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-20211026125128-ad197bcd36fd h1:jupbuQFZtwOBg/3EmK91/rGaYFkqCb9bwHOnwn7Cav0= github.com/insomniacslk/dhcp v0.0.0-20211214070828-5297eed8f489 h1:jhdHqd7DxBrzfuFSoPxjD6nUVaV/1RIn9aHA0WCf/as=
github.com/insomniacslk/dhcp v0.0.0-20211026125128-ad197bcd36fd/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E= github.com/insomniacslk/dhcp v0.0.0-20211214070828-5297eed8f489/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
@ -313,8 +313,8 @@ github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcK
github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o= github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=
github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg= github.com/miekg/dns v1.1.45 h1:g5fRIhm9nx7g8osrAvgb16QJfmyMsyOCb+J7LSv+Qzk=
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= github.com/miekg/dns v1.1.45/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@ -413,13 +413,12 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q
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-20201118062508-3632bf3b7499 h1:QHESTXtfgc1ABV+ArlbPVqUx9Ht5I0dDkYhxYoXFxNo=
github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499/go.mod h1:5TB2+k58gx4A4g2Nf5miSHNDF6CuAzHKpWBooLAshTs= github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499/go.mod h1:5TB2+k58gx4A4g2Nf5miSHNDF6CuAzHKpWBooLAshTs=
github.com/yaling888/go-lwip v0.0.0-20211103185822-c9d650538091 h1:uOaYhg8ue1gAzV7KNAz1uc/qvjEDRtl16nvTPYiaphM=
github.com/yaling888/go-lwip v0.0.0-20211103185822-c9d650538091/go.mod h1:Y+f95PkWh183q1oDJxdlxTHa2mpdHG5zvBhV0TUhhSY=
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=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
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=
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=
@ -447,11 +446,13 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
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-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
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/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -486,6 +487,8 @@ 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.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/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/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=
@ -503,6 +506,7 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -531,11 +535,14 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v
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-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-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-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-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-20211105192438-b53810dc28af h1:SMeNJG/vclJ5wyBBd4xupMsSJIHTd1coW9g7q6KOjmY= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211105192438-b53810dc28af/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM=
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
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=
@ -555,6 +562,7 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -620,24 +628,26 @@ golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/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-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/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-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-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-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-20210514084401-e8d321eab015/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-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-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-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-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-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-20211107104306-e0b2ad06fe42 h1:G2DDmludOQZoWbpCr7OKDxnl478ZBGMcOhrv+ooX/Q4= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211107104306-e0b2ad06fe42/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -676,6 +686,7 @@ golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
@ -711,11 +722,17 @@ 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.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/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.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/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= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.zx2c4.com/wireguard/windows v0.5.1 h1:OnYw96PF+CsIMrqWo5QP3Q59q5hY1rFErk/yN3cS+JQ= golang.zx2c4.com/wireguard/windows v0.5.1 h1:OnYw96PF+CsIMrqWo5QP3Q59q5hY1rFErk/yN3cS+JQ=
golang.zx2c4.com/wireguard/windows v0.5.1/go.mod h1:EApyTk/ZNrkbZjurHL1nleDYnsPpJYBO7LZEBCyDAHk= golang.zx2c4.com/wireguard/windows v0.5.1/go.mod h1:EApyTk/ZNrkbZjurHL1nleDYnsPpJYBO7LZEBCyDAHk=

View File

@ -9,6 +9,8 @@ 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"
@ -24,7 +26,6 @@ import (
"github.com/Dreamacro/clash/dns" "github.com/Dreamacro/clash/dns"
P "github.com/Dreamacro/clash/listener" P "github.com/Dreamacro/clash/listener"
authStore "github.com/Dreamacro/clash/listener/auth" authStore "github.com/Dreamacro/clash/listener/auth"
"github.com/Dreamacro/clash/listener/tproxy"
"github.com/Dreamacro/clash/listener/tun/dev" "github.com/Dreamacro/clash/listener/tun/dev"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/tunnel" "github.com/Dreamacro/clash/tunnel"
@ -74,14 +75,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,7 +102,6 @@ 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(),
@ -113,8 +116,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 { if !c.Enable && !Tun.Enable {
resolver.DefaultResolver = nil resolver.DefaultResolver = nil
resolver.MainResolver = nil resolver.MainResolver = nil
resolver.DefaultHostMapper = nil resolver.DefaultHostMapper = nil
@ -152,19 +155,14 @@ 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
} }
if err := dns.ReCreateServer(c.Listen, r, m); err != nil { if c.Enable {
log.Errorln("Start DNS server error: %s", err.Error()) dns.ReCreateServer(c.Listen, r, m)
return
}
if c.Listen != "" {
log.Infoln("DNS server listening at: %s", c.Listen)
} }
} }
@ -180,11 +178,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)
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>" {
@ -217,32 +248,27 @@ func updateGeneral(general *config.General, force bool) {
tcpIn := tunnel.TCPIn() tcpIn := tunnel.TCPIn()
udpIn := tunnel.UDPIn() udpIn := tunnel.UDPIn()
if err := P.ReCreateHTTP(general.Port, tcpIn); err != nil { P.ReCreateHTTP(general.Port, tcpIn)
log.Errorln("Start HTTP server error: %s", err.Error()) P.ReCreateSocks(general.SocksPort, tcpIn, udpIn)
P.ReCreateRedir(general.RedirPort, tcpIn, udpIn)
P.ReCreateTProxy(general.TProxyPort, tcpIn, udpIn)
P.ReCreateMixed(general.MixedPort, tcpIn, udpIn)
log.SetLevel(general.LogLevel)
} }
if err := P.ReCreateSocks(general.SocksPort, tcpIn, udpIn); err != nil { func updateTun(Tun *config.Tun) {
log.Errorln("Start SOCKS server error: %s", err.Error()) if Tun == nil {
return
} }
if err := P.ReCreateRedir(general.RedirPort, tcpIn, udpIn); err != nil { tcpIn := tunnel.TCPIn()
log.Errorln("Start Redir server error: %s", err.Error()) udpIn := tunnel.UDPIn()
}
if err := P.ReCreateTProxy(general.TProxyPort, tcpIn, udpIn); err != nil { if err := P.ReCreateTun(*Tun, tcpIn, udpIn); err != nil {
log.Errorln("Start TProxy server error: %s", err.Error())
}
if err := P.ReCreateMixed(general.MixedPort, tcpIn, udpIn); err != nil {
log.Errorln("Start Mixed(http and socks) server error: %s", err.Error())
}
if err := P.ReCreateTun(general.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) {
@ -288,8 +314,9 @@ 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) {
if runtime.GOOS != "linux" || dns.Listen == "" || general.TProxyPort == 0 || general.Tun.Enable { AutoIptables := C.AutoIptables
if runtime.GOOS != "linux" || dns.Listen == "" || general.TProxyPort == 0 || tun.Enable || AutoIptables != "Enable" {
return return
} }
@ -315,8 +342,8 @@ 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()
} }
} }

View File

@ -79,7 +79,7 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) {
P.ReCreateMixed(pointerOrDefault(general.MixedPort, ports.MixedPort), tcpIn, udpIn) P.ReCreateMixed(pointerOrDefault(general.MixedPort, ports.MixedPort), tcpIn, udpIn)
if general.Tun != nil { if general.Tun != nil {
err := P.ReCreateTun(*general.Tun, nil, nil) err := P.ReCreateTun(*general.Tun, tcpIn, udpIn)
if err == nil { if err == nil {
log.Infoln("Recreate tun success.") log.Infoln("Recreate tun success.")
} else { } else {

View File

@ -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
View 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)
}

View File

@ -9,6 +9,7 @@ import (
"time" "time"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
_ "github.com/Dreamacro/clash/constant/mime"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/tunnel/statistic" "github.com/Dreamacro/clash/tunnel/statistic"
@ -71,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 != "" {
@ -240,5 +242,5 @@ func getLogs(w http.ResponseWriter, r *http.Request) {
} }
func version(w http.ResponseWriter, r *http.Request) { func version(w http.ResponseWriter, r *http.Request) {
render.JSON(w, r, render.M{"version": C.Version}) render.JSON(w, r, render.M{"meta": C.Meta, "version": C.Version})
} }

20
listener/inner/tcp.go Normal file
View 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
}

View File

@ -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(),
} }
} }
@ -80,38 +81,52 @@ func SetBindAddress(host string) {
bindAddress = host bindAddress = host
} }
func ReCreateHTTP(port int, tcpIn chan<- C.ConnContext) error { func ReCreateHTTP(port int, tcpIn chan<- C.ConnContext) {
httpMux.Lock() httpMux.Lock()
defer httpMux.Unlock() defer httpMux.Unlock()
var err error
defer func() {
if err != nil {
log.Errorln("Start HTTP server error: %s", err.Error())
}
}()
addr := genAddr(bindAddress, port, allowLan) addr := genAddr(bindAddress, port, allowLan)
if httpListener != nil { if httpListener != nil {
if httpListener.RawAddress() == addr { if httpListener.RawAddress() == addr {
return nil return
} }
httpListener.Close() httpListener.Close()
httpListener = nil httpListener = nil
} }
if portIsZero(addr) { if portIsZero(addr) {
return nil return
} }
var err error
httpListener, err = http.New(addr, tcpIn) httpListener, err = http.New(addr, tcpIn)
if err != nil { if err != nil {
return err log.Errorln("Start HTTP server error: %s", err.Error())
return
} }
log.Infoln("HTTP proxy listening at: %s", httpListener.Address()) log.Infoln("HTTP proxy listening at: %s", httpListener.Address())
return nil
} }
func ReCreateSocks(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) error { func ReCreateSocks(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) {
socksMux.Lock() socksMux.Lock()
defer socksMux.Unlock() defer socksMux.Unlock()
var err error
defer func() {
if err != nil {
log.Errorln("Start SOCKS server error: %s", err.Error())
}
}()
inner.New(tcpIn)
addr := genAddr(bindAddress, port, allowLan) addr := genAddr(bindAddress, port, allowLan)
shouldTCPIgnore := false shouldTCPIgnore := false
@ -136,40 +151,46 @@ func ReCreateSocks(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.P
} }
if shouldTCPIgnore && shouldUDPIgnore { if shouldTCPIgnore && shouldUDPIgnore {
return nil return
} }
if portIsZero(addr) { if portIsZero(addr) {
return nil return
} }
tcpListener, err := socks.New(addr, tcpIn) tcpListener, err := socks.New(addr, tcpIn)
if err != nil { if err != nil {
return err return
} }
udpListener, err := socks.NewUDP(addr, udpIn) udpListener, err := socks.NewUDP(addr, udpIn)
if err != nil { if err != nil {
tcpListener.Close() tcpListener.Close()
return err return
} }
socksListener = tcpListener socksListener = tcpListener
socksUDPListener = udpListener socksUDPListener = udpListener
log.Infoln("SOCKS proxy listening at: %s", socksListener.Address()) log.Infoln("SOCKS proxy listening at: %s", socksListener.Address())
return nil
} }
func ReCreateRedir(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) error { func ReCreateRedir(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) {
redirMux.Lock() redirMux.Lock()
defer redirMux.Unlock() defer redirMux.Unlock()
var err error
defer func() {
if err != nil {
log.Errorln("Start Redir server error: %s", err.Error())
}
}()
addr := genAddr(bindAddress, port, allowLan) addr := genAddr(bindAddress, port, allowLan)
if redirListener != nil { if redirListener != nil {
if redirListener.RawAddress() == addr { if redirListener.RawAddress() == addr {
return nil return
} }
redirListener.Close() redirListener.Close()
redirListener = nil redirListener = nil
@ -177,20 +198,19 @@ func ReCreateRedir(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.P
if redirUDPListener != nil { if redirUDPListener != nil {
if redirUDPListener.RawAddress() == addr { if redirUDPListener.RawAddress() == addr {
return nil return
} }
redirUDPListener.Close() redirUDPListener.Close()
redirUDPListener = nil redirUDPListener = nil
} }
if portIsZero(addr) { if portIsZero(addr) {
return nil return
} }
var err error
redirListener, err = redir.New(addr, tcpIn) redirListener, err = redir.New(addr, tcpIn)
if err != nil { if err != nil {
return err return
} }
redirUDPListener, err = tproxy.NewUDP(addr, udpIn) redirUDPListener, err = tproxy.NewUDP(addr, udpIn)
@ -199,18 +219,24 @@ func ReCreateRedir(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.P
} }
log.Infoln("Redirect proxy listening at: %s", redirListener.Address()) log.Infoln("Redirect proxy listening at: %s", redirListener.Address())
return nil
} }
func ReCreateTProxy(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) error { func ReCreateTProxy(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) {
tproxyMux.Lock() tproxyMux.Lock()
defer tproxyMux.Unlock() defer tproxyMux.Unlock()
var err error
defer func() {
if err != nil {
log.Errorln("Start TProxy server error: %s", err.Error())
}
}()
addr := genAddr(bindAddress, port, allowLan) addr := genAddr(bindAddress, port, allowLan)
if tproxyListener != nil { if tproxyListener != nil {
if tproxyListener.RawAddress() == addr { if tproxyListener.RawAddress() == addr {
return nil return
} }
tproxyListener.Close() tproxyListener.Close()
tproxyListener = nil tproxyListener = nil
@ -218,20 +244,19 @@ func ReCreateTProxy(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.
if tproxyUDPListener != nil { if tproxyUDPListener != nil {
if tproxyUDPListener.RawAddress() == addr { if tproxyUDPListener.RawAddress() == addr {
return nil return
} }
tproxyUDPListener.Close() tproxyUDPListener.Close()
tproxyUDPListener = nil tproxyUDPListener = nil
} }
if portIsZero(addr) { if portIsZero(addr) {
return nil return
} }
var err error
tproxyListener, err = tproxy.New(addr, tcpIn) tproxyListener, err = tproxy.New(addr, tcpIn)
if err != nil { if err != nil {
return err return
} }
tproxyUDPListener, err = tproxy.NewUDP(addr, udpIn) tproxyUDPListener, err = tproxy.NewUDP(addr, udpIn)
@ -240,13 +265,19 @@ func ReCreateTProxy(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.
} }
log.Infoln("TProxy server listening at: %s", tproxyListener.Address()) log.Infoln("TProxy server listening at: %s", tproxyListener.Address())
return nil
} }
func ReCreateMixed(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) error { func ReCreateMixed(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) {
mixedMux.Lock() mixedMux.Lock()
defer mixedMux.Unlock() defer mixedMux.Unlock()
var err error
defer func() {
if err != nil {
log.Errorln("Start Mixed(http+socks) server error: %s", err.Error())
}
}()
addr := genAddr(bindAddress, port, allowLan) addr := genAddr(bindAddress, port, allowLan)
shouldTCPIgnore := false shouldTCPIgnore := false
@ -270,27 +301,25 @@ func ReCreateMixed(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.P
} }
if shouldTCPIgnore && shouldUDPIgnore { if shouldTCPIgnore && shouldUDPIgnore {
return nil return
} }
if portIsZero(addr) { if portIsZero(addr) {
return nil return
} }
var err error
mixedListener, err = mixed.New(addr, tcpIn) mixedListener, err = mixed.New(addr, tcpIn)
if err != nil { if err != nil {
return err return
} }
mixedUDPLister, err = socks.NewUDP(addr, udpIn) mixedUDPLister, err = socks.NewUDP(addr, udpIn)
if err != nil { if err != nil {
mixedListener.Close() mixedListener.Close()
return err return
} }
log.Infoln("Mixed(http+socks) proxy listening at: %s", mixedListener.Address()) log.Infoln("Mixed(http+socks) proxy listening at: %s", mixedListener.Address())
return nil
} }
func ReCreateTun(conf config.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) error { func ReCreateTun(conf config.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) error {

View File

@ -20,7 +20,7 @@ var (
const ( const (
PROXY_FWMARK = "0x2d0" PROXY_FWMARK = "0x2d0"
PROXY_ROUTE_TABLE = "0x2d0" PROXY_ROUTE_TABLE = "0x2d0"
USERNAME = "clash" USERNAME = "Clash.Meta"
) )
func SetTProxyLinuxIPTables(ifname string, tport int, dport int) error { func SetTProxyLinuxIPTables(ifname string, tport int, dport int) error {

View File

@ -1,12 +1,5 @@
package dev package dev
import (
"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
@ -17,50 +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("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("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, "198.18.0.1")
if err := cmd.Run(); err != nil {
log.Errorln("[auto route] Failed to add system route: %s, cmd: %s", err.Error(), cmd.String())
}
}
func delLinuxSystemRoute(net string) {
if runtime.GOOS != "darwin" && runtime.GOOS != "linux" {
return
}
cmd := exec.Command("route", "delete", "-net", net, "198.18.0.1")
_ = cmd.Run()
//if err := cmd.Run(); err != nil {
// log.Errorln("[auto route]Failed to delete system route: %s, cmd: %s", err.Error(), cmd.String())
//}
}

View File

@ -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 return "", err
err := cmd.Run() } else {
resultString := string(result)
reg, err := regexp.Compile("(interface:)(.*)")
if err != nil { if err != nil {
return "", err return "", err
} }
if out.Len() == 0 { matchResult := reg.FindStringSubmatch(resultString)
return "", errors.New("interface not found by default route") 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())
} }
return out.String(), nil
} }

View File

@ -7,10 +7,12 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"github.com/Dreamacro/clash/log"
"net/url" "net/url"
"os" "os"
"os/exec" "os/exec"
"strconv" "strconv"
"strings"
"sync" "sync"
"syscall" "syscall"
"unsafe" "unsafe"
@ -37,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://clash0") 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{
@ -54,9 +56,16 @@ func OpenTunDevice(tunAddress string, autoRoute bool) (TunDevice, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if autoRoute {
SetLinuxAutoRoute() err = t.configInterface()
if err != nil {
return nil, err
} }
if autoRoute {
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)
@ -69,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
} }
@ -98,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()
}) })
@ -128,7 +134,9 @@ func (t *tunLinux) openDeviceByName(name string) (TunDevice, error) {
if len(nameBytes) >= unix.IFNAMSIZ { if len(nameBytes) >= unix.IFNAMSIZ {
return nil, errors.New("interface name too long") return nil, errors.New("interface name too long")
} }
copy(ifr[:], nameBytes) copy(ifr[:], nameBytes)
*(*uint16)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = flags *(*uint16)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = flags
_, _, errno := unix.Syscall( _, _, errno := unix.Syscall(
@ -140,11 +148,11 @@ func (t *tunLinux) openDeviceByName(name string) (TunDevice, error) {
if errno != 0 { if errno != 0 {
return nil, errno return nil, errno
} }
err = unix.SetNonblock(nfd, true) err = unix.SetNonblock(nfd, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Note that the above -- open,ioctl,nonblock -- must happen prior to handing it to netpoll as below this line. // Note that the above -- open,ioctl,nonblock -- must happen prior to handing it to netpoll as below this line.
t.tunFile = os.NewFile(uintptr(nfd), cloneDevicePath) t.tunFile = os.NewFile(uintptr(nfd), cloneDevicePath)
@ -157,6 +165,74 @@ func (t *tunLinux) openDeviceByName(name string) (TunDevice, error) {
return t, nil return t, nil
} }
func (t *tunLinux) configInterface() error {
var ifr [ifReqSize]byte
nameBytes := []byte(t.name)
if len(nameBytes) >= unix.IFNAMSIZ {
return errors.New("interface name too long")
}
copy(ifr[:], nameBytes)
fd, _, errno := syscall.Syscall(unix.SYS_SOCKET, unix.AF_INET, unix.SOCK_STREAM, 0)
if errno != 0 {
return errno
}
// set addr for tun
var ip []byte
for _, num := range strings.Split(t.tunAddress, ".") {
value, err := strconv.Atoi(num)
if err != nil {
return err
}
ip = append(ip, byte(value))
}
*(*uint16)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = uint16(unix.AF_INET)
copy(ifr[unix.IFNAMSIZ+4:], ip)
_, _, errno = unix.Syscall(
unix.SYS_IOCTL,
fd,
uintptr(unix.SIOCSIFADDR),
uintptr(unsafe.Pointer(&ifr[0])))
if errno != 0 {
return errno
}
// set netmask for tun
netmask := []byte{255, 255, 0, 0}
copy(ifr[unix.IFNAMSIZ+4:], netmask)
_, _, errno = unix.Syscall(
unix.SYS_IOCTL,
fd,
uintptr(unix.SIOCSIFNETMASK),
uintptr(unsafe.Pointer(&ifr[0])))
if errno != 0 {
return errno
}
// interface up
_, _, errno = syscall.Syscall(unix.SYS_IOCTL, fd, uintptr(unix.SIOCSIFFLAGS), uintptr(unsafe.Pointer(&ifr[0])))
var flags = uint16(unix.IFF_UP | unix.IFF_TUN | unix.IFF_MULTICAST | unix.IFF_RUNNING | unix.IFF_NOARP)
*(*uint16)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = flags
_, _, errno = syscall.Syscall(
unix.SYS_IOCTL,
fd,
uintptr(unix.SIOCSIFFLAGS),
uintptr(unsafe.Pointer(&ifr[0])))
if errno != 0 {
return errno
}
return nil
}
func (t *tunLinux) openDeviceByFd(fd int) (TunDevice, error) { func (t *tunLinux) openDeviceByFd(fd int) (TunDevice, error) {
var ifr struct { var ifr struct {
name [16]byte name [16]byte
@ -253,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())
}
}

View File

@ -50,7 +50,7 @@ func OpenTunDevice(tunAddress string, autoRoute bool) (TunDevice, error) {
log.Warnln("Error parese GUID from string: %v", err) log.Warnln("Error parese GUID from string: %v", err)
} }
interfaceName := "Clash.Mini" interfaceName := "Meta Tunnel"
mtu := 9000 mtu := 9000
tun, err := CreateTUN(interfaceName, mtu, tunAddress, autoRoute) tun, err := CreateTUN(interfaceName, mtu, tunAddress, autoRoute)

View File

@ -86,5 +86,7 @@ func (session Session) AllocateSendPacket(packetSize int) (packet []byte, err er
} }
func (session Session) SendPacket(packet []byte) { func (session Session) SendPacket(packet []byte) {
if packet != nil && len(packet) > 0 {
syscall.Syscall(procWintunSendPacket.Addr(), 2, session.handle, uintptr(unsafe.Pointer(&packet[0])), 0) syscall.Syscall(procWintunSendPacket.Addr(), 2, session.handle, uintptr(unsafe.Pointer(&packet[0])), 0)
} }
}

View File

@ -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,8 +47,8 @@ type gvisorAdapter struct {
writeHandle *channel.NotificationHandle writeHandle *channel.NotificationHandle
} }
// GvisorAdapter create GvisorAdapter // NewAdapter GvisorAdapter create GvisorAdapter
func NewAdapter(device dev.TunDevice, conf config.Tun, tunAddress string, 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},
TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol, udp.NewProtocol}, TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol, udp.NewProtocol},
@ -113,7 +113,7 @@ func NewAdapter(device dev.TunDevice, conf config.Tun, tunAddress string, tcpIn
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 +132,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()
} }

View File

@ -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
tcpListeners []net.Listener
resolver *dns.Resolver 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,7 @@ 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", id.LocalAddress.String(), id.LocalPort)
go e.server.ServeDNS(&writer, &msg) go e.server.ServeDNS(&writer, &msg)
} }
@ -129,26 +149,66 @@ 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
handler := dns.NewHandler(resolver, mapper)
serverIn := &dns.Server{}
serverIn.SetHandler(handler)
tcpDnsArr := make([]net.TCPAddr, 0, len(dnsHijack))
udpDnsArr := make([]net.UDPAddr, 0, len(dnsHijack))
for _, d := range dnsHijack {
switch d.(type) {
case *net.TCPAddr:
{
tcpDnsArr = append(tcpDnsArr, *d.(*net.TCPAddr))
break
}
case *net.UDPAddr:
{
udpDnsArr = append(udpDnsArr, *d.(*net.UDPAddr))
break
}
}
}
endpoints, ids := hijackUdpDns(udpDnsArr, s, serverIn)
tcpListeners, dnsServers := hijackTcpDns(tcpDnsArr, s, serverIn)
server := &DNSServer{
resolver: resolver,
stack: s,
udpEndpoints: endpoints,
udpEndpointIDs: ids,
NICID: nicID,
tcpListeners: tcpListeners,
}
server.dnsServers = dnsServers
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)} address := tcpip.FullAddress{NIC: nicID, Port: uint16(port)}
var protocol tcpip.NetworkProtocolNumber var protocol tcpip.NetworkProtocolNumber
if ip.To4() != nil { if ip.To4() != nil {
v4 = true
address.Addr = tcpip.Address(ip.To4()) address.Addr = tcpip.Address(ip.To4())
protocol = ipv4.ProtocolNumber protocol = ipv4.ProtocolNumber
} else { } else {
v4 = false
address.Addr = tcpip.Address(ip.To16()) address.Addr = tcpip.Address(ip.To16())
protocol = ipv6.ProtocolNumber protocol = ipv6.ProtocolNumber
} }
protocolAddr := tcpip.ProtocolAddress{ protocolAddr := tcpip.ProtocolAddress{
Protocol: protocol, Protocol: protocol,
AddressWithPrefix: address.Addr.WithPrefix(), AddressWithPrefix: address.Addr.WithPrefix(),
} }
// netstack will only reassemble IP fragments when its' dest ip address is registered in NIC.endpoints // 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 { if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil {
log.Errorln("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err) log.Errorln("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err)
@ -158,10 +218,6 @@ func CreateDNSServer(s *stack.Stack, resolver *dns.Resolver, mapper *dns.Resolve
address.Addr = "" address.Addr = ""
} }
handler := dns.NewHandler(resolver, mapper)
serverIn := &dns.Server{}
serverIn.SetHandler(handler)
// UDP DNS // UDP DNS
id := &stack.TransportEndpointID{ id := &stack.TransportEndpointID{
LocalAddress: address.Addr, LocalAddress: address.Addr,
@ -190,44 +246,72 @@ func CreateDNSServer(s *stack.Stack, resolver *dns.Resolver, mapper *dns.Resolve
log.Errorln("Unable to start UDP DNS on tun: %v", tcpiperr.String()) log.Errorln("Unable to start UDP DNS on tun: %v", tcpiperr.String())
} }
// TCP DNS 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 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 { if v4 {
tcpListener, err = gonet.ListenTCP(s, address, ipv4.ProtocolNumber) tcpListener, err = gonet.ListenTCP(s, address, ipv4.ProtocolNumber)
} else { } else {
tcpListener, err = gonet.ListenTCP(s, address, ipv6.ProtocolNumber) tcpListener, err = gonet.ListenTCP(s, address, ipv6.ProtocolNumber)
} }
if err != nil { if err != nil {
return nil, fmt.Errorf("can not listen on tun: %v", err) 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
} }
server := &DNSServer{
Server: serverIn,
resolver: resolver,
stack: s,
tcpListener: tcpListener,
udpEndpoint: endpoint,
udpEndpointID: id,
NICID: nicID,
} }
server.SetHandler(handler) //
server.Server.Server = &D.Server{Listener: tcpListener, Handler: server} //for _, listener := range tcpListeners {
// server := &D.Server{Listener: listener, Handler: serverIn}
//
// dnsServers = append(dnsServers, &dnsServer)
// go dnsServer.ActivateAndServe()
//}
go func() { return tcpListeners, dnsServers
server.ActivateAndServe()
}()
return server, err
} }
// 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 // remove udp endpoint from stack
s.stack.UnregisterTransportEndpoint( s.stack.UnregisterTransportEndpoint(
[]tcpip.NetworkProtocolNumber{ []tcpip.NetworkProtocolNumber{
@ -235,57 +319,106 @@ func (s *DNSServer) Stop() {
ipv6.ProtocolNumber, ipv6.ProtocolNumber,
}, },
udp.ProtocolNumber, udp.ProtocolNumber,
*s.udpEndpointID, *id,
s.udpEndpoint, ep,
ports.Flags{LoadBalanced: true}, // should match the RegisterTransportEndpoint ports.Flags{LoadBalanced: true}, // should match the RegisterTransportEndpoint
s.NICID) s.NICID)
} }
// DNSListen return the listening address of DNS Server for _, server := range s.dnsServers {
func (t *gvisorAdapter) DNSListen() string { server.Shutdown()
if t.dnsserver != nil {
id := t.dnsserver.udpEndpointID
return fmt.Sprintf("%s:%d", id.LocalAddress.String(), id.LocalPort)
}
return ""
} }
// Stop stop the DNS Server on tun for _, listener := range s.tcpListeners {
func (t *gvisorAdapter) ReCreateDNSServer(resolver *dns.Resolver, mapper *dns.ResolverEnhancer, addr string) error { listener.Close()
if addr == "" && t.dnsserver == nil { }
return nil
} }
if addr == t.DNSListen() && t.dnsserver != nil && t.dnsserver.resolver == resolver { // DnsHijack return the listening address of DNS Server
return nil func (t *gvisorAdapter) DnsHijack() []string {
dnsHijackArr := make([]string, len(t.dnsServer.udpEndpoints))
for _, id := range t.dnsServer.udpEndpointIDs {
dnsHijackArr = append(dnsHijackArr, fmt.Sprintf("%s:%d", id.LocalAddress.String(), id.LocalPort))
} }
if t.dnsserver != nil { return dnsHijackArr
t.dnsserver.Stop() }
t.dnsserver = nil
func (t *gvisorAdapter) StopDNSServer() {
t.dnsServer.Stop()
log.Debugln("tun DNS server stoped") log.Debugln("tun DNS server stoped")
t.dnsServer = nil
} }
var err error // ReCreateDNSServer recreate the DNS Server on tun
_, port, err := net.SplitHostPort(addr) func (t *gvisorAdapter) ReCreateDNSServer(resolver *dns.Resolver, mapper *dns.ResolverEnhancer, dnsHijackArr []string) error {
if port == "0" || port == "" || err != nil { t.StopDNSServer()
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 { if err != nil {
return err return err
} }
server, err := CreateDNSServer(t.ipstack, resolver, mapper, udpAddr.IP, udpAddr.Port, nicID) 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 { if err != nil {
return err return err
} }
t.dnsserver = server
log.Infoln("Tun DNS server listening at: %s, fake ip enabled: %v", addr, mapper.FakeIPEnabled()) 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 {
return err
}
t.dnsServer = server
return nil return nil
} }

View File

@ -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
} }

View File

@ -21,7 +21,7 @@ type systemAdapter struct {
tun *tun2socket.Tun2Socket tun *tun2socket.Tun2Socket
lock sync.Mutex lock sync.Mutex
stackName string stackName string
dnsListen string dnsHackjack []string
autoRoute bool autoRoute bool
} }
@ -29,14 +29,14 @@ func NewAdapter(device dev.TunDevice, conf config.Tun, mtu int, gateway, mirror
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() {

View File

@ -4,6 +4,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"strings" "strings"
"time"
"github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/adapter/inbound"
"github.com/Dreamacro/clash/config" "github.com/Dreamacro/clash/config"
@ -23,9 +24,19 @@ func New(conf config.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.Pack
var tunAdapter ipstack.TunAdapter var tunAdapter ipstack.TunAdapter
device, err := dev.OpenTunDevice(tunAddress, autoRoute) device, err := dev.OpenTunDevice(tunAddress, autoRoute)
if err != nil {
for i := 1; i < 3; i++ {
time.Sleep(time.Second * 1)
device, err = dev.OpenTunDevice(tunAddress, autoRoute)
if err == nil {
break
}
}
if err != nil { if err != nil {
return nil, fmt.Errorf("can't open tun: %v", err) return nil, fmt.Errorf("can't open tun: %v", err)
} }
}
mtu, err := device.MTU() mtu, err := device.MTU()
if err != nil { if err != nil {
@ -36,7 +47,7 @@ func New(conf config.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.Pack
if strings.EqualFold(stack, "system") { if strings.EqualFold(stack, "system") {
tunAdapter, err = system.NewAdapter(device, conf, mtu, tunAddress, tunAddress, func() {}, tcpIn, udpIn) tunAdapter, err = system.NewAdapter(device, conf, mtu, tunAddress, tunAddress, func() {}, tcpIn, udpIn)
} else if strings.EqualFold(stack, "gvisor") { } else if strings.EqualFold(stack, "gvisor") {
tunAdapter, err = gvisor.NewAdapter(device, conf, tunAddress, tcpIn, udpIn) tunAdapter, err = gvisor.NewAdapter(device, conf, tcpIn, udpIn)
} else { } else {
err = fmt.Errorf("can not support tun ip stack: %s, only support \"lwip\" \"system\" and \"gvisor\"", stack) err = fmt.Errorf("can not support tun ip stack: %s, only support \"lwip\" \"system\" and \"gvisor\"", stack)
} }

View File

@ -48,7 +48,7 @@ func init() {
func main() { func main() {
_, _ = maxprocs.Set(maxprocs.Logger(func(string, ...interface{}) {})) _, _ = maxprocs.Set(maxprocs.Logger(func(string, ...interface{}) {}))
if version { if version {
fmt.Printf("Clash Plus Pro %s %s %s with %s %s\n", C.Version, runtime.GOOS, runtime.GOARCH, runtime.Version(), C.BuildTime) fmt.Printf("Clash Meta %s %s %s with %s %s\n", C.Version, runtime.GOOS, runtime.GOARCH, runtime.Version(), C.BuildTime)
return return
} }

View File

@ -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 {

View File

@ -1,4 +1,4 @@
package rules package common
import ( import (
"strings" "strings"

View File

@ -1,4 +1,4 @@
package rules package common
import ( import (
"strings" "strings"

View File

@ -1,4 +1,4 @@
package rules package common
import ( import (
"strings" "strings"

View File

@ -1,4 +1,4 @@
package rules package common
import ( import (
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"

View File

@ -1,4 +1,4 @@
package rules package common
import ( import (
"strings" "strings"

View File

@ -1,4 +1,4 @@
package rules package common
import ( import (
"fmt" "fmt"

View File

@ -1,4 +1,4 @@
package rules package common
import ( import (
"net" "net"

View 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
}

View File

@ -1,4 +1,4 @@
package rules package common
import ( import (
"fmt" "fmt"

View File

@ -1,4 +1,4 @@
package rules package common
import ( import (
"fmt" "fmt"
@ -27,13 +27,15 @@ func (ps *Process) Match(metadata *C.Metadata) bool {
if metadata.Process != "" { if metadata.Process != "" {
return strings.EqualFold(metadata.Process, ps.process) return strings.EqualFold(metadata.Process, ps.process)
} }
// ignore match in proxy type "tproxy" // ignore match in proxy type "tproxy"
if metadata.Type == C.TPROXY { //if metadata.Type == C.TPROXY || !C.AutoIptables {
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)
if strings.TrimSpace(metadata.Process) == "" {
cached, hit := processCache.Get(key) cached, hit := processCache.Get(key)
if !hit { if !hit {
srcPort, err := strconv.Atoi(metadata.SrcPort) srcPort, err := strconv.Atoi(metadata.SrcPort)
@ -53,6 +55,7 @@ func (ps *Process) Match(metadata *C.Metadata) bool {
} }
metadata.Process = cached.(string) 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
View 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
View 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
View 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
View 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
}

View File

@ -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
}

View File

@ -1,4 +1,4 @@
package rules package provider
import ( import (
"bytes" "bytes"

90
rule/provider/parse.go Normal file
View 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
}

View File

@ -1,4 +1,4 @@
package rules package provider
import ( import (
"encoding/json" "encoding/json"
@ -13,7 +13,7 @@ import (
) )
var ( var (
ruleProviders = map[string]*P.RuleProvider{} ruleProviders = map[string]P.RuleProvider{}
) )
type ruleSetProvider struct { type ruleSetProvider struct {
@ -38,13 +38,13 @@ type RulePayload struct {
Rules []string `yaml:"payload"` Rules []string `yaml:"payload"`
} }
func RuleProviders() map[string]*P.RuleProvider { func RuleProviders() map[string]P.RuleProvider {
return ruleProviders return ruleProviders
} }
func SetRuleProvider(ruleProvider *P.RuleProvider) { func SetRuleProvider(ruleProvider P.RuleProvider) {
if ruleProvider != nil { if ruleProvider != nil {
ruleProviders[(*ruleProvider).Name()] = ruleProvider ruleProviders[(ruleProvider).Name()] = ruleProvider
} }
} }
@ -75,6 +75,10 @@ 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.Search(metadata.Host) != nil
@ -126,7 +130,6 @@ func NewRuleSetProvider(name string, behavior P.RuleType, interval time.Duration
return err return err
} }
rp.shouldResolveIP = false
rp.setRules(rules) rp.setRules(rules)
return nil return nil
} }
@ -202,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
} }
@ -242,5 +245,6 @@ func (rp *ruleSetProvider) setRules(rules interface{}) {
rp.IPCIDRRules = rules.(*trie.IpCidrTrie) rp.IPCIDRRules = rules.(*trie.IpCidrTrie)
rp.shouldResolveIP = true rp.shouldResolveIP = true
default: default:
rp.shouldResolveIP = false
} }
} }

View File

@ -1,4 +1,4 @@
package rules package provider
import ( import (
"fmt" "fmt"
@ -9,7 +9,7 @@ import (
type RuleSet struct { type RuleSet struct {
ruleProviderName string ruleProviderName string
adapter string adapter string
ruleProvider *P.RuleProvider ruleProvider P.RuleProvider
ruleExtra *C.RuleExtra ruleExtra *C.RuleExtra
} }
@ -30,7 +30,7 @@ func (rs *RuleSet) Payload() string {
} }
func (rs *RuleSet) ShouldResolveIP() bool { func (rs *RuleSet) ShouldResolveIP() bool {
return rs.getProviders().Behavior() != P.Domain return rs.getProviders().ShouldResolveIP()
} }
func (rs *RuleSet) getProviders() P.RuleProvider { func (rs *RuleSet) getProviders() P.RuleProvider {
if rs.ruleProvider == nil { if rs.ruleProvider == nil {
@ -38,7 +38,7 @@ func (rs *RuleSet) getProviders() P.RuleProvider {
rs.ruleProvider = rp rs.ruleProvider = rp
} }
return *rs.ruleProvider return rs.ruleProvider
} }
func (rs *RuleSet) RuleExtra() *C.RuleExtra { func (rs *RuleSet) RuleExtra() *C.RuleExtra {

View File

@ -15,10 +15,10 @@ import (
"testing" "testing"
"time" "time"
"github.com/Dreamacro/clash/adapter/outbound" "github.com/Dreamacro/Clash.Meta/adapter/outbound"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/Clash.Meta/constant"
"github.com/Dreamacro/clash/hub/executor" "github.com/Dreamacro/Clash.Meta/hub/executor"
"github.com/Dreamacro/clash/transport/socks5" "github.com/Dreamacro/Clash.Meta/transport/socks5"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/client" "github.com/docker/docker/client"
@ -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"
) )

View File

@ -4,11 +4,11 @@ go 1.17
require ( require (
github.com/Dreamacro/clash v1.7.2-0.20211108085948-bd2ea2b917aa github.com/Dreamacro/clash v1.7.2-0.20211108085948-bd2ea2b917aa
github.com/docker/docker v20.10.10+incompatible github.com/docker/docker v20.10.12+incompatible
github.com/docker/go-connections v0.4.0 github.com/docker/go-connections v0.4.0
github.com/miekg/dns v1.1.43 github.com/miekg/dns v1.1.45
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
golang.org/x/net v0.0.0-20211105192438-b53810dc28af golang.org/x/net v0.0.0-20211216030914-fe4d6282115f
) )
replace github.com/Dreamacro/clash => ../ replace github.com/Dreamacro/clash => ../
@ -16,22 +16,22 @@ replace github.com/Dreamacro/clash => ../
require ( require (
github.com/Dreamacro/go-shadowsocks2 v0.1.7 // indirect github.com/Dreamacro/go-shadowsocks2 v0.1.7 // indirect
github.com/Microsoft/go-winio v0.5.1 // indirect github.com/Microsoft/go-winio v0.5.1 // indirect
github.com/containerd/containerd v1.5.7 // indirect github.com/containerd/containerd v1.5.8 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/docker/distribution v2.7.1+incompatible // indirect github.com/docker/distribution v2.7.1+incompatible // indirect
github.com/docker/go-units v0.4.0 // indirect github.com/docker/go-units v0.4.0 // indirect
github.com/gofrs/uuid v4.1.0+incompatible // indirect github.com/gofrs/uuid v4.2.0+incompatible // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.2 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/google/btree v1.0.1 // indirect github.com/google/btree v1.0.1 // indirect
github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/websocket v1.4.2 // indirect github.com/gorilla/websocket v1.4.2 // indirect
github.com/insomniacslk/dhcp v0.0.0-20211026125128-ad197bcd36fd // indirect github.com/insomniacslk/dhcp v0.0.0-20211214070828-5297eed8f489 // indirect
github.com/kr328/tun2socket v0.0.0-20210412191540-3d56c47e2d99 // indirect github.com/kr328/tun2socket v0.0.0-20210412191540-3d56c47e2d99 // indirect
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
github.com/morikuni/aec v1.0.0 // indirect github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.1 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/oschwald/geoip2-golang v1.5.0 // indirect github.com/oschwald/geoip2-golang v1.5.0 // indirect
github.com/oschwald/maxminddb-golang v1.8.0 // indirect github.com/oschwald/maxminddb-golang v1.8.0 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
@ -42,8 +42,17 @@ require (
github.com/yaling888/go-lwip v0.0.0-20211103185822-c9d650538091 // indirect github.com/yaling888/go-lwip v0.0.0-20211103185822-c9d650538091 // indirect
go.etcd.io/bbolt v1.3.6 // indirect go.etcd.io/bbolt v1.3.6 // indirect
go.uber.org/atomic v1.9.0 // indirect go.uber.org/atomic v1.9.0 // indirect
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
golang.org/x/mod v0.4.2 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
golang.org/x/text v0.3.6 // indirect
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a // indirect
google.golang.org/grpc v1.43.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
golang.org/x/sys v0.0.0-20211107104306-e0b2ad06fe42 // indirect golang.org/x/sys v0.0.0-20211107104306-e0b2ad06fe42 // 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-20210723032227-1f47c861a9ac // indirect golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect

View File

@ -83,7 +83,7 @@ github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg3
github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg=
github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
@ -118,7 +118,7 @@ github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
github.com/cenkalti/backoff v1.1.1-0.20190506075156-2146c9339422/go.mod h1:b6Nc7NRH5C4aCISLry0tLnTjcuTEvoiqcWDdsU0sOGM= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@ -170,13 +170,13 @@ github.com/containerd/containerd v1.3.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMX
github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.4.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ= github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ=
github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU= github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU=
github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI= github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI=
github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s= github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s=
github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g= github.com/containerd/containerd v1.5.8 h1:NmkCC1/QxyZFBny8JogwLpOy2f+VEbO/f6bV2Mqtwuw=
github.com/containerd/containerd v1.5.7 h1:rQyoYtj4KddB3bxG6SAqd4+08gePNyJjRqvOIfV3rkM= github.com/containerd/containerd v1.5.8/go.mod h1:YdFSv5bTFLpG2HIYmfqDpSYYTDX+mc5qtSuYx1YUb/s=
github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
@ -210,6 +210,7 @@ github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDG
github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8=
github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ=
github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk=
github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg=
@ -264,10 +265,9 @@ github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TT
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+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/docker v20.10.10+incompatible h1:GKkP0T7U4ks6X3lmmHKC2QDprnpRJor2Z5a8m62R9ZM=
github.com/docker/docker v20.10.10+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/docker v20.10.12+incompatible h1:CEeNmFM0QZIsJCZKMkZx0ZcahTiewkrgiwfYD+dfl1U=
github.com/docker/docker v20.10.12+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
@ -306,7 +306,7 @@ github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXt
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-chi/chi/v5 v5.0.5/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1OvJns= github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1OvJns=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
@ -336,9 +336,8 @@ github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblf
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
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.1.0+incompatible h1:sIa2eCvUTwgjbqXrPLfNwUf9S3i3mpH1O1atV+iL/Wk= github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU=
github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=
github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4=
@ -471,8 +470,8 @@ github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
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-20211026125128-ad197bcd36fd h1:jupbuQFZtwOBg/3EmK91/rGaYFkqCb9bwHOnwn7Cav0= github.com/insomniacslk/dhcp v0.0.0-20211214070828-5297eed8f489 h1:jhdHqd7DxBrzfuFSoPxjD6nUVaV/1RIn9aHA0WCf/as=
github.com/insomniacslk/dhcp v0.0.0-20211026125128-ad197bcd36fd/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E= github.com/insomniacslk/dhcp v0.0.0-20211214070828-5297eed8f489/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E=
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
@ -532,8 +531,8 @@ github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcK
github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o= github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=
github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg= github.com/miekg/dns v1.1.45 h1:g5fRIhm9nx7g8osrAvgb16QJfmyMsyOCb+J7LSv+Qzk=
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= github.com/miekg/dns v1.1.45/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@ -584,8 +583,9 @@ github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
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.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
github.com/opencontainers/image-spec v1.0.2/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 v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
@ -730,13 +730,6 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q
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-20201118062508-3632bf3b7499 h1:QHESTXtfgc1ABV+ArlbPVqUx9Ht5I0dDkYhxYoXFxNo=
github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499/go.mod h1:5TB2+k58gx4A4g2Nf5miSHNDF6CuAzHKpWBooLAshTs= github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499/go.mod h1:5TB2+k58gx4A4g2Nf5miSHNDF6CuAzHKpWBooLAshTs=
github.com/yaling888/go-lwip v0.0.0-20211103185822-c9d650538091 h1:uOaYhg8ue1gAzV7KNAz1uc/qvjEDRtl16nvTPYiaphM=
github.com/yaling888/go-lwip v0.0.0-20211103185822-c9d650538091/go.mod h1:Y+f95PkWh183q1oDJxdlxTHa2mpdHG5zvBhV0TUhhSY=
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.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
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/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
@ -781,8 +774,8 @@ golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/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-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -815,6 +808,8 @@ 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.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.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.1/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=
@ -866,11 +861,6 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/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-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211105192438-b53810dc28af h1:SMeNJG/vclJ5wyBBd4xupMsSJIHTd1coW9g7q6KOjmY= golang.org/x/net v0.0.0-20211105192438-b53810dc28af h1:SMeNJG/vclJ5wyBBd4xupMsSJIHTd1coW9g7q6KOjmY=
golang.org/x/net v0.0.0-20211105192438-b53810dc28af/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211105192438-b53810dc28af/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -878,14 +868,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=
@ -978,39 +960,24 @@ golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/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-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-20210303074136-134d130e1a04/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-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/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-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/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-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-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-20210809222454-d867a43fc93e/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-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211107104306-e0b2ad06fe42 h1:G2DDmludOQZoWbpCr7OKDxnl478ZBGMcOhrv+ooX/Q4= golang.org/x/sys v0.0.0-20211107104306-e0b2ad06fe42 h1:G2DDmludOQZoWbpCr7OKDxnl478ZBGMcOhrv+ooX/Q4=
golang.org/x/sys v0.0.0-20211107104306-e0b2ad06fe42/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211107104306-e0b2ad06fe42/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b h1:NXqSWXSRUSCaFuvitrWtU169I3876zRTalMRbfd6LL0=
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -1020,7 +987,6 @@ golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2M
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@ -1053,38 +1019,14 @@ golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
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-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.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
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=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.zx2c4.com/wireguard/windows v0.5.1 h1:OnYw96PF+CsIMrqWo5QP3Q59q5hY1rFErk/yN3cS+JQ=
golang.zx2c4.com/wireguard/windows v0.5.1/go.mod h1:EApyTk/ZNrkbZjurHL1nleDYnsPpJYBO7LZEBCyDAHk=
google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
@ -1095,29 +1037,12 @@ google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.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.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=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@ -1138,38 +1063,11 @@ google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvx
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a h1:pOwg4OoaRYScjmR4LlLgdtnyoHYTSAVhhqe5uPdpII8=
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-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-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/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 h1:YORWxaStkWBnWgELOHTmDrqNlFXuVGEbhwbB5iK94bQ=
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
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=
@ -1182,25 +1080,12 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
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.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.43.0 h1:Eeu7bZtDZ2DpRCsLhUlcrLnvYaMK1Gz86a+hMVvELmM=
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
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.42.0-dev.0.20211020220737-f00baa6c3c84/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A=
google.golang.org/grpc v1.42.0/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=

View File

@ -5,8 +5,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/Dreamacro/clash/adapter/outbound" "github.com/Dreamacro/Clash.Meta/adapter/outbound"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/Clash.Meta/constant"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -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,

View File

@ -4,7 +4,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/Dreamacro/clash/adapter/outbound" "github.com/Dreamacro/Clash.Meta/adapter/outbound"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"

View File

@ -5,8 +5,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/Dreamacro/clash/adapter/outbound" "github.com/Dreamacro/Clash.Meta/adapter/outbound"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/Clash.Meta/constant"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"

View File

@ -5,8 +5,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/Dreamacro/clash/adapter/outbound" "github.com/Dreamacro/Clash.Meta/adapter/outbound"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/Clash.Meta/constant"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"

View File

@ -5,8 +5,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/Dreamacro/clash/adapter/outbound" "github.com/Dreamacro/Clash.Meta/adapter/outbound"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/Clash.Meta/constant"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"

View File

@ -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
} }

View File

@ -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
}

View File

@ -1,6 +1,7 @@
package trojan package trojan
import ( import (
"context"
"crypto/sha256" "crypto/sha256"
"crypto/tls" "crypto/tls"
"encoding/binary" "encoding/binary"
@ -12,6 +13,7 @@ import (
"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"
) )
@ -68,7 +70,11 @@ func (t *Trojan) StreamConn(conn net.Conn) (net.Conn, error) {
} }
tlsConn := tls.Client(conn, tlsConfig) tlsConn := tls.Client(conn, tlsConfig)
if err := tlsConn.Handshake(); err != nil {
// 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 nil, err
} }

View File

@ -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
} }

View File

@ -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
@ -230,7 +230,7 @@ func handleUDPConn(packet *inbound.PacketAdapter) {
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultUDPTimeout) ctx, cancel := context.WithTimeout(context.Background(), C.DefaultUDPTimeout)
defer cancel() defer cancel()
rawPc, err := proxy.ListenPacketContext(ctx, metadata.Pure()) rawPc, err := proxy.ListenPacketContext(ctx, metadata)
if err != nil { if err != nil {
if rule == nil { if rule == nil {
log.Warnln("[UDP] dial %s to %s error: %s", proxy.Name(), metadata.RemoteAddress(), err.Error()) log.Warnln("[UDP] dial %s to %s error: %s", proxy.Name(), metadata.RemoteAddress(), err.Error())
@ -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
@ -284,7 +288,7 @@ func handleTCPConn(connCtx C.ConnContext) {
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout) ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout)
defer cancel() defer cancel()
remoteConn, err := proxy.DialContext(ctx, metadata.Pure()) remoteConn, err := proxy.DialContext(ctx, metadata)
if err != nil { if err != nil {
if rule == nil { if rule == nil {
log.Warnln("[TCP] dial %s to %s error: %s", proxy.Name(), metadata.RemoteAddress(), err.Error()) log.Warnln("[TCP] dial %s to %s error: %s", proxy.Name(), metadata.RemoteAddress(), err.Error())
@ -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)