Compare commits

...
139 Commits
Author SHA1 Message Date
xjasonlyu 8fcd8fee85 Fix(fd): compile error 2021-11-01 14:01:21 +08:00
xjasonlyu e06cce1dd4 Chore: update go modules
$ go mod tidy -compat=1.17
2021-11-01 13:07:07 +08:00
xjasonlyu 867cfefa76 Chore(workflows/go): ignore docs 2021-10-19 21:13:14 +08:00
xjasonlyu 176324412b Chore: update README 2021-10-19 21:11:29 +08:00
xjasonlyu 66e9c6d4e9 Chore: update modules 2021-10-17 14:30:19 +08:00
xjasonlyu 3928350e57 Chore: minor reposition 2021-10-17 14:29:08 +08:00
xjasonlyu f6ba31f121 Feature: support fd device
Experimental support for file descriptor based device, may be used like `fd://3`
2021-10-17 14:21:37 +08:00
xjasonlyu bf3f4599cc Chore(tun): remove with options 2021-10-17 14:12:54 +08:00
xjasonlyu dc8e4f1ba1 Feature: new fd driver 2021-10-17 14:07:11 +08:00
xjasonlyu ad53cc7ffe Chore: correct a typo 2021-10-12 19:55:21 +08:00
xjasonlyu 10022388a0 Chore(workflows): ignore GSC tags 2021-10-04 13:32:18 +08:00
xjasonlyu 377aae12c7 Platform: Windows ARM64 2021-10-04 13:13:31 +08:00
xjasonlyu 3f5b3c9eb3 Chore: update go modules 2021-10-04 11:35:37 +08:00
xjasonlyu 07ce5e6422 Feature: socks5 over unix domain socket(UDS) support
this feature is compatible with tor proxy.
2021-09-09 12:50:23 +08:00
xjasonlyu e1ca5069e0 Revert(engine): default scheme
This reverts commit a86608e31a.
2021-09-09 12:10:57 +08:00
xjasonlyu 05f4938053 Chore: minor improvement 2021-09-05 23:34:02 +08:00
xjasonlyu a86608e31a Optimize(engine): default scheme 2021-09-04 22:11:08 +08:00
xjasonlyu c478adee34 Fix: rwbased interface implementation 2021-09-04 21:46:40 +08:00
xjasonlyu a3f1713d14 Chore: update modules 2021-09-04 21:45:56 +08:00
xjasonlyu 525d424fca Chore: go1.17 build constraints 2021-08-21 10:48:37 +08:00
xjasonlyu f1420b9592 Chore: update go modules 2021-08-21 10:38:27 +08:00
xjasonlyu 4601b4ef74 Chore: bump go version to 1.17 2021-08-21 10:29:29 +08:00
xjasonlyu 85cf694b8f Chore: bump mod version 2021-08-13 11:44:34 +08:00
xjasonlyu bf59ddf897 Refactor: move to transport 2021-07-19 14:08:46 +08:00
xjasonlyu ccc35c3c1b Refactor(tunnel): using parseAddr 2021-07-19 14:04:17 +08:00
xjasonlyu e77c12156a Chore: update modules 2021-07-18 16:32:48 +08:00
xjasonlyu f60e5add20 Fix(socks4): various improvement 2021-07-18 16:29:23 +08:00
xjasonlyu ebc275c5f7 Fix(socks4): using io.ReadFull 2021-07-17 13:03:43 +08:00
xjasonlyu b6d4272e58 Chore: disable nightly release 2021-07-17 10:48:19 +08:00
xjasonlyu 591361abb3 Refactor(socks4a): using isReservedIP 2021-07-17 10:44:59 +08:00
xjasonlyu 7dea46e6f2 Chore: update README 2021-07-16 20:26:41 +08:00
xjasonlyu e0d6c6d5af Feature: SOCKS4/SOCKS4A proxy support 2021-07-16 20:23:00 +08:00
xjasonlyu ca331e5ef6 Chore: bump mod version 2021-07-16 18:42:22 +08:00
xjasonlyu ab2f4043f7 Feature: HTTP proxy support 2021-07-16 18:39:46 +08:00
xjasonlyu 33e2aed86c Refactor(proxy): replace with safeConnClose 2021-07-16 17:51:58 +08:00
xjasonlyu c2ad0930b0 Fix: invalid workflow file 2021-07-16 17:07:50 +08:00
xjasonlyu 5e90e34f93 Chore: update actions 2021-07-16 17:05:53 +08:00
xjasonlyu 991ad5a967 Chore: remove NewBase 2021-07-16 16:43:50 +08:00
xjasonlyu 27ecddbbf6 Chore: update go modules
Main modules:
- gvisor.dev/gvisor v0.0.0-20210528151111-2153eaa44276 => v0.0.0-20210715005044-a22d3ae8e0fd
- golang.zx2c4.com/wireguard v0.0.0-20210525143454-64cb82f2b3f5 => v0.0.0-20210624150102-15b24b6179e0
2021-07-15 20:01:55 +08:00
xjasonlyu 842920c39b Feature: add reject proxy 2021-07-15 19:54:56 +08:00
xjasonlyu 67cc84d1d0 Chore: update go modules 2021-05-31 18:33:22 +08:00
xjasonlyu 94c0b4a873 Chore: rename SetForwarding to SetForwardingDefaultAndAllNICs 2021-05-24 17:19:02 +08:00
xjasonlyu 659f4c3020 Chore: update go modules 2021-05-24 17:18:11 +08:00
xjasonlyu b95e2794b3 Chore: comment text 2021-05-13 14:06:07 +08:00
xjasonlyu 70afaf3d55 Fix(stack): update udp transport 2021-05-13 13:29:26 +08:00
xjasonlyu b51ad6feb1 Fix(rwbased): endpoint interface 2021-05-13 13:13:22 +08:00
xjasonlyu 9618b7a7b8 Chore: update go modules
use original gvisor tcpip stack.
2021-05-13 13:10:32 +08:00
xjasonlyu 60021cc0ef Chore: update discussions 2021-05-05 13:40:41 +08:00
xjasonlyu 293fab7635 Chore: update README_ZH 2021-05-05 13:20:33 +08:00
Jason LyuandGitHub 1c4e782314 Update issue templates 2021-05-05 13:01:17 +08:00
xjasonlyu 66710aa203 Fix: panics with invalid ss url (https://github.com/xjasonlyu/tun2socks/issues/49) 2021-05-05 11:59:47 +08:00
xjasonlyu 3f7fdc1d83 Fix: atomic operation panic
This reverts commit 094199656b.
2021-03-22 13:04:49 +08:00
xjasonlyu 1bd8029562 Optimize: use gvisor tun for linux 2021-03-21 21:13:07 +08:00
xjasonlyu a1847d7153 Fix: udp for gvisor stack 2021-03-21 20:57:18 +08:00
xjasonlyu 36144e7484 Chore: update dependencies 2021-03-21 20:44:57 +08:00
xjasonlyu 094199656b Chore: make set operation atomic 2021-03-13 11:50:14 +08:00
xjasonlyu f41b844e43 Chore: minor changes in actions 2021-03-03 12:56:02 +08:00
xjasonlyu 688d74a407 Chore: add more info to socks5 2021-03-03 12:46:31 +08:00
xjasonlyu 1b2dddff31 Chore: update dependencies 2021-03-02 23:25:52 +08:00
xjasonlyu 82ac59b0f2 Fix: invalid argument when set MTU (https://github.com/xjasonlyu/tun2socks/issues/33) 2021-03-01 21:37:46 +08:00
xjasonlyu 6887c1180e Chore: add udp-timeout option to docker image 2021-02-28 14:16:23 +08:00
xjasonlyu 9502706ed9 Feature: add an option to set udp timeout 2021-02-26 14:22:16 +08:00
xjasonlyu ec4d98c4bf Fix: reset udp timeout after sending 2021-02-26 09:50:34 +08:00
xjasonlyu ee932ff16c Chore: update static check command 2021-02-22 14:16:39 +08:00
xjasonlyu a8fdfe537d Chore: update dependencies 2021-02-22 12:39:47 +08:00
xjasonlyu ac07d3d6fd Feature: add 32bit support 2021-02-17 17:42:06 +08:00
xjasonlyu d5d4b17256 Fix: dirty commit string 2021-02-17 17:02:15 +08:00
xjasonlyu 4531a74a20 Feature: add darwin-arm64 support (https://github.com/xjasonlyu/tun2socks/issues/29) 2021-02-17 16:12:01 +08:00
xjasonlyu b15f93225b Chore: bump to go1.16 2021-02-17 16:10:11 +08:00
xjasonlyu edf76afd11 Chore: tidy Dockerfile 2021-02-17 13:32:39 +08:00
xjasonlyu bb702f57d8 Feature: add linux-s390x 2021-02-15 20:18:33 +08:00
xjasonlyu b5980dd79d Chore: update README 2021-02-14 20:46:08 +08:00
xjasonlyu 2fee5a6d55 Chore: update dependencies 2021-02-14 20:41:50 +08:00
xjasonlyu b2b7e8bc46 Chore(tun): minor changes 2021-02-14 20:38:26 +08:00
xjasonlyu 0e1e04acc7 Fix: avoid extra copy on windows 2021-02-14 20:25:04 +08:00
xjasonlyu 361a8133c9 Chore: spaces to tab 2021-02-14 17:33:12 +08:00
xjasonlyu 3f73becd66 Fix: ignore static check 2021-02-14 15:50:44 +08:00
xjasonlyu 14b905c125 Feature: full 64bit support 2021-02-14 15:45:42 +08:00
xjasonlyu 4294f56125 Chore: use gVisor 20210213011838-e7ae604b523e 2021-02-14 11:44:54 +08:00
xjasonlyu d98e2234d9 Chore: always use zip to release 2021-02-14 11:21:36 +08:00
xjasonlyu 43b8dd885d Chore: udp timeout => 60s 2021-02-13 13:18:30 +08:00
xjasonlyu 3e3990ef8d Chore: update README 2021-02-12 14:41:33 +08:00
xjasonlyu 88e9402793 Chore: go workflow ignore docker 2021-02-11 22:26:59 +08:00
xjasonlyu f0129eb7ca Chore: optimize docker/entrypoint.sh 2021-02-11 18:51:05 +08:00
xjasonlyu fe9be45844 Chore: tidy go.sum 2021-02-11 16:56:20 +08:00
xjasonlyu b54d9936f9 Chore: unexported globals with _
Use uber’s go style.
2021-02-11 16:10:40 +08:00
xjasonlyu 7e6a9b6a09 Chore: add a comment to dialer 2021-02-11 16:04:20 +08:00
xjasonlyu 454ea0a49b Fix(log): default level may race
Rename global variables in uber’s style.
2021-02-11 15:56:45 +08:00
xjasonlyu 04d0e1e9a7 Chore: move to wiki 2021-02-11 14:19:37 +08:00
xjasonlyu e849c9a451 Fix(stack/udp): shadow variables 2021-02-11 14:01:36 +08:00
xjasonlyu c28690bfc9 Fix: deprecate metadata.Valid method 2021-02-11 13:55:53 +08:00
xjasonlyu 7955052b01 Chore: adjust version output format 2021-02-11 13:40:01 +08:00
xjasonlyu 7e55b71b30 Fix: replace pflag with flag
pflag was deprecated due to poor maintenance
2021-02-11 13:06:12 +08:00
xjasonlyu c96c5946c8 Fix: /proc/sys permission in docker 2021-02-10 20:21:22 +08:00
xjasonlyu 708b7b234d Chore: update README 2021-02-10 16:55:31 +08:00
xjasonlyu 96e0c8c390 Chore: adapt fwmark option 2021-02-10 16:40:36 +08:00
xjasonlyu 7f7f2913a8 Feature: add fwmark support 2021-02-10 15:46:55 +08:00
xjasonlyu ea62deb0b6 Refactor: rewrite engine 2021-02-10 13:11:11 +08:00
xjasonlyu 34fb632f38 Chore: trim spaces 2021-02-09 14:16:55 +08:00
xjasonlyu 08f236a01c Fix: lost stack log info 2021-02-08 20:23:02 +08:00
xjasonlyu ae77a8a009 Refactor: autonomize core package 2021-02-08 20:04:51 +08:00
xjasonlyu 203e545241 Chore: update README 2021-02-08 18:55:58 +08:00
xjasonlyu 136c90d310 Chore: ignore all .md files 2021-02-08 18:32:05 +08:00
xjasonlyu 06a7cf6718 Chore: use gVisor 20210207054208-21036aed5e58 2021-02-08 16:03:16 +08:00
xjasonlyu ab59724d87 Chore: rewrite README 2021-02-08 14:55:09 +08:00
xjasonlyu 50bed22076 Chore: Makefile rename docker -> tun2socks 2021-02-08 14:35:58 +08:00
xjasonlyu 849f47baf7 Chore: decrease maxUDPQueueSize 2021-02-07 20:43:55 +08:00
xjasonlyu ace24826d2 Chore: move stack & device to core 2021-02-07 18:49:55 +08:00
xjasonlyu 669a601f1a Chore: move stack & device to component 2021-02-07 18:45:52 +08:00
xjasonlyu 103009cb1d Chore: add stack field to Engine 2021-02-07 18:38:19 +08:00
xjasonlyu ea1832adaa Chore: cleanup Makefile 2021-02-07 18:24:01 +08:00
xjasonlyu cf4ac9b207 Refactor(proxy): use proto sub package 2021-02-07 18:22:00 +08:00
xjasonlyu 2fe6caab12 Chore: optimize docker files 2021-02-07 14:44:56 +08:00
xjasonlyu 6fd3fd0f8c Chore(workflows): go add paths-ignore 2021-02-07 13:56:06 +08:00
xjasonlyu 2e0b9d5e24 Chore: update command line help messages 2021-02-07 11:31:03 +08:00
xjasonlyu 035504020e Refactor: manager -> statistic 2021-02-07 10:54:29 +08:00
xjasonlyu 84b7c17268 Chore: use gVisor 20210207010352-2042ce9bee2d 2021-02-07 10:40:13 +08:00
xjasonlyu ee00315894 Chore: rename proxy Type() to Proto() 2021-02-07 10:38:07 +08:00
xjasonlyu a3ff3a5a15 Chore: const tun.Driver = "tun" 2021-02-07 10:09:26 +08:00
xjasonlyu 79aa91da41 Chore: optimize docker entrypoint.sh 2021-02-07 10:06:43 +08:00
xjasonlyu cc268bc2a3 Feature: use wintun for windows 2021-02-06 20:01:11 +08:00
xjasonlyu b79ab7335a Chore: rename ShadowSocks to Shadowsocks 2021-02-06 19:01:01 +08:00
xjasonlyu 496d25ff23 Fix: panic when using direct proxy 2021-02-06 18:58:56 +08:00
xjasonlyu 9caf06760d Chore: update engine log of proxy & device 2021-02-06 18:58:27 +08:00
xjasonlyu a84eebe284 Chore: add Type() method to proxy.Proxy 2021-02-06 18:54:42 +08:00
xjasonlyu 6375708e4a Chore: add Type() method to device.Device 2021-02-06 18:36:57 +08:00
xjasonlyu e524acdb10 Optimize: rwbased link endpoint 2021-02-06 18:22:42 +08:00
xjasonlyu 6763ca4852 Chore: update stack icmp 2021-02-06 17:22:46 +08:00
xjasonlyu b1700c62f4 Feature: windows tun more params support
Supported params:

- Name
- MTU
- ComponentID
- Network
2021-02-06 16:20:45 +08:00
xjasonlyu 38b9357469 Fix: error when proxy or device empty 2021-02-06 15:40:11 +08:00
xjasonlyu 5f95bc9091 Fix: set MTU on windows 2021-02-06 15:05:21 +08:00
xjasonlyu c04d998bb2 Chore: adjust .dockerignore 2021-02-06 14:03:55 +08:00
xjasonlyu e0956ce58c Feature: add simple-obfs support for ss 2021-02-06 13:41:44 +08:00
xjasonlyu 44e47cc86c Fix: replace outdated params 2021-02-06 12:14:10 +08:00
xjasonlyu 441e6c3dfb Chore: update gVisor 2021-02-06 12:11:06 +08:00
xjasonlyu 26c1bfc461 Chore: adjust docker env params 2021-02-06 11:50:33 +08:00
xjasonlyu 93c739d2d9 Chore: use strict log level 2021-02-06 11:46:35 +08:00
xjasonlyu aa703ac90d Chore: rename secret to token 2021-02-06 11:39:25 +08:00
xjasonlyu d1df910888 Chore: adjust workflows 2021-02-06 11:30:14 +08:00
94 changed files with 2273 additions and 1864 deletions
+4 -1
View File
@@ -1,3 +1,6 @@
.github
.gitignore
.dockerignore
# Other
build/*
docs/*
+33
View File
@@ -0,0 +1,33 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Environment**
- OS: [e.g. `Ubuntu-20.04`]
- Version: [e.g. `v2.1.0`]
- Network: [e.g. route tables, iptables rules]
**Log**
Paste the tun2socks log below with the log level set to `DEBUG`.
```
```
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. [First Step]
2. [Second Step]
3. ……
**Expected behavior**
A clear and concise description of what you expected to happen.
**Additional context**
Add any other context about the problem here.
+20
View File
@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem?**
A clear and concise description of what the problem is.
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
+14 -14
View File
@@ -3,12 +3,12 @@ name: Publish Docker Image
on:
push:
branches:
- dev
- 'main'
tags:
- '*'
paths-ignore:
- '**.md'
- 'docs/**'
- 'README.md'
jobs:
@@ -45,29 +45,29 @@ jobs:
username: xjasonlyu
password: ${{ secrets.CR_PAT }}
- name: Build and Push (dev)
if: github.ref == 'refs/heads/dev'
uses: docker/build-push-action@v2
with:
context: .
push: true
platforms: linux/amd64,linux/arm64
tags: |
xjasonlyu/tun2socks:dev
ghcr.io/xjasonlyu/tun2socks:dev
- name: Get Version
id: shell
run: |
echo ::set-output name=version::$(git describe --tags --abbrev=0)
- name: Build and Push (nightly)
if: github.ref == 'refs/heads/main'
uses: docker/build-push-action@v2
with:
context: .
push: true
platforms: linux/amd64,linux/arm/v7,linux/arm64
tags: |
xjasonlyu/tun2socks:nightly
ghcr.io/xjasonlyu/tun2socks:nightly
- name: Build and Push (latest)
if: startsWith(github.ref, 'refs/tags/')
uses: docker/build-push-action@v2
with:
context: .
push: true
platforms: linux/amd64,linux/arm64
platforms: linux/amd64,linux/arm/v7,linux/arm64
tags: |
xjasonlyu/tun2socks:latest
xjasonlyu/tun2socks:${{ steps.shell.outputs.version }}
+14 -24
View File
@@ -1,27 +1,31 @@
name: Go
name: Go Static Check
on:
pull_request:
push:
branches:
- main
- dev
- '*'
tags-ignore:
- '*'
paths-ignore:
- '**.md'
- 'docs/**'
pull_request:
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: 1.15.x
- name: Check out code into the Go module directory
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: 1.17.x
- name: Cache go module
uses: actions/cache@v2
with:
@@ -34,19 +38,5 @@ jobs:
run: |
go test ./...
go vet ./...
go get -u honnef.co/go/tools/cmd/staticcheck
go install honnef.co/go/tools/cmd/staticcheck@latest
staticcheck -- $(go list ./...)
- name: Build
if: startsWith(github.ref, 'refs/tags/')
run: make -j releases
- name: Upload Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
files: bin/*
draft: true
prerelease: true
+38
View File
@@ -0,0 +1,38 @@
name: Publish Go Releases
on:
push:
tags:
- '*'
paths-ignore:
- '**.md'
- 'docs/**'
- 'docker/**'
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: Setup Go
uses: actions/setup-go@v2
with:
go-version: 1.17.x
- name: Build
run: make -j releases
- name: Upload Releases
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
files: build/*
draft: true
prerelease: false
+1 -1
View File
@@ -4,7 +4,7 @@
*.dll
*.so
*.dylib
bin/
build/
# IDE
.idea/
+12 -12
View File
@@ -4,9 +4,8 @@ WORKDIR /tun2socks-src
COPY . /tun2socks-src
RUN apk add --no-cache make git \
&& go mod download \
&& make docker \
&& mv ./bin/tun2socks-docker /tun2socks
&& make tun2socks \
&& mv ./build/tun2socks /tun2socks
FROM alpine:latest
LABEL org.opencontainers.image.source="https://github.com/xjasonlyu/tun2socks"
@@ -17,15 +16,16 @@ COPY --from=builder /tun2socks /usr/bin/tun2socks
RUN apk add --update --no-cache iptables iproute2 \
&& chmod +x /entrypoint.sh
ENV TUN tun0
ENV ETH eth0
ENV TUN_ADDR=
ENV TUN_MASK=
ENV LOGLEVEL=
ENV EXCLUDED=
ENV EXTRACMD=
ENV PROXY=
ENV TUN=tun0
ENV ADDR=198.18.0.1/15
ENV LOGLEVEL=info
ENV PROXY=direct://
ENV MTU=9000
ENV STATS=
ENV SECRET=
ENV TOKEN=
ENV UDP_TIMEOUT=
ENV EXTRA_COMMANDS=
ENV TUN_INCLUDED_ROUTES=
ENV TUN_EXCLUDED_ROUTES=
ENTRYPOINT ["/entrypoint.sh"]
+111 -32
View File
@@ -1,72 +1,151 @@
BINDIR = "bin"
NAME = "tun2socks"
BINARY := tun2socks
MODULE := github.com/xjasonlyu/tun2socks
TAGS = ""
BUILD_FLAGS = "-v"
BUILD_DIR := build
BUILD_TAGS :=
BUILD_FLAGS := -v
BUILD_COMMIT := $(shell git rev-parse --short HEAD)
BUILD_VERSION := $(shell git describe --abbrev=0 --tags HEAD)
VERSION = $(shell git describe --tags || echo "unknown version")
BUILD_TIME = $(shell date -u '+%FT%TZ')
CGO_ENABLED := 0
GO111MODULE := on
LDFLAGS += -w -s -buildid=
LDFLAGS += -X "github.com/xjasonlyu/tun2socks/constant.Version=$(VERSION)"
LDFLAGS += -X "github.com/xjasonlyu/tun2socks/constant.BuildTime=$(BUILD_TIME)" # RFC3339
GO_BUILD = GO111MODULE=on CGO_ENABLED=0 go build $(BUILD_FLAGS) -ldflags '$(LDFLAGS)' -tags '$(TAGS)' -trimpath
LDFLAGS += -X "$(MODULE)/constant.Version=$(BUILD_VERSION)"
LDFLAGS += -X "$(MODULE)/constant.GitCommit=$(BUILD_COMMIT)"
PLATFORM_LIST = \
GO_BUILD = GO111MODULE=$(GO111MODULE) CGO_ENABLED=$(CGO_ENABLED) \
go build $(BUILD_FLAGS) -ldflags '$(LDFLAGS)' -tags '$(BUILD_TAGS)' -trimpath
UNIX_ARCH_LIST = \
darwin-amd64 \
darwin-arm64 \
freebsd-386 \
freebsd-amd64 \
freebsd-arm64 \
linux-386 \
linux-amd64 \
linux-arm64 \
linux-armv5 \
linux-armv6 \
linux-armv7 \
linux-mips-softfloat \
linux-mips-hardfloat \
linux-mipsle-softfloat \
linux-mipsle-hardfloat \
linux-mips64 \
linux-mips64le \
linux-ppc64 \
linux-ppc64le \
linux-s390x \
openbsd-386 \
openbsd-amd64 \
openbsd-arm64 \
openbsd-arm64
WINDOWS_ARCH_LIST = \
windows-386 \
windows-amd64 \
windows-arm64 \
windows-arm32v7
all: linux-amd64 darwin-amd64 windows-amd64
.PHONY: docker
docker:
$(GO_BUILD) -o $(BINDIR)/$(NAME)-$@
tun2socks:
$(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)
darwin-amd64:
GOARCH=amd64 GOOS=darwin $(GO_BUILD) -o $(BINDIR)/$(NAME)-$@
GOARCH=amd64 GOOS=darwin $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
darwin-arm64:
GOARCH=arm64 GOOS=darwin $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
freebsd-386:
GOARCH=386 GOOS=freebsd $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
freebsd-amd64:
GOARCH=amd64 GOOS=freebsd $(GO_BUILD) -o $(BINDIR)/$(NAME)-$@
GOARCH=amd64 GOOS=freebsd $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
freebsd-arm64:
GOARCH=arm64 GOOS=freebsd $(GO_BUILD) -o $(BINDIR)/$(NAME)-$@
GOARCH=arm64 GOOS=freebsd $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
linux-386:
GOARCH=386 GOOS=linux $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
linux-amd64:
GOARCH=amd64 GOOS=linux $(GO_BUILD) -o $(BINDIR)/$(NAME)-$@
GOARCH=amd64 GOOS=linux $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
linux-arm64:
GOARCH=arm64 GOOS=linux $(GO_BUILD) -o $(BINDIR)/$(NAME)-$@
GOARCH=arm64 GOOS=linux $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
linux-armv5:
GOARCH=arm GOARM=5 GOOS=linux $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
linux-armv6:
GOARCH=arm GOARM=6 GOOS=linux $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
linux-armv7:
GOARCH=arm GOARM=7 GOOS=linux $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
linux-mips-softfloat:
GOARCH=mips GOMIPS=softfloat GOOS=linux $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
linux-mips-hardfloat:
GOARCH=mips GOMIPS=hardfloat GOOS=linux $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
linux-mipsle-softfloat:
GOARCH=mipsle GOMIPS=softfloat GOOS=linux $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
linux-mipsle-hardfloat:
GOARCH=mipsle GOMIPS=hardfloat GOOS=linux $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
linux-mips64:
GOARCH=mips64 GOOS=linux $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
linux-mips64le:
GOARCH=mips64le GOOS=linux $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
linux-ppc64:
GOARCH=ppc64 GOOS=linux $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
linux-ppc64le:
GOARCH=ppc64le GOOS=linux $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
linux-s390x:
GOARCH=s390x GOOS=linux $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
openbsd-386:
GOARCH=386 GOOS=openbsd $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
openbsd-amd64:
GOARCH=amd64 GOOS=openbsd $(GO_BUILD) -o $(BINDIR)/$(NAME)-$@
GOARCH=amd64 GOOS=openbsd $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
openbsd-arm64:
GOARCH=arm64 GOOS=openbsd $(GO_BUILD) -o $(BINDIR)/$(NAME)-$@
GOARCH=arm64 GOOS=openbsd $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
windows-386:
GOARCH=386 GOOS=windows $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@.exe
windows-amd64:
GOARCH=amd64 GOOS=windows $(GO_BUILD) -o $(BINDIR)/$(NAME)-$@.exe
GOARCH=amd64 GOOS=windows $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@.exe
gz_releases=$(addsuffix .gz, $(PLATFORM_LIST))
zip_releases=$(addsuffix .zip, $(WINDOWS_ARCH_LIST))
windows-arm64:
GOARCH=arm64 GOOS=windows $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@.exe
$(gz_releases): %.gz : %
chmod +x $(BINDIR)/$(NAME)-$(basename $@)
gzip -f -S .gz $(BINDIR)/$(NAME)-$(basename $@)
windows-arm32v7:
GOARCH=arm GOARM=7 GOOS=windows $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@.exe
$(zip_releases): %.zip : %
zip -m -j $(BINDIR)/$(NAME)-$(basename $@).zip $(BINDIR)/$(NAME)-$(basename $@).exe
unix_releases := $(addsuffix .zip, $(UNIX_ARCH_LIST))
windows_releases := $(addsuffix .zip, $(WINDOWS_ARCH_LIST))
all-arch: $(PLATFORM_LIST) $(WINDOWS_ARCH_LIST)
$(unix_releases): %.zip: %
@zip -qmj $(BUILD_DIR)/$(BINARY)-$(basename $@).zip $(BUILD_DIR)/$(BINARY)-$(basename $@)
releases: $(gz_releases) $(zip_releases)
$(windows_releases): %.zip: %
@zip -qmj $(BUILD_DIR)/$(BINARY)-$(basename $@).zip $(BUILD_DIR)/$(BINARY)-$(basename $@).exe
all-arch: $(UNIX_ARCH_LIST) $(WINDOWS_ARCH_LIST)
releases: $(unix_releases) $(windows_releases)
clean:
rm $(BINDIR)/*
rm -rf $(BUILD_DIR)
+48 -276
View File
@@ -1,291 +1,63 @@
<h1 align="center">tun2socks</h1>
<h3 align="center">A tun2socks powered by gVisor TCP/IP stack.</h3>
![tun2socks](docs/logo.png)
<p align="center">
<a href="https://github.com/xjasonlyu/tun2socks/actions">
<img src="https://img.shields.io/github/workflow/status/xjasonlyu/tun2socks/Go/master?style=flat-square" alt="GitHub Workflow">
</a>
<a href="https://hub.docker.com/r/xjasonlyu/tun2socks">
<img src="https://img.shields.io/docker/pulls/xjasonlyu/tun2socks?style=flat-square" alt="Docker Pulls">
</a>
<a href="https://img.shields.io/github/go-mod/go-version/xjasonlyu/tun2socks">
<img src="https://img.shields.io/github/go-mod/go-version/xjasonlyu/tun2socks?style=flat-square" alt="Go Version">
</a>
<a href="https://goreportcard.com/badge/github.com/xjasonlyu/tun2socks">
<img src="https://goreportcard.com/badge/github.com/xjasonlyu/tun2socks?style=flat-square" alt="Go Report">
</a>
<a href="https://github.com/xjasonlyu/tun2socks/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/xjasonlyu/tun2socks?style=flat-square" alt="GitHub License">
</a>
<a href="https://img.shields.io/tokei/lines/github/xjasonlyu/tun2socks">
<img src="https://img.shields.io/tokei/lines/github/xjasonlyu/tun2socks?style=flat-square" alt="Total Lines">
</a>
<a href="https://github.com/xjasonlyu/tun2socks/releases">
<img src="https://img.shields.io/github/v/release/xjasonlyu/tun2socks?include_prereleases&style=flat-square" alt="Release">
</a>
</p>
[![GitHub Workflow][1]](https://github.com/xjasonlyu/tun2socks/actions)
[![Go Version][2]](https://github.com/xjasonlyu/tun2socks/blob/main/go.mod)
[![Go Report][3]](https://goreportcard.com/badge/github.com/xjasonlyu/tun2socks)
[![GitHub License][4]](https://github.com/xjasonlyu/tun2socks/blob/main/LICENSE)
[![Releases][5]](https://github.com/xjasonlyu/tun2socks/releases)
[1]: https://img.shields.io/github/workflow/status/xjasonlyu/tun2socks/Go?style=flat-square
[2]: https://img.shields.io/github/go-mod/go-version/xjasonlyu/tun2socks/main?style=flat-square
[3]: https://goreportcard.com/badge/github.com/xjasonlyu/tun2socks?style=flat-square
[4]: https://img.shields.io/github/license/xjasonlyu/tun2socks?style=flat-square
[5]: https://img.shields.io/github/v/release/xjasonlyu/tun2socks?include_prereleases&style=flat-square
English | [简体中文](README_ZH.md)
## Features
- ICMP echoing
- IPv6 support
- Optimized UDP transmission for game acceleration
- Pure Go implementation, no more CGO required
- Router mode, routing all the traffic in LAN
- Socks5, Shadowsocks protocol support for remote connections
- TCP/IP stack powered by [gVisor](https://github.com/google/gvisor)
- Up to 2.5Gbps throughput (10x faster than [v1](https://github.com/xjasonlyu/tun2socks/tree/v1))
- **Network Support**
- Dualstack: `IPv4/IPv6`
- Forwarder: `TCP/UDP`
- Ping Echo: `ICMP`
- **Platform Support**
- Linux
- MacOS
- Windows
- FreeBSD
- OpenBSD
- **Proxy Protocol**
- HTTP
- Socks4
- Socks5
- Shadowsocks
- **Extra Feature**
- Improved stability without CGO
- Optimized UDP transmission for game
- Performed with >2.5Gbps throughput
- TCP/IP stack powered by **[gVisor](https://github.com/google/gvisor)**
## Requirements
## Documentation
| Target | Minimum | Recommended |
| :----- | :-----: | :---------: |
| System | linux darwin freebsd openbsd | linux |
| Memory | >20MB | >128MB |
| CPU | amd64 arm64 | amd64 |
Docs and quick start guides can be found at [Github Wiki](https://github.com/xjasonlyu/tun2socks/wiki).
## Performance
## Community
> iPerf3 tested on Debian 10 with i5-10500, 8G RAM
## How to Build
### build from source code
Go compiler version >= 1.15 is required
```text
$ git clone https://github.com/xjasonlyu/tun2socks.git
$ cd tun2socks
$ make
```
### build docker image
```text
$ docker build -t tun2socks .
```
or
```text
$ docker build -t tun2socks -f .Dockerfile.aarch64 .
```
## QuickStart
Download from precompiled [Releases](https://github.com/xjasonlyu/tun2socks/releases).
<details>
<summary><b>With Docker</b></summary>
> Since Go 1.12, the runtime now uses MADV_FREE to release unused memory on **linux**. This is more efficient but may result in higher reported RSS. The kernel will reclaim the unused data when it is needed. To revert to the Go 1.11 behavior (MADV_DONTNEED), set the environment variable GODEBUG=madvdontneed=1.
### create docker network (macvlan mode)
```shell script
docker network create -d macvlan \
--subnet=172.20.1.0/25 \
--gateway=172.20.1.1 \
-o parent=eth0 \
switch
```
### pull `tun2socks` docker image
```shell script
docker pull xjasonlyu/tun2socks:latest
```
### run as gateway
> DNS configuration is required.
```shell script
docker run -d \
--network switch \
--name tun2socks \
--ip 172.20.1.2 \
--privileged \
--restart always \
--sysctl net.ipv4.ip_forward=1 \
-e PROXY=socks5://server:port \
-e KEY=VALUE... \
xjasonlyu/tun2socks:latest
```
### use docker-compose (recommended)
```yaml
version: '2.4'
services:
tun2socks:
image: xjasonlyu/tun2socks:latest
cap_add:
- NET_ADMIN
devices:
- '/dev/net/tun:/dev/net/tun'
environment:
# - GODEBUG=madvdontneed=1
- PROXY=socks5://server:port
- LOGLEVEL=INFO
- API=api://:8080
- DNS=dns://:53
- HOSTS=localhost=127.0.0.1,router.local=172.20.1.1
- EXCLUDED=1.1.1.1,1.0.0.1
- EXTRACMD=
networks:
switch:
ipv4_address: 172.20.1.2
restart: always
container_name: tun2socks
networks:
switch:
name: switch
ipam:
driver: default
config:
- subnet: '172.20.1.0/25'
gateway: 172.20.1.1
driver: macvlan
driver_opts:
parent: eth0
```
</details>
<details>
<summary><b>With Linux</b></summary>
### create tun
```shell script
ip tuntap add mode tun dev tun0
ip addr add 198.18.0.1/15 dev tun0
ip link set dev tun0 up
```
### config policy routing
```shell script
echo "100 tun2socks" >> /etc/iproute2/rt_tables
ip route add default via 198.18.0.1 dev tun0 table tun2socks
ip route add 172.17.0.0/16 dev eth0 src 172.17.0.3 table tun2socks
ip route add 198.18.0.0/15 dev tun0 src 198.18.0.1 table tun2socks
ip rule add from 172.20.0.3 to 198.18.0.0/15 priority 1000 prohibit
ip rule add from 172.20.0.3 priority 2000 table main
ip rule add from all priority 3000 table tun2socks
```
### run
> bind to a specific interface to prevent traffic looping.
```shell script
./tun2socks --loglevel info --device tun://tun0 --proxy socks5://server:port --interface eth0
```
</details>
<details>
<summary><b>With MacOS</b></summary>
### start tun2socks
```shell script
./tun2socks --loglevel info --device tun://utun123 --proxy socks5://server:port --interface eth0
```
### config interface
```shell script
sudo ifconfig utun123 198.18.0.1 netmask 255.255.255.255 198.18.0.1 up
```
### config route
```shell script
sudo route del default
sudo route add default 198.18.0.1
sudo route add ${proxy_server_ip} ${your_gateway}
```
### check route table
```shell script
netstat -nr
```
</details>
<details>
<summary><b>With Script</b></summary>
> entrypoint.sh would take care of tun & routes.
```shell script
PROXY=socks5://server:port LOGLEVEL=INFO sh ./scripts/entrypoint.sh
```
</details>
## Details
<details>
<summary><b>API Reference</b></summary>
| Path | Methods | Parameters | Description |
| :--- | :------ | :--------: | :---------- |
| `/logs` | GET | `level` | Get real-time logs |
| `/traffic` | GET | / | Get real-time traffic data |
| `/version` | GET | / | Get current version |
| `/connections` | GET | `interval` | Get all connections |
| `/connections` | DELETE | / | Close all connections |
| `/connections/{id}` | DELETE | / | Close connection by `id` |
</details>
<details>
<summary><b>Help Text</b></summary>
```text
Usage of tun2socks:
-d, --device string Use this device [driver://]name
-i, --interface string Use network INTERFACE (Darwin/Linux only)
-l, --loglevel string Log level [debug|info|warn|error|silent] (default "info")
-m, --mtu int Maximum transmission unit
-p, --proxy string Use this proxy [protocol://]host[:port]
--secret string HTTP statistic server auth secret
--stats string HTTP statistic server listen address
-v, --version Show version information and quit
```
</details>
<details>
<summary><b>Proxy URL</b></summary>
| Protocol | Scheme | Examples |
| :------- | :----- | :------- |
| direct | `direct` | `direct://` |
| socks5 | `socks5` | `socks5://username:password@server:port` |
| shadowsocks | `ss`, `shadowsocks` | `ss://method:password@server:port` |
</details>
Welcome and feel free to ask any questions at [Github Discussions](https://github.com/xjasonlyu/tun2socks/discussions).
## Credits
- [Dreamacro/clash](https://github.com/Dreamacro/clash)
- [google/gvisor](https://github.com/google/gvisor)
- [majek/slirpnetstack](https://github.com/majek/slirpnetstack)
- [WireGuard/wireguard-go](https://github.com/WireGuard/wireguard-go)
- [Dreamacro/clash](https://github.com/Dreamacro/clash) - A rule-based tunnel in Go
- [google/gvisor](https://github.com/google/gvisor) - Application Kernel for Containers
- [wireguard-go](https://git.zx2c4.com/wireguard-go) - Go Implementation of WireGuard
## Known Issues
## License
Due to the implementation of pure Go, the memory usage is higher than the previous version.
If you are sensitive to memory, please go back to [v1](https://github.com/xjasonlyu/tun2socks/tree/v1).
[GPL-3.0](https://github.com/xjasonlyu/tun2socks/blob/main/LICENSE)
## TODO
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fxjasonlyu%2Ftun2socks.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fxjasonlyu%2Ftun2socks?ref=badge_large)
- [x] Windows support
- [x] FreeBSD support
- [x] OpenBSD support
## Stargazers over time
[![Stargazers over time](https://starchart.cc/xjasonlyu/tun2socks.svg)](https://starchart.cc/xjasonlyu/tun2socks)
+68
View File
@@ -0,0 +1,68 @@
![tun2socks](docs/logo.png)
[![GitHub Workflow][1]](https://github.com/xjasonlyu/tun2socks/actions)
[![Go Version][2]](https://github.com/xjasonlyu/tun2socks/blob/main/go.mod)
[![Go Report][3]](https://goreportcard.com/badge/github.com/xjasonlyu/tun2socks)
[![GitHub License][4]](https://github.com/xjasonlyu/tun2socks/blob/main/LICENSE)
[![Releases][5]](https://github.com/xjasonlyu/tun2socks/releases)
[1]: https://img.shields.io/github/workflow/status/xjasonlyu/tun2socks/Go?style=flat-square
[2]: https://img.shields.io/github/go-mod/go-version/xjasonlyu/tun2socks/main?style=flat-square
[3]: https://goreportcard.com/badge/github.com/xjasonlyu/tun2socks?style=flat-square
[4]: https://img.shields.io/github/license/xjasonlyu/tun2socks?style=flat-square
[5]: https://img.shields.io/github/v/release/xjasonlyu/tun2socks?include_prereleases&style=flat-square
[English](README.md) | 简体中文
## 为什么使用 tun2socks
通过在主机上运行`tun2socks`,可以轻松地接管所有的`TCP/UDP`流量,同时提供诸多专业的功能特性,这包括:
- 强制使不支持代理的程序走代理
- 配合Clash、V2Ray等工具实现全局代理上网
- 配合Burp、Charles等工具进行应用层数据的调试
- 配合DHCP、CoreDNS等工具部署路由模式代理局域网流量
## 特性介绍
- **全面支持:** IPv4/IPv6/ICMP/TCP/UDP
- **代理协议:** HTTP/Socks4/Socks5/Shadowsocks
- **游戏加速:** 针对UDP传输的优化
- **纯Go实现:** 无需CGO,稳定性提升
- **路由模式:** 转发代理局域网内所有流量
- **TCP/IP栈:** 由 **[gVisor](https://github.com/google/gvisor)** 强力驱动
- **高性能:** >2.5Gbps 的带宽吞吐量
## 硬件需求
| 目标 | 最小 | 建议 |
| :--- | :---: | :---: |
| 系统 | Linux MacOS Freebsd OpenBSD Windows | Linux or MacOS |
| 内存 | >20MB | >128MB |
| 架构 | ANY | AMD64 or ARM64 |
## 使用文档
文档以及使用方式,请看 [Github Wiki](https://github.com/xjasonlyu/tun2socks/wiki)。
## 交流讨论
欢迎来讨论区交流提问,[Github Discussions](https://github.com/xjasonlyu/tun2socks/discussions)。
## 注意事项
1. 由于采用了纯Go实现,所以这一版本的`tun2socks`在有大量连接时内存消耗通常较多。如果您的需求对内存消耗极为敏感,请继续使用 [v1](https://github.com/xjasonlyu/tun2socks/tree/v1) 版本。
2. `tun2socks`只应该专注于将网络层的TCP/UDP流量转发给SOCKS服务器,其他的如DNS(DoH)、DHCP等模块功能应该交由第三方应用实现,所以弃用了DNS模块。
3. 因为是通过用户空间的网络栈接管所有流量并处理转发,在高吞吐时CPU的使用量会剧增,所以CPU的性能直接与可以达到的最大带宽挂钩。
## 特别感谢
- [Dreamacro/clash](https://github.com/Dreamacro/clash) - A rule-based tunnel in Go
- [google/gvisor](https://github.com/google/gvisor) - Application Kernel for Containers
- [wireguard-go](https://git.zx2c4.com/wireguard-go) - Go Implementation of WireGuard
## License
[GPL-3.0](https://github.com/xjasonlyu/tun2socks/blob/main/LICENSE)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fxjasonlyu%2Ftun2socks.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fxjasonlyu%2Ftun2socks?ref=badge_large)
+9 -3
View File
@@ -1,8 +1,11 @@
package dialer
import "net"
import (
"net"
"sync"
)
var _boundInterface *net.Interface
var _bindOnce sync.Once
// BindToInterface binds dialer to specific interface.
func BindToInterface(name string) error {
@@ -10,6 +13,9 @@ func BindToInterface(name string) error {
if err != nil {
return err
}
_boundInterface = i
_bindOnce.Do(func() {
addControl(bindToInterface(i))
})
return nil
}
+15 -13
View File
@@ -7,18 +7,20 @@ import (
"golang.org/x/sys/unix"
)
func bindToInterface(network, address string, c syscall.RawConn) error {
ipStr, _, _ := net.SplitHostPort(address)
if ip := net.ParseIP(ipStr); ip != nil && !ip.IsGlobalUnicast() {
return nil
}
return c.Control(func(fd uintptr) {
switch network {
case "tcp4", "udp4":
unix.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BOUND_IF, _boundInterface.Index)
case "tcp6", "udp6":
unix.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_BOUND_IF, _boundInterface.Index)
func bindToInterface(i *net.Interface) controlFunc {
return func(network, address string, c syscall.RawConn) error {
ipStr, _, _ := net.SplitHostPort(address)
if ip := net.ParseIP(ipStr); ip != nil && !ip.IsGlobalUnicast() {
return nil
}
})
return c.Control(func(fd uintptr) {
switch network {
case "tcp4", "udp4":
unix.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BOUND_IF, i.Index)
case "tcp6", "udp6":
unix.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_BOUND_IF, i.Index)
}
})
}
}
+10 -8
View File
@@ -7,13 +7,15 @@ import (
"golang.org/x/sys/unix"
)
func bindToInterface(network, address string, c syscall.RawConn) error {
ipStr, _, _ := net.SplitHostPort(address)
if ip := net.ParseIP(ipStr); ip != nil && !ip.IsGlobalUnicast() {
return nil
}
func bindToInterface(i *net.Interface) controlFunc {
return func(network, address string, c syscall.RawConn) error {
ipStr, _, _ := net.SplitHostPort(address)
if ip := net.ParseIP(ipStr); ip != nil && !ip.IsGlobalUnicast() {
return nil
}
return c.Control(func(fd uintptr) {
unix.BindToDevice(int(fd), _boundInterface.Name)
})
return c.Control(func(fd uintptr) {
unix.BindToDevice(int(fd), i.Name)
})
}
}
+6 -3
View File
@@ -1,12 +1,15 @@
// +build !linux,!darwin
//go:build !linux && !darwin
package dialer
import (
"errors"
"net"
"syscall"
)
func bindToInterface(network, address string, c syscall.RawConn) error {
return errors.New("unsupported platform")
func bindToInterface(_ *net.Interface) controlFunc {
return func(string, string, syscall.RawConn) error {
return errors.New("unsupported platform")
}
}
+37
View File
@@ -0,0 +1,37 @@
package dialer
import (
"errors"
"net"
"syscall"
)
type controlFunc func(string, string, syscall.RawConn) error
var (
_controlPool = make([]controlFunc, 0, 2)
)
func addControl(f controlFunc) {
_controlPool = append(_controlPool, f)
}
func setControl(i interface{}) {
control := func(address, network string, c syscall.RawConn) error {
for _, f := range _controlPool {
if err := f(address, network, c); err != nil {
return err
}
}
return nil
}
switch v := i.(type) {
case *net.Dialer:
v.Control = control
case *net.ListenConfig:
v.Control = control
default:
panic(errors.New("wrong type"))
}
}
+2 -10
View File
@@ -11,20 +11,12 @@ func Dial(network, address string) (net.Conn, error) {
func DialContext(ctx context.Context, network, address string) (net.Conn, error) {
d := &net.Dialer{}
if _boundInterface != nil {
d.Control = bindToInterface
}
setControl(d)
return d.DialContext(ctx, network, address)
}
func ListenPacket(network, address string) (net.PacketConn, error) {
lc := &net.ListenConfig{}
if _boundInterface != nil {
lc.Control = bindToInterface
}
setControl(lc)
return lc.ListenPacket(context.Background(), network, address)
}
+14
View File
@@ -0,0 +1,14 @@
package dialer
import (
"sync"
)
var _setOnce sync.Once
// SetMark sets the mark for each packet sent through this dialer(socket).
func SetMark(i int) {
_setOnce.Do(func() {
addControl(setMark(i))
})
}
+15
View File
@@ -0,0 +1,15 @@
package dialer
import (
"syscall"
"golang.org/x/sys/unix"
)
func setMark(i int) controlFunc {
return func(_, _ string, c syscall.RawConn) error {
return c.Control(func(fd uintptr) {
unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_MARK, i)
})
}
}
+14
View File
@@ -0,0 +1,14 @@
//go:build !linux
package dialer
import (
"errors"
"syscall"
)
func setMark(_ int) controlFunc {
return func(string, string, syscall.RawConn) error {
return errors.New("fwmark: linux only")
}
}
+2
View File
@@ -3,6 +3,8 @@ package dialer
import "net"
func init() {
// We must use this DialContext to query DNS
// when using net default resolver.
net.DefaultResolver.PreferGo = true
net.DefaultResolver.Dial = DialContext
}
+94
View File
@@ -0,0 +1,94 @@
package obfs
import (
"bytes"
"encoding/base64"
"fmt"
"io"
"math/rand"
"net"
"net/http"
"github.com/xjasonlyu/tun2socks/common/pool"
)
// HTTPObfs is shadowsocks http simple-obfs implementation
type HTTPObfs struct {
net.Conn
host string
port string
buf []byte
offset int
firstRequest bool
firstResponse bool
}
func (ho *HTTPObfs) Read(b []byte) (int, error) {
if ho.buf != nil {
n := copy(b, ho.buf[ho.offset:])
ho.offset += n
if ho.offset == len(ho.buf) {
pool.Put(ho.buf)
ho.buf = nil
}
return n, nil
}
if ho.firstResponse {
buf := pool.Get(pool.RelayBufferSize)
n, err := ho.Conn.Read(buf)
if err != nil {
pool.Put(buf)
return 0, err
}
idx := bytes.Index(buf[:n], []byte("\r\n\r\n"))
if idx == -1 {
pool.Put(buf)
return 0, io.EOF
}
ho.firstResponse = false
length := n - (idx + 4)
n = copy(b, buf[idx+4:n])
if length > n {
ho.buf = buf[:idx+4+length]
ho.offset = idx + 4 + n
} else {
pool.Put(buf)
}
return n, nil
}
return ho.Conn.Read(b)
}
func (ho *HTTPObfs) Write(b []byte) (int, error) {
if ho.firstRequest {
randBytes := make([]byte, 16)
rand.Read(randBytes)
req, _ := http.NewRequest("GET", fmt.Sprintf("http://%s/", ho.host), bytes.NewBuffer(b[:]))
req.Header.Set("User-Agent", fmt.Sprintf("curl/7.%d.%d", rand.Int()%54, rand.Int()%2))
req.Header.Set("Upgrade", "websocket")
req.Header.Set("Connection", "Upgrade")
req.Host = ho.host
if ho.port != "80" {
req.Host = fmt.Sprintf("%s:%s", ho.host, ho.port)
}
req.Header.Set("Sec-WebSocket-Key", base64.URLEncoding.EncodeToString(randBytes))
req.ContentLength = int64(len(b))
err := req.Write(ho.Conn)
ho.firstRequest = false
return len(b), err
}
return ho.Conn.Write(b)
}
// NewHTTPObfs return a HTTPObfs
func NewHTTPObfs(conn net.Conn, host string, port string) net.Conn {
return &HTTPObfs{
Conn: conn,
firstRequest: true,
firstResponse: true,
host: host,
port: port,
}
}
+4
View File
@@ -0,0 +1,4 @@
// Package obfs provides obfuscation functionality for Shadowsocks protocol.
package obfs
// Ref: github.com/Dreamacro/clash/component/simple-obfs
+198
View File
@@ -0,0 +1,198 @@
package obfs
import (
"bytes"
"encoding/binary"
"io"
"math/rand"
"net"
"time"
"github.com/xjasonlyu/tun2socks/common/pool"
)
func init() {
rand.Seed(time.Now().Unix())
}
const (
chunkSize = 1 << 14 // 2 ** 14 == 16 * 1024
)
// TLSObfs is shadowsocks tls simple-obfs implementation
type TLSObfs struct {
net.Conn
server string
remain int
firstRequest bool
firstResponse bool
}
func (to *TLSObfs) read(b []byte, discardN int) (int, error) {
buf := pool.Get(discardN)
_, err := io.ReadFull(to.Conn, buf)
if err != nil {
return 0, err
}
pool.Put(buf)
sizeBuf := make([]byte, 2)
_, err = io.ReadFull(to.Conn, sizeBuf)
if err != nil {
return 0, nil
}
length := int(binary.BigEndian.Uint16(sizeBuf))
if length > len(b) {
n, err := to.Conn.Read(b)
if err != nil {
return n, err
}
to.remain = length - n
return n, nil
}
return io.ReadFull(to.Conn, b[:length])
}
func (to *TLSObfs) Read(b []byte) (int, error) {
if to.remain > 0 {
length := to.remain
if length > len(b) {
length = len(b)
}
n, err := io.ReadFull(to.Conn, b[:length])
to.remain -= n
return n, err
}
if to.firstResponse {
// type + ver + len_size + 91 = 96
// type + ver + len_size + 1 = 6
// type + ver = 3
to.firstResponse = false
return to.read(b, 105)
}
// type + ver = 3
return to.read(b, 3)
}
func (to *TLSObfs) Write(b []byte) (int, error) {
length := len(b)
for i := 0; i < length; i += chunkSize {
end := i + chunkSize
if end > length {
end = length
}
n, err := to.write(b[i:end])
if err != nil {
return n, err
}
}
return length, nil
}
func (to *TLSObfs) write(b []byte) (int, error) {
if to.firstRequest {
helloMsg := makeClientHelloMsg(b, to.server)
_, err := to.Conn.Write(helloMsg)
to.firstRequest = false
return len(b), err
}
buf := &bytes.Buffer{}
buf.Write([]byte{0x17, 0x03, 0x03})
binary.Write(buf, binary.BigEndian, uint16(len(b)))
buf.Write(b)
_, err := to.Conn.Write(buf.Bytes())
return len(b), err
}
// NewTLSObfs return a SimpleObfs
func NewTLSObfs(conn net.Conn, server string) net.Conn {
return &TLSObfs{
Conn: conn,
server: server,
firstRequest: true,
firstResponse: true,
}
}
func makeClientHelloMsg(data []byte, server string) []byte {
random := make([]byte, 28)
sessionID := make([]byte, 32)
rand.Read(random)
rand.Read(sessionID)
buf := &bytes.Buffer{}
// handshake, TLS 1.0 version, length
buf.WriteByte(22)
buf.Write([]byte{0x03, 0x01})
length := uint16(212 + len(data) + len(server))
buf.WriteByte(byte(length >> 8))
buf.WriteByte(byte(length & 0xff))
// clientHello, length, TLS 1.2 version
buf.WriteByte(1)
buf.WriteByte(0)
binary.Write(buf, binary.BigEndian, uint16(208+len(data)+len(server)))
buf.Write([]byte{0x03, 0x03})
// random with timestamp, sid len, sid
binary.Write(buf, binary.BigEndian, uint32(time.Now().Unix()))
buf.Write(random)
buf.WriteByte(32)
buf.Write(sessionID)
// cipher suites
buf.Write([]byte{0x00, 0x38})
buf.Write([]byte{
0xc0, 0x2c, 0xc0, 0x30, 0x00, 0x9f, 0xcc, 0xa9, 0xcc, 0xa8, 0xcc, 0xaa, 0xc0, 0x2b, 0xc0, 0x2f,
0x00, 0x9e, 0xc0, 0x24, 0xc0, 0x28, 0x00, 0x6b, 0xc0, 0x23, 0xc0, 0x27, 0x00, 0x67, 0xc0, 0x0a,
0xc0, 0x14, 0x00, 0x39, 0xc0, 0x09, 0xc0, 0x13, 0x00, 0x33, 0x00, 0x9d, 0x00, 0x9c, 0x00, 0x3d,
0x00, 0x3c, 0x00, 0x35, 0x00, 0x2f, 0x00, 0xff,
})
// compression
buf.Write([]byte{0x01, 0x00})
// extension length
binary.Write(buf, binary.BigEndian, uint16(79+len(data)+len(server)))
// session ticket
buf.Write([]byte{0x00, 0x23})
binary.Write(buf, binary.BigEndian, uint16(len(data)))
buf.Write(data)
// server name
buf.Write([]byte{0x00, 0x00})
binary.Write(buf, binary.BigEndian, uint16(len(server)+5))
binary.Write(buf, binary.BigEndian, uint16(len(server)+3))
buf.WriteByte(0)
binary.Write(buf, binary.BigEndian, uint16(len(server)))
buf.Write([]byte(server))
// ec_point
buf.Write([]byte{0x00, 0x0b, 0x00, 0x04, 0x03, 0x01, 0x00, 0x02})
// groups
buf.Write([]byte{0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x19, 0x00, 0x18})
// signature
buf.Write([]byte{
0x00, 0x0d, 0x00, 0x20, 0x00, 0x1e, 0x06, 0x01, 0x06, 0x02, 0x06, 0x03, 0x05,
0x01, 0x05, 0x02, 0x05, 0x03, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x03, 0x01,
0x03, 0x02, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x03,
})
// encrypt then mac
buf.Write([]byte{0x00, 0x16, 0x00, 0x00})
// extended master secret
buf.Write([]byte{0x00, 0x17, 0x00, 0x00})
return buf.Bytes()
}
-2
View File
@@ -1,2 +0,0 @@
// Package constant provides global constants/variables of this project.
package constant
@@ -1,4 +1,4 @@
package adapter
package constant
import (
"bytes"
@@ -7,7 +7,7 @@ import (
"net"
"strconv"
"github.com/xjasonlyu/tun2socks/component/socks5"
"github.com/xjasonlyu/tun2socks/transport/socks5"
)
const (
@@ -87,7 +87,3 @@ func (m *Metadata) Network() string {
func (m *Metadata) String() string {
return m.DestinationAddress()
}
func (m *Metadata) Valid() bool {
return m.SrcIP != nil && m.DstIP != nil
}
+5 -3
View File
@@ -1,8 +1,10 @@
package constant
const Name = "tun2socks"
const (
Name = "tun2socks"
)
var (
Version = ""
BuildTime = ""
Version string
GitCommit string
)
+7 -5
View File
@@ -1,12 +1,14 @@
package adapter
package core
import (
"net"
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
type TCPConn interface {
net.Conn
Metadata() *Metadata
ID() *stack.TransportEndpointID
}
type UDPPacket interface {
@@ -16,12 +18,12 @@ type UDPPacket interface {
// Drop call after packet is used, could release resources in this function.
Drop()
// ID returns the transport endpoint id of packet.
ID() *stack.TransportEndpointID
// LocalAddr returns the source IP/Port of packet.
LocalAddr() net.Addr
// Metadata returns the metadata of packet.
Metadata() *Metadata
// RemoteAddr returns the destination IP/Port of packet.
RemoteAddr() net.Addr
@@ -14,4 +14,7 @@ type Device interface {
// Name returns the current name of the device.
Name() string
// Type returns the driver type of the device.
Type() string
}
+3
View File
@@ -0,0 +1,3 @@
package fd
const Driver = "fd"
+41
View File
@@ -0,0 +1,41 @@
//go:build !windows
package fd
import (
"fmt"
"strconv"
"github.com/xjasonlyu/tun2socks/core/device"
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
type FD struct {
stack.LinkEndpoint
fd int
mtu uint32
}
func Open(name string, mtu uint32) (device.Device, error) {
fd, err := strconv.Atoi(name)
if err != nil {
return nil, fmt.Errorf("cannot open fd: %s", name)
}
return open(fd, mtu)
}
func (f *FD) Type() string {
return Driver
}
func (f *FD) Name() string {
return strconv.Itoa(f.fd)
}
func (f *FD) Close() error {
return unix.Close(f.fd)
}
var _ device.Device = (*FD)(nil)
+11
View File
@@ -0,0 +1,11 @@
package fd
import (
"errors"
"github.com/xjasonlyu/tun2socks/core/device"
)
func Open(name string, mtu uint32) (device.Device, error) {
return nil, errors.New("not supported")
}
+24
View File
@@ -0,0 +1,24 @@
package fd
import (
"fmt"
"github.com/xjasonlyu/tun2socks/core/device"
"gvisor.dev/gvisor/pkg/tcpip/link/fdbased"
)
func open(fd int, mtu uint32) (device.Device, error) {
f := &FD{fd: fd, mtu: mtu}
ep, err := fdbased.New(&fdbased.Options{
MTU: mtu,
FDs: []int{fd},
EthernetHeader: false,
})
if err != nil {
return nil, fmt.Errorf("create endpoint: %w", err)
}
f.LinkEndpoint = ep
return f, nil
}
+23
View File
@@ -0,0 +1,23 @@
//go:build !linux && !windows
package fd
import (
"fmt"
"os"
"github.com/xjasonlyu/tun2socks/core/device"
"github.com/xjasonlyu/tun2socks/core/device/rwbased"
)
func open(fd int, mtu uint32) (device.Device, error) {
f := &FD{fd: fd, mtu: mtu}
ep, err := rwbased.New(os.NewFile(uintptr(fd), f.Name()), mtu)
if err != nil {
return nil, fmt.Errorf("create endpoint: %w", err)
}
f.LinkEndpoint = ep
return f, nil
}
@@ -1,4 +1,4 @@
// Package channel provides the implementation of io.ReadWriter
// Package rwbased provides the implementation of io.ReadWriter
// based data-link layer endpoints.
package rwbased
@@ -22,9 +22,6 @@ type Endpoint struct {
// mtu (maximum transmission unit) is the maximum size of a packet.
mtu uint32
// caps holds the endpoint capabilities.
caps stack.LinkEndpointCapabilities
dispatcher stack.NetworkDispatcher
}
@@ -70,44 +67,35 @@ func (e *Endpoint) dispatchLoop() {
continue
}
var p tcpip.NetworkProtocolNumber
pkb := stack.NewPacketBuffer(stack.PacketBufferOptions{
Data: buffer.NewVectorisedView(n, []buffer.View{buffer.NewViewFromBytes(packet)}),
})
switch header.IPVersion(packet) {
case header.IPv4Version:
p = header.IPv4ProtocolNumber
e.dispatcher.DeliverNetworkPacket("", "", header.IPv4ProtocolNumber, pkb)
case header.IPv6Version:
p = header.IPv6ProtocolNumber
e.dispatcher.DeliverNetworkPacket("", "", header.IPv6ProtocolNumber, pkb)
}
e.dispatcher.DeliverNetworkPacket("", "", p, &stack.PacketBuffer{
Data: buffer.View(packet[:n]).ToVectorisedView(),
})
}
}
func (e *Endpoint) writePacket(pkt *stack.PacketBuffer) tcpip.Error {
networkHdr := pkt.NetworkHeader().View()
transportHdr := pkt.TransportHeader().View()
payload := pkt.Data.ToView()
vView := buffer.NewVectorisedView(pkt.Size(), pkt.Views())
buf := buffer.NewVectorisedView(
len(networkHdr)+len(transportHdr)+len(payload),
[]buffer.View{networkHdr, transportHdr, payload},
)
if _, err := e.rw.Write(buf.ToView()); err != nil {
if _, err := e.rw.Write(vView.ToView()); err != nil {
return &tcpip.ErrInvalidEndpointState{}
}
return nil
}
// WritePacket writes packet back into io.ReadWriter.
func (e *Endpoint) WritePacket(_ stack.RouteInfo, _ *stack.GSO, _ tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) tcpip.Error {
func (e *Endpoint) WritePacket(_ stack.RouteInfo, _ tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) tcpip.Error {
return e.writePacket(pkt)
}
// WritePackets writes packets back into io.ReadWriter.
func (e *Endpoint) WritePackets(_ stack.RouteInfo, _ *stack.GSO, pkts stack.PacketBufferList, _ tcpip.NetworkProtocolNumber) (int, tcpip.Error) {
func (e *Endpoint) WritePackets(_ stack.RouteInfo, pkts stack.PacketBufferList, _ tcpip.NetworkProtocolNumber) (int, tcpip.Error) {
n := 0
for pkt := pkts.Front(); pkt != nil; pkt = pkt.Next() {
if err := e.writePacket(pkt); err != nil {
@@ -118,12 +106,8 @@ func (e *Endpoint) WritePackets(_ stack.RouteInfo, _ *stack.GSO, pkts stack.Pack
return n, nil
}
// WriteRawPacket implements stack.LinkEndpoint.WriteRawPacket.
func (e *Endpoint) WriteRawPacket(vv buffer.VectorisedView) tcpip.Error {
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
Data: vv,
})
return e.writePacket(pkt)
func (e *Endpoint) WriteRawPacket(packetBuffer *stack.PacketBuffer) tcpip.Error {
return &tcpip.ErrNotSupported{}
}
// MTU implements stack.LinkEndpoint.MTU.
@@ -133,12 +117,7 @@ func (e *Endpoint) MTU() uint32 {
// Capabilities implements stack.LinkEndpoint.Capabilities.
func (e *Endpoint) Capabilities() stack.LinkEndpointCapabilities {
return e.caps
}
// GSOMaxSize returns the maximum GSO packet size.
func (*Endpoint) GSOMaxSize() uint32 {
return 1 << 15 /* default */
return stack.CapabilityNone
}
// MaxHeaderLength returns the maximum size of the link layer header. Given it
+33
View File
@@ -0,0 +1,33 @@
//go:build darwin || freebsd || openbsd
package tun
import (
"github.com/xjasonlyu/tun2socks/common/pool"
)
const (
offset = 4 /* 4 bytes TUN_PI */
defaultMTU = 1500
)
func (t *TUN) Read(packet []byte) (n int, err error) {
buf := pool.Get(offset + len(packet))
defer pool.Put(buf)
if n, err = t.nt.Read(buf, offset); err != nil {
return
}
copy(packet, buf[offset:offset+n])
return
}
func (t *TUN) Write(packet []byte) (int, error) {
buf := pool.Get(offset + len(packet))
defer pool.Put(buf)
copy(buf[offset:], packet)
return t.nt.Write(buf[:offset+len(packet)], offset)
}
+15
View File
@@ -0,0 +1,15 @@
package tun
const (
offset = 0
defaultMTU = 0 /* auto */
)
func (t *TUN) Read(packet []byte) (int, error) {
return t.nt.Read(packet, offset)
}
func (t *TUN) Write(packet []byte) (int, error) {
return t.nt.Write(packet, offset)
}
+14
View File
@@ -0,0 +1,14 @@
// Package tun provides TUN which implemented device.Device interface.
package tun
import (
"github.com/xjasonlyu/tun2socks/core/device"
)
const Driver = "tun"
func (t *TUN) Type() string {
return Driver
}
var _ device.Device = (*TUN)(nil)
@@ -1,11 +1,12 @@
//go:build linux
package tun
import (
"errors"
"fmt"
"unsafe"
"github.com/xjasonlyu/tun2socks/device"
"github.com/xjasonlyu/tun2socks/core/device"
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/tcpip/link/fdbased"
@@ -22,15 +23,11 @@ type TUN struct {
name string
}
func Open(opts ...Option) (device.Device, error) {
t := &TUN{}
for _, opt := range opts {
opt(t)
}
func Open(name string, mtu uint32) (device.Device, error) {
t := &TUN{name: name, mtu: mtu}
if len(t.name) >= unix.IFNAMSIZ {
return nil, errors.New("interface name too long")
return nil, fmt.Errorf("interface name too long: %s", t.name)
}
fd, err := tun.Open(t.name)
@@ -45,11 +42,11 @@ func Open(opts ...Option) (device.Device, error) {
}
}
mtu, err := rawfile.GetMTU(t.name)
_mtu, err := rawfile.GetMTU(t.name)
if err != nil {
return nil, fmt.Errorf("get mtu: %w", err)
}
t.mtu = mtu
t.mtu = _mtu
ep, err := fdbased.New(&fdbased.Options{
MTU: t.mtu,
@@ -100,7 +97,7 @@ func setMTU(name string, n uint32) error {
)
if errno != 0 {
return errors.New("failed to set MTU")
return fmt.Errorf("failed to set MTU: %w", errno)
}
return nil
+58
View File
@@ -0,0 +1,58 @@
//go:build !linux
package tun
import (
"fmt"
"github.com/xjasonlyu/tun2socks/core/device"
"github.com/xjasonlyu/tun2socks/core/device/rwbased"
"golang.zx2c4.com/wireguard/tun"
)
type TUN struct {
*rwbased.Endpoint
nt *tun.NativeTun
mtu uint32
name string
}
func Open(name string, mtu uint32) (device.Device, error) {
t := &TUN{name: name, mtu: mtu}
forcedMTU := defaultMTU
if t.mtu > 0 {
forcedMTU = int(t.mtu)
}
nt, err := tun.CreateTUN(t.name, forcedMTU)
if err != nil {
return nil, fmt.Errorf("create tun: %w", err)
}
t.nt = nt.(*tun.NativeTun)
_mtu, err := nt.MTU()
if err != nil {
return nil, fmt.Errorf("get mtu: %w", err)
}
t.mtu = uint32(_mtu)
ep, err := rwbased.New(t, t.mtu)
if err != nil {
return nil, fmt.Errorf("create endpoint: %w", err)
}
t.Endpoint = ep
return t, nil
}
func (t *TUN) Name() string {
name, _ := t.nt.Name()
return name
}
func (t *TUN) Close() error {
return t.nt.Close()
}
+6
View File
@@ -0,0 +1,6 @@
package core
type Handler interface {
Add(TCPConn)
AddPacket(UDPPacket)
}
+24
View File
@@ -0,0 +1,24 @@
package stack
import (
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/header"
)
func withICMPHandler() Option {
return func(s *Stack) error {
// Add default route table for IPv4 and IPv6.
// This will handle all incoming ICMP packets.
s.SetRouteTable([]tcpip.Route{
{
Destination: header.IPv4EmptySubnet,
NIC: s.nicID,
},
{
Destination: header.IPv6EmptySubnet,
NIC: s.nicID,
},
})
return nil
}
}
View File
+2 -2
View File
@@ -111,10 +111,10 @@ func WithDefaultTTL(ttl uint8) Option {
// WithForwarding sets packet forwarding between NICs for IPv4 & IPv6.
func WithForwarding(v bool) Option {
return func(s *Stack) error {
if err := s.SetForwarding(ipv4.ProtocolNumber, v); err != nil {
if err := s.SetForwardingDefaultAndAllNICs(ipv4.ProtocolNumber, v); err != nil {
return fmt.Errorf("set ipv4 forwarding: %s", err)
}
if err := s.SetForwarding(ipv6.ProtocolNumber, v); err != nil {
if err := s.SetForwardingDefaultAndAllNICs(ipv6.ProtocolNumber, v); err != nil {
return fmt.Errorf("set ipv6 forwarding: %s", err)
}
return nil
+4 -2
View File
@@ -2,6 +2,8 @@
package stack
import (
"github.com/xjasonlyu/tun2socks/core"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
@@ -14,12 +16,12 @@ import (
type Stack struct {
*stack.Stack
handler Handler
handler core.Handler
nicID tcpip.NICID
}
// New allocates a new *Stack with given options.
func New(ep stack.LinkEndpoint, handler Handler, opts ...Option) (*Stack, error) {
func New(ep stack.LinkEndpoint, handler core.Handler, opts ...Option) (*Stack, error) {
s := &Stack{
Stack: stack.New(stack.Options{
NetworkProtocols: []stack.NetworkProtocolFactory{
+5 -13
View File
@@ -5,10 +5,9 @@ import (
"net"
"time"
"github.com/xjasonlyu/tun2socks/common/adapter"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
"gvisor.dev/gvisor/pkg/waiter"
)
@@ -50,15 +49,8 @@ func withTCPHandler() Option {
conn := &tcpConn{
Conn: gonet.NewTCPConn(&wq, ep),
metadata: &adapter.Metadata{
Net: adapter.TCP,
SrcIP: net.IP(id.RemoteAddress),
SrcPort: id.RemotePort,
DstIP: net.IP(id.LocalAddress),
DstPort: id.LocalPort,
},
id: &id,
}
s.handler.Add(conn)
})
s.SetTransportProtocolHandler(tcp.ProtocolNumber, tcpForwarder.HandlePacket)
@@ -83,9 +75,9 @@ func setKeepalive(ep tcpip.Endpoint) error {
type tcpConn struct {
net.Conn
metadata *adapter.Metadata
id *stack.TransportEndpointID
}
func (c *tcpConn) Metadata() *adapter.Metadata {
return c.metadata
func (c *tcpConn) ID() *stack.TransportEndpointID {
return c.id
}
+31 -46
View File
@@ -4,8 +4,6 @@ import (
"fmt"
"net"
"github.com/xjasonlyu/tun2socks/common/adapter"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
"gvisor.dev/gvisor/pkg/tcpip/header"
@@ -23,7 +21,7 @@ func withUDPHandler() Option {
udpHandlePacket := func(id stack.TransportEndpointID, pkt *stack.PacketBuffer) bool {
// Ref: gVisor pkg/tcpip/transport/udp/endpoint.go HandlePacket
udpHdr := header.UDP(pkt.TransportHeader().View())
if int(udpHdr.Length()) > pkt.Data.Size()+header.UDPMinimumSize {
if int(udpHdr.Length()) > pkt.Data().Size()+header.UDPMinimumSize {
// Malformed packet.
s.Stats().UDP.MalformedPacketsReceived.Increment()
return true
@@ -39,18 +37,11 @@ func withUDPHandler() Option {
packet := &udpPacket{
s: s,
id: id,
id: &id,
data: pkt.Data().ExtractVV(),
nicID: pkt.NICID,
netHdr: pkt.Network(),
netProto: pkt.NetworkProtocolNumber,
payload: pkt.Data.ToView(),
metadata: &adapter.Metadata{
Net: adapter.UDP,
SrcIP: net.IP(id.RemoteAddress),
SrcPort: id.RemotePort,
DstIP: net.IP(id.LocalAddress),
DstPort: id.LocalPort,
},
}
s.handler.AddPacket(packet)
@@ -63,30 +54,27 @@ func withUDPHandler() Option {
type udpPacket struct {
s *Stack
id stack.TransportEndpointID
id *stack.TransportEndpointID
data buffer.VectorisedView
nicID tcpip.NICID
netHdr header.Network
netProto tcpip.NetworkProtocolNumber
payload []byte
metadata *adapter.Metadata
}
func (p *udpPacket) Data() []byte {
return p.payload
return p.data.ToView()
}
func (p *udpPacket) Drop() {
/* Release */
func (p *udpPacket) Drop() {}
func (p *udpPacket) ID() *stack.TransportEndpointID {
return p.id
}
func (p *udpPacket) LocalAddr() net.Addr {
return &net.UDPAddr{IP: net.IP(p.id.LocalAddress), Port: int(p.id.LocalPort)}
}
func (p *udpPacket) Metadata() *adapter.Metadata {
return p.metadata
}
func (p *udpPacket) RemoteAddr() net.Addr {
return &net.UDPAddr{IP: net.IP(p.id.RemoteAddress), Port: int(p.id.RemotePort)}
}
@@ -98,33 +86,30 @@ func (p *udpPacket) WriteBack(b []byte, addr net.Addr) (int, error) {
return 0, fmt.Errorf("%s", &tcpip.ErrMessageTooLong{})
}
route, err := p.s.FindRoute(p.nicID, p.netHdr.DestinationAddress(), p.netHdr.SourceAddress(), p.netProto, false /* multicastLoop */)
var (
localAddress tcpip.Address
localPort uint16
)
if udpAddr, ok := addr.(*net.UDPAddr); !ok {
localAddress = p.netHdr.DestinationAddress()
localPort = p.id.LocalPort
} else if ipv4 := udpAddr.IP.To4(); ipv4 != nil {
localAddress = tcpip.Address(ipv4)
localPort = uint16(udpAddr.Port)
} else {
localAddress = tcpip.Address(udpAddr.IP)
localPort = uint16(udpAddr.Port)
}
route, err := p.s.FindRoute(p.nicID, localAddress, p.netHdr.SourceAddress(), p.netProto, false /* multicastLoop */)
if err != nil {
return 0, fmt.Errorf("%#v find route: %s", p.id, err)
}
defer route.Release()
data := v.ToVectorisedView()
// if addr is not provided, write back use original dst Addr as src Addr.
if addr == nil {
if err := sendUDP(route, data, p.id.LocalPort, p.id.RemotePort, udpNoChecksum); err != nil {
return 0, fmt.Errorf("%v", err)
}
return data.Size(), nil
}
udpAddr, ok := addr.(*net.UDPAddr)
if !ok {
return 0, fmt.Errorf("type %T is not a valid udp address", addr)
}
if ipv4 := udpAddr.IP.To4(); ipv4 != nil {
route.LocalAddress = tcpip.Address(ipv4)
} else {
route.LocalAddress = tcpip.Address(udpAddr.IP)
}
if err := sendUDP(route, data, uint16(udpAddr.Port), p.id.RemotePort, udpNoChecksum); err != nil {
if err = sendUDP(route, data, localPort, p.id.RemotePort, udpNoChecksum); err != nil {
return 0, fmt.Errorf("%v", err)
}
return data.Size(), nil
@@ -154,7 +139,7 @@ func sendUDP(r *stack.Route, data buffer.VectorisedView, localPort, remotePort u
// transmitter skipped the checksum generation (RFC768).
// On IPv6, UDP checksum is not optional (RFC2460 Section 8.1).
if r.RequiresTXTransportChecksum() &&
(!noChecksum || r.NetProto == header.IPv6ProtocolNumber) {
(!noChecksum || r.NetProto() == header.IPv6ProtocolNumber) {
xsum := r.PseudoHeaderChecksum(udp.ProtocolNumber, length)
for _, v := range data.Views() {
xsum = header.Checksum(v, xsum)
@@ -164,7 +149,7 @@ func sendUDP(r *stack.Route, data buffer.VectorisedView, localPort, remotePort u
ttl := r.DefaultTTL()
if err := r.WritePacket(nil /* gso */, stack.NetworkHeaderParams{
if err := r.WritePacket(stack.NetworkHeaderParams{
Protocol: udp.ProtocolNumber,
TTL: ttl,
TOS: 0, /* default */
@@ -187,7 +172,7 @@ func verifyChecksum(hdr header.UDP, pkt *stack.PacketBuffer) bool {
(hdr.Checksum() != 0 || pkt.NetworkProtocolNumber == header.IPv6ProtocolNumber) {
netHdr := pkt.Network()
xsum := header.PseudoHeaderChecksum(udp.ProtocolNumber, netHdr.DestinationAddress(), netHdr.SourceAddress(), hdr.Length())
for _, v := range pkt.Data.Views() {
for _, v := range pkt.Data().Views() {
xsum = header.Checksum(v, xsum)
}
return hdr.CalculateChecksum(xsum) == 0xffff
-15
View File
@@ -1,15 +0,0 @@
package tun
type Option func(*TUN)
func WithName(name string) Option {
return func(t *TUN) {
t.name = name
}
}
func WithMTU(mtu uint32) Option {
return func(t *TUN) {
t.mtu = mtu
}
}
-13
View File
@@ -1,13 +0,0 @@
package tun
func WithComponentID(componentID string) Option {
return func(t *TUN) {
t.componentID = componentID
}
}
func WithNetwork(network string) Option {
return func(t *TUN) {
t.network = network
}
}
-2
View File
@@ -1,2 +0,0 @@
// Package tun provides TUN which implemented device.Device interface.
package tun
-80
View File
@@ -1,80 +0,0 @@
// +build darwin freebsd openbsd
package tun
import (
"fmt"
"github.com/xjasonlyu/tun2socks/common/pool"
"github.com/xjasonlyu/tun2socks/device"
"github.com/xjasonlyu/tun2socks/device/rwbased"
"golang.zx2c4.com/wireguard/tun"
)
const offset = 4 /* 4 bytes TUN_PI */
type TUN struct {
*rwbased.Endpoint
nt *tun.NativeTun
mtu uint32
name string
}
func Open(opts ...Option) (device.Device, error) {
t := &TUN{}
for _, opt := range opts {
opt(t)
}
nt, err := tun.CreateTUN(t.name, int(t.mtu))
if err != nil {
return nil, fmt.Errorf("create tun: %w", err)
}
t.nt = nt.(*tun.NativeTun)
mtu, err := nt.MTU()
if err != nil {
return nil, fmt.Errorf("get mtu: %w", err)
}
t.mtu = uint32(mtu)
ep, err := rwbased.New(t, uint32(mtu))
if err != nil {
return nil, fmt.Errorf("create endpoint: %w", err)
}
t.Endpoint = ep
return t, nil
}
func (t *TUN) Read(packet []byte) (n int, err error) {
buf := pool.Get(offset + len(packet))
defer pool.Put(buf)
if n, err = t.nt.Read(buf, offset); err != nil {
return
}
copy(packet, buf[offset:offset+n])
return
}
func (t *TUN) Write(packet []byte) (int, error) {
buf := pool.Get(offset + len(packet))
defer pool.Put(buf)
copy(buf[offset:], packet)
return t.nt.Write(buf[:offset+len(packet)], offset)
}
func (t *TUN) Name() string {
name, _ := t.nt.Name()
return name
}
func (t *TUN) Close() error {
return t.nt.Close()
}
-66
View File
@@ -1,66 +0,0 @@
package tun
import (
"fmt"
"github.com/xjasonlyu/tun2socks/device"
"github.com/xjasonlyu/tun2socks/device/rwbased"
"github.com/songgao/water"
)
const defaultMTU = 1500
type TUN struct {
*rwbased.Endpoint
iface *water.Interface
mtu uint32
name string
// windows only
componentID string
network string
}
func Open(opts ...Option) (device.Device, error) {
t := &TUN{}
for _, opt := range opts {
opt(t)
}
iface, err := water.New(water.Config{
DeviceType: water.TUN,
PlatformSpecificParams: water.PlatformSpecificParams{
ComponentID: t.componentID,
InterfaceName: t.name,
Network: t.network,
},
})
if err != nil {
return nil, fmt.Errorf("create tun: %w", err)
}
t.iface = iface
t.mtu = defaultMTU
if t.mtu > 0 {
/* ignore */
}
ep, err := rwbased.New(iface, t.mtu)
if err != nil {
return nil, fmt.Errorf("create endpoint: %w", err)
}
t.Endpoint = ep
return t, nil
}
func (t *TUN) Name() string {
return t.name
}
func (t *TUN) Close() error {
return t.iface.Close()
}
-37
View File
@@ -1,37 +0,0 @@
version: '2.4'
services:
tun2socks:
image: ghcr.io/xjasonlyu/tun2socks:latest
cap_add:
- NET_ADMIN
devices:
- '/dev/net/tun:/dev/net/tun'
environment:
- GODEBUG=madvdontneed=1
- PROXY=
- LOGLEVEL=
- STATS=
- SECRET=
- EXCLUDED=
- EXTRACMD=
networks:
switch:
ipv4_address: 172.20.1.2
sysctls:
- net.ipv4.ip_forward=1
- net.ipv4.conf.all.rp_filter=0
restart: unless-stopped
container_name: tun2socks
networks:
switch:
name: switch
ipam:
driver: default
config:
- subnet: '172.20.1.0/24'
gateway: 172.20.1.1
driver: macvlan
driver_opts:
parent: eth0
+55 -49
View File
@@ -1,77 +1,83 @@
#!/bin/sh
TUN="${TUN:-tun0}"
ETH="${ETH:-eth0}"
TUN_ADDR="${TUN_ADDR:-198.18.0.1}"
TUN_MASK="${TUN_MASK:-255.254.0.0}"
LOGLEVEL="${LOGLEVEL:-INFO}"
ADDR="${ADDR:-198.18.0.1/15}"
LOGLEVEL="${LOGLEVEL:-info}"
mk_tun() {
# params
NAME="$1"
ADDR="$2"
MASK="$3"
# default values
TABLE="${TABLE:-0x22b}"
FWMARK="${FWMARK:-0x22b}"
CLONE_MAIN="${CLONE_MAIN:-1}"
create_tun() {
# create tun device
ip tuntap add mode tun dev "$NAME"
ip addr add "$ADDR/$MASK" dev "$NAME"
ip link set dev "$NAME" up
ip tuntap add mode tun dev "$TUN"
ip addr add "$ADDR" dev "$TUN"
ip link set dev "$TUN" up
}
create_table() {
if [ "$CLONE_MAIN" -ne 0 ]; then
# clone main route table
ip route show table main |
while read -r route; do
ip route add ${route%linkdown*} table "$TABLE"
done
# replace default route
ip route replace default dev "$TUN" table "$TABLE"
else
# just add default route
ip route add default dev "$TUN" table "$TABLE"
fi
}
config_route() {
# params
TABLE="$1"
TUN_IF="$2"
ETH_IF="$3"
TUN_EXCLUDED="$4"
# add custom table
printf "%s\t%s\n" 100 "$TABLE" >>/etc/iproute2/rt_tables
# clone main route
ip route show table main |
while read -r route; do
ip route add ${route%linkdown*} table "$TABLE"
done
# config default route
ip route del default table "$TABLE"
ip route add default dev "$TUN_IF" table "$TABLE"
# policy routing
tun=$(ip -4 addr show "$TUN_IF" | awk 'NR==2 {print $2}')
eth=$(ip -4 addr show "$ETH_IF" | awk 'NR==2 {split($2,a,"/");print a[1]}')
ip rule add from "$eth" to "$tun" priority 1000 prohibit
ip rule add from "$eth" priority 2000 table main
ip rule add from all priority 3000 table "$TABLE"
ip rule add not fwmark "$FWMARK" table "$TABLE"
ip rule add fwmark "$FWMARK" to "$ADDR" prohibit
# add tun excluded to route
for addr in $(echo "$TUN_EXCLUDED" | tr ',' '\n'); do
# add tun included routes
for addr in $(echo "$TUN_INCLUDED_ROUTES" | tr ',' '\n'); do
ip rule add to "$addr" table "$TABLE"
done
# add tun excluded routes
for addr in $(echo "$TUN_EXCLUDED_ROUTES" | tr ',' '\n'); do
ip rule add to "$addr" table main
done
}
main() {
mk_tun "$TUN" "$TUN_ADDR" "$TUN_MASK"
config_route "tun2socks" "$TUN" "$ETH" "$EXCLUDED"
create_tun
create_table
config_route
# execute extra commands
if [ -n "$EXTRACMD" ]; then
sh -c "$EXTRACMD"
if [ -n "$EXTRA_COMMANDS" ]; then
sh -c "$EXTRA_COMMANDS"
fi
if [ -n "$MTU" ]; then
ARGS="-mtu $MTU"
fi
if [ -n "$STATS" ]; then
ARGS="--stats $STATS"
ARGS="$ARGS -stats $STATS"
fi
if [ -n "$SECRET" ]; then
ARGS="$ARGS --secret $SECRET"
if [ -n "$TOKEN" ]; then
ARGS="$ARGS -token $TOKEN"
fi
if [ -n "$UDP_TIMEOUT" ]; then
ARGS="$ARGS -udp-timeout $UDP_TIMEOUT"
fi
exec tun2socks \
--loglevel "$LOGLEVEL" \
--interface "$ETH" \
--device "$TUN" \
--proxy "$PROXY" \
-loglevel "$LOGLEVEL" \
-fwmark "$FWMARK" \
-device "$TUN" \
-proxy "$PROXY" \
$ARGS
}
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
# Create the necessary file structure for /dev/net/tun
if [ ! -c /dev/net/tun ]; then
if [ ! -d /dev/net ]; then
mkdir -m 755 /dev/net
fi
mknod /dev/net/tun c 10 200
chmod 0755 /dev/net/tun
fi
# Load the tun module if not already loaded
if ( ! (lsmod | grep -q "^tun\s")); then
insmod /lib/modules/tun.ko
fi
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

+108 -51
View File
@@ -1,61 +1,96 @@
package engine
import (
"errors"
"os"
"github.com/xjasonlyu/tun2socks/component/dialer"
"github.com/xjasonlyu/tun2socks/device"
"github.com/xjasonlyu/tun2socks/core/device"
"github.com/xjasonlyu/tun2socks/core/stack"
"github.com/xjasonlyu/tun2socks/log"
"github.com/xjasonlyu/tun2socks/proxy"
"github.com/xjasonlyu/tun2socks/stack"
"github.com/xjasonlyu/tun2socks/stats"
"github.com/xjasonlyu/tun2socks/tunnel"
)
type Engine struct {
mtu uint32
iface string
secret string
stats string
logLevel string
rawProxy string
rawDevice string
var _engine = &engine{}
// Start starts the default engine up.
func Start() error {
return _engine.start()
}
// Stop shuts the default engine down.
func Stop() error {
return _engine.stop()
}
// Insert loads *Key to the default engine.
func Insert(k *Key) {
_engine.insert(k)
}
type Key struct {
MTU int
Mark int
UDPTimeout int
Proxy string
Stats string
Token string
Device string
LogLevel string
Interface string
Version bool
}
type engine struct {
*Key
stack *stack.Stack
proxy proxy.Proxy
device device.Device
}
func New(opts ...Option) *Engine {
e := &Engine{}
for _, opt := range opts {
opt(e)
func (e *engine) start() error {
if e.Key == nil {
return errors.New("empty key")
}
return e
}
func (e *Engine) Start() error {
for _, set := range []func() error{
if e.Version {
showVersion()
os.Exit(0)
}
for _, f := range []func() error{
e.setLogLevel,
e.setMark,
e.setInterface,
e.setStats,
e.setUDPTimeout,
e.setProxy,
e.setDevice,
e.setStack,
} {
if err := set(); err != nil {
if err := f(); err != nil {
return err
}
}
return nil
}
func (e *Engine) Stop() {
func (e *engine) stop() error {
if e.device != nil {
if err := e.device.Close(); err != nil {
log.Fatalf("%v", err)
}
return e.device.Close()
}
return nil
}
func (e *Engine) setLogLevel() error {
level, err := log.ParseLevel(e.logLevel)
func (e *engine) insert(k *Key) {
e.Key = k
}
func (e *engine) setLogLevel() error {
level, err := log.ParseLevel(e.LogLevel)
if err != nil {
return err
}
@@ -63,49 +98,71 @@ func (e *Engine) setLogLevel() error {
return nil
}
func (e *Engine) setInterface() error {
if e.iface != "" {
if err := dialer.BindToInterface(e.iface); err != nil {
func (e *engine) setMark() error {
if e.Mark != 0 {
dialer.SetMark(e.Mark)
log.Infof("[DIALER] set fwmark: %#x", e.Mark)
}
return nil
}
func (e *engine) setInterface() error {
if e.Interface != "" {
if err := dialer.BindToInterface(e.Interface); err != nil {
return err
}
log.Infof("[BOUND] bind to interface: %s", e.iface)
log.Infof("[DIALER] use interface: %s", e.Interface)
}
return nil
}
func (e *Engine) setStats() error {
if e.stats != "" {
func (e *engine) setStats() error {
if e.Stats != "" {
go func() {
_ = stats.Start(e.stats, e.secret)
_ = stats.Start(e.Stats, e.Token)
}()
log.Infof("[STATS] listen and serve at: http://%s", e.stats)
log.Infof("[STATS] serve at: http://%s", e.Stats)
}
return nil
}
func (e *Engine) setProxy() error {
d, err := parseProxy(e.rawProxy)
if err != nil {
return err
func (e *engine) setUDPTimeout() error {
if e.UDPTimeout > 0 {
tunnel.SetUDPTimeout(e.UDPTimeout)
}
proxy.SetDialer(d)
return nil
}
func (e *Engine) setDevice() error {
d, err := parseDevice(e.rawDevice, e.mtu)
if err != nil {
return err
func (e *engine) setProxy() (err error) {
if e.Proxy == "" {
return errors.New("empty proxy")
}
e.device = d
return nil
e.proxy, err = parseProxy(e.Proxy)
proxy.SetDialer(e.proxy)
return
}
func (e *Engine) setStack() error {
handler := &fakeTunnel{}
if _, err := stack.New(e.device, handler, stack.WithDefault()); err != nil {
return err
func (e *engine) setDevice() (err error) {
if e.Device == "" {
return errors.New("empty device")
}
log.Infof("[STACK] %s <-> %s", e.rawDevice, e.rawProxy)
return nil
e.device, err = parseDevice(e.Device, uint32(e.MTU))
return
}
func (e *engine) setStack() (err error) {
defer func() {
if err == nil {
log.Infof(
"[STACK] %s://%s <-> %s://%s",
e.device.Type(), e.device.Name(),
e.proxy.Proto(), e.proxy.Addr(),
)
}
}()
e.stack, err = stack.New(e.device, &fakeTunnel{}, stack.WithDefault())
return
}
-40
View File
@@ -1,40 +0,0 @@
package engine
type Option func(*Engine)
func WithDevice(device string) Option {
return func(e *Engine) {
e.rawDevice = device
}
}
func WithInterface(iface string) Option {
return func(e *Engine) {
e.iface = iface
}
}
func WithLogLevel(level string) Option {
return func(e *Engine) {
e.logLevel = level
}
}
func WithMTU(mtu int) Option {
return func(e *Engine) {
e.mtu = uint32(mtu)
}
}
func WithProxy(proxy string) Option {
return func(e *Engine) {
e.rawProxy = proxy
}
}
func WithStats(stats, secret string) Option {
return func(e *Engine) {
e.stats = stats
e.secret = secret
}
}
+85 -30
View File
@@ -1,19 +1,21 @@
package engine
import (
"encoding/base64"
"fmt"
"net/url"
"strings"
"github.com/xjasonlyu/tun2socks/device"
"github.com/xjasonlyu/tun2socks/device/tun"
"github.com/xjasonlyu/tun2socks/core/device"
"github.com/xjasonlyu/tun2socks/core/device/fd"
"github.com/xjasonlyu/tun2socks/core/device/tun"
"github.com/xjasonlyu/tun2socks/proxy"
"github.com/xjasonlyu/tun2socks/proxy/proto"
)
func parseDevice(s string, mtu uint32) (device.Device, error) {
const defaultDriver = "tun"
if !strings.Contains(s, "://") {
s = defaultDriver + "://" + s
s = fmt.Sprintf("%s://%s", tun.Driver /* default driver */, s)
}
u, err := url.Parse(s)
@@ -22,27 +24,21 @@ func parseDevice(s string, mtu uint32) (device.Device, error) {
}
name := u.Host
driver := u.Scheme
var d device.Device
driver := strings.ToLower(u.Scheme)
switch driver {
case "tun":
d, err = tun.Open(tun.WithName(name), tun.WithMTU(mtu))
case fd.Driver:
return fd.Open(name, mtu)
case tun.Driver:
return tun.Open(name, mtu)
default:
err = fmt.Errorf("unsupported driver: %s", driver)
return nil, fmt.Errorf("unsupported driver: %s", driver)
}
if err != nil {
return nil, err
}
return d, nil
}
func parseProxy(s string) (proxy.Dialer, error) {
const defaultProto = "socks5"
func parseProxy(s string) (proxy.Proxy, error) {
if !strings.Contains(s, "://") {
s = defaultProto + "://" + s
s = fmt.Sprintf("%s://%s", proto.Socks5 /* default protocol */, s)
}
u, err := url.Parse(s)
@@ -50,20 +46,79 @@ func parseProxy(s string) (proxy.Dialer, error) {
return nil, err
}
addr := u.Host
user := u.User.Username()
pass, _ := u.User.Password()
proto := strings.ToLower(u.Scheme)
protocol := strings.ToLower(u.Scheme)
switch proto {
case "direct":
switch protocol {
case proto.Direct.String():
return proxy.NewDirect(), nil
case "socks5":
return proxy.NewSocks5(addr, user, pass)
case "ss", "shadowsocks":
method, password := user, pass
return proxy.NewShadowSocks(addr, method, password)
case proto.Reject.String():
return proxy.NewReject(), nil
case proto.HTTP.String():
return proxy.NewHTTP(parseHTTP(u))
case proto.Socks4.String():
return proxy.NewSocks4(parseSocks4(u))
case proto.Socks5.String():
return proxy.NewSocks5(parseSocks5(u))
case proto.Shadowsocks.String():
return proxy.NewShadowsocks(parseShadowsocks(u))
default:
return nil, fmt.Errorf("unsupported protocol: %s", protocol)
}
}
func parseHTTP(u *url.URL) (address, username, password string) {
address, username = u.Host, u.User.Username()
password, _ = u.User.Password()
return
}
func parseSocks4(u *url.URL) (address, username string) {
address, username = u.Host, u.User.Username()
return
}
func parseSocks5(u *url.URL) (address, username, password string) {
address, username = u.Host, u.User.Username()
password, _ = u.User.Password()
// Socks5 over UDS
if address == "" {
address = u.Path
}
return
}
func parseShadowsocks(u *url.URL) (address, method, password, obfsMode, obfsHost string) {
address = u.Host
if pass, set := u.User.Password(); set {
method = u.User.Username()
password = pass
} else {
data, _ := base64.RawURLEncoding.DecodeString(u.User.String())
userInfo := strings.SplitN(string(data), ":", 2)
if len(userInfo) == 2 {
method = userInfo[0]
password = userInfo[1]
}
}
return nil, fmt.Errorf("unsupported protocol: %s", proto)
rawQuery, _ := url.QueryUnescape(u.RawQuery)
for _, s := range strings.Split(rawQuery, ";") {
data := strings.SplitN(s, "=", 2)
if len(data) != 2 {
continue
}
key := data[0]
value := data[1]
switch key {
case "obfs":
obfsMode = value
case "obfs-host":
obfsHost = value
}
}
return
}
+4 -5
View File
@@ -1,19 +1,18 @@
package engine
import (
"github.com/xjasonlyu/tun2socks/common/adapter"
"github.com/xjasonlyu/tun2socks/stack"
"github.com/xjasonlyu/tun2socks/core"
"github.com/xjasonlyu/tun2socks/tunnel"
)
var _ stack.Handler = (*fakeTunnel)(nil)
var _ core.Handler = (*fakeTunnel)(nil)
type fakeTunnel struct{}
func (*fakeTunnel) Add(conn adapter.TCPConn) {
func (*fakeTunnel) Add(conn core.TCPConn) {
tunnel.Add(conn)
}
func (*fakeTunnel) AddPacket(packet adapter.UDPPacket) {
func (*fakeTunnel) AddPacket(packet core.UDPPacket) {
tunnel.AddPacket(packet)
}
+22
View File
@@ -0,0 +1,22 @@
package engine
import (
"fmt"
"runtime"
"strings"
V "github.com/xjasonlyu/tun2socks/constant"
)
func showVersion() {
fmt.Print(versionString())
fmt.Print(releaseString())
}
func versionString() string {
return fmt.Sprintf("%s-%s\n", V.Name, strings.TrimPrefix(V.Version, "v"))
}
func releaseString() string {
return fmt.Sprintf("%s/%s, %s, %s\n", runtime.GOOS, runtime.GOARCH, runtime.Version(), V.GitCommit)
}
+20 -15
View File
@@ -1,23 +1,28 @@
module github.com/xjasonlyu/tun2socks
go 1.15
go 1.17
require (
github.com/Dreamacro/go-shadowsocks2 v0.1.6
github.com/Dreamacro/go-shadowsocks2 v0.1.7
github.com/go-chi/chi v4.1.2+incompatible
github.com/go-chi/cors v1.1.1
github.com/go-chi/cors v1.2.0
github.com/go-chi/render v1.0.1
github.com/gofrs/uuid v4.0.0+incompatible
github.com/gofrs/uuid v4.1.0+incompatible
github.com/gorilla/websocket v1.4.2
github.com/sirupsen/logrus v1.7.0
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.5.1
go.uber.org/atomic v1.7.0
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 // indirect
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324
golang.zx2c4.com/wireguard v0.0.20201118
gvisor.dev/gvisor v0.0.0-20210205020539-1dbf4e4527a5
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.0
go.uber.org/atomic v1.9.0
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
golang.org/x/net v0.0.0-20211029224645-99673261e6eb // indirect
golang.org/x/sys v0.0.0-20211031064116-611d5d643895
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
golang.zx2c4.com/wireguard v0.0.0-20211030003956-52704c4b9288
gvisor.dev/gvisor v0.0.0-20211029210705-806fa5c3235c
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)
+31 -629
View File
@@ -1,649 +1,51 @@
bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Dreamacro/go-shadowsocks2 v0.1.6 h1:PysSf9sLT3Qn8jhlin5v7Rk68gOQG4K5BZFY1nxLGxI=
github.com/Dreamacro/go-shadowsocks2 v0.1.6/go.mod h1:LSXCjyHesPY3pLjhwff1mQX72ItcBT/N2xNC685cYeU=
github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/cenkalti/backoff v1.1.1-0.20190506075156-2146c9339422/go.mod h1:b6Nc7NRH5C4aCISLry0tLnTjcuTEvoiqcWDdsU0sOGM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg=
github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM=
github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw=
github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.3.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y=
github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
github.com/containerd/fifo v0.0.0-20191213151349-ff969a566b00/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0=
github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g=
github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
github.com/containerd/typeurl v0.0.0-20200205145503-b45ef1f1f737/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg=
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/Dreamacro/go-shadowsocks2 v0.1.7 h1:8CtbE1HoPPMfrQZGXmlluq6dO2lL31W6WRRE8fabc4Q=
github.com/Dreamacro/go-shadowsocks2 v0.1.7/go.mod h1:8p5G4cAj5ZlXwUR+Ww63gfSikr8kvw8uw3TDwLAJpUc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v1.4.2-0.20191028175130-9e7d5ac5ea55/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
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/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec=
github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/cors v1.1.1 h1:eHuqxsIw89iXcWnWUN8R72JMibABJTN/4IOYI5WERvw=
github.com/go-chi/cors v1.1.1/go.mod h1:K2Yje0VW/SJzxiyMYu6iPQYa7hMjQX2i/F491VChg1I=
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/render v1.0.1 h1:4/5tis2cKaNdnv9zFLfXzcquC9HbeZgCnxGnKrltBS8=
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/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/flock v0.6.1-0.20180915234121-886344bea079/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210115211752-39141e76b647/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/subcommands v1.0.2-0.20190508160503-636abe8753b8/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gofrs/uuid v4.1.0+incompatible h1:sIa2eCvUTwgjbqXrPLfNwUf9S3i3mpH1O1atV+iL/Wk=
github.com/gofrs/uuid v4.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.4-0.20190131011033-7dc38fb350b1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a/go.mod h1:M1qoD/MqPgTZIk0EWKB38wE28ACRfVcn+cU08jyArI0=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mohae/deepcopy v0.0.0-20170308212314-bb9b5e7adda9/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8=
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/vishvananda/netlink v1.0.1-0.20190930145447-2ec5bdc52b86/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/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=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/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 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
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-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/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.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/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-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
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-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-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 h1:42cLlJJdEh+ySyeUUbEQ5bsTiq8voBeTuweGVkY6Puw=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
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-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-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/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-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-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-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
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/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211029224645-99673261e6eb h1:pirldcYWx7rx7kE5r+9WsOXPXK0+WH5+uZ7uPmJ44uM=
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201117222635-ba5294a509c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/sys v0.0.0-20211031064116-611d5d643895 h1:iaNpwpnrgL5jzWS0vCNnfa8HqzxveCFpFx3uC/X4Tps=
golang.org/x/sys v0.0.0-20211031064116-611d5d643895/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
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.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
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-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE=
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
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-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-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/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-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-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-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/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-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-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-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-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.zx2c4.com/wireguard v0.0.20201118 h1:QL8y2C7uO8T6z1GY+UX/hSeWiYEBurQkXjOTRFtCvXU=
golang.zx2c4.com/wireguard v0.0.20201118/go.mod h1:Dz+cq5bnrai9EpgYj4GDof/+qaGzbRWbeaAOs1bUYa0=
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.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.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.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.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/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.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.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/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-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
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-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-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-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-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
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-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
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.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
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.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.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.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.36.0-dev.0.20210122012134-2c42474aca0c/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
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-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.25.1-0.20201020201750-d3470999428b/go.mod h1:hFxJC2f0epmp1elRCiEGJTKAWbwxZ2nvqZdHl3FQXCY=
golang.zx2c4.com/wireguard v0.0.0-20211030003956-52704c4b9288 h1:v3PAPzkDfgUxCCHa2ygoesDpj490YbYB4Q3ZuE6lFKk=
golang.zx2c4.com/wireguard v0.0.0-20211030003956-52704c4b9288/go.mod h1:RTjaYEQboNk7+2qfPGBotaMEh/5HIvmPZ6DIe10lTqI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gvisor.dev/gvisor v0.0.0-20210205020539-1dbf4e4527a5 h1:rXHdBmJgbj9e4FQHMUfvH+/QDIeh+GJT11TcOslPP30=
gvisor.dev/gvisor v0.0.0-20210205020539-1dbf4e4527a5/go.mod h1:bGHhdxWoqL+3AwdMfePr6TWTcvHO33egRmxDPAQFdJE=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.1.1/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
k8s.io/api v0.16.13/go.mod h1:QWu8UWSTiuQZMMeYjwLs6ILu5O74qKSJ0c+4vrchDxs=
k8s.io/apimachinery v0.16.13/go.mod h1:4HMHS3mDHtVttspuuhrJ1GGr/0S9B6iWYWZ57KnnZqQ=
k8s.io/apimachinery v0.16.14-rc.0/go.mod h1:4HMHS3mDHtVttspuuhrJ1GGr/0S9B6iWYWZ57KnnZqQ=
k8s.io/client-go v0.16.13/go.mod h1:UKvVT4cajC2iN7DCjLgT0KVY/cbY6DGdUCyRiIfws5M=
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
k8s.io/kube-openapi v0.0.0-20200410163147-594e756bea31/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gvisor.dev/gvisor v0.0.0-20211029210705-806fa5c3235c h1:S4L2OVKs48LB9vVbPaiEfRqon+dn0wm3MABd2cyvjkc=
gvisor.dev/gvisor v0.0.0-20211029210705-806fa5c3235c/go.mod h1:btyTBPTxT8AFMvW7yctFJ2nPCEDWZLpmKQEZ0gG+bbQ=
+5 -5
View File
@@ -8,8 +8,8 @@ import (
)
var (
logCh = make(chan interface{})
source = observable.NewObservable(logCh)
_logCh = make(chan interface{})
_source = observable.NewObservable(_logCh)
)
type Event struct {
@@ -24,16 +24,16 @@ func newEvent(level Level, format string, args ...interface{}) *Event {
Time: time.Now(),
Message: fmt.Sprintf(format, args...),
}
logCh <- event /* send all events to logCh */
_logCh <- event /* send all events to logCh */
return event
}
func Subscribe() observable.Subscription {
sub, _ := source.Subscribe()
sub, _ := _source.Subscribe()
return sub
}
func UnSubscribe(sub observable.Subscription) {
source.UnSubscribe(sub)
_source.UnSubscribe(sub)
}
+2 -2
View File
@@ -56,11 +56,11 @@ func (level Level) String() string {
func ParseLevel(lvl string) (Level, error) {
switch strings.ToLower(lvl) {
case "silent", "none":
case "silent":
return SilentLevel, nil
case "error":
return ErrorLevel, nil
case "warn", "warning":
case "warn":
return WarnLevel, nil
case "info":
return InfoLevel, nil
+5 -5
View File
@@ -2,14 +2,14 @@ package log
import (
"os"
"sync/atomic"
"github.com/sirupsen/logrus"
"go.uber.org/atomic"
)
var (
// defaultLevel is package default logging level.
defaultLevel = InfoLevel
// _defaultLevel is package default logging level.
_defaultLevel = atomic.NewUint32(uint32(InfoLevel))
)
func init() {
@@ -18,7 +18,7 @@ func init() {
}
func SetLevel(level Level) {
atomic.StoreUint32((*uint32)(&defaultLevel), uint32(level))
_defaultLevel.Store(uint32(level))
}
func Debugf(format string, args ...interface{}) {
@@ -43,7 +43,7 @@ func Fatalf(format string, args ...interface{}) {
func logf(level Level, format string, args ...interface{}) {
event := newEvent(level, format, args...)
if event.Level > defaultLevel {
if uint32(event.Level) > _defaultLevel.Load() {
return
}
+20 -47
View File
@@ -1,69 +1,42 @@
package main
import (
"fmt"
"flag"
"os"
"os/signal"
"runtime"
"syscall"
"github.com/xjasonlyu/tun2socks/constant"
"github.com/xjasonlyu/tun2socks/engine"
"github.com/xjasonlyu/tun2socks/log"
flag "github.com/spf13/pflag"
)
var (
device string
iface string
level string
proxy string
secret string
stats string
mtu int
version bool
)
var key = new(engine.Key)
func init() {
flag.StringVarP(&device, "device", "d", "", "Use this device [driver://]name")
flag.StringVarP(&iface, "interface", "i", "", "Use network INTERFACE (Darwin/Linux only)")
flag.StringVarP(&proxy, "proxy", "p", "", "Use this proxy [protocol://]host[:port]")
flag.StringVarP(&level, "loglevel", "l", "info", "Log level [debug|info|warn|error|silent]")
flag.StringVar(&secret, "secret", "", "HTTP statistic server auth secret")
flag.StringVar(&stats, "stats", "", "HTTP statistic server listen address")
flag.IntVarP(&mtu, "mtu", "m", 0, "Maximum transmission unit")
flag.BoolVarP(&version, "version", "v", false, "Show version information and quit")
flag.IntVar(&key.Mark, "fwmark", 0, "Set firewall MARK (Linux only)")
flag.IntVar(&key.MTU, "mtu", 0, "Set device maximum transmission unit (MTU)")
flag.IntVar(&key.UDPTimeout, "udp-timeout", 0, "Set timeout for each UDP session")
flag.BoolVar(&key.Version, "version", false, "Show version information and quit")
flag.StringVar(&key.Device, "device", "", "Use this device [driver://]name")
flag.StringVar(&key.Interface, "interface", "", "Use network INTERFACE (Linux/MacOS only)")
flag.StringVar(&key.LogLevel, "loglevel", "info", "Log level [debug|info|warn|error|silent]")
flag.StringVar(&key.Proxy, "proxy", "", "Use this proxy [protocol://]host[:port]")
flag.StringVar(&key.Stats, "stats", "", "HTTP statistic server listen address")
flag.StringVar(&key.Token, "token", "", "HTTP statistic server auth token")
flag.Parse()
}
func main() {
if version {
fmt.Printf("%s %s\n%s/%s, %s, %s\n",
constant.Name,
constant.Version,
runtime.GOOS,
runtime.GOARCH,
runtime.Version(),
constant.BuildTime,
)
os.Exit(0)
engine.Insert(key)
checkErr := func(msg string, f func() error) {
if err := f(); err != nil {
log.Fatalf("Failed to %s: %v", msg, err)
}
}
options := []engine.Option{
engine.WithDevice(device),
engine.WithInterface(iface),
engine.WithLogLevel(level),
engine.WithMTU(mtu),
engine.WithProxy(proxy),
engine.WithStats(stats, secret),
}
eng := engine.New(options...)
if err := eng.Start(); err != nil {
log.Fatalf("Start engine error: %v", err)
}
defer eng.Stop()
checkErr("start engine", engine.Start)
defer checkErr("stop engine", engine.Stop)
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
+12 -8
View File
@@ -5,25 +5,29 @@ import (
"errors"
"net"
"github.com/xjasonlyu/tun2socks/common/adapter"
M "github.com/xjasonlyu/tun2socks/constant"
"github.com/xjasonlyu/tun2socks/proxy/proto"
)
type Base struct {
addr string
}
var _ Proxy = (*Base)(nil)
func NewBase(addr string) *Base {
return &Base{addr: addr}
type Base struct {
addr string
proto proto.Proto
}
func (b *Base) Addr() string {
return b.addr
}
func (b *Base) DialContext(context.Context, *adapter.Metadata) (net.Conn, error) {
func (b *Base) Proto() proto.Proto {
return b.proto
}
func (b *Base) DialContext(context.Context, *M.Metadata) (net.Conn, error) {
return nil, errors.New("not supported")
}
func (b *Base) DialUDP(*adapter.Metadata) (net.PacketConn, error) {
func (b *Base) DialUDP(*M.Metadata) (net.PacketConn, error) {
return nil, errors.New("not supported")
}
+12 -5
View File
@@ -4,19 +4,26 @@ import (
"context"
"net"
"github.com/xjasonlyu/tun2socks/common/adapter"
"github.com/xjasonlyu/tun2socks/component/dialer"
M "github.com/xjasonlyu/tun2socks/constant"
"github.com/xjasonlyu/tun2socks/proxy/proto"
)
var _ Proxy = (*Direct)(nil)
type Direct struct {
*Base
}
func NewDirect() *Direct {
return &Direct{}
return &Direct{
Base: &Base{
proto: proto.Direct,
},
}
}
func (d *Direct) DialContext(ctx context.Context, metadata *adapter.Metadata) (net.Conn, error) {
func (d *Direct) DialContext(ctx context.Context, metadata *M.Metadata) (net.Conn, error) {
c, err := dialer.DialContext(ctx, "tcp", metadata.DestinationAddress())
if err != nil {
return nil, err
@@ -25,7 +32,7 @@ func (d *Direct) DialContext(ctx context.Context, metadata *adapter.Metadata) (n
return c, nil
}
func (d *Direct) DialUDP(_ *adapter.Metadata) (net.PacketConn, error) {
func (d *Direct) DialUDP(*M.Metadata) (net.PacketConn, error) {
pc, err := dialer.ListenPacket("udp", "")
if err != nil {
return nil, err
@@ -38,7 +45,7 @@ type directPacketConn struct {
}
func (pc *directPacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
if m, ok := addr.(*adapter.Metadata); ok && m.DstIP != nil {
if m, ok := addr.(*M.Metadata); ok && m.DstIP != nil {
return pc.PacketConn.WriteTo(b, m.UDPAddr())
}
+97
View File
@@ -0,0 +1,97 @@
package proxy
// Ref: https://github.com/Dreamacro/clash/adapter/outbound/http
import (
"bufio"
"context"
"encoding/base64"
"errors"
"fmt"
"io"
"net"
"net/http"
"net/url"
"github.com/xjasonlyu/tun2socks/component/dialer"
M "github.com/xjasonlyu/tun2socks/constant"
"github.com/xjasonlyu/tun2socks/proxy/proto"
)
type HTTP struct {
*Base
user string
pass string
}
func NewHTTP(addr, user, pass string) (*HTTP, error) {
return &HTTP{
Base: &Base{
addr: addr,
proto: proto.HTTP,
},
user: user,
pass: pass,
}, nil
}
func (h *HTTP) DialContext(ctx context.Context, metadata *M.Metadata) (c net.Conn, err error) {
c, err = dialer.DialContext(ctx, "tcp", h.Addr())
if err != nil {
return nil, fmt.Errorf("connect to %s: %w", h.Addr(), err)
}
setKeepAlive(c)
defer safeConnClose(c, err)
err = h.shakeHand(metadata, c)
return
}
func (h *HTTP) shakeHand(metadata *M.Metadata, rw io.ReadWriter) error {
addr := metadata.DestinationAddress()
req := &http.Request{
Method: http.MethodConnect,
URL: &url.URL{
Host: addr,
},
Host: addr,
Header: http.Header{
"Proxy-Connection": []string{"Keep-Alive"},
},
}
if h.user != "" && h.pass != "" {
auth := h.user + ":" + h.pass
req.Header.Add("Proxy-Authorization",
fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(auth))))
}
if err := req.Write(rw); err != nil {
return err
}
resp, err := http.ReadResponse(bufio.NewReader(rw), req)
if err != nil {
return err
}
if resp.StatusCode == http.StatusOK {
return nil
}
if resp.StatusCode == http.StatusProxyAuthRequired {
return errors.New("HTTP need auth")
}
if resp.StatusCode == http.StatusMethodNotAllowed {
return errors.New("CONNECT method not allowed by proxy")
}
if resp.StatusCode >= http.StatusInternalServerError {
return errors.New(resp.Status)
}
return fmt.Errorf("HTTP connect status code: %d", resp.StatusCode)
}
+33
View File
@@ -0,0 +1,33 @@
package proto
import "fmt"
const (
Direct Proto = iota
Reject
HTTP
Socks4
Socks5
Shadowsocks
)
type Proto uint8
func (proto Proto) String() string {
switch proto {
case Direct:
return "direct"
case Reject:
return "reject"
case HTTP:
return "http"
case Socks4:
return "socks4"
case Socks5:
return "socks5"
case Shadowsocks:
return "ss"
default:
return fmt.Sprintf("proto(%d)", proto)
}
}
+13 -6
View File
@@ -6,7 +6,8 @@ import (
"net"
"time"
"github.com/xjasonlyu/tun2socks/common/adapter"
M "github.com/xjasonlyu/tun2socks/constant"
"github.com/xjasonlyu/tun2socks/proxy/proto"
)
const (
@@ -18,8 +19,14 @@ var (
)
type Dialer interface {
DialContext(context.Context, *adapter.Metadata) (net.Conn, error)
DialUDP(*adapter.Metadata) (net.PacketConn, error)
DialContext(context.Context, *M.Metadata) (net.Conn, error)
DialUDP(*M.Metadata) (net.PacketConn, error)
}
type Proxy interface {
Dialer
Addr() string
Proto() proto.Proto
}
// SetDialer sets default Dialer.
@@ -28,18 +35,18 @@ func SetDialer(d Dialer) {
}
// Dial uses default Dialer to dial TCP.
func Dial(metadata *adapter.Metadata) (net.Conn, error) {
func Dial(metadata *M.Metadata) (net.Conn, error) {
ctx, cancel := context.WithTimeout(context.Background(), tcpConnectTimeout)
defer cancel()
return _defaultDialer.DialContext(ctx, metadata)
}
// DialContext uses default Dialer to dial TCP with context.
func DialContext(ctx context.Context, metadata *adapter.Metadata) (net.Conn, error) {
func DialContext(ctx context.Context, metadata *M.Metadata) (net.Conn, error) {
return _defaultDialer.DialContext(ctx, metadata)
}
// DialUDP uses default Dialer to dial UDP.
func DialUDP(metadata *adapter.Metadata) (net.PacketConn, error) {
func DialUDP(metadata *M.Metadata) (net.PacketConn, error) {
return _defaultDialer.DialUDP(metadata)
}
+32
View File
@@ -0,0 +1,32 @@
package proxy
import (
"context"
"errors"
"net"
M "github.com/xjasonlyu/tun2socks/constant"
"github.com/xjasonlyu/tun2socks/proxy/proto"
)
var _ Proxy = (*Reject)(nil)
type Reject struct {
*Base
}
func NewReject() *Reject {
return &Reject{
Base: &Base{
proto: proto.Reject,
},
}
}
func (r *Reject) DialContext(context.Context, *M.Metadata) (net.Conn, error) {
return nil, errors.New("TCP rejected")
}
func (r *Reject) DialUDP(*M.Metadata) (net.PacketConn, error) {
return nil, errors.New("UDP rejected")
}
+31 -15
View File
@@ -6,50 +6,66 @@ import (
"fmt"
"net"
"github.com/xjasonlyu/tun2socks/common/adapter"
"github.com/xjasonlyu/tun2socks/component/dialer"
"github.com/xjasonlyu/tun2socks/component/socks5"
obfs "github.com/xjasonlyu/tun2socks/component/simple-obfs"
M "github.com/xjasonlyu/tun2socks/constant"
"github.com/xjasonlyu/tun2socks/proxy/proto"
"github.com/xjasonlyu/tun2socks/transport/socks5"
"github.com/Dreamacro/go-shadowsocks2/core"
)
type ShadowSocks struct {
var _ Proxy = (*Shadowsocks)(nil)
type Shadowsocks struct {
*Base
cipher core.Cipher
// simple-obfs plugin
obfsMode, obfsHost string
}
func NewShadowSocks(addr, method, password string) (*ShadowSocks, error) {
func NewShadowsocks(addr, method, password, obfsMode, obfsHost string) (*Shadowsocks, error) {
cipher, err := core.PickCipher(method, nil, password)
if err != nil {
return nil, fmt.Errorf("ss initialize: %w", err)
}
return &ShadowSocks{
Base: NewBase(addr),
cipher: cipher,
return &Shadowsocks{
Base: &Base{
addr: addr,
proto: proto.Shadowsocks,
},
cipher: cipher,
obfsMode: obfsMode,
obfsHost: obfsHost,
}, nil
}
func (ss *ShadowSocks) DialContext(ctx context.Context, metadata *adapter.Metadata) (c net.Conn, err error) {
func (ss *Shadowsocks) DialContext(ctx context.Context, metadata *M.Metadata) (c net.Conn, err error) {
c, err = dialer.DialContext(ctx, "tcp", ss.Addr())
if err != nil {
return nil, fmt.Errorf("connect to %s: %w", ss.Addr(), err)
}
setKeepAlive(c)
defer func() {
if err != nil && c != nil {
c.Close()
}
}()
defer safeConnClose(c, err)
switch ss.obfsMode {
case "tls":
c = obfs.NewTLSObfs(c, ss.obfsHost)
case "http":
_, port, _ := net.SplitHostPort(ss.addr)
c = obfs.NewHTTPObfs(c, ss.obfsHost, port)
}
c = ss.cipher.StreamConn(c)
_, err = c.Write(metadata.SerializesSocksAddr())
return
}
func (ss *ShadowSocks) DialUDP(_ *adapter.Metadata) (net.PacketConn, error) {
func (ss *Shadowsocks) DialUDP(*M.Metadata) (net.PacketConn, error) {
pc, err := dialer.ListenPacket("udp", "")
if err != nil {
return nil, fmt.Errorf("listen packet: %w", err)
@@ -72,7 +88,7 @@ type ssPacketConn struct {
func (pc *ssPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
var packet []byte
if m, ok := addr.(*adapter.Metadata); ok {
if m, ok := addr.(*M.Metadata); ok {
packet, err = socks5.EncodeUDPPacket(m.SerializesSocksAddr(), b)
} else {
packet, err = socks5.EncodeUDPPacket(socks5.ParseAddrToSocksAddr(addr), b)
+43
View File
@@ -0,0 +1,43 @@
package proxy
import (
"context"
"fmt"
"net"
"github.com/xjasonlyu/tun2socks/component/dialer"
M "github.com/xjasonlyu/tun2socks/constant"
"github.com/xjasonlyu/tun2socks/proxy/proto"
"github.com/xjasonlyu/tun2socks/transport/socks4"
)
var _ Proxy = (*Socks4)(nil)
type Socks4 struct {
*Base
userID string
}
func NewSocks4(addr, userID string) (*Socks4, error) {
return &Socks4{
Base: &Base{
addr: addr,
proto: proto.Socks4,
},
userID: userID,
}, nil
}
func (ss *Socks4) DialContext(ctx context.Context, metadata *M.Metadata) (c net.Conn, err error) {
c, err = dialer.DialContext(ctx, "tcp", ss.Addr())
if err != nil {
return nil, fmt.Errorf("connect to %s: %w", ss.Addr(), err)
}
setKeepAlive(c)
defer safeConnClose(c, err)
err = socks4.ClientHandshake(c, metadata.DestinationAddress(), socks4.CmdConnect, ss.userID)
return
}
+30 -15
View File
@@ -2,43 +2,54 @@ package proxy
import (
"context"
"errors"
"fmt"
"io"
"io/ioutil"
"net"
"github.com/xjasonlyu/tun2socks/common/adapter"
"github.com/xjasonlyu/tun2socks/component/dialer"
"github.com/xjasonlyu/tun2socks/component/socks5"
M "github.com/xjasonlyu/tun2socks/constant"
"github.com/xjasonlyu/tun2socks/proxy/proto"
"github.com/xjasonlyu/tun2socks/transport/socks5"
)
var _ Proxy = (*Socks5)(nil)
type Socks5 struct {
*Base
user string
pass string
// unix indicates if socks5 over UDS is enabled.
unix bool
}
func NewSocks5(addr, user, pass string) (*Socks5, error) {
return &Socks5{
Base: NewBase(addr),
Base: &Base{
addr: addr,
proto: proto.Socks5,
},
user: user,
pass: pass,
unix: len(addr) > 0 && addr[0] == '/',
}, nil
}
func (ss *Socks5) DialContext(ctx context.Context, metadata *adapter.Metadata) (c net.Conn, err error) {
c, err = dialer.DialContext(ctx, "tcp", ss.Addr())
func (ss *Socks5) DialContext(ctx context.Context, metadata *M.Metadata) (c net.Conn, err error) {
var network = "tcp"
if ss.unix {
network = "unix"
}
c, err = dialer.DialContext(ctx, network, ss.Addr())
if err != nil {
return nil, fmt.Errorf("connect to %s: %w", ss.Addr(), err)
}
setKeepAlive(c)
defer func() {
if err != nil && c != nil {
c.Close()
}
}()
defer safeConnClose(c, err)
var user *socks5.User
if ss.user != "" {
@@ -52,7 +63,11 @@ func (ss *Socks5) DialContext(ctx context.Context, metadata *adapter.Metadata) (
return
}
func (ss *Socks5) DialUDP(_ *adapter.Metadata) (_ net.PacketConn, err error) {
func (ss *Socks5) DialUDP(*M.Metadata) (_ net.PacketConn, err error) {
if ss.unix {
return nil, errors.New("not supported when unix domain socket is enabled")
}
ctx, cancel := context.WithTimeout(context.Background(), tcpConnectTimeout)
defer cancel()
@@ -89,7 +104,7 @@ func (ss *Socks5) DialUDP(_ *adapter.Metadata) (_ net.PacketConn, err error) {
addr, err := socks5.ClientHandshake(c, targetAddr, socks5.CmdUDPAssociate, user)
if err != nil {
return nil, fmt.Errorf("client hanshake: %w", err)
return nil, fmt.Errorf("client handshake: %w", err)
}
pc, err := dialer.ListenPacket("udp", "")
@@ -98,7 +113,7 @@ func (ss *Socks5) DialUDP(_ *adapter.Metadata) (_ net.PacketConn, err error) {
}
go func() {
io.Copy(ioutil.Discard, c)
io.Copy(io.Discard, c)
c.Close()
// A UDP association terminates when the TCP connection that the UDP
// ASSOCIATE request arrived on terminates. RFC1928
@@ -126,7 +141,7 @@ type socksPacketConn struct {
func (pc *socksPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
var packet []byte
if m, ok := addr.(*adapter.Metadata); ok {
if m, ok := addr.(*M.Metadata); ok {
packet, err = socks5.EncodeUDPPacket(m.SerializesSocksAddr(), b)
} else {
packet, err = socks5.EncodeUDPPacket(socks5.ParseAddrToSocksAddr(addr), b)
+7
View File
@@ -16,3 +16,10 @@ func setKeepAlive(c net.Conn) {
tcp.SetKeepAlivePeriod(tcpKeepAlivePeriod)
}
}
// safeConnClose closes tcp connection safely.
func safeConnClose(c net.Conn, err error) {
if c != nil && err != nil {
c.Close()
}
}
-10
View File
@@ -1,10 +0,0 @@
package stack
import (
"github.com/xjasonlyu/tun2socks/common/adapter"
)
type Handler interface {
Add(adapter.TCPConn)
AddPacket(adapter.UDPPacket)
}
-40
View File
@@ -1,40 +0,0 @@
package stack
import (
"fmt"
"net"
"gvisor.dev/gvisor/pkg/tcpip"
)
func withICMPHandler() Option {
return func(s *Stack) error {
// Add default route table for IPv4 and IPv6.
// This will handle all incoming ICMP packets.
s.SetRouteTable([]tcpip.Route{
{
Destination: mustSubnet("0.0.0.0/0"),
NIC: s.nicID,
},
{
Destination: mustSubnet("::/0"),
NIC: s.nicID,
},
})
return nil
}
}
// mustSubnet returns tcpip.Subnet from CIDR string.
func mustSubnet(s string) tcpip.Subnet {
_, ipNet, err := net.ParseCIDR(s)
if err != nil {
panic(fmt.Errorf("parse CIDR: %w", err))
}
subnet, err := tcpip.NewSubnet(tcpip.Address(ipNet.IP), tcpip.AddressMask(ipNet.Mask))
if err != nil {
panic(fmt.Errorf("new subnet: %w", err))
}
return subnet
}
+6 -6
View File
@@ -7,7 +7,7 @@ import (
"strconv"
"time"
"github.com/xjasonlyu/tun2socks/tunnel"
"github.com/xjasonlyu/tun2socks/tunnel/statistic"
"github.com/go-chi/chi"
"github.com/go-chi/render"
@@ -26,12 +26,12 @@ func connectionRouter() http.Handler {
func getConnections(w http.ResponseWriter, r *http.Request) {
if !websocket.IsWebSocketUpgrade(r) {
snapshot := tunnel.DefaultManager.Snapshot()
snapshot := statistic.DefaultManager.Snapshot()
render.JSON(w, r, snapshot)
return
}
conn, err := upgrader.Upgrade(w, r, nil)
conn, err := _upgrader.Upgrade(w, r, nil)
if err != nil {
return
}
@@ -52,7 +52,7 @@ func getConnections(w http.ResponseWriter, r *http.Request) {
buf := &bytes.Buffer{}
sendSnapshot := func() error {
buf.Reset()
snapshot := tunnel.DefaultManager.Snapshot()
snapshot := statistic.DefaultManager.Snapshot()
if err := json.NewEncoder(buf).Encode(snapshot); err != nil {
return err
}
@@ -75,7 +75,7 @@ func getConnections(w http.ResponseWriter, r *http.Request) {
func closeConnection(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
snapshot := tunnel.DefaultManager.Snapshot()
snapshot := statistic.DefaultManager.Snapshot()
for _, c := range snapshot.Connections {
if id == c.ID() {
_ = c.Close()
@@ -86,7 +86,7 @@ func closeConnection(w http.ResponseWriter, r *http.Request) {
}
func closeAllConnections(w http.ResponseWriter, r *http.Request) {
snapshot := tunnel.DefaultManager.Snapshot()
snapshot := statistic.DefaultManager.Snapshot()
for _, c := range snapshot.Connections {
_ = c.Close()
}
+16 -16
View File
@@ -8,9 +8,9 @@ import (
"strings"
"time"
"github.com/xjasonlyu/tun2socks/constant"
V "github.com/xjasonlyu/tun2socks/constant"
"github.com/xjasonlyu/tun2socks/log"
"github.com/xjasonlyu/tun2socks/tunnel"
"github.com/xjasonlyu/tun2socks/tunnel/statistic"
"github.com/go-chi/chi"
"github.com/go-chi/cors"
@@ -19,14 +19,14 @@ import (
)
var (
upgrader = websocket.Upgrader{
_upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
)
func Start(addr, secret string) error {
func Start(addr, token string) error {
r := chi.NewRouter()
c := cors.New(cors.Options{
@@ -38,7 +38,7 @@ func Start(addr, secret string) error {
r.Use(c.Handler)
r.Group(func(r chi.Router) {
r.Use(authenticator(secret))
r.Use(authenticator(token))
r.Get("/", hello)
r.Get("/logs", getLogs)
r.Get("/traffic", traffic)
@@ -60,21 +60,21 @@ func Start(addr, secret string) error {
}
func hello(w http.ResponseWriter, r *http.Request) {
render.JSON(w, r, render.M{"hello": constant.Name})
render.JSON(w, r, render.M{"hello": V.Name})
}
func authenticator(secret string) func(http.Handler) http.Handler {
func authenticator(token string) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
if secret == "" {
if token == "" {
next.ServeHTTP(w, r)
return
}
// Browser websocket not support custom header
if websocket.IsWebSocketUpgrade(r) && r.URL.Query().Get("token") != "" {
token := r.URL.Query().Get("token")
if token != secret {
t := r.URL.Query().Get("token")
if t != token {
render.Status(r, http.StatusUnauthorized)
render.JSON(w, r, ErrUnauthorized)
return
@@ -87,8 +87,8 @@ func authenticator(secret string) func(http.Handler) http.Handler {
text := strings.SplitN(header, " ", 2)
hasInvalidHeader := text[0] != "Bearer"
hasInvalidSecret := len(text) != 2 || text[1] != secret
if hasInvalidHeader || hasInvalidSecret {
hasInvalidToken := len(text) != 2 || text[1] != token
if hasInvalidHeader || hasInvalidToken {
render.Status(r, http.StatusUnauthorized)
render.JSON(w, r, ErrUnauthorized)
return
@@ -114,7 +114,7 @@ func getLogs(w http.ResponseWriter, r *http.Request) {
var wsConn *websocket.Conn
if websocket.IsWebSocketUpgrade(r) {
wsConn, err = upgrader.Upgrade(w, r, nil)
wsConn, err = _upgrader.Upgrade(w, r, nil)
if err != nil {
return
}
@@ -163,7 +163,7 @@ func traffic(w http.ResponseWriter, r *http.Request) {
var wsConn *websocket.Conn
if websocket.IsWebSocketUpgrade(r) {
var err error
wsConn, err = upgrader.Upgrade(w, r, nil)
wsConn, err = _upgrader.Upgrade(w, r, nil)
if err != nil {
return
}
@@ -176,7 +176,7 @@ func traffic(w http.ResponseWriter, r *http.Request) {
tick := time.NewTicker(time.Second)
defer tick.Stop()
t := tunnel.DefaultManager
t := statistic.DefaultManager
buf := &bytes.Buffer{}
var err error
for range tick.C {
@@ -203,5 +203,5 @@ func traffic(w http.ResponseWriter, r *http.Request) {
}
func version(w http.ResponseWriter, r *http.Request) {
render.JSON(w, r, render.M{"version": constant.Version})
render.JSON(w, r, render.M{"version": V.Version, "commit": V.GitCommit})
}
+127
View File
@@ -0,0 +1,127 @@
// Package socks4 provides SOCKS4/SOCKS4A client functionalities.
package socks4
import (
"bytes"
"encoding/binary"
"errors"
"io"
"net"
"strconv"
)
const Version = 0x04
type Command = uint8
const (
CmdConnect Command = 0x01
CmdBind Command = 0x02
)
type Code = uint8
const (
RequestGranted Code = 90
RequestRejected Code = 91
RequestIdentdFailed Code = 92
RequestIdentdMismatched Code = 93
)
var (
errVersionMismatched = errors.New("version code mismatched")
errIPv6NotSupported = errors.New("IPv6 not supported")
ErrRequestRejected = errors.New("request rejected or failed")
ErrRequestIdentdFailed = errors.New("request rejected because SOCKS server cannot connect to identd on the client")
ErrRequestIdentdMismatched = errors.New("request rejected because the client program and identd report different user-ids")
ErrRequestUnknownCode = errors.New("request failed with unknown code")
)
func ClientHandshake(rw io.ReadWriter, addr string, command Command, userID string) (err error) {
var (
host string
port uint16
)
if host, port, err = splitHostPort(addr); err != nil {
return err
}
ip := net.ParseIP(host)
if ip == nil /* HOST */ {
ip = net.IPv4(0, 0, 0, 1)
} else if ip.To4() == nil /* IPv6 */ {
return errIPv6NotSupported
}
dstIP := /* [4]byte */ ip.To4()
req := &bytes.Buffer{}
req.WriteByte(Version)
req.WriteByte(command)
binary.Write(req, binary.BigEndian, port)
req.Write(dstIP)
req.WriteString(userID)
req.WriteByte(0) /* NULL */
if isReservedIP(dstIP) /* SOCKS4A */ {
req.WriteString(host)
req.WriteByte(0) /* NULL */
}
if _, err = rw.Write(req.Bytes()); err != nil {
return err
}
var resp [8]byte
if _, err = io.ReadFull(rw, resp[:]); err != nil {
return err
}
if resp[0] != 0x00 {
return errVersionMismatched
}
switch resp[1] {
case RequestGranted:
return nil
case RequestRejected:
return ErrRequestRejected
case RequestIdentdFailed:
return ErrRequestIdentdFailed
case RequestIdentdMismatched:
return ErrRequestIdentdMismatched
default:
return ErrRequestUnknownCode
}
}
// For version 4A, if the client cannot resolve the destination host's
// domain name to find its IP address, it should set the first three bytes
// of DSTIP to NULL and the last byte to a non-zero value. (This corresponds
// to IP address 0.0.0.x, with x nonzero. As decreed by IANA -- The
// Internet Assigned Numbers Authority -- such an address is inadmissible
// as a destination IP address and thus should never occur if the client
// can resolve the domain name.)
func isReservedIP(ip net.IP) bool {
subnet := net.IPNet{
IP: net.IPv4zero,
Mask: net.IPv4Mask(0xff, 0xff, 0xff, 0x00),
}
return !ip.IsUnspecified() && subnet.Contains(ip)
}
func splitHostPort(addr string) (string, uint16, error) {
host, portStr, err := net.SplitHostPort(addr)
if err != nil {
return "", 0, err
}
portInt, err := strconv.ParseUint(portStr, 10, 16)
if err != nil {
return "", 0, err
}
return host, uint16(portInt), nil
}
+152
View File
@@ -0,0 +1,152 @@
SOCKS: A protocol for TCP proxy across firewalls
Ying-Da Lee
Principal Member Technical Staff
NEC Systems Laboratory, CSTC
ylee@syl.dl.nec.com
SOCKS was originally developed by David Koblas and subsequently modified
and extended by me to its current running version -- version 4. It is a
protocol that relays TCP sessions at a firewall host to allow application
users transparent access across the firewall. Because the protocol is
independent of application protocols, it can be (and has been) used for
many different services, such as telnet, ftp, finger, whois, gopher, WWW,
etc. Access control can be applied at the beginning of each TCP session;
thereafter the server simply relays the data between the client and the
application server, incurring minimum processing overhead. Since SOCKS
never has to know anything about the application protocol, it should also
be easy for it to accommodate applications which use encryption to protect
their traffic from nosey snoopers.
Two operations are defined: CONNECT and BIND.
1) CONNECT
The client connects to the SOCKS server and sends a CONNECT request when
it wants to establish a connection to an application server. The client
includes in the request packet the IP address and the port number of the
destination host, and userid, in the following format.
+----+----+----+----+----+----+----+----+----+----+....+----+
| VN | CD | DSTPORT | DSTIP | USERID |NULL|
+----+----+----+----+----+----+----+----+----+----+....+----+
# of bytes: 1 1 2 4 variable 1
VN is the SOCKS protocol version number and should be 4. CD is the
SOCKS command code and should be 1 for CONNECT request. NULL is a byte
of all zero bits.
The SOCKS server checks to see whether such a request should be granted
based on any combination of source IP address, destination IP address,
destination port number, the userid, and information it may obtain by
consulting IDENT, cf. RFC 1413. If the request is granted, the SOCKS
server makes a connection to the specified port of the destination host.
A reply packet is sent to the client when this connection is established,
or when the request is rejected or the operation fails.
+----+----+----+----+----+----+----+----+
| VN | CD | DSTPORT | DSTIP |
+----+----+----+----+----+----+----+----+
# of bytes: 1 1 2 4
VN is the version of the reply code and should be 0. CD is the result
code with one of the following values:
90: request granted
91: request rejected or failed
92: request rejected becasue SOCKS server cannot connect to
identd on the client
93: request rejected because the client program and identd
report different user-ids
The remaining fields are ignored.
The SOCKS server closes its connection immediately after notifying
the client of a failed or rejected request. For a successful request,
the SOCKS server gets ready to relay traffic on both directions. This
enables the client to do I/O on its connection as if it were directly
connected to the application server.
2) BIND
The client connects to the SOCKS server and sends a BIND request when
it wants to prepare for an inbound connection from an application server.
This should only happen after a primary connection to the application
server has been established with a CONNECT. Typically, this is part of
the sequence of actions:
-bind(): obtain a socket
-getsockname(): get the IP address and port number of the socket
-listen(): ready to accept call from the application server
-use the primary connection to inform the application server of
the IP address and the port number that it should connect to.
-accept(): accept a connection from the application server
The purpose of SOCKS BIND operation is to support such a sequence
but using a socket on the SOCKS server rather than on the client.
The client includes in the request packet the IP address of the
application server, the destination port used in the primary connection,
and the userid.
+----+----+----+----+----+----+----+----+----+----+....+----+
| VN | CD | DSTPORT | DSTIP | USERID |NULL|
+----+----+----+----+----+----+----+----+----+----+....+----+
# of bytes: 1 1 2 4 variable 1
VN is again 4 for the SOCKS protocol version number. CD must be 2 to
indicate BIND request.
The SOCKS server uses the client information to decide whether the
request is to be granted. The reply it sends back to the client has
the same format as the reply for CONNECT request, i.e.,
+----+----+----+----+----+----+----+----+
| VN | CD | DSTPORT | DSTIP |
+----+----+----+----+----+----+----+----+
# of bytes: 1 1 2 4
VN is the version of the reply code and should be 0. CD is the result
code with one of the following values:
90: request granted
91: request rejected or failed
92: request rejected becasue SOCKS server cannot connect to
identd on the client
93: request rejected because the client program and identd
report different user-ids.
However, for a granted request (CD is 90), the DSTPORT and DSTIP fields
are meaningful. In that case, the SOCKS server obtains a socket to wait
for an incoming connection and sends the port number and the IP address
of that socket to the client in DSTPORT and DSTIP, respectively. If the
DSTIP in the reply is 0 (the value of constant INADDR_ANY), then the
client should replace it by the IP address of the SOCKS server to which
the cleint is connected. (This happens if the SOCKS server is not a
multi-homed host.) In the typical scenario, these two numbers are
made available to the application client prgram via the result of the
subsequent getsockname() call. The application protocol must provide a
way for these two pieces of information to be sent from the client to
the application server so that it can initiate the connection, which
connects it to the SOCKS server rather than directly to the application
client as it normally would.
The SOCKS server sends a second reply packet to the client when the
anticipated connection from the application server is established.
The SOCKS server checks the IP address of the originating host against
the value of DSTIP specified in the client's BIND request. If a mismatch
is found, the CD field in the second reply is set to 91 and the SOCKS
server closes both connections. If the two match, CD in the second
reply is set to 90 and the SOCKS server gets ready to relay the traffic
on its two connections. From then on the client does I/O on its connection
to the SOCKS server as if it were directly connected to the application
server.
For both CONNECT and BIND operations, the server sets a time limit
(2 minutes in current CSTC implementation) for the establishment of its
connection with the application server. If the connection is still not
establiched when the time limit expires, the server closes its connection
to the client and gives up.
+39
View File
@@ -0,0 +1,39 @@
SOCKS 4A: A Simple Extension to SOCKS 4 Protocol
Ying-Da Lee
yingda@best.com or yingda@esd.sgi.com
Please read SOCKS4.protocol first for an description of the version 4
protocol. This extension is intended to allow the use of SOCKS on hosts
which are not capable of resolving all domain names.
In version 4, the client sends the following packet to the SOCKS server
to request a CONNECT or a BIND operation:
+----+----+----+----+----+----+----+----+----+----+....+----+
| VN | CD | DSTPORT | DSTIP | USERID |NULL|
+----+----+----+----+----+----+----+----+----+----+....+----+
# of bytes: 1 1 2 4 variable 1
VN is the SOCKS protocol version number and should be 4. CD is the
SOCKS command code and should be 1 for CONNECT or 2 for BIND. NULL
is a byte of all zero bits.
For version 4A, if the client cannot resolve the destination host's
domain name to find its IP address, it should set the first three bytes
of DSTIP to NULL and the last byte to a non-zero value. (This corresponds
to IP address 0.0.0.x, with x nonzero. As decreed by IANA -- The
Internet Assigned Numbers Authority -- such an address is inadmissible
as a destination IP address and thus should never occur if the client
can resolve the domain name.) Following the NULL byte terminating
USERID, the client must sends the destination domain name and termiantes
it with another NULL byte. This is used for both CONNECT and BIND requests.
A server using protocol 4A must check the DSTIP in the request packet.
If it represent address 0.0.0.x with nonzero x, the server must read
in the domain name that the client sends in the packet. The server
should resolve the domain name and make connection to the destination
host if it can.
SOCKSified sockd may pass domain names that it cannot resolve to
the next-hop SOCKS server.
@@ -35,6 +35,34 @@ const (
AtypIPv6 Atyp = 0x04
)
// Reply field as defined in RFC 1928 section 6.
type Reply uint8
func (r Reply) String() string {
switch r {
case 0x00:
return "succeeded"
case 0x01:
return "general SOCKS server failure"
case 0x02:
return "connection not allowed by ruleset"
case 0x03:
return "network unreachable"
case 0x04:
return "host unreachable"
case 0x05:
return "connection refused"
case 0x06:
return "TTL expired"
case 0x07:
return "command not supported"
case 0x08:
return "address type not supported"
default:
return "unassigned"
}
}
// MaxAddrLen is the maximum size of SOCKS address in bytes.
const MaxAddrLen = 1 + 1 + 255 + 2
@@ -120,15 +148,16 @@ type User struct {
// ClientHandshake fast-tracks SOCKS initialization to get target address to connect on client side.
func ClientHandshake(rw io.ReadWriter, addr Addr, command Command, user *User) (Addr, error) {
buf := make([]byte, MaxAddrLen)
var err error
var method uint8
if user != nil {
method = 0x02 /* USERNAME/PASSWORD */
} else {
method = 0x00 /* NO AUTHENTICATION REQUIRED */
}
// VER, NMETHODS, METHODS
if user != nil {
_, err = rw.Write([]byte{Version, 0x01 /* NMETHODS */, 0x02 /* USERNAME/PASSWORD */})
} else {
_, err = rw.Write([]byte{Version, 0x01 /* NMETHODS */, 0x00 /* NO AUTHENTICATION REQUIRED */})
}
if err != nil {
if _, err := rw.Write([]byte{Version, 0x01 /* NMETHODS */, method}); err != nil {
return nil, err
}
@@ -184,8 +213,8 @@ func ClientHandshake(rw io.ReadWriter, addr Addr, command Command, user *User) (
return nil, err
}
if buf[1] != 0x00 /* SUCCEEDED */ {
return nil, fmt.Errorf("unsucceed reply: %X", buf[1])
if rep := Reply(buf[1]); rep != 0x00 /* SUCCEEDED */ {
return nil, fmt.Errorf("%#02x: %s", uint8(rep), rep)
}
return ReadAddr(rw, buf)
-22
View File
@@ -1,22 +0,0 @@
package tunnel
import (
"net"
"github.com/xjasonlyu/tun2socks/common/adapter"
"github.com/xjasonlyu/tun2socks/component/manager"
)
var (
// DefaultManager is the default traffic and connections
// manager used by tunnel.
DefaultManager = manager.New()
)
func newTCPTracker(conn net.Conn, metadata *adapter.Metadata) net.Conn {
return manager.NewTCPTracker(conn, metadata, DefaultManager)
}
func newUDPTracker(conn net.PacketConn, metadata *adapter.Metadata) net.PacketConn {
return manager.NewUDPTracker(conn, metadata, DefaultManager)
}
@@ -1,5 +1,4 @@
// Package manager provides statistic management of connections.
package manager
package statistic
import (
"sync"
@@ -8,6 +7,21 @@ import (
"go.uber.org/atomic"
)
var DefaultManager *Manager
func init() {
DefaultManager = &Manager{
uploadTemp: atomic.NewInt64(0),
downloadTemp: atomic.NewInt64(0),
uploadBlip: atomic.NewInt64(0),
downloadBlip: atomic.NewInt64(0),
uploadTotal: atomic.NewInt64(0),
downloadTotal: atomic.NewInt64(0),
}
go DefaultManager.handle()
}
type Manager struct {
connections sync.Map
uploadTemp *atomic.Int64
@@ -18,20 +32,6 @@ type Manager struct {
downloadTotal *atomic.Int64
}
func New() *Manager {
manager := &Manager{
uploadTemp: atomic.NewInt64(0),
downloadTemp: atomic.NewInt64(0),
uploadBlip: atomic.NewInt64(0),
downloadBlip: atomic.NewInt64(0),
uploadTotal: atomic.NewInt64(0),
downloadTotal: atomic.NewInt64(0),
}
go manager.handle()
return manager
}
func (m *Manager) Join(c tracker) {
m.connections.Store(c.ID(), c)
}
@@ -1,10 +1,10 @@
package manager
package statistic
import (
"net"
"time"
"github.com/xjasonlyu/tun2socks/common/adapter"
M "github.com/xjasonlyu/tun2socks/constant"
"github.com/gofrs/uuid"
"go.uber.org/atomic"
@@ -16,11 +16,11 @@ type tracker interface {
}
type trackerInfo struct {
Start time.Time `json:"start"`
UUID uuid.UUID `json:"id"`
Metadata *adapter.Metadata `json:"metadata"`
UploadTotal *atomic.Int64 `json:"upload"`
DownloadTotal *atomic.Int64 `json:"download"`
Start time.Time `json:"start"`
UUID uuid.UUID `json:"id"`
Metadata *M.Metadata `json:"metadata"`
UploadTotal *atomic.Int64 `json:"upload"`
DownloadTotal *atomic.Int64 `json:"download"`
}
type tcpTracker struct {
@@ -30,7 +30,7 @@ type tcpTracker struct {
manager *Manager
}
func NewTCPTracker(conn net.Conn, metadata *adapter.Metadata, manager *Manager) *tcpTracker {
func NewTCPTracker(conn net.Conn, metadata *M.Metadata, manager *Manager) *tcpTracker {
id, _ := uuid.NewV4()
tt := &tcpTracker{
@@ -81,7 +81,7 @@ type udpTracker struct {
manager *Manager
}
func NewUDPTracker(conn net.PacketConn, metadata *adapter.Metadata, manager *Manager) *udpTracker {
func NewUDPTracker(conn net.PacketConn, metadata *M.Metadata, manager *Manager) *udpTracker {
id, _ := uuid.NewV4()
ut := &udpTracker{
+16 -11
View File
@@ -3,27 +3,35 @@ package tunnel
import (
"io"
"net"
"strconv"
"sync"
"time"
"github.com/xjasonlyu/tun2socks/common/adapter"
"github.com/xjasonlyu/tun2socks/common/pool"
M "github.com/xjasonlyu/tun2socks/constant"
"github.com/xjasonlyu/tun2socks/core"
"github.com/xjasonlyu/tun2socks/log"
"github.com/xjasonlyu/tun2socks/proxy"
"github.com/xjasonlyu/tun2socks/tunnel/statistic"
)
const (
tcpWaitTimeout = 5 * time.Second
)
func handleTCP(localConn adapter.TCPConn) {
func newTCPTracker(conn net.Conn, metadata *M.Metadata) net.Conn {
return statistic.NewTCPTracker(conn, metadata, statistic.DefaultManager)
}
func handleTCP(localConn core.TCPConn) {
defer localConn.Close()
metadata := localConn.Metadata()
if !metadata.Valid() {
log.Warnf("[Metadata] not valid: %#v", metadata)
return
id := localConn.ID()
metadata := &M.Metadata{
Net: M.TCP,
SrcIP: net.IP(id.RemoteAddress),
SrcPort: id.RemotePort,
DstIP: net.IP(id.LocalAddress),
DstPort: id.LocalPort,
}
targetConn, err := proxy.Dial(metadata)
@@ -36,10 +44,7 @@ func handleTCP(localConn adapter.TCPConn) {
metadata.MidIP = dialerAddr.IP
metadata.MidPort = uint16(dialerAddr.Port)
} else { /* fallback */
ip, p, _ := net.SplitHostPort(targetConn.LocalAddr().String())
port, _ := strconv.ParseUint(p, 10, 16)
metadata.MidIP = net.ParseIP(ip)
metadata.MidPort = uint16(port)
metadata.MidIP, metadata.MidPort = parseAddr(targetConn.LocalAddr().String())
}
targetConn = newTCPTracker(targetConn, metadata)
+12 -19
View File
@@ -3,7 +3,7 @@ package tunnel
import (
"runtime"
"github.com/xjasonlyu/tun2socks/common/adapter"
"github.com/xjasonlyu/tun2socks/core"
"github.com/xjasonlyu/tun2socks/log"
)
@@ -11,13 +11,13 @@ const (
// maxUDPQueueSize is the max number of UDP packets
// could be buffered. if queue is full, upcoming packets
// would be dropped util queue is ready again.
maxUDPQueueSize = 2 << 10
maxUDPQueueSize = 1 << 9
)
var (
tcpQueue = make(chan adapter.TCPConn) /* unbuffered */
udpQueue = make(chan adapter.UDPPacket, maxUDPQueueSize)
numUDPWorkers = max(runtime.NumCPU(), 4 /* at least 4 workers */)
_tcpQueue = make(chan core.TCPConn) /* unbuffered */
_udpQueue = make(chan core.UDPPacket, maxUDPQueueSize)
_numUDPWorkers = max(runtime.NumCPU(), 4 /* at least 4 workers */)
)
func init() {
@@ -25,30 +25,23 @@ func init() {
}
// Add adds tcpConn to tcpQueue.
func Add(conn adapter.TCPConn) {
tcpQueue <- conn
func Add(conn core.TCPConn) {
_tcpQueue <- conn
}
// AddPacket adds udpPacket to udpQueue.
func AddPacket(packet adapter.UDPPacket) {
func AddPacket(packet core.UDPPacket) {
select {
case udpQueue <- packet:
case _udpQueue <- packet:
default:
log.Warnf("queue is currently full, packet will be dropped")
packet.Drop()
}
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
func process() {
for i := 0; i < numUDPWorkers; i++ {
queue := udpQueue
for i := 0; i < _numUDPWorkers; i++ {
queue := _udpQueue
go func() {
for packet := range queue {
handleUDP(packet)
@@ -56,7 +49,7 @@ func process() {
}()
}
for conn := range tcpQueue {
for conn := range _tcpQueue {
go handleTCP(conn)
}
}
+38 -28
View File
@@ -4,40 +4,52 @@ import (
"errors"
"net"
"os"
"strconv"
"time"
"github.com/xjasonlyu/tun2socks/common/adapter"
"github.com/xjasonlyu/tun2socks/common/pool"
"github.com/xjasonlyu/tun2socks/component/nat"
M "github.com/xjasonlyu/tun2socks/constant"
"github.com/xjasonlyu/tun2socks/core"
"github.com/xjasonlyu/tun2socks/log"
"github.com/xjasonlyu/tun2socks/proxy"
)
const (
udpSessionTimeout = 30 * time.Second
"github.com/xjasonlyu/tun2socks/tunnel/statistic"
)
var (
// natTable uses source udp packet information
// _natTable uses source udp packet information
// as key to store destination udp packetConn.
natTable = nat.NewTable()
_natTable = nat.NewTable()
// _udpSessionTimeout is the default timeout for
// each UDP session.
_udpSessionTimeout = 60 * time.Second
)
func handleUDP(packet adapter.UDPPacket) {
metadata := packet.Metadata()
if !metadata.Valid() {
log.Warnf("[Metadata] not valid: %#v", metadata)
return
func SetUDPTimeout(v int) {
_udpSessionTimeout = time.Duration(v) * time.Second
}
func newUDPTracker(conn net.PacketConn, metadata *M.Metadata) net.PacketConn {
return statistic.NewUDPTracker(conn, metadata, statistic.DefaultManager)
}
func handleUDP(packet core.UDPPacket) {
id := packet.ID()
metadata := &M.Metadata{
Net: M.UDP,
SrcIP: net.IP(id.RemoteAddress),
SrcPort: id.RemotePort,
DstIP: net.IP(id.LocalAddress),
DstPort: id.LocalPort,
}
generateNATKey := func(m *adapter.Metadata) string {
return m.SourceAddress() /* Full Cone NAT Key */
generateNATKey := func(m *M.Metadata) string {
return m.SourceAddress() /* as Full Cone NAT Key */
}
key := generateNATKey(metadata)
handle := func(drop bool) bool {
pc := natTable.Get(key)
pc := _natTable.Get(key)
if pc != nil {
handleUDPToRemote(packet, pc, metadata /* as net.Addr */, drop)
return true
@@ -50,7 +62,7 @@ func handleUDP(packet adapter.UDPPacket) {
}
lockKey := key + "-lock"
cond, loaded := natTable.GetOrCreateLock(lockKey)
cond, loaded := _natTable.GetOrCreateLock(lockKey)
go func() {
if loaded {
cond.L.Lock()
@@ -61,7 +73,7 @@ func handleUDP(packet adapter.UDPPacket) {
}
defer func() {
natTable.Delete(lockKey)
_natTable.Delete(lockKey)
cond.Broadcast()
}()
@@ -75,10 +87,7 @@ func handleUDP(packet adapter.UDPPacket) {
metadata.MidIP = dialerAddr.IP
metadata.MidPort = uint16(dialerAddr.Port)
} else { /* fallback */
ip, p, _ := net.SplitHostPort(pc.LocalAddr().String())
port, _ := strconv.ParseUint(p, 10, 16)
metadata.MidIP = net.ParseIP(ip)
metadata.MidPort = uint16(port)
metadata.MidIP, metadata.MidPort = parseAddr(pc.LocalAddr().String())
}
pc = newUDPTracker(pc, metadata)
@@ -86,17 +95,17 @@ func handleUDP(packet adapter.UDPPacket) {
go func() {
defer pc.Close()
defer packet.Drop()
defer natTable.Delete(key)
defer _natTable.Delete(key)
handleUDPToLocal(packet, pc, udpSessionTimeout)
handleUDPToLocal(packet, pc)
}()
natTable.Set(key, pc)
_natTable.Set(key, pc)
handle(false /* drop */)
}()
}
func handleUDPToRemote(packet adapter.UDPPacket, pc net.PacketConn, remote net.Addr, drop bool) {
func handleUDPToRemote(packet core.UDPPacket, pc net.PacketConn, remote net.Addr, drop bool) {
defer func() {
if drop {
packet.Drop()
@@ -106,16 +115,17 @@ func handleUDPToRemote(packet adapter.UDPPacket, pc net.PacketConn, remote net.A
if _, err := pc.WriteTo(packet.Data() /* data */, remote); err != nil {
log.Warnf("[UDP] write to %s error: %v", remote, err)
}
pc.SetReadDeadline(time.Now().Add(_udpSessionTimeout)) /* reset timeout */
log.Infof("[UDP] %s --> %s", packet.RemoteAddr(), remote)
}
func handleUDPToLocal(packet adapter.UDPPacket, pc net.PacketConn, timeout time.Duration) {
func handleUDPToLocal(packet core.UDPPacket, pc net.PacketConn) {
buf := pool.Get(pool.MaxSegmentSize)
defer pool.Put(buf)
for /* just loop */ {
pc.SetReadDeadline(time.Now().Add(timeout))
pc.SetReadDeadline(time.Now().Add(_udpSessionTimeout))
n, from, err := pc.ReadFrom(buf)
if err != nil {
if !errors.Is(err, os.ErrDeadlineExceeded) /* ignore i/o timeout */ {
+20
View File
@@ -0,0 +1,20 @@
package tunnel
import (
"net"
"strconv"
)
func max(a, b int) int {
if a > b {
return a
}
return b
}
// parseAddr parses address to IP and port.
func parseAddr(addr string) (net.IP, uint16) {
host, portStr, _ := net.SplitHostPort(addr)
portInt, _ := strconv.ParseUint(portStr, 10, 16)
return net.ParseIP(host), uint16(portInt)
}