mirror of
https://github.com/xjasonlyu/tun2socks.git
synced 2024-12-30 02:37:01 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
@@ -1,4 +1,4 @@
|
||||
blank_issues_enabled: true
|
||||
blank_issues_enabled: false
|
||||
|
||||
contact_links:
|
||||
- name: tun2socks GitHub Wiki
|
||||
|
||||
@@ -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@v3
|
||||
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
|
||||
|
||||
+1
-1
@@ -13,4 +13,4 @@ linters-settings:
|
||||
- prefix(github.com/xjasonlyu/tun2socks)
|
||||
- default
|
||||
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)
|
||||
|
||||
|
||||
+2
-2
@@ -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) | 简体中文
|
||||
|
||||
|
||||
+4
-3
@@ -7,9 +7,10 @@ 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
|
||||
)
|
||||
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
@@ -2,10 +2,11 @@ package obfs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
mRand "math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
@@ -65,7 +66,7 @@ func (ho *HTTPObfs) Write(b []byte) (int, error) {
|
||||
randBytes := make([]byte, 16)
|
||||
rand.Read(randBytes)
|
||||
req, _ := http.NewRequest("GET", fmt.Sprintf("http://%s/", ho.host), bytes.NewBuffer(b[:]))
|
||||
req.Header.Set("User-Agent", fmt.Sprintf("curl/7.%d.%d", rand.Int()%54, rand.Int()%2))
|
||||
req.Header.Set("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
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -6,10 +6,10 @@ 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"
|
||||
)
|
||||
|
||||
type FD struct {
|
||||
|
||||
@@ -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/bufferv2"
|
||||
"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: bufferv2.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 := bufferv2.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,4 +1,4 @@
|
||||
//go:build linux
|
||||
//go:build (linux && amd64) || (linux && arm64)
|
||||
|
||||
package tun
|
||||
|
||||
@@ -6,13 +6,13 @@ 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 {
|
||||
|
||||
@@ -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,7 +34,14 @@ 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 {
|
||||
@@ -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 {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build !linux && !windows
|
||||
//go:build unix
|
||||
|
||||
package tun
|
||||
|
||||
|
||||
+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 (
|
||||
|
||||
+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),
|
||||
|
||||
+6
-5
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
+31
-9
@@ -2,11 +2,16 @@ package engine
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/docker/go-units"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
|
||||
"github.com/xjasonlyu/tun2socks/v2/component/dialer"
|
||||
"github.com/xjasonlyu/tun2socks/v2/core"
|
||||
"github.com/xjasonlyu/tun2socks/v2/core/device"
|
||||
@@ -16,10 +21,6 @@ import (
|
||||
"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,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.0
|
||||
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.10.0
|
||||
go.uber.org/automaxprocs v1.5.2
|
||||
golang.org/x/sys v0.7.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-20230401011607-0333bf067633
|
||||
)
|
||||
|
||||
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.7.0 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||
)
|
||||
|
||||
@@ -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.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/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.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
||||
go.uber.org/atomic v1.10.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.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||
golang.org/x/sys v0.7.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-20230401011607-0333bf067633 h1:trSjCkJT04PkOY8WayMOlk9MV6SK2LqvMBRnoi9jy5E=
|
||||
gvisor.dev/gvisor v0.0.0-20230401011607-0333bf067633/go.mod h1:pzr6sy8gDLfVmDAg8OYrlKvGEHw5C3PGTiBXBTCx76Q=
|
||||
|
||||
@@ -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...)
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -6,13 +6,13 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/Dreamacro/go-shadowsocks2/core"
|
||||
|
||||
"github.com/xjasonlyu/tun2socks/v2/component/dialer"
|
||||
obfs "github.com/xjasonlyu/tun2socks/v2/component/simple-obfs"
|
||||
M "github.com/xjasonlyu/tun2socks/v2/metadata"
|
||||
"github.com/xjasonlyu/tun2socks/v2/proxy/proto"
|
||||
"github.com/xjasonlyu/tun2socks/v2/transport/socks5"
|
||||
|
||||
"github.com/Dreamacro/go-shadowsocks2/core"
|
||||
)
|
||||
|
||||
var _ Proxy = (*Shadowsocks)(nil)
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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
-4
@@ -10,14 +10,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 (
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
+28
-37
@@ -15,17 +15,14 @@ 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),
|
||||
@@ -34,51 +31,45 @@ func handleTCPConn(localConn adapter.TCPConn) {
|
||||
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))
|
||||
}
|
||||
|
||||
+16
-21
@@ -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()
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user