Compare commits

...
16 Commits
Author SHA1 Message Date
xjasonlyu d42cf2ceb5 freebsd/openbsd support (experimental) 2020-11-08 21:39:55 +08:00
xjasonlyu 25749c7596 add macos usage 2020-11-08 16:47:45 +08:00
xjasonlyu 2835cfae75 adjust: udpBufferSize 2020-11-08 15:54:23 +08:00
xjasonlyu 0e2d98b951 chore: rwc 2020-11-08 15:01:33 +08:00
xjasonlyu b435fbc51a use unix getMTU 2020-11-08 14:12:00 +08:00
xjasonlyu b858c8758a readme 2020-11-08 13:50:31 +08:00
xjasonlyu 08674e64af mod: update 2020-11-08 12:14:36 +08:00
xjasonlyu 3b641119db adjust actions 2020-11-08 12:00:41 +08:00
xjasonlyu 8c7075050c fix: empty version 2020-11-08 11:37:35 +08:00
xjasonlyu ca7d161f58 add .dockerignore 2020-11-08 00:15:17 +08:00
xjasonlyu f559f9bd3c fix: trim linkdown 2020-11-07 20:51:48 +08:00
xjasonlyu f3ae66ec62 update gVisor
ref: https://github.com/google/gvisor/commit/8c0701462a84ff77e602f1626aec49479c308127
2020-11-07 15:19:48 +08:00
xjasonlyu 38272319ee change about text 2020-11-07 13:52:12 +08:00
xjasonlyu 36b02f7d92 improve 2020-11-07 13:33:55 +08:00
xjasonlyu 39495de718 readme 2020-11-06 21:43:08 +08:00
xjasonlyu 88c5cac669 chore 2020-11-06 12:14:58 +08:00
25 changed files with 657 additions and 293 deletions
+9
View File
@@ -0,0 +1,9 @@
.github/
.github/**
assets/
assets/**
.dockerignore
*.yml
*.md
.gitignore
Dockerfile*
+67
View File
@@ -0,0 +1,67 @@
name: Publish Docker Image
on:
push:
branches:
- master
tags:
- '*'
paths-ignore:
- '.github/**'
- 'assets/**'
- '.gitignore'
- 'README.md'
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
with:
platforms: all
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
with:
version: latest
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push (dev)
if: github.ref == 'refs/heads/master'
uses: docker/build-push-action@v2
with:
context: .
push: true
platforms: linux/amd64,linux/arm64
tags: |
xjasonlyu/tun2socks:dev
- name: Get Version
id: shell
run: |
echo ::set-output name=version::$(git describe --tags --abbrev=0)
- name: Build and Push (latest)
if: startsWith(github.ref, 'refs/tags/')
uses: docker/build-push-action@v2
with:
context: .
push: true
platforms: linux/amd64,linux/arm64
tags: |
xjasonlyu/tun2socks:latest
xjasonlyu/tun2socks:${{ steps.shell.outputs.version }}
+7 -3
View File
@@ -6,6 +6,11 @@ on:
- master
tags:
- '*'
paths-ignore:
- '.github/**'
- 'assets/**'
- '.gitignore'
- 'README.md'
jobs:
@@ -20,6 +25,8 @@ jobs:
- name: Check out code into the Go module directory
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Cache go module
uses: actions/cache@v2
@@ -38,9 +45,6 @@ jobs:
- name: Build
if: startsWith(github.ref, 'refs/tags/')
env:
DIR: bin
NAME: tun2socks
run: make -j releases
- name: Upload Release
+4 -4
View File
@@ -1,17 +1,17 @@
FROM golang:alpine AS builder
WORKDIR /app
COPY . /app
WORKDIR /tun2socks-src
COPY . /tun2socks-src
RUN apk add --no-cache make git \
&& go mod download \
&& make docker \
&& /app/bin/tun2socks-docker -v
&& mv ./bin/tun2socks-docker /tun2socks
FROM alpine:latest
COPY ./scripts/entrypoint.sh /entrypoint.sh
COPY --from=builder /app/bin/tun2socks-docker /usr/bin/tun2socks
COPY --from=builder /tun2socks /usr/bin/tun2socks
RUN apk add --update --no-cache iptables iproute2 \
&& chmod +x /entrypoint.sh
+18 -2
View File
@@ -4,7 +4,7 @@ NAME = "tun2socks"
TAGS = ""
BUILD_FLAGS = "-v"
VERSION = $(shell git describe --tags)
VERSION = $(shell git describe --tags || echo "unknown version")
BUILD_TIME = $(shell date -u '+%FT%TZ')
LDFLAGS += -w -s -buildid=
@@ -14,10 +14,14 @@ GO_BUILD = CGO_ENABLED=0 go build $(BUILD_FLAGS) -ldflags '$(LDFLAGS)' -tags '$(
PLATFORM_LIST = \
darwin-amd64 \
freebsd-amd64 \
freebsd-arm64 \
linux-amd64 \
linux-arm64 \
openbsd-amd64 \
openbsd-arm64 \
.PHONY: $(PLATFORM_LIST)
.PHONY: all docker $(PLATFORM_LIST)
all: $(PLATFORM_LIST)
@@ -27,12 +31,24 @@ docker:
darwin-amd64:
GOARCH=amd64 GOOS=darwin $(GO_BUILD) -o $(DIR)/$(NAME)-$@
freebsd-amd64:
GOARCH=amd64 GOOS=freebsd $(GO_BUILD) -o $(DIR)/$(NAME)-$@
freebsd-arm64:
GOARCH=arm64 GOOS=freebsd $(GO_BUILD) -o $(DIR)/$(NAME)-$@
linux-amd64:
GOARCH=amd64 GOOS=linux $(GO_BUILD) -o $(DIR)/$(NAME)-$@
linux-arm64:
GOARCH=arm64 GOOS=linux $(GO_BUILD) -o $(DIR)/$(NAME)-$@
openbsd-amd64:
GOARCH=amd64 GOOS=openbsd $(GO_BUILD) -o $(DIR)/$(NAME)-$@
openbsd-arm64:
GOARCH=arm64 GOOS=openbsd $(GO_BUILD) -o $(DIR)/$(NAME)-$@
zip_releases=$(addsuffix .zip, $(PLATFORM_LIST))
$(zip_releases): %.zip : %
+267 -41
View File
@@ -1,56 +1,60 @@
# tun2socks
<h1 align="center">tun2socks</h1>
<h3 align="center">A tun2socks powered by gVisor TCP/IP stack.</h3>
![build](https://img.shields.io/github/workflow/status/xjasonlyu/tun2socks/Go?style=flat-square)
![go report](https://goreportcard.com/badge/github.com/xjasonlyu/tun2socks?style=flat-square)
![license](https://img.shields.io/github/license/xjasonlyu/tun2socks?style=flat-square)
![release](https://img.shields.io/github/v/release/xjasonlyu/tun2socks.svg?include_prereleases&style=flat-square)
A tun2socks implementation written in Go.
<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>
## Features
- External RESTful API support
- Fake DNS with manual hosts support
- IPv4/IPv6 support
- ICMP echoing
- IPv6 support
- Optimized UDP transmission for game acceleration
- Pure Go implementation, no CGO required
- 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))
### Requirements
## Requirements
| Target | Minimum | Recommended |
| --- | --- | --- |
| System | linux darwin | linux |
| Memory | >20MB | +∞ |
| CPU | ANY | amd64 arm64 |
| :----- | :-----: | :---------: |
| System | linux darwin freebsd openbsd | linux |
| Memory | >20MB | >128MB |
| CPU | amd64 arm64 | amd64 |
## QuickStart
## Performance
Download from precompiled [Releases](https://github.com/xjasonlyu/tun2socks/releases).
> iPerf3 tested on Debian 10 with i5-10500, 8G RAM
create tun
![iPerf3 Test](assets/iperf3.png)
```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
```
## How to Build
run
### build from source code
```shell script
./tun2socks --loglevel WARN --device tun://tun0 --proxy socks5://server:port --interface eth0
```
or just
```shell script
PROXY=socks5://server:port LOGLEVEL=WARN sh ./scripts/entrypoint.sh
```
## Build from source
Go compiler version >= 1.15 is required
```text
$ git clone https://github.com/xjasonlyu/tun2socks.git
@@ -58,17 +62,239 @@ $ cd tun2socks
$ make
```
## Issues
### build docker image
Due to the implementation of pure Go, the memory usage is higher than the previous version.
If you are memory sensitive, please go back to [v1](https://github.com/xjasonlyu/tun2socks/tree/v1).
```text
$ docker build -t tun2socks .
```
## TODO
or
- [ ] Windows support
```text
$ docker build -t tun2socks -f ./docker/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
NAME:
tun2socks - A tun2socks powered by gVisor TCP/IP stack.
USAGE:
tun2socks [global options] [arguments...]
GLOBAL OPTIONS:
--api value URL of external API to listen
--device value, -d value URL of device to open
--dns value URL of fake DNS to listen
--hosts value Extra hosts mapping
--interface value, -i value Bind interface to dial
--loglevel value, -l value Set logging level (default: "INFO")
--proxy value, -p value URL of proxy to dial
--version, -v Print current version (default: false)
--help, -h show help (default: false)
```
</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>
## 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)
## Known Issues
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).
## TODO
- [ ] Windows support
- [x] FreeBSD support
- [x] OpenBSD support
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

+4 -4
View File
@@ -2,7 +2,7 @@ version: '2.4'
services:
tun2socks:
image: xjasonlyu/tun2socks:arm64-dev
image: xjasonlyu/tun2socks:latest
cap_add:
- NET_ADMIN
devices:
@@ -10,15 +10,15 @@ services:
environment:
- GODEBUG=madvdontneed=1
- PROXY=
- LOGLEVEL=warning
- API=:8080
- LOGLEVEL=
- API=
- DNS=
- HOSTS=
- EXCLUDED=
- EXTRACMD=
networks:
switch:
ipv4_address: 172.20.1.20
ipv4_address: 172.20.1.2
restart: always
container_name: tun2socks
+5 -3
View File
@@ -9,14 +9,16 @@ require (
github.com/go-chi/render v1.0.1
github.com/gofrs/uuid v3.3.0+incompatible
github.com/gorilla/websocket v1.4.2
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sirupsen/logrus v1.7.0
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8
github.com/urfave/cli/v2 v2.2.0
github.com/urfave/cli/v2 v2.3.0
github.com/xjasonlyu/clash v0.15.1-0.20201105074459-aa45c8b56cf6
go.uber.org/atomic v1.7.0
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 // indirect
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1 // indirect
golang.org/x/sys v0.0.0-20201107080550-4d91cf3a1aaf
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e
golang.zx2c4.com/wireguard v0.0.20200320
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
gvisor.dev/gvisor v0.0.0-20201105065002-ab9a79fe812a
gvisor.dev/gvisor v0.0.0-20201107072535-9e848922ed33
)
+14 -6
View File
@@ -201,6 +201,8 @@ github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7z
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/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/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=
@@ -227,8 +229,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
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/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4=
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/vishvananda/netlink v1.0.1-0.20190930145447-2ec5bdc52b86/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/xjasonlyu/clash v0.15.1-0.20201105074459-aa45c8b56cf6 h1:iQsLkjayjJs29VOeXaeznpy1jddiuRjstj6MfFbKVoM=
@@ -245,6 +247,7 @@ golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -284,6 +287,7 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
@@ -332,12 +336,13 @@ golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201029080932-201ba4db2418 h1:HlFl4V6pEMziuLXyRkm5BIYq1y1GAbb02pRlWvI54OM=
golang.org/x/sys v0.0.0-20201029080932-201ba4db2418/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1 h1:a/mKvvZr9Jcc8oKfcmgzyp7OwF73JPWsQLvH1z2Kxck=
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201107080550-4d91cf3a1aaf h1:kt3wY1Lu5MJAnKTfoMR52Cu4gwvna4VTzNOiT8tY73s=
golang.org/x/sys v0.0.0-20201107080550-4d91cf3a1aaf/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/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=
@@ -380,6 +385,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.20200320 h1:1vE6zVeO7fix9cJX1Z9ZQ+ikPIIx7vIyU0o0tLDD88g=
golang.zx2c4.com/wireguard v0.0.20200320/go.mod h1:lDian4Sw4poJ04SgHh35nzMVwGSYlPumkdnHcucAQoY=
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=
@@ -423,6 +430,7 @@ 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.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -431,8 +439,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gvisor.dev/gvisor v0.0.0-20201105065002-ab9a79fe812a h1:io3nR9e7V26iORClxbTxnrNBhxAvdvgMKU8E+at6idc=
gvisor.dev/gvisor v0.0.0-20201105065002-ab9a79fe812a/go.mod h1:t4GUXJhnQEPtYSvrvRNW5CNdBQ2oWZBy7P+FbCVKBFY=
gvisor.dev/gvisor v0.0.0-20201107072535-9e848922ed33 h1:Iy80PPGcHGhOacbFJk/Cn8lV0k8dcg8UJBo8e5qV9Ac=
gvisor.dev/gvisor v0.0.0-20201107072535-9e848922ed33/go.mod h1:t4GUXJhnQEPtYSvrvRNW5CNdBQ2oWZBy7P+FbCVKBFY=
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 -10
View File
@@ -13,11 +13,11 @@ import (
"github.com/xjasonlyu/clash/component/dialer"
"github.com/xjasonlyu/tun2socks/internal/api"
"github.com/xjasonlyu/tun2socks/internal/core"
"github.com/xjasonlyu/tun2socks/internal/dev"
"github.com/xjasonlyu/tun2socks/internal/dns"
"github.com/xjasonlyu/tun2socks/internal/proxy"
"github.com/xjasonlyu/tun2socks/internal/tunnel"
"github.com/xjasonlyu/tun2socks/pkg/log"
"github.com/xjasonlyu/tun2socks/pkg/tun"
)
func bindToInterface(name string) {
@@ -51,7 +51,7 @@ func Main(c *cli.Context) error {
if c.IsSet("interface") {
name := c.String("interface")
bindToInterface(name)
log.Infof("[IFCE] bind to interface: %s", name)
log.Infof("[DIALER] bind to interface: %s", name)
}
if c.IsSet("api") { /* initiate API */
@@ -71,16 +71,11 @@ func Main(c *cli.Context) error {
}
deviceURL := c.String("device")
device, err := dev.Open(deviceURL)
device, err := tun.Open(deviceURL)
if err != nil {
return fmt.Errorf("open device %s: %w", deviceURL, err)
}
defer func() {
err := device.Close()
if err != nil {
log.Errorf("close device %s error: %v", deviceURL, err)
}
}()
defer device.Close()
proxyURL := c.String("proxy")
if err := proxy.Register(proxyURL); err != nil {
@@ -90,7 +85,7 @@ func Main(c *cli.Context) error {
if _, err := core.NewDefaultStack(device, tunnel.Add, tunnel.AddPacket); err != nil {
return fmt.Errorf("initiate stack: %w", err)
}
log.Infof("[STACK] %s --> %s", device.String(), proxy.String())
log.Infof("[STACK] %s --> %s", deviceURL, proxyURL)
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
+11
View File
@@ -77,6 +77,17 @@ func NewDefaultStack(linkEp stack.LinkEndpoint, th tcpHandleFunc, uh udpHandleFu
// Ref: https://github.com/majek/slirpnetstack/blob/master/stack.go
WithPromiscuousMode(defaultNICID, nicPromiscuousModeEnabled),
// Enable spoofing if a stack may send packets from unowned addresses.
// This change required changes to some netgophers since previously,
// promiscuous mode was enough to let the netstack respond to all
// incoming packets regardless of the packet's destination address. Now
// that a stack.Route is not held for each incoming packet, finding a route
// may fail with local addresses we don't own but accepted packets for
// while in promiscuous mode. Since we also want to be able to send from
// any address (in response the received promiscuous mode packets), we need
// to enable spoofing.
//
// Ref: https://github.com/google/gvisor/commit/8c0701462a84ff77e602f1626aec49479c308127
WithSpoofing(defaultNICID, nicSpoofingEnabled),
)
}
+19 -11
View File
@@ -11,6 +11,7 @@ import (
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
"github.com/xjasonlyu/tun2socks/internal/adapter"
"github.com/xjasonlyu/tun2socks/pkg/log"
)
const udpNoChecksum = true
@@ -19,16 +20,16 @@ type udpHandleFunc func(adapter.UDPPacket)
func WithUDPHandler(handle udpHandleFunc) Option {
return func(s *stack.Stack) error {
udpHandlePacket := func(r *stack.Route, id stack.TransportEndpointID, pkt *stack.PacketBuffer) bool {
udpHandlePacket := func(id stack.TransportEndpointID, pkt *stack.PacketBuffer) bool {
// Ref: gVisor pkg/tcpip/transport/udp/endpoint.go HandlePacket
hdr := header.UDP(pkt.TransportHeader().View())
if int(hdr.Length()) > pkt.Data.Size()+header.UDPMinimumSize {
udpHdr := header.UDP(pkt.TransportHeader().View())
if int(udpHdr.Length()) > pkt.Data.Size()+header.UDPMinimumSize {
// Malformed packet.
s.Stats().UDP.MalformedPacketsReceived.Increment()
return true
}
if !verifyChecksum(r, hdr, pkt) {
if !verifyChecksum(udpHdr, pkt) {
// Checksum error.
s.Stats().UDP.ChecksumErrors.Increment()
return true
@@ -36,8 +37,14 @@ func WithUDPHandler(handle udpHandleFunc) Option {
s.Stats().UDP.PacketsReceived.Increment()
// make a clone here.
route := r.Clone()
netHdr := pkt.Network()
route, err := s.FindRoute(pkt.NICID, netHdr.DestinationAddress(), netHdr.SourceAddress(), pkt.NetworkProtocolNumber, false /* multicastLoop */)
if err != nil {
log.Warnf("[STACK] find route error: %v", err)
return true
}
route.ResolveWith(pkt.SourceLinkAddress())
packet := &udpPacket{
id: id,
r: &route,
@@ -138,7 +145,7 @@ func sendUDP(r *stack.Route, data buffer.VectorisedView, localPort, remotePort u
// On IPv4, UDP checksum is optional, and a zero value indicates the
// transmitter skipped the checksum generation (RFC768).
// On IPv6, UDP checksum is not optional (RFC2460 Section 8.1).
if r.Capabilities()&stack.CapabilityTXChecksumOffload == 0 &&
if r.RequiresTXTransportChecksum() &&
(!noChecksum || r.NetProto == header.IPv6ProtocolNumber) {
xsum := r.PseudoHeaderChecksum(udp.ProtocolNumber, length)
for _, v := range data.Views() {
@@ -166,10 +173,11 @@ func sendUDP(r *stack.Route, data buffer.VectorisedView, localPort, remotePort u
// On IPv4, UDP checksum is optional, and a zero value means the transmitter
// omitted the checksum generation (RFC768).
// On IPv6, UDP checksum is not optional (RFC2460 Section 8.1).
func verifyChecksum(r *stack.Route, hdr header.UDP, pkt *stack.PacketBuffer) bool {
if r.Capabilities()&stack.CapabilityRXChecksumOffload == 0 &&
(hdr.Checksum() != 0 || r.NetProto == header.IPv6ProtocolNumber) {
xsum := r.PseudoHeaderChecksum(udp.ProtocolNumber, hdr.Length())
func verifyChecksum(hdr header.UDP, pkt *stack.PacketBuffer) bool {
if !pkt.RXTransportChecksumValidated &&
(hdr.Checksum() != 0 || pkt.NetworkProtocolNumber == header.IPv6ProtocolNumber) {
netHdr := pkt.Network()
xsum := header.PseudoHeaderChecksum(udp.ProtocolNumber, netHdr.DestinationAddress(), netHdr.SourceAddress(), hdr.Length())
for _, v := range pkt.Data.Views() {
xsum = header.Checksum(v, xsum)
}
-74
View File
@@ -1,74 +0,0 @@
package dev
import (
"errors"
"io"
"net/url"
"strings"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"github.com/xjasonlyu/tun2socks/internal/dev/tun"
)
const defaultScheme = "tun"
type Device struct {
url *url.URL
io.Closer
stack.LinkEndpoint
}
func Open(deviceURL string) (device *Device, err error) {
if !strings.Contains(deviceURL, "://") {
deviceURL = defaultScheme + "://" + deviceURL
}
var u *url.URL
if u, err = url.Parse(deviceURL); err != nil {
return
}
var (
ep stack.LinkEndpoint
c io.Closer
)
switch strings.ToLower(u.Scheme) {
case "tun":
name := u.Host
ep, c, err = tun.Open(name)
default:
err = errors.New("unsupported device type")
}
if err != nil {
return
}
device = &Device{
url: u,
Closer: c,
LinkEndpoint: ep,
}
return
}
// Close closes device.
func (d *Device) Close() error {
return d.Closer.Close()
}
// Name returns name of device.
func (d *Device) Name() string {
return d.url.Host
}
// Type returns type of device.
func (d *Device) Type() string {
return strings.ToLower(d.url.Scheme)
}
// String returns full URL string.
func (d *Device) String() string {
return d.url.String()
}
-15
View File
@@ -1,15 +0,0 @@
// +build !darwin,!linux
package tun
import (
"fmt"
"io"
"runtime"
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
func Open(_ string) (stack.LinkEndpoint, io.Closer, error) {
return nil, nil, fmt.Errorf("operation was not supported on %s", runtime.GOOS)
}
-70
View File
@@ -1,70 +0,0 @@
package tun
import (
"fmt"
"io"
"syscall"
"unsafe"
"github.com/songgao/water"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"github.com/xjasonlyu/tun2socks/pkg/link/rwc"
)
func Open(name string) (ep stack.LinkEndpoint, c io.Closer, err error) {
config := water.Config{
DeviceType: water.TUN,
}
config.Name = name
var ifce *water.Interface
ifce, err = water.New(config)
if err != nil {
return
}
var mtu uint32
mtu, err = getMTU(name)
if err != nil {
return
}
ep, err = rwc.New(ifce, mtu)
c = ifce
return
}
func getMTU(name string) (uint32, error) {
// open datagram socket
fd, err := syscall.Socket(
syscall.AF_INET,
syscall.SOCK_DGRAM,
0,
)
if err != nil {
return 0, err
}
defer syscall.Close(fd)
// do ioctl call
var ifr struct {
name [16]byte
mtu uint32
}
copy(ifr.name[:], name)
_, _, errno := syscall.Syscall(
syscall.SYS_IOCTL,
uintptr(fd),
uintptr(syscall.SIOCGIFMTU),
uintptr(unsafe.Pointer(&ifr)),
)
if errno != 0 {
return 0, fmt.Errorf("get MTU on %s: %s", name, errno.Error())
}
return ifr.mtu, nil
}
-43
View File
@@ -1,43 +0,0 @@
package tun
import (
"io"
"syscall"
"gvisor.dev/gvisor/pkg/tcpip/link/fdbased"
"gvisor.dev/gvisor/pkg/tcpip/link/rawfile"
"gvisor.dev/gvisor/pkg/tcpip/link/tun"
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
type closeFunc func() error
func (f closeFunc) Close() error {
return f()
}
func Open(name string) (ep stack.LinkEndpoint, c io.Closer, err error) {
var fd int
fd, err = tun.Open(name)
if err != nil {
return
}
var mtu uint32
mtu, err = rawfile.GetMTU(name)
if err != nil {
return
}
ep, err = fdbased.New(&fdbased.Options{
FDs: []int{fd},
MTU: mtu,
EthernetHeader: false,
})
c = closeFunc(func() error {
return syscall.Close(fd)
})
return
}
+1 -1
View File
@@ -18,7 +18,7 @@ import (
const (
udpTimeout = 30 * time.Second
udpBufferSize = 64 << 10 // KiB
udpBufferSize = (1 << 16) - 1 // largest possible UDP datagram
)
var (
+2 -2
View File
@@ -10,7 +10,7 @@ import (
"github.com/xjasonlyu/tun2socks/pkg/log"
)
const Usage = "A tun2socks implementation written in Go."
const About = "A tun2socks powered by gVisor TCP/IP stack."
var (
Version string
@@ -19,7 +19,7 @@ var (
func main() {
app := &cli.App{
Usage: Usage,
Usage: About,
Version: Version,
Action: cmd.Main,
Flags: []cli.Flag{
+2 -3
View File
@@ -162,8 +162,7 @@ func (e *Endpoint) Wait() {
e.wg.Wait()
}
// Close closes io.ReadWriteCloser and set closed to true.
// Close closes io.ReadWriteCloser.
func (e *Endpoint) Close() error {
e.rwc.Close()
return nil
return e.rwc.Close()
}
+44
View File
@@ -0,0 +1,44 @@
package tun
import (
"errors"
"net/url"
"strconv"
"strings"
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
const defaultScheme = "tun"
type Device interface {
stack.LinkEndpoint
Name() string // returns the current name
Close() error // stops and closes the tun
}
// Open opens TUN Device with given URL.
func Open(rawURL string) (Device, error) {
if !strings.Contains(rawURL, "://") {
rawURL = defaultScheme + "://" + rawURL
}
var u *url.URL
u, err := url.Parse(rawURL)
if err != nil {
return nil, err
}
if strings.ToLower(u.Scheme) != defaultScheme {
return nil, errors.New("unsupported TUN scheme")
}
var n uint64
if mtu := u.Query().Get("mtu"); mtu != "" {
n, _ = strconv.ParseUint(mtu, 10, 32)
}
name := u.Host
return CreateTUN(name, uint32(n))
}
+12
View File
@@ -0,0 +1,12 @@
// +build !darwin,!freebsd,!linux,!openbsd
package tun
import (
"fmt"
"runtime"
)
func CreateTUN(_ string, _ uint32) (Device, error) {
return nil, fmt.Errorf("operation was not supported on %s", runtime.GOOS)
}
+96
View File
@@ -0,0 +1,96 @@
package tun
import (
"errors"
"os"
"unsafe"
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/tcpip/link/fdbased"
"gvisor.dev/gvisor/pkg/tcpip/link/rawfile"
"gvisor.dev/gvisor/pkg/tcpip/link/tun"
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
type linuxTun struct {
stack.LinkEndpoint
tunName string
tunFile *os.File
}
func CreateTUN(name string, n uint32) (Device, error) {
fd, err := tun.Open(name)
if err != nil {
return nil, err
}
if n > 0 {
if err := setMTU(name, n); err != nil {
return nil, err
}
}
var mtu uint32
if mtu, err = rawfile.GetMTU(name); err != nil {
return nil, err
}
var ep stack.LinkEndpoint
if ep, err = fdbased.New(&fdbased.Options{
FDs: []int{fd},
MTU: mtu,
// TUN only
EthernetHeader: false,
}); err != nil {
return nil, err
}
return &linuxTun{
LinkEndpoint: ep,
tunName: name,
tunFile: os.NewFile(uintptr(fd), "tun"),
}, nil
}
func (t *linuxTun) Name() string {
return t.tunName
}
func (t *linuxTun) Close() error {
return t.tunFile.Close()
}
func setMTU(name string, n uint32) error {
// open datagram socket
fd, err := unix.Socket(
unix.AF_INET,
unix.SOCK_DGRAM,
0,
)
if err != nil {
return err
}
defer unix.Close(fd)
const ifReqSize = unix.IFNAMSIZ + 64
// do ioctl call
var ifr [ifReqSize]byte
copy(ifr[:], name)
*(*uint32)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = n
_, _, errno := unix.Syscall(
unix.SYS_IOCTL,
uintptr(fd),
uintptr(unix.SIOCSIFMTU),
uintptr(unsafe.Pointer(&ifr[0])),
)
if errno != 0 {
return errors.New("failed to set MTU of TUN device")
}
return nil
}
+69
View File
@@ -0,0 +1,69 @@
// +build darwin freebsd openbsd
package tun
import (
"golang.zx2c4.com/wireguard/tun"
"github.com/xjasonlyu/clash/common/pool"
"github.com/xjasonlyu/tun2socks/pkg/link/rwc"
)
const offset = 4
type unixTun struct {
*rwc.Endpoint
device tun.Device
}
func CreateTUN(name string, n uint32) (Device, error) {
device, err := tun.CreateTUN(name, int(n))
if err != nil {
return nil, err
}
mtu, err := device.MTU()
if err != nil {
return nil, err
}
ut := &unixTun{
device: device,
}
if ut.Endpoint, err = rwc.New(ut, uint32(mtu)); err != nil {
return nil, err
}
return ut, nil
}
func (t *unixTun) Read(packet []byte) (n int, err error) {
buf := pool.Get(offset + len(packet))
defer pool.Put(buf)
if n, err = t.device.Read(buf, offset); err != nil {
return
}
copy(packet, buf[offset:offset+n])
return
}
func (t *unixTun) Write(packet []byte) (int, error) {
buf := pool.Get(offset + len(packet))
defer pool.Put(buf)
copy(buf[offset:], packet)
return t.device.Write(buf[:offset+len(packet)], offset)
}
func (t *unixTun) Name() string {
name, _ := t.device.Name()
return name
}
func (t *unixTun) Close() error {
return t.device.Close()
}
+1 -1
View File
@@ -30,7 +30,7 @@ config_route() {
# clone main route
ip route show table main |
while read -r route; do
ip route add $route table "$TABLE"
ip route add ${route%linkdown*} table "$TABLE"
done
# config default route