Compare commits

..
94 Commits
Author SHA1 Message Date
xjasonlyu 7ab86fd9b0 Chore: use renamed buffer pkg 2023-06-05 14:54:58 +08:00
xjasonlyu 4868427efb Chore: update go modules 2023-06-05 14:54:29 +08:00
xjasonlyu 673a942fb3 Improve: set mtu with unix ioctl 2023-05-30 17:40:46 +08:00
xjasonlyu 44ad654d72 Fix: revert to classic TUN creation (#254) 2023-05-30 17:40:45 +08:00
xjasonlyu 46c04db29f Fix: tun issue with virtio_net_hdr (#254) 2023-05-26 16:23:01 +08:00
xjasonlyu 07a6a9f096 Chore: bump gVisor version 2023-05-26 14:45:37 +08:00
xjasonlyu cd6b118e63 Refactor: relocate simple-obfs pkg 2023-05-20 15:10:06 +08:00
xjasonlyu 9838f57e0d Refactor: relocate dialer pkg 2023-05-20 14:53:08 +08:00
xjasonlyu 9dfea44f48 Refactor: remove nat pkg 2023-05-20 14:37:49 +08:00
xjasonlyu 860cf31256 Fix: relocate unused const 2023-05-20 14:37:02 +08:00
xjasonlyu 8e20770bec Refactor: optimize http proxy 2023-05-20 14:32:16 +08:00
xjasonlyu 3320ba46e4 Fix: update tcpip.Address api 2023-05-18 21:38:29 +08:00
xjasonlyu 38bfbb2c3f Chore: update go mod 2023-05-18 21:16:44 +08:00
xjasonlyu 6c07927bba Chore: remove ref annotations 2023-05-18 21:15:04 +08:00
xjasonlyu 2813b4c581 Chore: move files to .github 2023-05-17 22:19:57 +08:00
Jason LyuandGitHub db7c3fd7d2 Chore: create CODE_OF_CONDUCT.md (#259) 2023-05-17 22:16:38 +08:00
Jason LyuandGitHub 4fc5c03e35 Chore: create SECURITY.md (#258) 2023-05-17 22:02:30 +08:00
Vladislav FursovandGitHub 3cbbf3068a Fix(socks5): panic with unassigned reply code (#255) 2023-05-17 10:06:56 +08:00
Jason LyuandGitHub 8da083b28e Chore: nolint in tun_wireguard_unix.go (#253) 2023-05-15 15:05:46 +08:00
xjasonlyu dc6eb815da CI(linter): enable new linters 2023-05-11 10:58:19 +08:00
Jason LyuandGitHub 3b54548914 CI: update golangci-lint config (#251) 2023-05-11 10:51:55 +08:00
SolynandGitHub d061f1c040 Feature: support setting log output (#248)
Signed-off-by: yusheng <yusheng@tencent.com>
2023-05-06 20:49:49 +08:00
xjasonlyu 8e8ccdab89 Chore: use Star History 2023-04-25 15:25:48 +08:00
xjasonlyu 9cbc99e8f5 Chore: bump golang.org/x/sys to v0.7.0 2023-04-06 12:54:12 +08:00
xjasonlyu 2dbd2caaa9 Fix: netstats JSON response 2023-04-03 19:59:37 +08:00
2d0bd1d219 Improve: tunnel/tcp pipe (#219)
Co-authored-by: xjasonlyu <xjasonlyu@gmail.com>
2023-04-03 19:15:24 +08:00
xjasonlyu 61a9d26815 Minor: UDP unidirectionalPacketStream 2023-04-03 19:13:03 +08:00
xjasonlyu 4cc02c822c Minor: improve tunnel/udp 2023-04-03 18:43:02 +08:00
xjasonlyu 20499c6432 Revert: cli tcp-wait-timeout option
This reverts commit 2c51a65685.
2023-04-03 17:57:13 +08:00
xjasonlyu ad522ebb35 Chore: minor renames 2023-04-03 17:43:19 +08:00
xjasonlyu 06d8bee2af Ignore: (*gonet.TCPConn).RemoteAddr() warning 2023-04-03 13:52:28 +08:00
xjasonlyu b809f89411 Revert: udp-rlybuf option
As a low-level networking tool, tun2socks should be able to handle UDP packets of all possible sizes. This reverts commit fb9ca95909.
2023-04-03 12:24:07 +08:00
xjasonlyu b8ff1859c1 Chore: update go mods 2023-04-02 20:20:56 +08:00
xjasonlyu 89c37dc156 Improve: deprecate isIgnorable
All errors should be returned by copyBuffer and handled by higher level functions.
2023-04-02 16:43:55 +08:00
xjasonlyu 1b8e063485 Fix: log message typo 2023-03-30 18:11:08 +08:00
xjasonlyu 195290884c Fix: potential crash by bad UDP address (#238) 2023-03-30 14:11:43 +08:00
xjasonlyu 3b343600e7 Chore: core loglevel to debug 2023-03-29 23:19:08 +08:00
2c51a65685 Feature: cli tcp-wait-timeout option (#156)
Co-authored-by: xjasonlyu <xjasonlyu@gmail.com>
2023-03-29 17:41:01 +08:00
xjasonlyu fb9ca95909 Feature: add udp-rlybuf option
* Default UDP relay buffer size: 16KiB
2023-03-29 16:56:03 +08:00
xjasonlyu 1e99f2d580 Chore: debug level log 2023-03-28 18:04:46 +08:00
xjasonlyu ce15b1b2c2 Improve: with default tracker 2023-03-28 18:00:05 +08:00
xjasonlyu c036db2e23 Chore: rm unused code 2023-03-27 19:11:56 +08:00
007c97fe67 Feature: support pre&post-up exec (#233)
* Add tun pre/post script
* Improve: pre & post tun

---------

Co-authored-by: xjasonlyu <xjasonlyu@gmail.com>
2023-03-27 13:26:39 +08:00
xjasonlyu 7327f2c784 Improve: with gvisor internal log 2023-03-27 13:21:10 +08:00
xjasonlyu 66860d3de8 Improve: enhance error handling 2023-03-27 00:43:39 +08:00
xjasonlyu c61d7b5a20 Chore: error is ignorable 2023-03-26 23:07:13 +08:00
xjasonlyu 680feede3b Improve: add tun io lock 2023-03-26 22:56:01 +08:00
xjasonlyu 22b15f6fab Improve: redirect stack log 2023-03-26 22:48:28 +08:00
xjasonlyu f7b4f75ed4 Fix: align with wireguard io 2023-03-26 22:10:21 +08:00
xjasonlyu 29feac8cd4 Chore: bump go mods 2023-03-26 14:40:39 +08:00
xjasonlyu 6cfc25309e Fix: rand linter
`math/rand.Read` has been deprecated since Go 1.20
2023-02-21 15:06:05 +08:00
xjasonlyu 1f63b239c3 Chore: update linter 2023-02-21 14:55:01 +08:00
xjasonlyu 041bc510ea Chore: bump go modules 2023-02-21 14:05:25 +08:00
xjasonlyu 51d8a27289 Chore: bump gvisor
v0.0.0-20230219185229-4f1045309c43
2023-02-21 14:03:17 +08:00
xjasonlyu 5ffb0186bf Improve: do not stale labeled issues 2023-02-12 14:04:35 +08:00
xjasonlyu 8a2e5cebeb Fix: deprecate rand.Seed 2023-02-06 15:39:37 +08:00
xjasonlyu 846d3d87a7 Chore: bump go.mod to 1.20 2023-02-06 15:39:15 +08:00
xjasonlyu b491e17bfa Chore: add v2 to prefix 2023-02-06 15:38:46 +08:00
xjasonlyu fbe4c22347 Revert: undo crypto/rand
This reverts commit 4a8bf64cb1.
2023-02-06 15:31:05 +08:00
xjasonlyu 4a8bf64cb1 Improve: use crypto/rand 2023-02-04 14:26:41 +08:00
xjasonlyu 059f661862 Chore: bump to go1.20 2023-02-04 13:52:29 +08:00
xjasonlyu ab05092671 Chore: update go mod 2023-02-04 13:52:19 +08:00
xjasonlyu 6809e7f835 Chore: bump gVisor 2023-01-22 13:27:11 +08:00
xjasonlyu bbdc9113d7 Chore: update go mod 2023-01-13 13:40:20 +08:00
xjasonlyu 30608f4925 Chore: bump gVisor 2023-01-01 15:55:12 +08:00
xjasonlyu 39b1406ffa Chore: update mods 2022-12-17 16:57:57 +08:00
xjasonlyu a1edb1c1bb Chore: update workflows 2022-12-17 16:53:30 +08:00
xjasonlyu ad014648ef Fix: build badges 2022-12-16 16:54:54 +08:00
xjasonlyu fa3317a94c Chore: bump go mods 2022-12-01 15:57:08 +08:00
xjasonlyu 8d3c28a516 Feature: support mark on FreeBSD & OpenBSD 2022-12-01 15:46:49 +08:00
LanceLiandGitHub 35f6888c30 Feature: support bind interface on windows (#192) 2022-11-26 23:10:23 +08:00
xjasonlyu 3cbc74b1cf Chore: update gvisor 2022-11-08 15:21:45 +08:00
xjasonlyu 24a53467f6 Chore: deprecate set-output command 2022-10-15 15:33:20 +08:00
xjasonlyu 702ba81ccd Chore: update workflows 2022-10-14 23:26:59 +08:00
xjasonlyu 7fce6e9544 Fix: PacketBufferPtr.IsNil 2022-10-14 22:54:12 +08:00
xjasonlyu 553c2f7a17 Chore: bump modules 2022-10-14 22:36:41 +08:00
xjasonlyu ccfb3a47f6 Fix: make build work
This commit may be reverted if gVisor updates its fdbased pkg.
2022-09-25 16:31:15 +08:00
xjasonlyu 0177157c69 Chore: deprecate openbsd-386 2022-09-25 16:23:47 +08:00
xjasonlyu 82546cd2c5 Chore: with unix build constraint 2022-09-25 15:49:39 +08:00
xjasonlyu 9895b3e048 Chore: update go mod 2022-09-25 15:08:23 +08:00
xjasonlyu 39b50f2bfb Chore: update go mod 2022-09-18 19:31:29 +08:00
xjasonlyu c45470650b Chore: reorder imports 2022-08-07 00:25:59 +08:00
xjasonlyu cb6408a17a Fix: update to bufferv2 2022-08-07 00:05:11 +08:00
xjasonlyu 77bd119d34 Chore: update go mod 2022-08-07 00:04:03 +08:00
xjasonlyu 595896dfc7 Chore: bump to go1.19 2022-08-06 23:51:15 +08:00
xjasonlyu 55a8d038d6 Improve: ignore tcp errors 2022-07-15 21:08:11 +08:00
xjasonlyu e31ffce0e6 Fix: adjust endpoint change 2022-07-15 20:59:37 +08:00
xjasonlyu 267cc6d1a9 Chore: update go mod 2022-07-15 20:17:27 +08:00
xjasonlyu 31468620e7 Chore: update badge logo 2022-06-01 00:10:41 +08:00
xjasonlyu 1536735456 Chore: disable blank issues 2022-05-24 15:30:51 +08:00
xjasonlyu b329f23a4e Chore: auth with GITHUB_TOKEN 2022-05-21 16:27:52 +08:00
xjasonlyu 1ecd587857 Fix(udp): ignore EOF 2022-04-26 16:06:01 +08:00
xjasonlyu 6076fd9a69 Chore(netstats): just render.JSON 2022-04-21 23:30:54 +08:00
xjasonlyu 3926f86613 Feature(docker): add tzdata 2022-04-07 10:56:24 +08:00
63 changed files with 721 additions and 387 deletions
+128
View File
@@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
xjasonlyu@gmail.com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
+1 -1
View File
@@ -1,4 +1,4 @@
blank_issues_enabled: true
blank_issues_enabled: false
contact_links:
- name: tun2socks GitHub Wiki
+28
View File
@@ -0,0 +1,28 @@
# Security Policy
## Supported Versions
| Version | Supported |
| :-----: | :----------------: |
| 2.x | :white_check_mark: |
| 1.x | :x: |
## Reporting a Vulnerability
If you believe you have found a security vulnerability in this repository, please report it to me through coordinated disclosure.
**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.**
Instead, please send an email to xjasonlyu[@]gmail.com.
Please include as much of the information listed below as you can to help me better understand and resolve the issue:
* The type of issue (e.g., buffer overflow, payload attack)
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help me triage your report more quickly.
+4 -4
View File
@@ -16,15 +16,15 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
- name: Autobuild
uses: github/codeql-action/autobuild@v1
uses: github/codeql-action/autobuild@v2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2
+12 -8
View File
@@ -20,36 +20,36 @@ jobs:
fetch-depth: 0
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
uses: docker/setup-qemu-action@v2
with:
platforms: all
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v2
with:
version: latest
- name: Login to DockerHub
uses: docker/login-action@v1
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
uses: docker/login-action@v2
with:
registry: ghcr.io
username: xjasonlyu
password: ${{ secrets.CR_PAT }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Get Version
id: shell
run: |
echo ::set-output name=version::$(git describe --tags --abbrev=0)
echo "version=$(git describe --tags --abbrev=0)" >> $GITHUB_OUTPUT
- name: Build and Push (dev)
if: github.ref == 'refs/heads/main'
uses: docker/build-push-action@v2
uses: docker/build-push-action@v3
with:
context: .
push: true
@@ -57,10 +57,12 @@ jobs:
tags: |
xjasonlyu/tun2socks:dev
ghcr.io/xjasonlyu/tun2socks:dev
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Build and Push (latest)
if: startsWith(github.ref, 'refs/tags/')
uses: docker/build-push-action@v2
uses: docker/build-push-action@v3
with:
context: .
push: true
@@ -70,3 +72,5 @@ jobs:
xjasonlyu/tun2socks:${{ steps.shell.outputs.version }}
ghcr.io/xjasonlyu/tun2socks:latest
ghcr.io/xjasonlyu/tun2socks:${{ steps.shell.outputs.version }}
cache-from: type=gha
cache-to: type=gha,mode=max
+3 -7
View File
@@ -6,15 +6,11 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Get latest go version
id: version
run: |
echo ::set-output name=go_version::$(curl -s https://raw.githubusercontent.com/actions/go-versions/main/versions-manifest.json | grep -oE '"version": "[0-9]{1}.[0-9]{1,}(.[0-9]{1,})?"' | head -1 | cut -d':' -f2 | sed 's/ //g; s/"//g')
- name: Setup Go
uses: actions/setup-go@v2
uses: actions/setup-go@v4
with:
go-version: ${{ steps.version.outputs.go_version }}
check-latest: true
go-version: '1.20'
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
+4 -8
View File
@@ -15,18 +15,14 @@ jobs:
with:
fetch-depth: 0
- name: Get latest Go version
id: version
run: |
echo ::set-output name=go_version::$(curl -s https://raw.githubusercontent.com/actions/go-versions/main/versions-manifest.json | grep -oE '"version": "[0-9]{1}.[0-9]{1,}(.[0-9]{1,})?"' | head -1 | cut -d':' -f2 | sed 's/ //g; s/"//g')
- name: Setup Go
uses: actions/setup-go@v2
uses: actions/setup-go@v3
with:
go-version: ${{ steps.version.outputs.go_version }}
check-latest: true
go-version: '1.20'
- name: Cache go module
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
+2 -2
View File
@@ -8,9 +8,9 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v3
- uses: actions/stale@v7
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days'
exempt-issue-labels: 'question,bug,enhancement'
days-before-stale: 60
days-before-close: 7
+12 -5
View File
@@ -1,16 +1,23 @@
linters:
disable-all: true
enable:
- gofumpt
- staticcheck
- govet
- gci
- gofumpt
- gosimple
- govet
- ineffassign
- misspell
- staticcheck
- unconvert
- unused
- usestdlibvars
linters-settings:
gci:
custom-order: true
sections:
- standard
- prefix(github.com/xjasonlyu/tun2socks)
- default
- prefix(github.com/xjasonlyu/tun2socks)
staticcheck:
go: '1.18'
go: '1.20'
+1 -1
View File
@@ -12,7 +12,7 @@ LABEL org.opencontainers.image.source="https://github.com/xjasonlyu/tun2socks"
COPY docker/entrypoint.sh /entrypoint.sh
COPY --from=builder /src/build/tun2socks /usr/bin/tun2socks
RUN apk add --update --no-cache iptables iproute2 \
RUN apk add --update --no-cache iptables iproute2 tzdata \
&& chmod +x /entrypoint.sh
ENV TUN=tun0
+5 -5
View File
@@ -41,7 +41,6 @@ UNIX_ARCH_LIST = \
linux-ppc64 \
linux-ppc64le \
linux-s390x \
openbsd-386 \
openbsd-amd64 \
openbsd-amd64-v3 \
openbsd-arm64
@@ -130,9 +129,6 @@ linux-ppc64le:
linux-s390x:
GOARCH=s390x GOOS=linux $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
openbsd-386:
GOARCH=386 GOOS=openbsd $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
openbsd-amd64:
GOARCH=amd64 GOOS=openbsd $(GO_BUILD) -o $(BUILD_DIR)/$(BINARY)-$@
@@ -171,7 +167,11 @@ all-arch: $(UNIX_ARCH_LIST) $(WINDOWS_ARCH_LIST)
releases: $(unix_releases) $(windows_releases)
lint:
golangci-lint run --disable-all -E govet -E gofumpt -E megacheck ./...
GOOS=darwin golangci-lint run ./...
GOOS=windows golangci-lint run ./...
GOOS=linux golangci-lint run ./...
GOOS=freebsd golangci-lint run ./...
GOOS=openbsd golangci-lint run ./...
clean:
rm -rf $(BUILD_DIR)
+4 -4
View File
@@ -8,13 +8,13 @@
[![Docker Pulls][6]](https://hub.docker.com/r/xjasonlyu/tun2socks)
[![Releases][7]](https://github.com/xjasonlyu/tun2socks/releases)
[1]: https://img.shields.io/github/workflow/status/xjasonlyu/tun2socks/Go?logo=github
[1]: https://img.shields.io/github/actions/workflow/status/xjasonlyu/tun2socks/release.yml?branch=main&logo=github
[2]: https://img.shields.io/github/go-mod/go-version/xjasonlyu/tun2socks?logo=go
[3]: https://goreportcard.com/badge/github.com/xjasonlyu/tun2socks
[4]: https://api.codeclimate.com/v1/badges/b5b30239174fc6603aca/maintainability
[5]: https://img.shields.io/github/license/xjasonlyu/tun2socks
[6]: https://img.shields.io/docker/pulls/xjasonlyu/tun2socks?logo=docker
[7]: https://img.shields.io/github/v/release/xjasonlyu/tun2socks
[7]: https://img.shields.io/github/v/release/xjasonlyu/tun2socks?logo=smartthings
English | [简体中文](README_ZH.md)
@@ -57,6 +57,6 @@ Welcome and feel free to ask any questions at [Discussions](https://github.com/x
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fxjasonlyu%2Ftun2socks.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fxjasonlyu%2Ftun2socks?ref=badge_large)
## Stargazers over time
## Star History
[![Stargazers over time](https://starchart.cc/xjasonlyu/tun2socks.svg)](https://starchart.cc/xjasonlyu/tun2socks)
[![Star History Chart](https://api.star-history.com/svg?repos=xjasonlyu/tun2socks&type=Date)](https://star-history.com/#xjasonlyu/tun2socks&Date)
+4 -4
View File
@@ -8,13 +8,13 @@
[![Docker Pulls][6]](https://hub.docker.com/r/xjasonlyu/tun2socks)
[![Releases][7]](https://github.com/xjasonlyu/tun2socks/releases)
[1]: https://img.shields.io/github/workflow/status/xjasonlyu/tun2socks/Go?logo=github
[1]: https://img.shields.io/github/actions/workflow/status/xjasonlyu/tun2socks/release.yml?branch=main&logo=github
[2]: https://img.shields.io/github/go-mod/go-version/xjasonlyu/tun2socks?logo=go
[3]: https://goreportcard.com/badge/github.com/xjasonlyu/tun2socks
[4]: https://api.codeclimate.com/v1/badges/b5b30239174fc6603aca/maintainability
[5]: https://img.shields.io/github/license/xjasonlyu/tun2socks
[6]: https://img.shields.io/docker/pulls/xjasonlyu/tun2socks?logo=docker
[7]: https://img.shields.io/github/v/release/xjasonlyu/tun2socks
[7]: https://img.shields.io/github/v/release/xjasonlyu/tun2socks?logo=smartthings
[English](README.md) | 简体中文
@@ -57,6 +57,6 @@
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fxjasonlyu%2Ftun2socks.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fxjasonlyu%2Ftun2socks?ref=badge_large)
## 星星走向
## 星星历史
[![Stargazers over time](https://starchart.cc/xjasonlyu/tun2socks.svg)](https://starchart.cc/xjasonlyu/tun2socks)
[![Star History Chart](https://api.star-history.com/svg?repos=xjasonlyu/tun2socks&type=Date)](https://star-history.com/#xjasonlyu/tun2socks&Date)
-2
View File
@@ -1,7 +1,5 @@
package observable
// Ref: github.com/Dreamacro/clash/common/observable
import (
"errors"
"sync"
+4 -5
View File
@@ -1,15 +1,14 @@
// Package pool provides a pool of []byte.
package pool
// Ref: github.com/Dreamacro/clash/common/pool
const (
// MaxSegmentSize is the largest possible UDP datagram size.
MaxSegmentSize = (1 << 16) - 1
// io.Copy default buffer size is 32 KiB, but the maximum packet
// size of vmess/shadowsocks is about 16 KiB, so define a buffer
// of 20 KiB to reduce the memory of each TCP relay.
// RelayBufferSize is a buffer of 20 KiB to reduce the memory
// of each TCP relay as io.Copy default buffer size is 32 KiB,
// but the maximum packet size of vmess/shadowsocks is about
// 16 KiB, so define .
RelayBufferSize = 20 << 10
)
-31
View File
@@ -1,31 +0,0 @@
/*
Package nat provides simple NAT table implements.
* Normal (Full Cone) NAT
A full cone NAT is one where all requests from the same internal IP address
and port are mapped to the same external IP address and port. Furthermore,
any external host can send a packet to the internal host, by sending a packet
to the mapped external address.
* Restricted Cone NAT
A restricted cone NAT is one where all requests from the same internal IP
address and port are mapped to the same external IP address and port.
Unlike a full cone NAT, an external host (with IP address X) can send a
packet to the internal host only if the internal host had previously sent
a packet to IP address X.
* Port Restricted Cone NAT
A port restricted cone NAT is like a restricted cone NAT, but the restriction
includes port numbers. Specifically, an external host can send a packet, with
source IP address X and source port P, to the internal host only if the internal
host had previously sent a packet to IP address X and port P.
* Symmetric NAT
A symmetric NAT is one where all requests from the same internal IP address
and port, to a specific destination IP address and port, are mapped to the
same external IP address and port. If the same host sends a packet with the
same source address and port, but to a different destination, a different mapping
is used. Furthermore, only the external host that receives a packet can send a
UDP packet back to the internal host.
*/
package nat
-35
View File
@@ -1,35 +0,0 @@
package nat
import (
"net"
"sync"
)
type Table struct {
mapping sync.Map
}
func (t *Table) Set(key string, pc net.PacketConn) {
t.mapping.Store(key, pc)
}
func (t *Table) Get(key string) net.PacketConn {
item, exist := t.mapping.Load(key)
if !exist {
return nil
}
return item.(net.PacketConn)
}
func (t *Table) GetOrCreateLock(key string) (*sync.Cond, bool) {
item, loaded := t.mapping.LoadOrStore(key, sync.NewCond(&sync.Mutex{}))
return item.(*sync.Cond), loaded
}
func (t *Table) Delete(key string) {
t.mapping.Delete(key)
}
func NewTable() *Table {
return &Table{}
}
-2
View File
@@ -1,5 +1,3 @@
package fdbased
const Driver = "fd"
const defaultMTU = 1500
+4 -2
View File
@@ -6,12 +6,14 @@ import (
"fmt"
"strconv"
"github.com/xjasonlyu/tun2socks/v2/core/device"
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"github.com/xjasonlyu/tun2socks/v2/core/device"
)
const defaultMTU = 1500
type FD struct {
stack.LinkEndpoint
+4 -2
View File
@@ -1,11 +1,13 @@
//go:build (linux && amd64) || (linux && arm64)
package fdbased
import (
"fmt"
"github.com/xjasonlyu/tun2socks/v2/core/device"
"gvisor.dev/gvisor/pkg/tcpip/link/fdbased"
"github.com/xjasonlyu/tun2socks/v2/core/device"
)
func open(fd int, mtu uint32) (device.Device, error) {
+1 -1
View File
@@ -1,4 +1,4 @@
//go:build !linux && !windows
//go:build !(linux && amd64) && !(linux && arm64) && !windows
package fdbased
+9 -11
View File
@@ -8,8 +8,8 @@ import (
"io"
"sync"
"gvisor.dev/gvisor/pkg/buffer"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/link/channel"
"gvisor.dev/gvisor/pkg/tcpip/stack"
@@ -110,7 +110,7 @@ func (e *Endpoint) dispatchLoop(cancel context.CancelFunc) {
}
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
Data: buffer.View(data[offset : offset+n]).ToVectorisedView(),
Payload: buffer.MakeWithData(data[offset : offset+n]),
})
switch header.IPVersion(data[offset:]) {
@@ -128,7 +128,7 @@ func (e *Endpoint) dispatchLoop(cancel context.CancelFunc) {
func (e *Endpoint) outboundLoop(ctx context.Context) {
for {
pkt := e.ReadContext(ctx)
if pkt == nil {
if pkt.IsNil() {
break
}
e.writePacket(pkt)
@@ -136,19 +136,17 @@ func (e *Endpoint) outboundLoop(ctx context.Context) {
}
// writePacket writes outbound packets to the io.Writer.
func (e *Endpoint) writePacket(pkt *stack.PacketBuffer) tcpip.Error {
func (e *Endpoint) writePacket(pkt stack.PacketBufferPtr) tcpip.Error {
defer pkt.DecRef()
size := pkt.Size()
views := pkt.Views()
buf := pkt.ToBuffer()
defer buf.Release()
if e.offset != 0 {
views = append([]buffer.View{
make(buffer.View, e.offset),
}, views...)
v := buffer.NewViewWithData(make([]byte, e.offset))
_ = buf.Prepend(v)
}
vView := buffer.NewVectorisedView(size, views)
if _, err := e.rw.Write(vView.ToView()); err != nil {
if _, err := e.rw.Write(buf.Flatten()); err != nil {
return &tcpip.ErrInvalidEndpointState{}
}
return nil
+8 -22
View File
@@ -1,18 +1,17 @@
//go:build linux
//go:build (linux && amd64) || (linux && arm64)
package tun
import (
"fmt"
"unsafe"
"github.com/xjasonlyu/tun2socks/v2/core/device"
"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"
"github.com/xjasonlyu/tun2socks/v2/core/device"
)
type TUN struct {
@@ -81,7 +80,6 @@ func (t *TUN) Close() error {
return unix.Close(t.fd)
}
// Ref: wireguard tun/tun_linux.go setMTU.
func setMTU(name string, n uint32) error {
// open datagram socket
fd, err := unix.Socket(
@@ -95,22 +93,10 @@ func setMTU(name string, n uint32) error {
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 fmt.Errorf("failed to set MTU: %w", errno)
ifr, err := unix.NewIfreq(name)
if err != nil {
return err
}
return nil
ifr.SetUint32(n)
return unix.IoctlIfreq(fd, unix.SIOCSIFMTU, ifr)
}
+28 -7
View File
@@ -1,14 +1,15 @@
//go:build !linux
//go:build !(linux && amd64) && !(linux && arm64)
package tun
import (
"fmt"
"sync"
"golang.zx2c4.com/wireguard/tun"
"github.com/xjasonlyu/tun2socks/v2/core/device"
"github.com/xjasonlyu/tun2socks/v2/core/device/iobased"
"golang.zx2c4.com/wireguard/tun"
)
type TUN struct {
@@ -18,6 +19,12 @@ type TUN struct {
mtu uint32
name string
offset int
rSizes []int
rBuffs [][]byte
wBuffs [][]byte
rMutex sync.Mutex
wMutex sync.Mutex
}
func Open(name string, mtu uint32) (_ device.Device, err error) {
@@ -27,14 +34,21 @@ func Open(name string, mtu uint32) (_ device.Device, err error) {
}
}()
t := &TUN{name: name, mtu: mtu, offset: offset}
t := &TUN{
name: name,
mtu: mtu,
offset: offset,
rSizes: make([]int, 1),
rBuffs: make([][]byte, 1),
wBuffs: make([][]byte, 1),
}
forcedMTU := defaultMTU
if t.mtu > 0 {
forcedMTU = int(t.mtu)
}
nt, err := tun.CreateTUN(t.name, forcedMTU)
nt, err := createTUN(t.name, forcedMTU)
if err != nil {
return nil, fmt.Errorf("create tun: %w", err)
}
@@ -56,11 +70,18 @@ func Open(name string, mtu uint32) (_ device.Device, err error) {
}
func (t *TUN) Read(packet []byte) (int, error) {
return t.nt.Read(packet, t.offset)
t.rMutex.Lock()
defer t.rMutex.Unlock()
t.rBuffs[0] = packet
_, err := t.nt.Read(t.rBuffs, t.rSizes, t.offset)
return t.rSizes[0], err
}
func (t *TUN) Write(packet []byte) (int, error) {
return t.nt.Write(packet, t.offset)
t.wMutex.Lock()
defer t.wMutex.Unlock()
t.wBuffs[0] = packet
return t.nt.Write(t.wBuffs, t.offset)
}
func (t *TUN) Name() string {
+26
View File
@@ -0,0 +1,26 @@
//go:build linux && !(amd64 || arm64)
package tun
import (
"fmt"
"os"
"golang.zx2c4.com/wireguard/tun"
gun "gvisor.dev/gvisor/pkg/tcpip/link/tun"
)
const (
offset = 0 /* IFF_NO_PI */
defaultMTU = 1500
)
func createTUN(name string, mtu int) (tun.Device, error) {
nfd, err := gun.Open(name)
if err != nil {
return nil, fmt.Errorf("create tun: %w", err)
}
fd := os.NewFile(uintptr(nfd), "/dev/net/tun")
return tun.CreateTUNFromFile(fd, mtu)
}
+9 -1
View File
@@ -1,8 +1,16 @@
//go:build !linux && !windows
//go:build unix && !linux
package tun
import (
"golang.zx2c4.com/wireguard/tun"
)
const (
offset = 4 /* 4 bytes TUN_PI */
defaultMTU = 1500
)
func createTUN(name string, mtu int) (tun.Device, error) {
return tun.CreateTUN(name, mtu)
}
+8
View File
@@ -1,6 +1,14 @@
package tun
import (
"golang.zx2c4.com/wireguard/tun"
)
const (
offset = 0
defaultMTU = 0 /* auto */
)
func createTUN(name string, mtu int) (tun.Device, error) {
return tun.CreateTUN(name, mtu)
}
+2 -2
View File
@@ -3,10 +3,10 @@ package core
import (
"fmt"
"github.com/xjasonlyu/tun2socks/v2/core/option"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"github.com/xjasonlyu/tun2socks/v2/core/option"
)
const (
+2 -2
View File
@@ -1,11 +1,11 @@
package core
import (
"github.com/xjasonlyu/tun2socks/v2/core/option"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"github.com/xjasonlyu/tun2socks/v2/core/option"
)
func withRouteTable(nicID tcpip.NICID) option.Option {
+5 -13
View File
@@ -1,9 +1,6 @@
package core
import (
"github.com/xjasonlyu/tun2socks/v2/core/adapter"
"github.com/xjasonlyu/tun2socks/v2/core/option"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
@@ -11,6 +8,9 @@ import (
"gvisor.dev/gvisor/pkg/tcpip/transport/icmp"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
"github.com/xjasonlyu/tun2socks/v2/core/adapter"
"github.com/xjasonlyu/tun2socks/v2/core/option"
)
// Config is the configuration to create *stack.Stack.
@@ -23,10 +23,6 @@ type Config struct {
// stack to set transport handlers.
TransportHandler adapter.TransportHandler
// PrintFunc is the function that will be called
// to print internal stack events.
PrintFunc func(string, ...any)
// Options are supplement options to apply settings
// for the internal stack.
Options []option.Option
@@ -34,10 +30,6 @@ type Config struct {
// CreateStack creates *stack.Stack with given config.
func CreateStack(cfg *Config) (*stack.Stack, error) {
if cfg.PrintFunc == nil {
cfg.PrintFunc = func(string, ...any) {}
}
opts := []option.Option{option.WithDefault()}
if len(opts) > 0 {
opts = append(opts, cfg.Options...)
@@ -64,8 +56,8 @@ func CreateStack(cfg *Config) (*stack.Stack, error) {
// before creating NIC, otherwise NIC would dispatch packets
// to stack and cause race condition.
// Initiate transport protocol (TCP/UDP) with given handler.
withTCPHandler(cfg.TransportHandler.HandleTCP, cfg.PrintFunc),
withUDPHandler(cfg.TransportHandler.HandleUDP, cfg.PrintFunc),
withTCPHandler(cfg.TransportHandler.HandleTCP),
withUDPHandler(cfg.TransportHandler.HandleUDP),
// Create stack NIC and then bind link endpoint to it.
withCreatingNIC(nicID, cfg.LinkEndpoint),
+6 -5
View File
@@ -3,15 +3,16 @@ package core
import (
"time"
"github.com/xjasonlyu/tun2socks/v2/core/adapter"
"github.com/xjasonlyu/tun2socks/v2/core/option"
glog "gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
"gvisor.dev/gvisor/pkg/waiter"
"github.com/xjasonlyu/tun2socks/v2/core/adapter"
"github.com/xjasonlyu/tun2socks/v2/core/option"
)
const (
@@ -40,7 +41,7 @@ const (
tcpKeepaliveInterval = 30 * time.Second
)
func withTCPHandler(handle func(adapter.TCPConn), printf func(string, ...any)) option.Option {
func withTCPHandler(handle func(adapter.TCPConn)) option.Option {
return func(s *stack.Stack) error {
tcpForwarder := tcp.NewForwarder(s, defaultWndSize, maxConnAttempts, func(r *tcp.ForwarderRequest) {
var (
@@ -52,7 +53,7 @@ func withTCPHandler(handle func(adapter.TCPConn), printf func(string, ...any)) o
defer func() {
if err != nil {
printf("forward tcp request %s:%d->%s:%d: %s",
glog.Debugf("forward tcp request: %s:%d->%s:%d: %s",
id.RemoteAddress, id.RemotePort, id.LocalAddress, id.LocalPort, err)
}
}()
+6 -5
View File
@@ -1,16 +1,17 @@
package core
import (
"github.com/xjasonlyu/tun2socks/v2/core/adapter"
"github.com/xjasonlyu/tun2socks/v2/core/option"
glog "gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
"gvisor.dev/gvisor/pkg/waiter"
"github.com/xjasonlyu/tun2socks/v2/core/adapter"
"github.com/xjasonlyu/tun2socks/v2/core/option"
)
func withUDPHandler(handle func(adapter.UDPConn), printf func(string, ...any)) option.Option {
func withUDPHandler(handle func(adapter.UDPConn)) option.Option {
return func(s *stack.Stack) error {
udpForwarder := udp.NewForwarder(s, func(r *udp.ForwarderRequest) {
var (
@@ -19,7 +20,7 @@ func withUDPHandler(handle func(adapter.UDPConn), printf func(string, ...any)) o
)
ep, err := r.CreateEndpoint(&wq)
if err != nil {
printf("udp forwarder request %s:%d->%s:%d: %s",
glog.Debugf("forward udp request: %s:%d->%s:%d: %s",
id.RemoteAddress, id.RemotePort, id.LocalAddress, id.LocalPort, err)
return
}
+33
View File
@@ -0,0 +1,33 @@
package dialer
import (
"net"
"syscall"
"golang.org/x/sys/unix"
)
func setSocketOptions(network, address string, c syscall.RawConn, opts *Options) (err error) {
if opts == nil || !isTCPSocket(network) && !isUDPSocket(network) {
return
}
var innerErr error
err = c.Control(func(fd uintptr) {
host, _, _ := net.SplitHostPort(address)
if ip := net.ParseIP(host); ip != nil && !ip.IsGlobalUnicast() {
return
}
if opts.RoutingMark != 0 {
if innerErr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_USER_COOKIE, opts.RoutingMark); innerErr != nil {
return
}
}
})
if innerErr != nil {
err = innerErr
}
return
}
+33
View File
@@ -0,0 +1,33 @@
package dialer
import (
"net"
"syscall"
"golang.org/x/sys/unix"
)
func setSocketOptions(network, address string, c syscall.RawConn, opts *Options) (err error) {
if opts == nil || !isTCPSocket(network) && !isUDPSocket(network) {
return
}
var innerErr error
err = c.Control(func(fd uintptr) {
host, _, _ := net.SplitHostPort(address)
if ip := net.ParseIP(host); ip != nil && !ip.IsGlobalUnicast() {
return
}
if opts.RoutingMark != 0 {
if innerErr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RTABLE, opts.RoutingMark); innerErr != nil {
return
}
}
})
if innerErr != nil {
err = innerErr
}
return
}
@@ -1,4 +1,4 @@
//go:build !linux && !darwin
//go:build !unix && !windows
package dialer
+68
View File
@@ -0,0 +1,68 @@
package dialer
import (
"encoding/binary"
"net"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
const (
IP_UNICAST_IF = 31
IPV6_UNICAST_IF = 31
)
func setSocketOptions(network, address string, c syscall.RawConn, opts *Options) (err error) {
if opts == nil || !isTCPSocket(network) && !isUDPSocket(network) {
return
}
var innerErr error
err = c.Control(func(fd uintptr) {
host, _, _ := net.SplitHostPort(address)
ip := net.ParseIP(host)
if ip != nil && !ip.IsGlobalUnicast() {
return
}
if opts.InterfaceIndex == 0 && opts.InterfaceName != "" {
if iface, err := net.InterfaceByName(opts.InterfaceName); err == nil {
opts.InterfaceIndex = iface.Index
}
}
if opts.InterfaceIndex != 0 {
switch network {
case "tcp4", "udp4":
innerErr = bindSocketToInterface4(windows.Handle(fd), uint32(opts.InterfaceIndex))
case "tcp6", "udp6":
innerErr = bindSocketToInterface6(windows.Handle(fd), uint32(opts.InterfaceIndex))
if network == "udp6" && ip == nil {
// The underlying IP net maybe IPv4 even if the `network` param is `udp6`,
// so we should bind socket to interface4 at the same time.
innerErr = bindSocketToInterface4(windows.Handle(fd), uint32(opts.InterfaceIndex))
}
}
}
})
if innerErr != nil {
err = innerErr
}
return
}
func bindSocketToInterface4(handle windows.Handle, index uint32) error {
// For IPv4, this parameter must be an interface index in network byte order.
// Ref: https://learn.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options
var bytes [4]byte
binary.BigEndian.PutUint32(bytes[:], index)
index = *(*uint32)(unsafe.Pointer(&bytes[0]))
return windows.SetsockoptInt(handle, windows.IPPROTO_IP, IP_UNICAST_IF, int(index))
}
func bindSocketToInterface6(handle windows.Handle, index uint32) error {
return windows.SetsockoptInt(handle, windows.IPPROTO_IPV6, IPV6_UNICAST_IF, int(index))
}
+1 -1
View File
@@ -3,7 +3,7 @@ package dns
import (
"net"
"github.com/xjasonlyu/tun2socks/v2/component/dialer"
"github.com/xjasonlyu/tun2socks/v2/dialer"
)
func init() {
+32 -10
View File
@@ -2,24 +2,25 @@ package engine
import (
"errors"
"fmt"
"net"
"os/exec"
"strings"
"sync"
"time"
"github.com/xjasonlyu/tun2socks/v2/component/dialer"
"github.com/docker/go-units"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"github.com/xjasonlyu/tun2socks/v2/core"
"github.com/xjasonlyu/tun2socks/v2/core/device"
"github.com/xjasonlyu/tun2socks/v2/core/option"
"github.com/xjasonlyu/tun2socks/v2/dialer"
"github.com/xjasonlyu/tun2socks/v2/engine/mirror"
"github.com/xjasonlyu/tun2socks/v2/log"
"github.com/xjasonlyu/tun2socks/v2/proxy"
"github.com/xjasonlyu/tun2socks/v2/restapi"
"github.com/xjasonlyu/tun2socks/v2/tunnel"
"github.com/docker/go-units"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
var (
@@ -91,6 +92,15 @@ func stop() (err error) {
return err
}
func execCommand(cmd string) error {
parts := strings.Fields(cmd)
if len(parts) == 0 {
return errors.New("empty command")
}
_, err := exec.Command(parts[0], parts[1:]...).Output()
return err
}
func general(k *Key) error {
level, err := log.ParseLevel(k.LogLevel)
if err != nil {
@@ -159,6 +169,21 @@ func netstack(k *Key) (err error) {
return errors.New("empty device")
}
if k.TUNPreUp != "" {
if preUpErr := execCommand(k.TUNPreUp); preUpErr != nil {
log.Warnf("[TUN] failed to pre-execute: %s: %v", k.TUNPreUp, preUpErr)
}
}
defer func() {
if k.TUNPostUp == "" || err != nil {
return
}
if postUpErr := execCommand(k.TUNPostUp); postUpErr != nil {
log.Warnf("[TUN] failed to post-execute: %s: %v", k.TUNPostUp, postUpErr)
}
}()
if _defaultProxy, err = parseProxy(k.Proxy); err != nil {
return
}
@@ -192,10 +217,7 @@ func netstack(k *Key) (err error) {
if _defaultStack, err = core.CreateStack(&core.Config{
LinkEndpoint: _defaultDevice,
TransportHandler: &mirror.Tunnel{},
PrintFunc: func(format string, v ...any) {
log.Warnf("[STACK] %s", fmt.Sprintf(format, v...))
},
Options: opts,
Options: opts,
}); err != nil {
return
}
+2
View File
@@ -13,5 +13,7 @@ type Key struct {
TCPModerateReceiveBuffer bool `yaml:"tcp-moderate-receive-buffer"`
TCPSendBufferSize string `yaml:"tcp-send-buffer-size"`
TCPReceiveBufferSize string `yaml:"tcp-receive-buffer-size"`
TUNPreUp string `yaml:"tun-pre-up"`
TUNPostUp string `yaml:"tun-post-up"`
UDPTimeout time.Duration `yaml:"udp-timeout"`
}
+19 -18
View File
@@ -1,32 +1,33 @@
module github.com/xjasonlyu/tun2socks/v2
go 1.18
go 1.20
require (
github.com/Dreamacro/go-shadowsocks2 v0.1.7
github.com/docker/go-units v0.4.0
github.com/go-chi/chi/v5 v5.0.7
github.com/go-chi/cors v1.2.0
github.com/go-chi/render v1.0.1
github.com/Dreamacro/go-shadowsocks2 v0.1.8
github.com/docker/go-units v0.5.0
github.com/go-chi/chi/v5 v5.0.8
github.com/go-chi/cors v1.2.1
github.com/go-chi/render v1.0.2
github.com/google/uuid v1.3.0
github.com/gorilla/websocket v1.5.0
github.com/sirupsen/logrus v1.8.1
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.7.1
go.uber.org/atomic v1.9.0
go.uber.org/automaxprocs v1.5.1
golang.org/x/sys v0.0.0-20220405210540-1e041c57c461
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65
golang.zx2c4.com/wireguard v0.0.0-20220318042302-193cf8d6a5d6
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
gvisor.dev/gvisor v0.0.0-20220405222207-795f4f0139bb
go.uber.org/atomic v1.11.0
go.uber.org/automaxprocs v1.5.2
golang.org/x/sys v0.8.0
golang.org/x/time v0.3.0
golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b
gopkg.in/yaml.v3 v3.0.1
gvisor.dev/gvisor v0.0.0-20230603040744-5c9219dedd33
)
require (
github.com/ajg/form v1.5.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/btree v1.1.2 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 // indirect
golang.org/x/net v0.0.0-20220403103023-749bd193bc2b // indirect
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
golang.org/x/crypto v0.9.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
)
+38 -43
View File
@@ -1,19 +1,21 @@
github.com/Dreamacro/go-shadowsocks2 v0.1.7 h1:8CtbE1HoPPMfrQZGXmlluq6dO2lL31W6WRRE8fabc4Q=
github.com/Dreamacro/go-shadowsocks2 v0.1.7/go.mod h1:8p5G4cAj5ZlXwUR+Ww63gfSikr8kvw8uw3TDwLAJpUc=
github.com/Dreamacro/go-shadowsocks2 v0.1.8 h1:Ixejp5JscEc866gAvm/l6TFd7BOBvDviKgwb1quWw3g=
github.com/Dreamacro/go-shadowsocks2 v0.1.8/go.mod h1:51y4Q6tJoCE7e8TmYXcQRqfoxPfE9Cvn79V6pB6Df7Y=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.0 h1:tV1g1XENQ8ku4Bq3K9ub2AtgG+p16SmzeMSGTwrOKdE=
github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-chi/render v1.0.1 h1:4/5tis2cKaNdnv9zFLfXzcquC9HbeZgCnxGnKrltBS8=
github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1OvJns=
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-chi/render v1.0.2 h1:4ER/udB0+fMWB2Jlf15RV3F4A2FDuYi/9f+lFttR/Lg=
github.com/go-chi/render v1.0.2/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
@@ -24,40 +26,33 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
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.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/automaxprocs v1.5.1 h1:e1YG66Lrk73dn4qhg8WFSvhF0JuFQF0ERIp4rpuV8Qk=
go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU=
golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 h1:tkVvjkPTB7pnW3jnid7kNyAMPVWllTNOf/qKDze4p9o=
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220403103023-749bd193bc2b h1:vI32FkLJNAWtGD4BwkThwEy6XS7ZLLMHkSkYfF8M0W0=
golang.org/x/net v0.0.0-20220403103023-749bd193bc2b/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220405210540-1e041c57c461 h1:kHVeDEnfKn3T238CvrUcz6KeEsFHVaKh4kMTt6Wsysg=
golang.org/x/sys v0.0.0-20220405210540-1e041c57c461/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs=
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY=
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
golang.zx2c4.com/wireguard v0.0.0-20220318042302-193cf8d6a5d6 h1:kgBK1EGuTIYbwoKROmsoV0FQp08gnCcVa110A4Unqhk=
golang.zx2c4.com/wireguard v0.0.0-20220318042302-193cf8d6a5d6/go.mod h1:bVQfyl2sCM/QIIGHpWbFGfHPuDvqnCNkT6MQLTCjO/U=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/automaxprocs v1.5.2 h1:2LxUOGiR3O6tw8ui5sZa2LAaHnsviZdVOUZw4fvbnME=
go.uber.org/automaxprocs v1.5.2/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b h1:J1CaxgLerRR5lgx3wnr6L04cJFbWoceSK9JWBdglINo=
golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b/go.mod h1:tqur9LnfstdR9ep2LaJT4lFUl0EjlHtge+gAjmsHUG4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gvisor.dev/gvisor v0.0.0-20220405222207-795f4f0139bb h1:AFXQ8bzBy3bvv18rPD8bjDGzylB0PZrMJWQKuXxvR7Y=
gvisor.dev/gvisor v0.0.0-20220405222207-795f4f0139bb/go.mod h1:tWwEcFvJavs154OdjFCw78axNrsDlz4Zh8jvPqwcpGI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gvisor.dev/gvisor v0.0.0-20230603040744-5c9219dedd33 h1:64QentohifmKGeTgJCHilDgfmQVuYE45fsaS9psJ3zY=
gvisor.dev/gvisor v0.0.0-20230603040744-5c9219dedd33/go.mod h1:sQuqOkxbfJq/GS2uSnqHphtXclHyk/ZrAGhZBxxsq6g=
+34
View File
@@ -0,0 +1,34 @@
package log
import (
"io"
"runtime"
"strings"
"time"
glog "gvisor.dev/gvisor/pkg/log"
)
func init() {
EnableStackLog(true)
}
func EnableStackLog(v bool) {
if v {
glog.SetTarget(&emitter{}) // built-in logger
} else {
glog.SetTarget(&glog.Writer{Next: io.Discard})
}
}
type emitter struct{}
func (emitter) Emit(depth int, level glog.Level, _ time.Time, format string, args ...any) {
if _, file, line, ok := runtime.Caller(depth + 1); ok {
// Ignore (*gonet.TCPConn).RemoteAddr() warning: `ep.GetRemoteAddress() failed`.
if line == 457 && strings.HasSuffix(file, "/pkg/tcpip/adapters/gonet/gonet.go") {
return
}
}
logf(Level(level)+2, "[STACK] "+format, args...)
}
+5
View File
@@ -1,6 +1,7 @@
package log
import (
"io"
"os"
"github.com/sirupsen/logrus"
@@ -15,6 +16,10 @@ func init() {
logrus.SetLevel(logrus.DebugLevel)
}
func SetOutput(out io.Writer) {
logrus.SetOutput(out)
}
func SetLevel(level Level) {
_defaultLevel.Store(uint32(level))
}
+5 -3
View File
@@ -7,13 +7,13 @@ import (
"os/signal"
"syscall"
"go.uber.org/automaxprocs/maxprocs"
"gopkg.in/yaml.v3"
_ "github.com/xjasonlyu/tun2socks/v2/dns"
"github.com/xjasonlyu/tun2socks/v2/engine"
"github.com/xjasonlyu/tun2socks/v2/internal/version"
"github.com/xjasonlyu/tun2socks/v2/log"
"go.uber.org/automaxprocs/maxprocs"
"gopkg.in/yaml.v3"
)
var (
@@ -36,6 +36,8 @@ func init() {
flag.StringVar(&key.TCPSendBufferSize, "tcp-sndbuf", "", "Set TCP send buffer size for netstack")
flag.StringVar(&key.TCPReceiveBufferSize, "tcp-rcvbuf", "", "Set TCP receive buffer size for netstack")
flag.BoolVar(&key.TCPModerateReceiveBuffer, "tcp-auto-tuning", false, "Enable TCP receive buffer auto-tuning")
flag.StringVar(&key.TUNPreUp, "tun-pre-up", "", "Execute a command before TUN device setup")
flag.StringVar(&key.TUNPostUp, "tun-post-up", "", "Execute a command after TUN device setup")
flag.BoolVar(&versionFlag, "version", false, "Show version and then quit")
flag.Parse()
}
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"context"
"net"
"github.com/xjasonlyu/tun2socks/v2/component/dialer"
"github.com/xjasonlyu/tun2socks/v2/dialer"
M "github.com/xjasonlyu/tun2socks/v2/metadata"
"github.com/xjasonlyu/tun2socks/v2/proxy/proto"
)
+20 -19
View File
@@ -1,7 +1,5 @@
package proxy
// Ref: https://github.com/Dreamacro/clash/adapter/outbound/http
import (
"bufio"
"context"
@@ -13,7 +11,7 @@ import (
"net/http"
"net/url"
"github.com/xjasonlyu/tun2socks/v2/component/dialer"
"github.com/xjasonlyu/tun2socks/v2/dialer"
M "github.com/xjasonlyu/tun2socks/v2/metadata"
"github.com/xjasonlyu/tun2socks/v2/proxy/proto"
)
@@ -63,9 +61,7 @@ func (h *HTTP) shakeHand(metadata *M.Metadata, rw io.ReadWriter) error {
}
if h.user != "" && h.pass != "" {
auth := h.user + ":" + h.pass
req.Header.Add("Proxy-Authorization",
fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(auth))))
req.Header.Set("Proxy-Authorization", basicAuth(h.user, h.pass))
}
if err := req.Write(rw); err != nil {
@@ -77,21 +73,26 @@ func (h *HTTP) shakeHand(metadata *M.Metadata, rw io.ReadWriter) error {
return err
}
if resp.StatusCode == http.StatusOK {
switch resp.StatusCode {
case http.StatusOK:
return nil
}
if resp.StatusCode == http.StatusProxyAuthRequired {
return errors.New("HTTP need auth")
}
if resp.StatusCode == http.StatusMethodNotAllowed {
case http.StatusProxyAuthRequired:
return errors.New("HTTP auth required by proxy")
case http.StatusMethodNotAllowed:
return errors.New("CONNECT method not allowed by proxy")
default:
return fmt.Errorf("HTTP connect status: %s", resp.Status)
}
}
if resp.StatusCode >= http.StatusInternalServerError {
return errors.New(resp.Status)
}
return fmt.Errorf("HTTP connect status code: %d", resp.StatusCode)
// The Basic authentication scheme is based on the model that the client
// needs to authenticate itself with a user-id and a password for each
// protection space ("realm"). The realm value is a free-form string
// that can only be compared for equality with other realms on that
// server. The server will service the request only if it can validate
// the user-id and password for the protection space applying to the
// requested resource.
func basicAuth(username, password string) string {
auth := username + ":" + password
return base64.StdEncoding.EncodeToString([]byte(auth))
}
+4 -4
View File
@@ -6,13 +6,13 @@ import (
"fmt"
"net"
"github.com/xjasonlyu/tun2socks/v2/component/dialer"
obfs "github.com/xjasonlyu/tun2socks/v2/component/simple-obfs"
"github.com/Dreamacro/go-shadowsocks2/core"
"github.com/xjasonlyu/tun2socks/v2/dialer"
M "github.com/xjasonlyu/tun2socks/v2/metadata"
"github.com/xjasonlyu/tun2socks/v2/proxy/proto"
obfs "github.com/xjasonlyu/tun2socks/v2/transport/simple-obfs"
"github.com/xjasonlyu/tun2socks/v2/transport/socks5"
"github.com/Dreamacro/go-shadowsocks2/core"
)
var _ Proxy = (*Shadowsocks)(nil)
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"fmt"
"net"
"github.com/xjasonlyu/tun2socks/v2/component/dialer"
"github.com/xjasonlyu/tun2socks/v2/dialer"
M "github.com/xjasonlyu/tun2socks/v2/metadata"
"github.com/xjasonlyu/tun2socks/v2/proxy/proto"
"github.com/xjasonlyu/tun2socks/v2/transport/socks4"
+5 -1
View File
@@ -7,7 +7,7 @@ import (
"io"
"net"
"github.com/xjasonlyu/tun2socks/v2/component/dialer"
"github.com/xjasonlyu/tun2socks/v2/dialer"
M "github.com/xjasonlyu/tun2socks/v2/metadata"
"github.com/xjasonlyu/tun2socks/v2/proxy/proto"
"github.com/xjasonlyu/tun2socks/v2/transport/socks5"
@@ -121,6 +121,10 @@ func (ss *Socks5) DialUDP(*M.Metadata) (_ net.PacketConn, err error) {
}()
bindAddr := addr.UDPAddr()
if bindAddr == nil {
return nil, fmt.Errorf("invalid UDP binding address: %#v", addr)
}
if bindAddr.IP.IsUnspecified() { /* e.g. "0.0.0.0" or "::" */
udpAddr, err := net.ResolveUDPAddr("udp", ss.Addr())
if err != nil {
+2 -2
View File
@@ -7,11 +7,11 @@ import (
"strconv"
"time"
"github.com/xjasonlyu/tun2socks/v2/tunnel/statistic"
"github.com/go-chi/chi/v5"
"github.com/go-chi/render"
"github.com/gorilla/websocket"
"github.com/xjasonlyu/tun2socks/v2/tunnel/statistic"
)
const defaultInterval = 1000
-1
View File
@@ -40,7 +40,6 @@ func getNetStats(w http.ResponseWriter, r *http.Request) {
if !websocket.IsWebSocketUpgrade(r) {
w.Header().Set("Content-Type", "application/json")
render.Status(r, http.StatusOK)
// write and flush.
w.Write(snapshot())
w.(http.Flusher).Flush()
return
+4 -6
View File
@@ -1,7 +1,5 @@
package restapi
// Ref: github.com/Dreamacro/clash/hub/route
import (
"bytes"
"encoding/json"
@@ -10,14 +8,14 @@ import (
"strings"
"time"
V "github.com/xjasonlyu/tun2socks/v2/internal/version"
"github.com/xjasonlyu/tun2socks/v2/log"
"github.com/xjasonlyu/tun2socks/v2/tunnel/statistic"
"github.com/go-chi/chi/v5"
"github.com/go-chi/cors"
"github.com/go-chi/render"
"github.com/gorilla/websocket"
V "github.com/xjasonlyu/tun2socks/v2/internal/version"
"github.com/xjasonlyu/tun2socks/v2/log"
"github.com/xjasonlyu/tun2socks/v2/tunnel/statistic"
)
var (
@@ -2,10 +2,11 @@ package obfs
import (
"bytes"
"crypto/rand"
"encoding/base64"
"fmt"
"io"
"math/rand"
mRand "math/rand"
"net"
"net/http"
@@ -64,8 +65,8 @@ 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, _ := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s/", ho.host), bytes.NewBuffer(b[:]))
req.Header.Set("User-Agent", fmt.Sprintf("curl/7.%d.%d", mRand.Int()%54, mRand.Int()%2))
req.Header.Set("Upgrade", "websocket")
req.Header.Set("Connection", "Upgrade")
req.Host = ho.host
@@ -1,4 +1,2 @@
// Package obfs provides obfuscation functionality for Shadowsocks protocol.
package obfs
// Ref: github.com/Dreamacro/clash/component/simple-obfs
@@ -2,19 +2,15 @@ package obfs
import (
"bytes"
"crypto/rand"
"encoding/binary"
"io"
"math/rand"
"net"
"time"
"github.com/xjasonlyu/tun2socks/v2/common/pool"
)
func init() {
rand.Seed(time.Now().Unix())
}
const (
chunkSize = 1 << 14 // 2 ** 14 == 16 * 1024
)
+1 -3
View File
@@ -1,8 +1,6 @@
// Package socks5 provides SOCKS5 client functionalities.
package socks5
// Ref: github.com/Dreamacro/clash/component/socks5
import (
"bytes"
"encoding/binary"
@@ -72,7 +70,7 @@ func (r Reply) String() string {
case 0x08:
return "address type not supported"
default:
return fmt.Sprintf("unassigned <%#02x>", r)
return fmt.Sprintf("unassigned <%#02x>", uint8(r))
}
}
+29 -4
View File
@@ -1,13 +1,14 @@
package statistic
import (
"errors"
"net"
"time"
M "github.com/xjasonlyu/tun2socks/v2/metadata"
"github.com/google/uuid"
"go.uber.org/atomic"
M "github.com/xjasonlyu/tun2socks/v2/metadata"
)
type tracker interface {
@@ -30,7 +31,7 @@ type tcpTracker struct {
manager *Manager
}
func NewTCPTracker(conn net.Conn, metadata *M.Metadata, manager *Manager) *tcpTracker {
func NewTCPTracker(conn net.Conn, metadata *M.Metadata, manager *Manager) net.Conn {
id, _ := uuid.NewRandom()
tt := &tcpTracker{
@@ -49,6 +50,11 @@ func NewTCPTracker(conn net.Conn, metadata *M.Metadata, manager *Manager) *tcpTr
return tt
}
// DefaultTCPTracker returns a new net.Conn(*tcpTacker) with default manager.
func DefaultTCPTracker(conn net.Conn, metadata *M.Metadata) net.Conn {
return NewTCPTracker(conn, metadata, DefaultManager)
}
func (tt *tcpTracker) ID() string {
return tt.UUID.String()
}
@@ -74,6 +80,20 @@ func (tt *tcpTracker) Close() error {
return tt.Conn.Close()
}
func (tt *tcpTracker) CloseRead() error {
if cr, ok := tt.Conn.(interface{ CloseRead() error }); ok {
return cr.CloseRead()
}
return errors.New("CloseRead is not implemented")
}
func (tt *tcpTracker) CloseWrite() error {
if cw, ok := tt.Conn.(interface{ CloseWrite() error }); ok {
return cw.CloseWrite()
}
return errors.New("CloseWrite is not implemented")
}
type udpTracker struct {
net.PacketConn `json:"-"`
@@ -81,7 +101,7 @@ type udpTracker struct {
manager *Manager
}
func NewUDPTracker(conn net.PacketConn, metadata *M.Metadata, manager *Manager) *udpTracker {
func NewUDPTracker(conn net.PacketConn, metadata *M.Metadata, manager *Manager) net.PacketConn {
id, _ := uuid.NewRandom()
ut := &udpTracker{
@@ -100,6 +120,11 @@ func NewUDPTracker(conn net.PacketConn, metadata *M.Metadata, manager *Manager)
return ut
}
// DefaultUDPTracker returns a new net.PacketConn(*udpTacker) with default manager.
func DefaultUDPTracker(conn net.PacketConn, metadata *M.Metadata) net.PacketConn {
return NewUDPTracker(conn, metadata, DefaultManager)
}
func (ut *udpTracker) ID() string {
return ut.UUID.String()
}
+30 -39
View File
@@ -15,70 +15,61 @@ import (
)
const (
tcpWaitTimeout = 5 * time.Second
// tcpWaitTimeout implements a TCP half-close timeout.
tcpWaitTimeout = 60 * time.Second
)
func newTCPTracker(conn net.Conn, metadata *M.Metadata) net.Conn {
return statistic.NewTCPTracker(conn, metadata, statistic.DefaultManager)
}
func handleTCPConn(originConn adapter.TCPConn) {
defer originConn.Close()
func handleTCPConn(localConn adapter.TCPConn) {
defer localConn.Close()
id := localConn.ID()
id := originConn.ID()
metadata := &M.Metadata{
Network: M.TCP,
SrcIP: net.IP(id.RemoteAddress),
SrcIP: net.IP(id.RemoteAddress.AsSlice()),
SrcPort: id.RemotePort,
DstIP: net.IP(id.LocalAddress),
DstIP: net.IP(id.LocalAddress.AsSlice()),
DstPort: id.LocalPort,
}
targetConn, err := proxy.Dial(metadata)
remoteConn, err := proxy.Dial(metadata)
if err != nil {
log.Warnf("[TCP] dial %s: %v", metadata.DestinationAddress(), err)
return
}
metadata.MidIP, metadata.MidPort = parseAddr(targetConn.LocalAddr())
metadata.MidIP, metadata.MidPort = parseAddr(remoteConn.LocalAddr())
targetConn = newTCPTracker(targetConn, metadata)
defer targetConn.Close()
remoteConn = statistic.DefaultTCPTracker(remoteConn, metadata)
defer remoteConn.Close()
log.Infof("[TCP] %s <-> %s", metadata.SourceAddress(), metadata.DestinationAddress())
relay(localConn, targetConn) /* relay connections */
pipe(originConn, remoteConn)
}
// relay copies between left and right bidirectionally.
func relay(left, right net.Conn) {
// pipe copies copy data to & from provided net.Conn(s) bidirectionally.
func pipe(origin, remote net.Conn) {
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
if err := copyBuffer(right, left); err != nil {
log.Warnf("[TCP] %v", err)
}
right.SetReadDeadline(time.Now().Add(tcpWaitTimeout))
}()
go func() {
defer wg.Done()
if err := copyBuffer(left, right); err != nil {
log.Warnf("[TCP] %v", err)
}
left.SetReadDeadline(time.Now().Add(tcpWaitTimeout))
}()
go unidirectionalStream(remote, origin, "origin->remote", &wg)
go unidirectionalStream(origin, remote, "remote->origin", &wg)
wg.Wait()
}
func copyBuffer(dst io.Writer, src io.Reader) error {
func unidirectionalStream(dst, src net.Conn, dir string, wg *sync.WaitGroup) {
defer wg.Done()
buf := pool.Get(pool.RelayBufferSize)
defer pool.Put(buf)
_, err := io.CopyBuffer(dst, src, buf)
if ne, ok := err.(net.Error); ok && ne.Timeout() {
return nil /* ignore I/O timeout */
if _, err := io.CopyBuffer(dst, src, buf); err != nil {
log.Debugf("[TCP] copy data for %s: %v", dir, err)
}
return err
pool.Put(buf)
// Do the upload/download side TCP half-close.
if cr, ok := src.(interface{ CloseRead() error }); ok {
cr.CloseRead()
}
if cw, ok := dst.(interface{ CloseWrite() error }); ok {
cw.CloseWrite()
}
// Set TCP half-close timeout.
dst.SetReadDeadline(time.Now().Add(tcpWaitTimeout))
}
+18 -23
View File
@@ -1,6 +1,7 @@
package tunnel
import (
"io"
"net"
"sync"
"time"
@@ -20,10 +21,6 @@ func SetUDPTimeout(t time.Duration) {
_udpSessionTimeout = t
}
func newUDPTracker(conn net.PacketConn, metadata *M.Metadata) net.PacketConn {
return statistic.NewUDPTracker(conn, metadata, statistic.DefaultManager)
}
// TODO: Port Restricted NAT support.
func handleUDPConn(uc adapter.UDPConn) {
defer uc.Close()
@@ -31,9 +28,9 @@ func handleUDPConn(uc adapter.UDPConn) {
id := uc.ID()
metadata := &M.Metadata{
Network: M.UDP,
SrcIP: net.IP(id.RemoteAddress),
SrcIP: net.IP(id.RemoteAddress.AsSlice()),
SrcPort: id.RemotePort,
DstIP: net.IP(id.LocalAddress),
DstIP: net.IP(id.LocalAddress.AsSlice()),
DstPort: id.LocalPort,
}
@@ -44,7 +41,7 @@ func handleUDPConn(uc adapter.UDPConn) {
}
metadata.MidIP, metadata.MidPort = parseAddr(pc.LocalAddr())
pc = newUDPTracker(pc, metadata)
pc = statistic.DefaultUDPTracker(pc, metadata)
defer pc.Close()
var remote net.Addr
@@ -56,31 +53,27 @@ func handleUDPConn(uc adapter.UDPConn) {
pc = newSymmetricNATPacketConn(pc, metadata)
log.Infof("[UDP] %s <-> %s", metadata.SourceAddress(), metadata.DestinationAddress())
relayPacket(uc, pc, remote)
pipePacket(uc, pc, remote)
}
func relayPacket(left net.PacketConn, right net.PacketConn, to net.Addr) {
func pipePacket(origin, remote net.PacketConn, to net.Addr) {
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
if err := copyPacketBuffer(right, left, to, _udpSessionTimeout); err != nil {
log.Warnf("[UDP] %v", err)
}
}()
go func() {
defer wg.Done()
if err := copyPacketBuffer(left, right, nil, _udpSessionTimeout); err != nil {
log.Warnf("[UDP] %v", err)
}
}()
go unidirectionalPacketStream(remote, origin, to, "origin->remote", &wg)
go unidirectionalPacketStream(origin, remote, nil, "remote->origin", &wg)
wg.Wait()
}
func copyPacketBuffer(dst net.PacketConn, src net.PacketConn, to net.Addr, timeout time.Duration) error {
func unidirectionalPacketStream(dst, src net.PacketConn, to net.Addr, dir string, wg *sync.WaitGroup) {
defer wg.Done()
if err := copyPacketData(dst, src, to, _udpSessionTimeout); err != nil {
log.Debugf("[UDP] copy data for %s: %v", dir, err)
}
}
func copyPacketData(dst, src net.PacketConn, to net.Addr, timeout time.Duration) error {
buf := pool.Get(pool.MaxSegmentSize)
defer pool.Put(buf)
@@ -89,6 +82,8 @@ func copyPacketBuffer(dst net.PacketConn, src net.PacketConn, to net.Addr, timeo
n, _, err := src.ReadFrom(buf)
if ne, ok := err.(net.Error); ok && ne.Timeout() {
return nil /* ignore I/O timeout */
} else if err == io.EOF {
return nil /* ignore EOF */
} else if err != nil {
return err
}