mirror of
https://github.com/xjasonlyu/tun2socks.git
synced 2024-12-30 02:37:01 +00:00
Compare commits
72
Commits
v2.1.0-beta1
...
v2.1.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4531a74a20 | ||
|
|
b15f93225b | ||
|
|
edf76afd11 | ||
|
|
bb702f57d8 | ||
|
|
b5980dd79d | ||
|
|
2fee5a6d55 | ||
|
|
b2b7e8bc46 | ||
|
|
0e1e04acc7 | ||
|
|
361a8133c9 | ||
|
|
3f73becd66 | ||
|
|
14b905c125 | ||
|
|
4294f56125 | ||
|
|
d98e2234d9 | ||
|
|
43b8dd885d | ||
|
|
3e3990ef8d | ||
|
|
88e9402793 | ||
|
|
f0129eb7ca | ||
|
|
fe9be45844 | ||
|
|
b54d9936f9 | ||
|
|
7e6a9b6a09 | ||
|
|
454ea0a49b | ||
|
|
04d0e1e9a7 | ||
|
|
e849c9a451 | ||
|
|
c28690bfc9 | ||
|
|
7955052b01 | ||
|
|
7e55b71b30 | ||
|
|
c96c5946c8 | ||
|
|
708b7b234d | ||
|
|
96e0c8c390 | ||
|
|
7f7f2913a8 | ||
|
|
ea62deb0b6 | ||
|
|
34fb632f38 | ||
|
|
08f236a01c | ||
|
|
ae77a8a009 | ||
|
|
203e545241 | ||
|
|
136c90d310 | ||
|
|
06a7cf6718 | ||
|
|
ab59724d87 | ||
|
|
50bed22076 | ||
|
|
849f47baf7 | ||
|
|
ace24826d2 | ||
|
|
669a601f1a | ||
|
|
103009cb1d | ||
|
|
ea1832adaa | ||
|
|
cf4ac9b207 | ||
|
|
2fe6caab12 | ||
|
|
6fd3fd0f8c | ||
|
|
2e0b9d5e24 | ||
|
|
035504020e | ||
|
|
84b7c17268 | ||
|
|
ee00315894 | ||
|
|
a3ff3a5a15 | ||
|
|
79aa91da41 | ||
|
|
cc268bc2a3 | ||
|
|
b79ab7335a | ||
|
|
496d25ff23 | ||
|
|
9caf06760d | ||
|
|
a84eebe284 | ||
|
|
6375708e4a | ||
|
|
e524acdb10 | ||
|
|
6763ca4852 | ||
|
|
b1700c62f4 | ||
|
|
38b9357469 | ||
|
|
5f95bc9091 | ||
|
|
c04d998bb2 | ||
|
|
e0956ce58c | ||
|
|
44e47cc86c | ||
|
|
441e6c3dfb | ||
|
|
26c1bfc461 | ||
|
|
93c739d2d9 | ||
|
|
aa703ac90d | ||
|
|
d1df910888 |
+4
-1
@@ -1,3 +1,6 @@
|
||||
.github
|
||||
.gitignore
|
||||
.dockerignore
|
||||
|
||||
# Other
|
||||
build/*
|
||||
docs/*
|
||||
|
||||
@@ -8,7 +8,7 @@ on:
|
||||
- '*'
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- 'README.md'
|
||||
- '**.md'
|
||||
|
||||
jobs:
|
||||
|
||||
|
||||
@@ -4,8 +4,13 @@ on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
tags:
|
||||
- '*'
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- 'docker/**'
|
||||
- '**.md'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -15,7 +20,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.15.x
|
||||
go-version: 1.16.x
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
@@ -47,6 +52,6 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
files: bin/*
|
||||
files: build/*
|
||||
draft: true
|
||||
prerelease: true
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
bin/
|
||||
build/
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
|
||||
+11
-12
@@ -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,15 @@ 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 EXTRA_COMMANDS=
|
||||
ENV TUN_INCLUDED_ROUTES=
|
||||
ENV TUN_EXCLUDED_ROUTES=
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
||||
@@ -1,23 +1,34 @@
|
||||
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 describe --dirty --always)
|
||||
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-amd64 \
|
||||
freebsd-arm64 \
|
||||
linux-amd64 \
|
||||
linux-arm64 \
|
||||
linux-mips64 \
|
||||
linux-mips64le \
|
||||
linux-ppc64 \
|
||||
linux-ppc64le \
|
||||
linux-s390x \
|
||||
openbsd-amd64 \
|
||||
openbsd-arm64 \
|
||||
|
||||
@@ -26,47 +37,63 @@ WINDOWS_ARCH_LIST = \
|
||||
|
||||
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-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-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-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-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-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))
|
||||
unix_releases := $(addsuffix .zip, $(UNIX_ARCH_LIST))
|
||||
windows_releases := $(addsuffix .zip, $(WINDOWS_ARCH_LIST))
|
||||
|
||||
$(gz_releases): %.gz : %
|
||||
chmod +x $(BINDIR)/$(NAME)-$(basename $@)
|
||||
gzip -f -S .gz $(BINDIR)/$(NAME)-$(basename $@)
|
||||
$(unix_releases): %.zip: %
|
||||
@zip -qmj $(BUILD_DIR)/$(BINARY)-$(basename $@).zip $(BUILD_DIR)/$(BINARY)-$(basename $@)
|
||||
|
||||
$(zip_releases): %.zip : %
|
||||
zip -m -j $(BINDIR)/$(NAME)-$(basename $@).zip $(BINDIR)/$(NAME)-$(basename $@).exe
|
||||
$(windows_releases): %.zip: %
|
||||
@zip -qmj $(BUILD_DIR)/$(BINARY)-$(basename $@).zip $(BUILD_DIR)/$(BINARY)-$(basename $@).exe
|
||||
|
||||
all-arch: $(PLATFORM_LIST) $(WINDOWS_ARCH_LIST)
|
||||
all-arch: $(UNIX_ARCH_LIST) $(WINDOWS_ARCH_LIST)
|
||||
|
||||
releases: $(gz_releases) $(zip_releases)
|
||||
releases: $(unix_releases) $(windows_releases)
|
||||
|
||||
clean:
|
||||
rm $(BINDIR)/*
|
||||
rm -rf $(BUILD_DIR)
|
||||
|
||||
@@ -1,291 +1,49 @@
|
||||
<h1 align="center">tun2socks</h1>
|
||||
<h3 align="center">A tun2socks powered by gVisor TCP/IP stack.</h3>
|
||||

|
||||
|
||||
<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))
|
||||
- **Fully support:** IPv4/IPv6/ICMP/TCP/UDP
|
||||
- **Proxy protocol:** Socks5/Shadowsocks
|
||||
- **Game ready:** optimized UDP transmission
|
||||
- **Pure Go:** no CGO required, stability improved
|
||||
- **Router mode:** forwarding packets in LAN
|
||||
- **TCP/IP stack:** powered by **[gVisor](https://github.com/google/gvisor)**
|
||||
- **High performance:** >2.5Gbps throughput
|
||||
|
||||
## Requirements
|
||||
|
||||
| Target | Minimum | Recommended |
|
||||
| :----- | :-----: | :---------: |
|
||||
| System | linux darwin freebsd openbsd | linux |
|
||||
| System | Linux MacOS Freebsd OpenBSD Windows | Linux or MacOS |
|
||||
| Memory | >20MB | >128MB |
|
||||
| CPU | amd64 arm64 | amd64 |
|
||||
| CPU | 64bit | AMD64 with AES-NI & AVX2 |
|
||||
|
||||
## Performance
|
||||
## Documentation
|
||||
|
||||
> 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>
|
||||
Documentations and quick start guides can be found at [Github Wiki](https://github.com/xjasonlyu/tun2socks/wiki).
|
||||
|
||||
## 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
|
||||
|
||||
- [x] Windows support
|
||||
- [x] FreeBSD support
|
||||
- [x] OpenBSD support
|
||||
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fxjasonlyu%2Ftun2socks?ref=badge_large)
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||

|
||||
|
||||
[![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
|
||||
- **代理协议:** 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 |
|
||||
| 架构 | 64bit | AMD64 with AES-NI & AVX2 |
|
||||
|
||||
## 使用文档
|
||||
|
||||
文档以及使用方式,请看 [Github Wiki](https://github.com/xjasonlyu/tun2socks/wiki)。
|
||||
|
||||
## 注意事项
|
||||
|
||||
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)
|
||||
|
||||
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fxjasonlyu%2Ftun2socks?ref=badge_large)
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,12 @@ 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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"))
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
})
|
||||
}
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// +build !linux
|
||||
|
||||
package dialer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func setMark(_ int) controlFunc {
|
||||
return func(string, string, syscall.RawConn) error {
|
||||
return errors.New("fwmark: linux only")
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// Package obfs provides obfuscation functionality for Shadowsocks protocol.
|
||||
package obfs
|
||||
|
||||
// Ref: github.com/Dreamacro/clash/component/simple-obfs
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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"
|
||||
@@ -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
@@ -1,8 +1,10 @@
|
||||
package constant
|
||||
|
||||
const Name = "tun2socks"
|
||||
const (
|
||||
Name = "tun2socks"
|
||||
)
|
||||
|
||||
var (
|
||||
Version = ""
|
||||
BuildTime = ""
|
||||
Version string
|
||||
GitCommit string
|
||||
)
|
||||
|
||||
Executable → Regular
+7
-5
@@ -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
|
||||
}
|
||||
@@ -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,34 +67,25 @@ 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
|
||||
}
|
||||
|
||||
@@ -118,14 +106,6 @@ 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)
|
||||
}
|
||||
|
||||
// MTU implements stack.LinkEndpoint.MTU.
|
||||
func (e *Endpoint) MTU() uint32 {
|
||||
return e.mtu
|
||||
@@ -133,12 +113,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
|
||||
@@ -0,0 +1,29 @@
|
||||
// +build darwin freebsd linux,!amd64,!arm64 openbsd
|
||||
|
||||
package tun
|
||||
|
||||
import (
|
||||
"github.com/xjasonlyu/tun2socks/common/pool"
|
||||
)
|
||||
|
||||
const offset = 4 /* 4 bytes TUN_PI */
|
||||
|
||||
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)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package tun
|
||||
|
||||
const offset = 0
|
||||
|
||||
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)
|
||||
}
|
||||
Executable
+14
@@ -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,13 @@
|
||||
// +build linux
|
||||
// +build amd64 arm64
|
||||
|
||||
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"
|
||||
@@ -30,7 +32,7 @@ func Open(opts ...Option) (device.Device, error) {
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -100,7 +102,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
|
||||
@@ -1,19 +1,16 @@
|
||||
// +build darwin freebsd openbsd
|
||||
// +build !linux !amd64,!arm64
|
||||
|
||||
package tun
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/xjasonlyu/tun2socks/common/pool"
|
||||
"github.com/xjasonlyu/tun2socks/device"
|
||||
"github.com/xjasonlyu/tun2socks/device/rwbased"
|
||||
"github.com/xjasonlyu/tun2socks/core/device"
|
||||
"github.com/xjasonlyu/tun2socks/core/device/rwbased"
|
||||
|
||||
"golang.zx2c4.com/wireguard/tun"
|
||||
)
|
||||
|
||||
const offset = 4 /* 4 bytes TUN_PI */
|
||||
|
||||
type TUN struct {
|
||||
*rwbased.Endpoint
|
||||
|
||||
@@ -50,26 +47,6 @@ func Open(opts ...Option) (device.Device, error) {
|
||||
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
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
package core
|
||||
|
||||
type Handler interface {
|
||||
Add(TCPConn)
|
||||
AddPacket(UDPPacket)
|
||||
}
|
||||
Executable
+24
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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,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
|
||||
}
|
||||
@@ -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"
|
||||
@@ -39,18 +37,11 @@ func withUDPHandler() Option {
|
||||
|
||||
packet := &udpPacket{
|
||||
s: s,
|
||||
id: id,
|
||||
id: &id,
|
||||
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
|
||||
nicID tcpip.NICID
|
||||
netHdr header.Network
|
||||
netProto tcpip.NetworkProtocolNumber
|
||||
payload []byte
|
||||
metadata *adapter.Metadata
|
||||
}
|
||||
|
||||
func (p *udpPacket) Data() []byte {
|
||||
return p.payload
|
||||
}
|
||||
|
||||
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)}
|
||||
}
|
||||
@@ -107,7 +95,7 @@ func (p *udpPacket) WriteBack(b []byte, addr net.Addr) (int, error) {
|
||||
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 {
|
||||
if err = sendUDP(route, data, p.id.LocalPort, p.id.RemotePort, udpNoChecksum); err != nil {
|
||||
return 0, fmt.Errorf("%v", err)
|
||||
}
|
||||
return data.Size(), nil
|
||||
@@ -124,7 +112,7 @@ func (p *udpPacket) WriteBack(b []byte, addr net.Addr) (int, error) {
|
||||
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, uint16(udpAddr.Port), p.id.RemotePort, udpNoChecksum); err != nil {
|
||||
return 0, fmt.Errorf("%v", err)
|
||||
}
|
||||
return data.Size(), nil
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
// Package tun provides TUN which implemented device.Device interface.
|
||||
package tun
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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
|
||||
+51
-49
@@ -1,77 +1,79 @@
|
||||
#!/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
|
||||
|
||||
exec tun2socks \
|
||||
--loglevel "$LOGLEVEL" \
|
||||
--interface "$ETH" \
|
||||
--device "$TUN" \
|
||||
--proxy "$PROXY" \
|
||||
-loglevel "$LOGLEVEL" \
|
||||
-fwmark "$FWMARK" \
|
||||
-device "$TUN" \
|
||||
-proxy "$PROXY" \
|
||||
$ARGS
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
+100
-53
@@ -1,61 +1,93 @@
|
||||
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"
|
||||
)
|
||||
|
||||
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
|
||||
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.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 +95,64 @@ 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) setProxy() (err error) {
|
||||
if e.Proxy == "" {
|
||||
return errors.New("empty proxy")
|
||||
}
|
||||
proxy.SetDialer(d)
|
||||
return nil
|
||||
|
||||
e.proxy, err = parseProxy(e.Proxy)
|
||||
proxy.SetDialer(e.proxy)
|
||||
return
|
||||
}
|
||||
|
||||
func (e *Engine) setDevice() error {
|
||||
d, err := parseDevice(e.rawDevice, e.mtu)
|
||||
if err != nil {
|
||||
return err
|
||||
func (e *engine) setDevice() (err error) {
|
||||
if e.Device == "" {
|
||||
return errors.New("empty device")
|
||||
}
|
||||
e.device = d
|
||||
return nil
|
||||
|
||||
e.device, err = parseDevice(e.Device, uint32(e.MTU))
|
||||
return
|
||||
}
|
||||
|
||||
func (e *Engine) setStack() error {
|
||||
handler := &fakeTunnel{}
|
||||
if _, err := stack.New(e.device, handler, stack.WithDefault()); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infof("[STACK] %s <-> %s", e.rawDevice, e.rawProxy)
|
||||
return nil
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
+59
-30
@@ -1,19 +1,20 @@
|
||||
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/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 = tun.Driver + "://" + s /* default driver */
|
||||
}
|
||||
|
||||
u, err := url.Parse(s)
|
||||
@@ -22,27 +23,19 @@ 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 tun.Driver:
|
||||
return tun.Open(tun.WithName(name), tun.WithMTU(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 = proto.Socks5.String() + "://" + s /* default protocol */
|
||||
}
|
||||
|
||||
u, err := url.Parse(s)
|
||||
@@ -50,20 +43,56 @@ 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.Socks5.String():
|
||||
return proxy.NewSocks5(parseSocks(u))
|
||||
case proto.Shadowsocks.String():
|
||||
return proxy.NewShadowsocks(parseShadowsocks(u))
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported protocol: %s", protocol)
|
||||
}
|
||||
}
|
||||
|
||||
func parseSocks(u *url.URL) (address, username, password string) {
|
||||
address = u.Host
|
||||
username = u.User.Username()
|
||||
password, _ = u.User.Password()
|
||||
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)
|
||||
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
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/xjasonlyu/tun2socks
|
||||
|
||||
go 1.15
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/Dreamacro/go-shadowsocks2 v0.1.6
|
||||
@@ -9,15 +9,13 @@ require (
|
||||
github.com/go-chi/render v1.0.1
|
||||
github.com/gofrs/uuid v4.0.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
|
||||
github.com/magefile/mage v1.11.0 // indirect
|
||||
github.com/sirupsen/logrus v1.7.1
|
||||
github.com/stretchr/testify v1.7.0
|
||||
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/sys v0.0.0-20210216224549-f992740a1bac
|
||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324
|
||||
golang.zx2c4.com/wireguard v0.0.20201118
|
||||
gvisor.dev/gvisor v0.0.0-20210205020539-1dbf4e4527a5
|
||||
golang.zx2c4.com/wireguard v0.0.0-20210216200525-4e439ea10e32
|
||||
gvisor.dev/gvisor v0.0.0-20210213011838-e7ae604b523e
|
||||
)
|
||||
|
||||
@@ -70,7 +70,7 @@ github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4q
|
||||
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/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ=
|
||||
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=
|
||||
@@ -81,9 +81,7 @@ github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kw
|
||||
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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -214,13 +212,15 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL
|
||||
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/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
|
||||
github.com/magefile/mage v1.11.0 h1:C/55Ywp9BpgVVclD3lRnSYCwXTYxmSppIgLeDYlNuls=
|
||||
github.com/magefile/mage v1.11.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
|
||||
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=
|
||||
@@ -254,34 +254,28 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:
|
||||
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/sirupsen/logrus v1.7.1 h1:rsizeFmZP+GYwyb4V6t6qpG7ZNWzA2bvgW/yC2xHCcg=
|
||||
github.com/sirupsen/logrus v1.7.1/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A=
|
||||
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/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/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
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=
|
||||
@@ -300,7 +294,6 @@ 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=
|
||||
@@ -309,9 +302,7 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
|
||||
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=
|
||||
@@ -374,12 +365,9 @@ golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/
|
||||
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=
|
||||
@@ -398,9 +386,7 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
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=
|
||||
@@ -420,7 +406,6 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
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=
|
||||
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=
|
||||
@@ -445,28 +430,23 @@ golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
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-20210105210732-16f7687f5001/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/sys v0.0.0-20210216224549-f992740a1bac h1:9glrpwtNjBYgRpb67AZJKHfzj1stG/8BL5H7In2oTC4=
|
||||
golang.org/x/sys v0.0.0-20210216224549-f992740a1bac/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
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=
|
||||
@@ -521,8 +501,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
||||
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=
|
||||
golang.zx2c4.com/wireguard v0.0.0-20210216200525-4e439ea10e32 h1:b9GuQq7q23DkzDMMlnL1Dfj6zCzYF34ZOg3A8wUwHPs=
|
||||
golang.zx2c4.com/wireguard v0.0.0-20210216200525-4e439ea10e32/go.mod h1:LofpIKqPJNvHiwKXuzsBshJCTe7IgRAz3iizquljFDk=
|
||||
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=
|
||||
@@ -598,7 +578,7 @@ google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM
|
||||
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/grpc v1.36.0-dev.0.20210208035533-9280052d3665/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=
|
||||
@@ -619,11 +599,12 @@ 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=
|
||||
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=
|
||||
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=
|
||||
gvisor.dev/gvisor v0.0.0-20210213011838-e7ae604b523e h1:Zd2ZRIhVwnYZjeWjpI1w79v6YSUOCh2JUFK9IYwO/kU=
|
||||
gvisor.dev/gvisor v0.0.0-20210213011838-e7ae604b523e/go.mod h1:TMDExUbPoyZXybG8K1+vm5ElIxI5qXUM5fwK7vI8YIg=
|
||||
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=
|
||||
|
||||
+5
-5
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -1,69 +1,41 @@
|
||||
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.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)
|
||||
|
||||
+14
-6
@@ -5,25 +5,33 @@ import (
|
||||
"errors"
|
||||
"net"
|
||||
|
||||
"github.com/xjasonlyu/tun2socks/common/adapter"
|
||||
M "github.com/xjasonlyu/tun2socks/constant"
|
||||
"github.com/xjasonlyu/tun2socks/proxy/proto"
|
||||
)
|
||||
|
||||
var _ Proxy = (*Base)(nil)
|
||||
|
||||
type Base struct {
|
||||
addr string
|
||||
addr string
|
||||
proto proto.Proto
|
||||
}
|
||||
|
||||
func NewBase(addr string) *Base {
|
||||
return &Base{addr: addr}
|
||||
func NewBase(addr string, proto proto.Proto) *Base {
|
||||
return &Base{addr: addr, 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
@@ -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())
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package proto
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
Direct Proto = iota
|
||||
Shadowsocks
|
||||
Socks5
|
||||
)
|
||||
|
||||
type Proto uint8
|
||||
|
||||
func (proto Proto) String() string {
|
||||
switch proto {
|
||||
case Direct:
|
||||
return "direct"
|
||||
case Shadowsocks:
|
||||
return "ss"
|
||||
case Socks5:
|
||||
return "socks5"
|
||||
default:
|
||||
return fmt.Sprintf("proto(%d)", proto)
|
||||
}
|
||||
}
|
||||
+13
-6
@@ -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)
|
||||
}
|
||||
|
||||
+29
-9
@@ -6,32 +6,44 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/xjasonlyu/tun2socks/common/adapter"
|
||||
"github.com/xjasonlyu/tun2socks/component/dialer"
|
||||
obfs "github.com/xjasonlyu/tun2socks/component/simple-obfs"
|
||||
"github.com/xjasonlyu/tun2socks/component/socks5"
|
||||
M "github.com/xjasonlyu/tun2socks/constant"
|
||||
"github.com/xjasonlyu/tun2socks/proxy/proto"
|
||||
|
||||
"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)
|
||||
@@ -44,12 +56,20 @@ func (ss *ShadowSocks) DialContext(ctx context.Context, metadata *adapter.Metada
|
||||
}
|
||||
}()
|
||||
|
||||
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 +92,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)
|
||||
|
||||
+12
-7
@@ -4,14 +4,16 @@ import (
|
||||
"context"
|
||||
"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"
|
||||
)
|
||||
|
||||
var _ Proxy = (*Socks5)(nil)
|
||||
|
||||
type Socks5 struct {
|
||||
*Base
|
||||
|
||||
@@ -21,13 +23,16 @@ type Socks5 struct {
|
||||
|
||||
func NewSocks5(addr, user, pass string) (*Socks5, error) {
|
||||
return &Socks5{
|
||||
Base: NewBase(addr),
|
||||
Base: &Base{
|
||||
addr: addr,
|
||||
proto: proto.Socks5,
|
||||
},
|
||||
user: user,
|
||||
pass: pass,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ss *Socks5) DialContext(ctx context.Context, metadata *adapter.Metadata) (c net.Conn, err error) {
|
||||
func (ss *Socks5) 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)
|
||||
@@ -52,7 +57,7 @@ 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) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), tcpConnectTimeout)
|
||||
defer cancel()
|
||||
|
||||
@@ -98,7 +103,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 +131,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)
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
package stack
|
||||
|
||||
import (
|
||||
"github.com/xjasonlyu/tun2socks/common/adapter"
|
||||
)
|
||||
|
||||
type Handler interface {
|
||||
Add(adapter.TCPConn)
|
||||
AddPacket(adapter.UDPPacket)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
@@ -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})
|
||||
}
|
||||
|
||||
@@ -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{
|
||||
+15
-6
@@ -7,23 +7,32 @@ import (
|
||||
"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)
|
||||
|
||||
+12
-12
@@ -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,14 +25,14 @@ 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()
|
||||
@@ -47,8 +47,8 @@ func max(a, b int) int {
|
||||
}
|
||||
|
||||
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 +56,7 @@ func process() {
|
||||
}()
|
||||
}
|
||||
|
||||
for conn := range tcpQueue {
|
||||
for conn := range _tcpQueue {
|
||||
go handleTCP(conn)
|
||||
}
|
||||
}
|
||||
|
||||
+27
-18
@@ -7,37 +7,46 @@ import (
|
||||
"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"
|
||||
"github.com/xjasonlyu/tun2socks/tunnel/statistic"
|
||||
)
|
||||
|
||||
const (
|
||||
udpSessionTimeout = 30 * time.Second
|
||||
udpSessionTimeout = 60 * time.Second
|
||||
)
|
||||
|
||||
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()
|
||||
)
|
||||
|
||||
func handleUDP(packet adapter.UDPPacket) {
|
||||
metadata := packet.Metadata()
|
||||
if !metadata.Valid() {
|
||||
log.Warnf("[Metadata] not valid: %#v", metadata)
|
||||
return
|
||||
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 +59,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 +70,7 @@ func handleUDP(packet adapter.UDPPacket) {
|
||||
}
|
||||
|
||||
defer func() {
|
||||
natTable.Delete(lockKey)
|
||||
_natTable.Delete(lockKey)
|
||||
cond.Broadcast()
|
||||
}()
|
||||
|
||||
@@ -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)
|
||||
}()
|
||||
|
||||
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()
|
||||
@@ -110,7 +119,7 @@ func handleUDPToRemote(packet adapter.UDPPacket, pc net.PacketConn, remote net.A
|
||||
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, timeout time.Duration) {
|
||||
buf := pool.Get(pool.MaxSegmentSize)
|
||||
defer pool.Put(buf)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user