mirror of
https://github.com/xjasonlyu/tun2socks.git
synced 2024-12-30 02:37:01 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ab86fd9b0 | ||
|
|
4868427efb | ||
|
|
673a942fb3 | ||
|
|
44ad654d72 | ||
|
|
46c04db29f | ||
|
|
07a6a9f096 | ||
|
|
cd6b118e63 | ||
|
|
9838f57e0d | ||
|
|
9dfea44f48 | ||
|
|
860cf31256 | ||
|
|
8e20770bec | ||
|
|
3320ba46e4 | ||
|
|
38bfbb2c3f | ||
|
|
6c07927bba | ||
|
|
2813b4c581 | ||
|
|
db7c3fd7d2 | ||
|
|
4fc5c03e35 | ||
|
|
3cbbf3068a | ||
|
|
8da083b28e | ||
|
|
dc6eb815da | ||
|
|
3b54548914 | ||
|
|
d061f1c040 | ||
|
|
8e8ccdab89 | ||
|
|
9cbc99e8f5 | ||
|
|
2dbd2caaa9 | ||
|
|
2d0bd1d219 | ||
|
|
61a9d26815 | ||
|
|
4cc02c822c | ||
|
|
20499c6432 | ||
|
|
ad522ebb35 | ||
|
|
06d8bee2af | ||
|
|
b809f89411 | ||
|
|
b8ff1859c1 | ||
|
|
89c37dc156 | ||
|
|
1b8e063485 | ||
|
|
195290884c | ||
|
|
3b343600e7 | ||
|
|
2c51a65685 | ||
|
|
fb9ca95909 | ||
|
|
1e99f2d580 | ||
|
|
ce15b1b2c2 | ||
|
|
c036db2e23 | ||
|
|
007c97fe67 | ||
|
|
7327f2c784 | ||
|
|
66860d3de8 | ||
|
|
c61d7b5a20 | ||
|
|
680feede3b | ||
|
|
22b15f6fab | ||
|
|
f7b4f75ed4 | ||
|
|
29feac8cd4 | ||
|
|
6cfc25309e | ||
|
|
1f63b239c3 | ||
|
|
041bc510ea | ||
|
|
51d8a27289 | ||
|
|
5ffb0186bf | ||
|
|
8a2e5cebeb | ||
|
|
846d3d87a7 | ||
|
|
b491e17bfa | ||
|
|
fbe4c22347 | ||
|
|
4a8bf64cb1 | ||
|
|
059f661862 | ||
|
|
ab05092671 | ||
|
|
6809e7f835 | ||
|
|
bbdc9113d7 | ||
|
|
30608f4925 | ||
|
|
39b1406ffa | ||
|
|
a1edb1c1bb | ||
|
|
ad014648ef | ||
|
|
fa3317a94c | ||
|
|
8d3c28a516 | ||
|
|
35f6888c30 | ||
|
|
3cbc74b1cf | ||
|
|
24a53467f6 | ||
|
|
702ba81ccd | ||
|
|
7fce6e9544 | ||
|
|
553c2f7a17 | ||
|
|
ccfb3a47f6 | ||
|
|
0177157c69 | ||
|
|
82546cd2c5 | ||
|
|
9895b3e048 | ||
|
|
39b50f2bfb | ||
|
|
c45470650b | ||
|
|
cb6408a17a | ||
|
|
77bd119d34 | ||
|
|
595896dfc7 | ||
|
|
55a8d038d6 | ||
|
|
e31ffce0e6 | ||
|
|
267cc6d1a9 | ||
|
|
31468620e7 | ||
|
|
1536735456 | ||
|
|
b329f23a4e | ||
|
|
1ecd587857 | ||
|
|
6076fd9a69 | ||
|
|
3926f86613 | ||
|
|
77e8ad4810 | ||
|
|
a8e8a2dc4c | ||
|
|
f2cfa15945 | ||
|
|
764657d657 | ||
|
|
d65d3b08d0 | ||
|
|
c35f28b3a3 | ||
|
|
23a6e28768 | ||
|
|
102b46e9f6 | ||
|
|
ab728bd8cc | ||
|
|
4aea88c36e | ||
|
|
e4801c3989 | ||
|
|
fd8223e4d0 |
@@ -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,4 +1,4 @@
|
||||
blank_issues_enabled: true
|
||||
blank_issues_enabled: false
|
||||
|
||||
contact_links:
|
||||
- name: tun2socks GitHub Wiki
|
||||
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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') }}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fxjasonlyu%2Ftun2socks?ref=badge_large)
|
||||
|
||||
## Stargazers over time
|
||||
## Star History
|
||||
|
||||
[](https://starchart.cc/xjasonlyu/tun2socks)
|
||||
[](https://star-history.com/#xjasonlyu/tun2socks&Date)
|
||||
|
||||
+4
-4
@@ -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 @@
|
||||
|
||||
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fxjasonlyu%2Ftun2socks?ref=badge_large)
|
||||
|
||||
## 星星走向
|
||||
## 星星历史
|
||||
|
||||
[](https://starchart.cc/xjasonlyu/tun2socks)
|
||||
[](https://star-history.com/#xjasonlyu/tun2socks&Date)
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package observable
|
||||
|
||||
// Ref: github.com/Dreamacro/clash/common/observable
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
+4
-5
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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{}
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
package fdbased
|
||||
|
||||
const Driver = "fd"
|
||||
|
||||
const defaultMTU = 1500
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,4 +1,4 @@
|
||||
//go:build !linux && !windows
|
||||
//go:build !(linux && amd64) && !(linux && arm64) && !windows
|
||||
|
||||
package fdbased
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
@@ -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 (
|
||||
|
||||
@@ -54,11 +54,11 @@ const (
|
||||
|
||||
// tcpDefaultBufferSize is the default size of the send buffer for
|
||||
// a transport endpoint.
|
||||
tcpDefaultSendBufferSize = stack.DefaultBufferSize
|
||||
tcpDefaultSendBufferSize = tcp.DefaultSendBufferSize
|
||||
|
||||
// tcpDefaultReceiveBufferSize is the default size of the receive buffer
|
||||
// for a transport endpoint.
|
||||
tcpDefaultReceiveBufferSize = stack.DefaultBufferSize
|
||||
tcpDefaultReceiveBufferSize = tcp.DefaultReceiveBufferSize
|
||||
)
|
||||
|
||||
type Option func(*stack.Stack) error
|
||||
|
||||
+2
-2
@@ -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
@@ -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),
|
||||
|
||||
+9
-6
@@ -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,18 +41,20 @@ 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 (
|
||||
wq waiter.Queue
|
||||
ep tcpip.Endpoint
|
||||
err tcpip.Error
|
||||
id = r.ID()
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
printf("tcp forwarder request: %s", err)
|
||||
glog.Debugf("forward tcp request: %s:%d->%s:%d: %s",
|
||||
id.RemoteAddress, id.RemotePort, id.LocalAddress, id.LocalPort, err)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -68,7 +71,7 @@ func withTCPHandler(handle func(adapter.TCPConn), printf func(string, ...any)) o
|
||||
|
||||
conn := &tcpConn{
|
||||
TCPConn: gonet.NewTCPConn(&wq, ep),
|
||||
id: r.ID(),
|
||||
id: id,
|
||||
}
|
||||
handle(conn)
|
||||
})
|
||||
|
||||
+12
-7
@@ -1,28 +1,33 @@
|
||||
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 wq waiter.Queue
|
||||
var (
|
||||
wq waiter.Queue
|
||||
id = r.ID()
|
||||
)
|
||||
ep, err := r.CreateEndpoint(&wq)
|
||||
if err != nil {
|
||||
printf("udp forwarder request: %s", err)
|
||||
glog.Debugf("forward udp request: %s:%d->%s:%d: %s",
|
||||
id.RemoteAddress, id.RemotePort, id.LocalAddress, id.LocalPort, err)
|
||||
return
|
||||
}
|
||||
|
||||
conn := &udpConn{
|
||||
UDPConn: gonet.NewUDPConn(s, &wq, ep),
|
||||
id: r.ID(),
|
||||
id: id,
|
||||
}
|
||||
handle(conn)
|
||||
})
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -3,7 +3,7 @@ package dns
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/xjasonlyu/tun2socks/v2/component/dialer"
|
||||
"github.com/xjasonlyu/tun2socks/v2/dialer"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -77,7 +77,7 @@ run() {
|
||||
ARGS="$ARGS --tcp-rcvbuf $TCP_RCVBUF"
|
||||
fi
|
||||
|
||||
if [ "$TCP_AUTO_TUNING" -eq 1 ]; then
|
||||
if [ "$TCP_AUTO_TUNING" = 1 ]; then
|
||||
ARGS="$ARGS --tcp-auto-tuning"
|
||||
fi
|
||||
|
||||
|
||||
+32
-10
@@ -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
|
||||
}
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -1,31 +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/stretchr/testify v1.7.0
|
||||
go.uber.org/atomic v1.9.0
|
||||
go.uber.org/automaxprocs v1.4.0
|
||||
golang.org/x/sys v0.0.0-20220403205710-6acee93ad0eb
|
||||
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-20220401222657-54142f50892f
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/stretchr/testify v1.7.1
|
||||
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
|
||||
)
|
||||
|
||||
@@ -1,66 +1,58 @@
|
||||
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=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
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/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
||||
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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/automaxprocs v1.4.0 h1:CpDZl6aOlLhReez+8S3eEotD7Jx0Os++lemPlMULQP0=
|
||||
go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q=
|
||||
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-20220403205710-6acee93ad0eb h1:PVGECzEo9Y3uOidtkHGdd347NjLtITfJFO9BxFpmRoo=
|
||||
golang.org/x/sys v0.0.0-20220403205710-6acee93ad0eb/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=
|
||||
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.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/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
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-20220401222657-54142f50892f h1:nrRW7+UI7oDyWsuJSZTKMWTisiYUqSG9LU0eageG77c=
|
||||
gvisor.dev/gvisor v0.0.0-20220401222657-54142f50892f/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=
|
||||
|
||||
@@ -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...)
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
@@ -7,15 +7,19 @@ 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
|
||||
|
||||
func init() {
|
||||
registerMountPoint("/connections", connectionRouter())
|
||||
}
|
||||
|
||||
func connectionRouter() http.Handler {
|
||||
r := chi.NewRouter()
|
||||
r.Get("/", getConnections)
|
||||
|
||||
+40
-28
@@ -2,9 +2,9 @@ package restapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/render"
|
||||
@@ -12,26 +12,36 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
)
|
||||
|
||||
var _statsFunc func() tcpip.Stats
|
||||
var _stackStatsFunc func() tcpip.Stats
|
||||
|
||||
func SetStatsFunc(s func() tcpip.Stats) {
|
||||
_statsFunc = s
|
||||
_stackStatsFunc = s
|
||||
}
|
||||
|
||||
func init() {
|
||||
registerMountPoint("/netstats", http.HandlerFunc(getNetStats))
|
||||
}
|
||||
|
||||
func getNetStats(w http.ResponseWriter, r *http.Request) {
|
||||
if _statsFunc == nil {
|
||||
if _stackStatsFunc == nil {
|
||||
render.Status(r, http.StatusInternalServerError)
|
||||
render.JSON(w, r, ErrUninitialized)
|
||||
return
|
||||
}
|
||||
|
||||
snapshot := func() any {
|
||||
s := _statsFunc()
|
||||
return dump(reflect.ValueOf(&s).Elem())
|
||||
b := &bytes.Buffer{}
|
||||
snapshot := func() []byte {
|
||||
s := _stackStatsFunc()
|
||||
b.Reset() /* reset buffer */
|
||||
encodeToJSON(reflect.ValueOf(&s).Elem(), b)
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
if !websocket.IsWebSocketUpgrade(r) {
|
||||
render.JSON(w, r, snapshot())
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
render.Status(r, http.StatusOK)
|
||||
w.Write(snapshot())
|
||||
w.(http.Flusher).Flush()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -43,42 +53,44 @@ func getNetStats(w http.ResponseWriter, r *http.Request) {
|
||||
tick := time.NewTicker(time.Second)
|
||||
defer tick.Stop()
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
for range tick.C {
|
||||
buf.Reset()
|
||||
|
||||
if err = json.NewEncoder(buf).Encode(snapshot()); err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
if err = conn.WriteMessage(websocket.TextMessage, buf.Bytes()); err != nil {
|
||||
if err = conn.WriteMessage(websocket.TextMessage, snapshot()); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func dump(value reflect.Value) map[string]any {
|
||||
numField := value.NumField()
|
||||
structure := make(map[string]any, numField)
|
||||
func encodeToJSON(value reflect.Value, b *bytes.Buffer) {
|
||||
b.WriteByte('{')
|
||||
defer b.WriteByte('}')
|
||||
|
||||
for i := 0; i < numField; i++ {
|
||||
for i, numField := 0, value.NumField(); i < numField; i++ {
|
||||
field := value.Type().Field(i)
|
||||
value := value.Field(i)
|
||||
|
||||
b.WriteString("\"" + field.Name + "\":")
|
||||
|
||||
switch v := value.Addr().Interface().(type) {
|
||||
case **tcpip.StatCounter:
|
||||
structure[field.Name] = (*v).Value()
|
||||
b.WriteString(strconv.FormatUint((*v).Value(), 10))
|
||||
case **tcpip.IntegralStatCounterMap:
|
||||
counterMap := make(map[uint64]uint64)
|
||||
for _, k := range (*v).Keys() {
|
||||
if counter, ok := (*v).Get(k); ok {
|
||||
counterMap[k] = counter.Value()
|
||||
b.WriteByte('{')
|
||||
for j, keys := 0, (*v).Keys(); j < len(keys); j++ {
|
||||
if counter, ok := (*v).Get(keys[j]); ok {
|
||||
k := strconv.FormatUint(keys[j], 10)
|
||||
v := strconv.FormatUint(counter.Value(), 10)
|
||||
b.WriteString("\"" + k + "\":" + v)
|
||||
if j < len(keys)-1 {
|
||||
b.WriteByte(',')
|
||||
}
|
||||
}
|
||||
}
|
||||
structure[field.Name] = counterMap
|
||||
b.WriteByte('}')
|
||||
default:
|
||||
structure[field.Name] = dump(value)
|
||||
encodeToJSON(value, b)
|
||||
}
|
||||
if i < numField-1 {
|
||||
b.WriteByte(',')
|
||||
}
|
||||
}
|
||||
return structure
|
||||
}
|
||||
|
||||
+20
-12
@@ -1,7 +1,5 @@
|
||||
package restapi
|
||||
|
||||
// Ref: github.com/Dreamacro/clash/hub/route
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
@@ -10,20 +8,28 @@ 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 _upgrader = websocket.Upgrader{
|
||||
CheckOrigin: func(r *http.Request) bool {
|
||||
return true
|
||||
},
|
||||
var (
|
||||
_upgrader = websocket.Upgrader{
|
||||
CheckOrigin: func(r *http.Request) bool {
|
||||
return true
|
||||
},
|
||||
}
|
||||
|
||||
_mountPoints = make(map[string]http.Handler)
|
||||
)
|
||||
|
||||
func registerMountPoint(pattern string, handler http.Handler) {
|
||||
_mountPoints[pattern] = handler
|
||||
}
|
||||
|
||||
func Start(addr, token string) error {
|
||||
@@ -43,8 +49,10 @@ func Start(addr, token string) error {
|
||||
r.Get("/logs", getLogs)
|
||||
r.Get("/traffic", traffic)
|
||||
r.Get("/version", version)
|
||||
r.Get("/netstats", getNetStats)
|
||||
r.Mount("/connections", connectionRouter())
|
||||
// attach HTTP handlers
|
||||
for pattern, handler := range _mountPoints {
|
||||
r.Mount(pattern, handler)
|
||||
}
|
||||
})
|
||||
|
||||
listener, err := net.Listen("tcp", addr)
|
||||
|
||||
@@ -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,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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
+31
-33
@@ -15,63 +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()
|
||||
_ = copyBuffer(right, left) /* ignore error */
|
||||
right.SetReadDeadline(time.Now().Add(tcpWaitTimeout))
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
_ = copyBuffer(left, right) /* ignore error */
|
||||
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)
|
||||
return err
|
||||
if _, err := io.CopyBuffer(dst, src, buf); err != nil {
|
||||
log.Debugf("[TCP] copy data for %s: %v", dir, 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))
|
||||
}
|
||||
|
||||
+57
-41
@@ -1,9 +1,9 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/xjasonlyu/tun2socks/v2/common/pool"
|
||||
@@ -21,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()
|
||||
@@ -32,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,
|
||||
}
|
||||
|
||||
@@ -45,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
|
||||
@@ -54,54 +50,74 @@ func handleUDPConn(uc adapter.UDPConn) {
|
||||
} else {
|
||||
remote = metadata.Addr()
|
||||
}
|
||||
pc = newSymmetricNATPacketConn(pc, metadata)
|
||||
|
||||
go handleUDPToRemote(uc, pc, remote)
|
||||
handleUDPToLocal(uc, pc, remote)
|
||||
log.Infof("[UDP] %s <-> %s", metadata.SourceAddress(), metadata.DestinationAddress())
|
||||
pipePacket(uc, pc, remote)
|
||||
}
|
||||
|
||||
func handleUDPToRemote(uc adapter.UDPConn, pc net.PacketConn, remote net.Addr) {
|
||||
func pipePacket(origin, remote net.PacketConn, to net.Addr) {
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(2)
|
||||
|
||||
go unidirectionalPacketStream(remote, origin, to, "origin->remote", &wg)
|
||||
go unidirectionalPacketStream(origin, remote, nil, "remote->origin", &wg)
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
for {
|
||||
n, err := uc.Read(buf)
|
||||
if err != nil {
|
||||
return
|
||||
src.SetReadDeadline(time.Now().Add(timeout))
|
||||
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
|
||||
}
|
||||
|
||||
if _, err := pc.WriteTo(buf[:n], remote); err != nil {
|
||||
log.Warnf("[UDP] write to %s: %v", remote, err)
|
||||
if _, err = dst.WriteTo(buf[:n], to); err != nil {
|
||||
return err
|
||||
}
|
||||
pc.SetReadDeadline(time.Now().Add(_udpSessionTimeout)) /* reset timeout */
|
||||
|
||||
log.Infof("[UDP] %s --> %s", uc.RemoteAddr(), remote)
|
||||
dst.SetReadDeadline(time.Now().Add(timeout))
|
||||
}
|
||||
}
|
||||
|
||||
func handleUDPToLocal(uc adapter.UDPConn, pc net.PacketConn, remote net.Addr) {
|
||||
buf := pool.Get(pool.MaxSegmentSize)
|
||||
defer pool.Put(buf)
|
||||
type symmetricNATPacketConn struct {
|
||||
net.PacketConn
|
||||
src string
|
||||
dst string
|
||||
}
|
||||
|
||||
func newSymmetricNATPacketConn(pc net.PacketConn, metadata *M.Metadata) *symmetricNATPacketConn {
|
||||
return &symmetricNATPacketConn{
|
||||
PacketConn: pc,
|
||||
src: metadata.SourceAddress(),
|
||||
dst: metadata.DestinationAddress(),
|
||||
}
|
||||
}
|
||||
|
||||
func (pc *symmetricNATPacketConn) ReadFrom(p []byte) (int, net.Addr, error) {
|
||||
for {
|
||||
pc.SetReadDeadline(time.Now().Add(_udpSessionTimeout))
|
||||
n, from, err := pc.ReadFrom(buf)
|
||||
if err != nil {
|
||||
if !errors.Is(err, os.ErrDeadlineExceeded) /* ignore I/O timeout */ {
|
||||
log.Warnf("[UDP] read from %s: %v", pc.LocalAddr(), err)
|
||||
}
|
||||
return
|
||||
n, from, err := pc.PacketConn.ReadFrom(p)
|
||||
|
||||
if from != nil && from.String() != pc.dst {
|
||||
log.Warnf("[UDP] symmetric NAT %s->%s: drop packet from %s", pc.src, pc.dst, from)
|
||||
continue
|
||||
}
|
||||
|
||||
if from == nil || from.Network() != remote.Network() || from.String() != remote.String() {
|
||||
log.Warnf("[UDP] drop unknown packet from %v", from)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := uc.Write(buf[:n]); err != nil {
|
||||
log.Warnf("[UDP] write back from %s: %v", from, err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Infof("[UDP] %s <-- %s", uc.RemoteAddr(), from)
|
||||
return n, from, err
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user