Compare commits
No commits in common. "master" and "v2.11.0" have entirely different histories.
72
.github/workflows/buildx.yml
vendored
72
.github/workflows/buildx.yml
vendored
@ -1,72 +0,0 @@
|
||||
# ref: https://docs.docker.com/ci-cd/github-actions/
|
||||
# https://blog.oddbit.com/post/2020-09-25-building-multi-architecture-im/
|
||||
|
||||
name: docker
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Prepare
|
||||
id: prepare
|
||||
run: |
|
||||
DOCKER_IMAGE=${{ secrets.DOCKER_IMAGE }}
|
||||
VERSION=latest
|
||||
|
||||
# If this is git tag, use the tag name as a docker tag
|
||||
if [[ $GITHUB_REF == refs/tags/* ]]; then
|
||||
VERSION=${GITHUB_REF#refs/tags/v}
|
||||
fi
|
||||
TAGS="${DOCKER_IMAGE}:${VERSION}"
|
||||
|
||||
# If the VERSION looks like a version number, assume that
|
||||
# this is the most recent version of the image and also
|
||||
# tag it 'latest'.
|
||||
if [[ $VERSION =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
|
||||
MAJOR_VERSION=`echo $VERSION | awk '{split($0,a,"."); print a[1]}'`
|
||||
MINOR_VERSION=`echo $VERSION | awk '{split($0,a,"."); print a[2]}'`
|
||||
TAGS="$TAGS,${DOCKER_IMAGE}:${MAJOR_VERSION},${DOCKER_IMAGE}:${MAJOR_VERSION}.${MINOR_VERSION},${DOCKER_IMAGE}:latest"
|
||||
fi
|
||||
|
||||
# Set output parameters.
|
||||
echo "tags=${TAGS}" >> $GITHUB_OUTPUT
|
||||
echo "docker_image=${DOCKER_IMAGE}" >> $GITHUB_OUTPUT
|
||||
echo "docker_platforms=linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/s390x,linux/riscv64" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Environment
|
||||
run: |
|
||||
echo home=$HOME
|
||||
echo git_ref=$GITHUB_REF
|
||||
echo git_sha=$GITHUB_SHA
|
||||
echo image=${{ steps.prepare.outputs.docker_image }}
|
||||
echo tags=${{ steps.prepare.outputs.tags }}
|
||||
echo platforms=${{ steps.prepare.outputs.docker_platforms }}
|
||||
echo avail_platforms=${{ steps.buildx.outputs.platforms }}
|
||||
|
||||
- name: Login to DockerHub
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Buildx and push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
platforms: ${{ steps.prepare.outputs.docker_platforms }}
|
||||
push: true
|
||||
tags: ${{ steps.prepare.outputs.tags }}
|
38
.github/workflows/release.yml
vendored
38
.github/workflows/release.yml
vendored
@ -1,38 +0,0 @@
|
||||
name: goreleaser
|
||||
|
||||
on:
|
||||
push:
|
||||
# run only against tags
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
# packages: write
|
||||
# issues: write
|
||||
|
||||
jobs:
|
||||
goreleaser:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- run: git fetch --force --tags
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
# More assembly might be required: Docker logins, GPG, etc. It all depends
|
||||
# on your needs.
|
||||
- uses: goreleaser/goreleaser-action@v4
|
||||
with:
|
||||
# either 'goreleaser' (default) or 'goreleaser-pro':
|
||||
distribution: goreleaser
|
||||
version: latest
|
||||
args: release --clean
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Your GoReleaser Pro key, if you are using the 'goreleaser-pro'
|
||||
# distribution:
|
||||
# GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -9,7 +9,6 @@ _test
|
||||
release
|
||||
debian
|
||||
bin
|
||||
dist/
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
@ -31,5 +30,5 @@ _testmain.go
|
||||
|
||||
*.bak
|
||||
|
||||
.vscode/
|
||||
cmd/gost/gost
|
||||
snap
|
||||
|
@ -1,58 +0,0 @@
|
||||
# This is an example .goreleaser.yml file with some sensible defaults.
|
||||
# Make sure to check the documentation at https://goreleaser.com
|
||||
before:
|
||||
hooks:
|
||||
# You may remove this if you don't use go modules.
|
||||
- go mod tidy
|
||||
# you may remove this if you don't need go generate
|
||||
# - go generate ./...
|
||||
builds:
|
||||
- env:
|
||||
- CGO_ENABLED=0
|
||||
main: ./cmd/gost
|
||||
targets:
|
||||
- darwin_amd64
|
||||
- darwin_arm64
|
||||
- linux_386
|
||||
- linux_amd64
|
||||
- linux_amd64_v3
|
||||
- linux_arm_5
|
||||
- linux_arm_6
|
||||
- linux_arm_7
|
||||
- linux_arm64
|
||||
- linux_mips_softfloat
|
||||
- linux_mips_hardfloat
|
||||
- linux_mipsle_softfloat
|
||||
- linux_mipsle_hardfloat
|
||||
- linux_mips64
|
||||
- linux_mips64le
|
||||
- linux_s390x
|
||||
- linux_riscv64
|
||||
- freebsd_386
|
||||
- freebsd_amd64
|
||||
- windows_386
|
||||
- windows_amd64
|
||||
- windows_amd64_v3
|
||||
- windows_arm64
|
||||
|
||||
archives:
|
||||
- format: tar.gz
|
||||
# use zip for windows archives
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
format: zip
|
||||
checksum:
|
||||
name_template: 'checksums.txt'
|
||||
snapshot:
|
||||
name_template: "{{ incpatch .Version }}-next"
|
||||
changelog:
|
||||
sort: asc
|
||||
filters:
|
||||
exclude:
|
||||
- '^docs:'
|
||||
- '^test:'
|
||||
|
||||
# The lines beneath this are called `modelines`. See `:help modeline`
|
||||
# Feel free to remove those if you don't want/use them.
|
||||
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
|
||||
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
|
31
Dockerfile
31
Dockerfile
@ -1,32 +1,19 @@
|
||||
FROM --platform=$BUILDPLATFORM tonistiigi/xx:1.5.0 AS xx
|
||||
FROM golang:1-alpine as builder
|
||||
|
||||
FROM --platform=$BUILDPLATFORM golang:1.23-alpine3.20 AS builder
|
||||
RUN apk add --no-cache musl-dev git gcc
|
||||
|
||||
COPY --from=xx / /
|
||||
ADD . /src
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
WORKDIR /src
|
||||
|
||||
RUN xx-info env
|
||||
ENV GO111MODULE=on
|
||||
|
||||
ENV CGO_ENABLED=0
|
||||
RUN cd cmd/gost && go build
|
||||
|
||||
ENV XX_VERIFY_STATIC=1
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN cd cmd/gost && \
|
||||
xx-go build && \
|
||||
xx-verify gost
|
||||
|
||||
FROM alpine:3.20
|
||||
|
||||
# add iptables for tun/tap
|
||||
RUN apk add --no-cache iptables
|
||||
FROM alpine:latest
|
||||
|
||||
WORKDIR /bin/
|
||||
|
||||
COPY --from=builder /app/cmd/gost/gost .
|
||||
COPY --from=builder /src/cmd/gost/gost .
|
||||
|
||||
ENTRYPOINT ["/bin/gost"]
|
||||
ENTRYPOINT ["/bin/gost"]
|
||||
|
20
Makefile
20
Makefile
@ -2,11 +2,10 @@ NAME=gost
|
||||
BINDIR=bin
|
||||
VERSION=$(shell cat gost.go | grep 'Version =' | sed 's/.*\"\(.*\)\".*/\1/g')
|
||||
GOBUILD=CGO_ENABLED=0 go build --ldflags="-s -w" -v -x -a
|
||||
GOFILES=cmd/gost/*.go
|
||||
GOFILES=cmd/gost/*
|
||||
|
||||
PLATFORM_LIST = \
|
||||
darwin-amd64 \
|
||||
darwin-arm64 \
|
||||
linux-386 \
|
||||
linux-amd64 \
|
||||
linux-armv5 \
|
||||
@ -19,24 +18,18 @@ PLATFORM_LIST = \
|
||||
linux-mipsle-hardfloat \
|
||||
linux-mips64 \
|
||||
linux-mips64le \
|
||||
linux-s390x \
|
||||
linux-riscv64 \
|
||||
freebsd-386 \
|
||||
freebsd-amd64
|
||||
|
||||
WINDOWS_ARCH_LIST = \
|
||||
windows-386 \
|
||||
windows-amd64 \
|
||||
windows-arm64
|
||||
windows-amd64
|
||||
|
||||
all: linux-amd64 darwin-amd64 windows-amd64 # Most used
|
||||
|
||||
darwin-amd64:
|
||||
GOARCH=amd64 GOOS=darwin $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)
|
||||
|
||||
darwin-arm64:
|
||||
GOARCH=arm64 GOOS=darwin $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)
|
||||
|
||||
linux-386:
|
||||
GOARCH=386 GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)
|
||||
|
||||
@ -73,12 +66,6 @@ linux-mips64:
|
||||
linux-mips64le:
|
||||
GOARCH=mips64le GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)
|
||||
|
||||
linux-s390x:
|
||||
GOARCH=s390x GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)
|
||||
|
||||
linux-riscv64:
|
||||
GOARCH=riscv64 GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)
|
||||
|
||||
freebsd-386:
|
||||
GOARCH=386 GOOS=freebsd $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)
|
||||
|
||||
@ -91,9 +78,6 @@ windows-386:
|
||||
windows-amd64:
|
||||
GOARCH=amd64 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe $(GOFILES)
|
||||
|
||||
windows-arm64:
|
||||
GOARCH=arm64 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe $(GOFILES)
|
||||
|
||||
gz_releases=$(addsuffix .gz, $(PLATFORM_LIST))
|
||||
zip_releases=$(addsuffix .zip, $(WINDOWS_ARCH_LIST))
|
||||
|
||||
|
48
README.md
48
README.md
@ -1,40 +1,39 @@
|
||||
GO Simple Tunnel
|
||||
gost - GO Simple Tunnel
|
||||
======
|
||||
|
||||
### GO语言实现的安全隧道
|
||||
|
||||
[](https://godoc.org/github.com/ginuerzh/gost)
|
||||
[](https://travis-ci.org/ginuerzh/gost)
|
||||
[](https://goreportcard.com/report/github.com/ginuerzh/gost)
|
||||
[](https://codecov.io/gh/ginuerzh/gost/branch/master)
|
||||
[](https://github.com/ginuerzh/gost/releases/latest)
|
||||
[](https://hub.docker.com/r/ginuerzh/gost/)
|
||||
[](https://snapcraft.io/gost)
|
||||
[](https://build.snapcraft.io/user/ginuerzh/gost)
|
||||
[](https://hub.docker.com/r/ginuerzh/gost/)
|
||||
|
||||
[English README](README_en.md)
|
||||
|
||||
### !!!!!
|
||||
|
||||
特性
|
||||
------
|
||||
|
||||
* 多端口监听
|
||||
* 可设置转发代理,支持多级转发(代理链)
|
||||
* 支持标准HTTP/HTTPS/HTTP2/SOCKS4(A)/SOCKS5代理协议
|
||||
* Web代理支持[探测防御](https://v2.gost.run/probe_resist/)
|
||||
* [支持多种隧道类型](https://v2.gost.run/configuration/)
|
||||
* [SOCKS5代理支持TLS协商加密](https://v2.gost.run/socks/)
|
||||
* [Tunnel UDP over TCP](https://v2.gost.run/socks/)
|
||||
* [TCP/UDP透明代理](https://v2.gost.run/redirect/)
|
||||
* [本地/远程TCP/UDP端口转发](https://v2.gost.run/port-forwarding/)
|
||||
* [支持Shadowsocks(TCP/UDP)协议](https://v2.gost.run/ss/)
|
||||
* [支持SNI代理](https://v2.gost.run/sni/)
|
||||
* [权限控制](https://v2.gost.run/permission/)
|
||||
* [负载均衡](https://v2.gost.run/load-balancing/)
|
||||
* [路由控制](https://v2.gost.run/bypass/)
|
||||
* DNS[解析](https://v2.gost.run/resolver/)和[代理](https://v2.gost.run/dns/)
|
||||
* [TUN/TAP设备](https://v2.gost.run/tuntap/)
|
||||
* Web代理支持[探测防御](https://docs.ginuerzh.xyz/gost/probe_resist/)
|
||||
* [支持多种隧道类型](https://docs.ginuerzh.xyz/gost/configuration/)
|
||||
* [SOCKS5代理支持TLS协商加密](https://docs.ginuerzh.xyz/gost/socks/)
|
||||
* [Tunnel UDP over TCP](https://docs.ginuerzh.xyz/gost/socks/)
|
||||
* [TCP/UDP透明代理](https://docs.ginuerzh.xyz/gost/redirect/)
|
||||
* [本地/远程TCP/UDP端口转发](https://docs.ginuerzh.xyz/gost/port-forwarding/)
|
||||
* [支持Shadowsocks(TCP/UDP)协议](https://docs.ginuerzh.xyz/gost/ss/)
|
||||
* [支持SNI代理](https://docs.ginuerzh.xyz/gost/sni/)
|
||||
* [权限控制](https://docs.ginuerzh.xyz/gost/permission/)
|
||||
* [负载均衡](https://docs.ginuerzh.xyz/gost/load-balancing/)
|
||||
* [路由控制](https://docs.ginuerzh.xyz/gost/bypass/)
|
||||
* DNS[解析](https://docs.ginuerzh.xyz/gost/resolver/)和[代理](https://docs.ginuerzh.xyz/gost/dns/)
|
||||
* [TUN/TAP设备](https://docs.ginuerzh.xyz/gost/tuntap/)
|
||||
|
||||
Wiki站点: [v2.gost.run](https://v2.gost.run)
|
||||
Wiki站点: <https://docs.ginuerzh.xyz/gost/>
|
||||
|
||||
Telegram讨论群: <https://t.me/gogost>
|
||||
|
||||
@ -58,18 +57,11 @@ go build
|
||||
#### Docker
|
||||
|
||||
```bash
|
||||
docker run --rm ginuerzh/gost -V
|
||||
```
|
||||
|
||||
#### Homebrew
|
||||
|
||||
```bash
|
||||
brew install gost
|
||||
docker pull ginuerzh/gost
|
||||
```
|
||||
|
||||
#### Ubuntu商店
|
||||
|
||||
|
||||
```bash
|
||||
sudo snap install core
|
||||
sudo snap install gost
|
||||
@ -195,7 +187,7 @@ gost -L=:8080 -F=h2://server_ip:443
|
||||
```
|
||||
|
||||
#### QUIC
|
||||
gost对QUIC的支持是基于[quic-go](https://github.com/quic-go/quic-go)库。
|
||||
gost对QUIC的支持是基于[quic-go](https://github.com/lucas-clemente/quic-go)库。
|
||||
|
||||
服务端:
|
||||
```bash
|
||||
|
45
README_en.md
45
README_en.md
@ -4,32 +4,33 @@ gost - GO Simple Tunnel
|
||||
### A simple security tunnel written in Golang
|
||||
|
||||
[](https://godoc.org/github.com/ginuerzh/gost)
|
||||
[](https://travis-ci.org/ginuerzh/gost)
|
||||
[](https://goreportcard.com/report/github.com/ginuerzh/gost)
|
||||
[](https://codecov.io/gh/ginuerzh/gost/branch/master)
|
||||
[](https://github.com/ginuerzh/gost/releases/latest)
|
||||
[](https://hub.docker.com/r/ginuerzh/gost/)
|
||||
[](https://snapcraft.io/gost)
|
||||
|
||||
[](https://build.snapcraft.io/user/ginuerzh/gost)
|
||||
[](https://hub.docker.com/r/ginuerzh/gost/)
|
||||
|
||||
Features
|
||||
------
|
||||
* Listening on multiple ports
|
||||
* Multi-level forward proxy - proxy chain
|
||||
* Standard HTTP/HTTPS/HTTP2/SOCKS4(A)/SOCKS5 proxy protocols support
|
||||
* [Probing resistance](https://v2.gost.run/en/probe_resist/) support for web proxy
|
||||
* [Support multiple tunnel types](https://v2.gost.run/en/configuration/)
|
||||
* [TLS encryption via negotiation support for SOCKS5 proxy](https://v2.gost.run/en/socks/)
|
||||
* [Tunnel UDP over TCP](https://v2.gost.run/en/socks/)
|
||||
* [TCP/UDP Transparent proxy](https://v2.gost.run/en/redirect/)
|
||||
* [Local/remote TCP/UDP port forwarding](https://v2.gost.run/en/port-forwarding/)
|
||||
* [Shadowsocks protocol](https://v2.gost.run/en/ss/)
|
||||
* [SNI proxy](https://v2.gost.run/en/sni/)
|
||||
* [Permission control](https://v2.gost.run/en/permission/)
|
||||
* [Load balancing](https://v2.gost.run/en/load-balancing/)
|
||||
* [Routing control](https://v2.gost.run/en/bypass/)
|
||||
* DNS [resolver](https://v2.gost.run/resolver/) and [proxy](https://v2.gost.run/dns/)
|
||||
* [TUN/TAP device](https://v2.gost.run/en/tuntap/)
|
||||
* [Probing resistance](https://docs.ginuerzh.xyz/gost/en/probe_resist/) support for web proxy
|
||||
* [Support multiple tunnel types](https://docs.ginuerzh.xyz/gost/en/configuration/)
|
||||
* [TLS encryption via negotiation support for SOCKS5 proxy](https://docs.ginuerzh.xyz/gost/en/socks/)
|
||||
* [Tunnel UDP over TCP](https://docs.ginuerzh.xyz/gost/en/socks/)
|
||||
* [TCP/UDP Transparent proxy](https://docs.ginuerzh.xyz/gost/en/redirect/)
|
||||
* [Local/remote TCP/UDP port forwarding](https://docs.ginuerzh.xyz/gost/en/port-forwarding/)
|
||||
* [Shadowsocks protocol](https://docs.ginuerzh.xyz/gost/en/ss/)
|
||||
* [SNI proxy](https://docs.ginuerzh.xyz/gost/en/sni/)
|
||||
* [Permission control](https://docs.ginuerzh.xyz/gost/en/permission/)
|
||||
* [Load balancing](https://docs.ginuerzh.xyz/gost/en/load-balancing/)
|
||||
* [Routing control](https://docs.ginuerzh.xyz/gost/en/bypass/)
|
||||
* DNS [resolver](https://docs.ginuerzh.xyz/gost/resolver/) and [proxy](https://docs.ginuerzh.xyz/gost/dns/)
|
||||
* [TUN/TAP device](https://docs.ginuerzh.xyz/gost/en/tuntap/)
|
||||
|
||||
Wiki: [v2.gost.run](https://v2.gost.run/en/)
|
||||
Wiki: <https://docs.ginuerzh.xyz/gost/en/>
|
||||
|
||||
Telegram group: <https://t.me/gogost>
|
||||
|
||||
@ -53,13 +54,7 @@ go build
|
||||
#### Docker
|
||||
|
||||
```bash
|
||||
docker run --rm ginuerzh/gost -V
|
||||
```
|
||||
|
||||
#### Homebrew
|
||||
|
||||
```bash
|
||||
brew install gost
|
||||
docker pull ginuerzh/gost
|
||||
```
|
||||
|
||||
#### Ubuntu store
|
||||
@ -218,7 +213,7 @@ gost -L=:8080 -F=h2://server_ip:443
|
||||
|
||||
#### QUIC
|
||||
|
||||
Support for QUIC is based on library [quic-go](https://github.com/quic-go/quic-go).
|
||||
Support for QUIC is based on library [quic-go](https://github.com/lucas-clemente/quic-go).
|
||||
|
||||
Server:
|
||||
|
||||
|
62
chain.go
62
chain.go
@ -3,9 +3,7 @@ package gost
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/go-log/log"
|
||||
@ -20,8 +18,6 @@ var (
|
||||
type Chain struct {
|
||||
isRoute bool
|
||||
Retries int
|
||||
Mark int
|
||||
Interface string
|
||||
nodeGroups []*NodeGroup
|
||||
route []Node // nodes in the selected route
|
||||
}
|
||||
@ -38,14 +34,10 @@ func NewChain(nodes ...Node) *Chain {
|
||||
|
||||
// newRoute creates a chain route.
|
||||
// a chain route is the final route after node selection.
|
||||
func (c *Chain) newRoute(nodes ...Node) *Chain {
|
||||
route := NewChain(nodes...)
|
||||
route.isRoute = true
|
||||
if !c.IsEmpty() {
|
||||
route.Interface = c.Interface
|
||||
route.Mark = c.Mark
|
||||
}
|
||||
return route
|
||||
func newRoute(nodes ...Node) *Chain {
|
||||
chain := NewChain(nodes...)
|
||||
chain.isRoute = true
|
||||
return chain
|
||||
}
|
||||
|
||||
// Nodes returns the proxy nodes that the chain holds.
|
||||
@ -143,9 +135,6 @@ func (c *Chain) dialWithOptions(ctx context.Context, network, address string, op
|
||||
if options == nil {
|
||||
options = &ChainOptions{}
|
||||
}
|
||||
if c == nil {
|
||||
c = &Chain{}
|
||||
}
|
||||
route, err := c.selectRouteFor(address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -154,9 +143,6 @@ func (c *Chain) dialWithOptions(ctx context.Context, network, address string, op
|
||||
ipAddr := address
|
||||
if address != "" {
|
||||
ipAddr = c.resolve(address, options.Resolver, options.Hosts)
|
||||
if ipAddr == "" {
|
||||
return nil, fmt.Errorf("resolver: domain %s does not exists", address)
|
||||
}
|
||||
}
|
||||
|
||||
timeout := options.Timeout
|
||||
@ -164,32 +150,6 @@ func (c *Chain) dialWithOptions(ctx context.Context, network, address string, op
|
||||
timeout = DialTimeout
|
||||
}
|
||||
|
||||
var controlFunction func(_ string, _ string, c syscall.RawConn) error = nil
|
||||
if c.Mark > 0 {
|
||||
controlFunction = func(_, _ string, cc syscall.RawConn) error {
|
||||
return cc.Control(func(fd uintptr) {
|
||||
ex := setSocketMark(int(fd), c.Mark)
|
||||
if ex != nil {
|
||||
log.Logf("net dialer set mark %d error: %s", c.Mark, ex)
|
||||
} else {
|
||||
// log.Logf("net dialer set mark %d success", options.Mark)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if c.Interface != "" {
|
||||
controlFunction = func(_, _ string, cc syscall.RawConn) error {
|
||||
return cc.Control(func(fd uintptr) {
|
||||
err := setSocketInterface(int(fd), c.Interface)
|
||||
|
||||
if err != nil {
|
||||
log.Logf("net dialer set interface %s error: %s", c.Interface, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if route.IsEmpty() {
|
||||
switch network {
|
||||
case "udp", "udp4", "udp6":
|
||||
@ -200,7 +160,6 @@ func (c *Chain) dialWithOptions(ctx context.Context, network, address string, op
|
||||
}
|
||||
d := &net.Dialer{
|
||||
Timeout: timeout,
|
||||
Control: controlFunction,
|
||||
// LocalAddr: laddr, // TODO: optional local address
|
||||
}
|
||||
return d.DialContext(ctx, network, ipAddr)
|
||||
@ -234,11 +193,9 @@ func (*Chain) resolve(addr string, resolver Resolver, hosts *Hosts) string {
|
||||
if err != nil {
|
||||
log.Logf("[resolver] %s: %v", host, err)
|
||||
}
|
||||
if len(ips) == 0 {
|
||||
log.Logf("[resolver] %s: domain does not exists", host)
|
||||
return ""
|
||||
if len(ips) > 0 {
|
||||
return net.JoinHostPort(ips[0].String(), port)
|
||||
}
|
||||
return net.JoinHostPort(ips[0].String(), port)
|
||||
}
|
||||
return addr
|
||||
}
|
||||
@ -329,13 +286,13 @@ func (c *Chain) selectRoute() (route *Chain, err error) {
|
||||
// selectRouteFor selects route with bypass testing.
|
||||
func (c *Chain) selectRouteFor(addr string) (route *Chain, err error) {
|
||||
if c.IsEmpty() {
|
||||
return c.newRoute(), nil
|
||||
return newRoute(), nil
|
||||
}
|
||||
if c.isRoute {
|
||||
return c, nil
|
||||
}
|
||||
|
||||
route = c.newRoute()
|
||||
route = newRoute()
|
||||
var nl []Node
|
||||
|
||||
for _, group := range c.nodeGroups {
|
||||
@ -353,7 +310,7 @@ func (c *Chain) selectRouteFor(addr string) (route *Chain, err error) {
|
||||
node.DialOptions = append(node.DialOptions,
|
||||
ChainDialOption(route),
|
||||
)
|
||||
route = c.newRoute() // cutoff the chain for multiplex node.
|
||||
route = newRoute() // cutoff the chain for multiplex node.
|
||||
}
|
||||
|
||||
route.AddNode(node)
|
||||
@ -371,7 +328,6 @@ type ChainOptions struct {
|
||||
Timeout time.Duration
|
||||
Hosts *Hosts
|
||||
Resolver Resolver
|
||||
Mark int
|
||||
}
|
||||
|
||||
// ChainOption allows a common way to set chain options.
|
||||
|
10
client.go
10
client.go
@ -7,7 +7,7 @@ import (
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/go-gost/gosocks5"
|
||||
"github.com/ginuerzh/gosocks5"
|
||||
)
|
||||
|
||||
// Client is a proxy client.
|
||||
@ -83,7 +83,6 @@ type Transporter interface {
|
||||
type DialOptions struct {
|
||||
Timeout time.Duration
|
||||
Chain *Chain
|
||||
Host string
|
||||
}
|
||||
|
||||
// DialOption allows a common way to set DialOptions.
|
||||
@ -103,13 +102,6 @@ func ChainDialOption(chain *Chain) DialOption {
|
||||
}
|
||||
}
|
||||
|
||||
// HostDialOption specifies the host used by Transporter.Dial
|
||||
func HostDialOption(host string) DialOption {
|
||||
return func(opts *DialOptions) {
|
||||
opts.Host = host
|
||||
}
|
||||
}
|
||||
|
||||
// HandshakeOptions describes the options for handshake.
|
||||
type HandshakeOptions struct {
|
||||
Addr string
|
||||
|
@ -5,7 +5,8 @@ import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
@ -43,9 +44,8 @@ var (
|
||||
defaultKeyFile = "key.pem"
|
||||
)
|
||||
|
||||
// Load the certificate from cert & key files and optional client CA file,
|
||||
// will use the default certificate if the provided info are invalid.
|
||||
func tlsConfig(certFile, keyFile, caFile string) (*tls.Config, error) {
|
||||
// Load the certificate from cert and key files, will use the default certificate if the provided info are invalid.
|
||||
func tlsConfig(certFile, keyFile string) (*tls.Config, error) {
|
||||
if certFile == "" || keyFile == "" {
|
||||
certFile, keyFile = defaultCertFile, defaultKeyFile
|
||||
}
|
||||
@ -54,19 +54,7 @@ func tlsConfig(certFile, keyFile, caFile string) (*tls.Config, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfg := &tls.Config{Certificates: []tls.Certificate{cert}}
|
||||
|
||||
pool, err := loadCA(caFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if pool != nil {
|
||||
cfg.ClientCAs = pool
|
||||
cfg.ClientAuth = tls.RequireAndVerifyClientCert
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
return &tls.Config{Certificates: []tls.Certificate{cert}}, nil
|
||||
}
|
||||
|
||||
func loadCA(caFile string) (cp *x509.CertPool, err error) {
|
||||
@ -74,12 +62,12 @@ func loadCA(caFile string) (cp *x509.CertPool, err error) {
|
||||
return
|
||||
}
|
||||
cp = x509.NewCertPool()
|
||||
data, err := os.ReadFile(caFile)
|
||||
data, err := ioutil.ReadFile(caFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !cp.AppendCertsFromPEM(data) {
|
||||
return nil, fmt.Errorf("loadCA %s: AppendCertsFromPEM failed", caFile)
|
||||
return nil, errors.New("AppendCertsFromPEM failed")
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -110,7 +98,6 @@ func parseUsers(authFile string) (users []*url.Userinfo, err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
@ -156,38 +143,33 @@ func parseIP(s string, port string) (ips []string) {
|
||||
port = "8080" // default port
|
||||
}
|
||||
|
||||
addrFn := func(s, port string) string {
|
||||
c := strings.Count(s, ":")
|
||||
if c == 0 || //ipv4 or domain
|
||||
s[len(s)-1] == ']' { //[ipv6]
|
||||
return s + ":" + port
|
||||
}
|
||||
if c > 1 && s[0] != '[' { // ipv6
|
||||
return "[" + s + "]:" + port
|
||||
}
|
||||
return s //ipv4:port or [ipv6]:port
|
||||
}
|
||||
|
||||
file, err := os.Open(s)
|
||||
if err != nil {
|
||||
ss := strings.Split(s, ",")
|
||||
for _, s := range ss {
|
||||
s = strings.TrimSpace(s)
|
||||
if s != "" {
|
||||
ips = append(ips, addrFn(s, port))
|
||||
// TODO: support IPv6
|
||||
if !strings.Contains(s, ":") {
|
||||
s = s + ":" + port
|
||||
}
|
||||
ips = append(ips, s)
|
||||
}
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
ips = append(ips, addrFn(line, port))
|
||||
if !strings.Contains(line, ":") {
|
||||
line = line + ":" + port
|
||||
}
|
||||
ips = append(ips, line)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -31,9 +31,7 @@ func init() {
|
||||
|
||||
flag.Var(&baseCfg.route.ChainNodes, "F", "forward address, can make a forward chain")
|
||||
flag.Var(&baseCfg.route.ServeNodes, "L", "listen address, can listen on multiple ports (required)")
|
||||
flag.IntVar(&baseCfg.route.Mark, "M", 0, "Specify out connection mark")
|
||||
flag.StringVar(&configureFile, "C", "", "configure file")
|
||||
flag.StringVar(&baseCfg.route.Interface, "I", "", "Interface to bind")
|
||||
flag.BoolVar(&baseCfg.Debug, "D", false, "enable debug log")
|
||||
flag.BoolVar(&printVersion, "V", false, "print version")
|
||||
if pprofEnabled {
|
||||
@ -42,7 +40,7 @@ func init() {
|
||||
flag.Parse()
|
||||
|
||||
if printVersion {
|
||||
fmt.Fprintf(os.Stdout, "gost %s (%s %s/%s)\n",
|
||||
fmt.Fprintf(os.Stderr, "gost %s (%s %s/%s)\n",
|
||||
gost.Version, runtime.Version(), runtime.GOOS, runtime.GOARCH)
|
||||
os.Exit(0)
|
||||
}
|
||||
@ -69,7 +67,7 @@ func main() {
|
||||
}
|
||||
|
||||
// NOTE: as of 2.6, you can use custom cert/key files to initialize the default certificate.
|
||||
tlsConfig, err := tlsConfig(defaultCertFile, defaultKeyFile, "")
|
||||
tlsConfig, err := tlsConfig(defaultCertFile, defaultKeyFile)
|
||||
if err != nil {
|
||||
// generate random self-signed certificate.
|
||||
cert, err := gost.GenCertificate()
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@ -13,16 +14,14 @@ import (
|
||||
)
|
||||
|
||||
type peerConfig struct {
|
||||
Strategy string `json:"strategy"`
|
||||
MaxFails int `json:"max_fails"`
|
||||
FastestCount int `json:"fastest_count"` // topN fastest node count
|
||||
FailTimeout time.Duration
|
||||
period time.Duration // the period for live reloading
|
||||
|
||||
Nodes []string `json:"nodes"`
|
||||
group *gost.NodeGroup
|
||||
baseNodes []gost.Node
|
||||
stopped chan struct{}
|
||||
Strategy string `json:"strategy"`
|
||||
MaxFails int `json:"max_fails"`
|
||||
FailTimeout time.Duration
|
||||
period time.Duration // the period for live reloading
|
||||
Nodes []string `json:"nodes"`
|
||||
group *gost.NodeGroup
|
||||
baseNodes []gost.Node
|
||||
stopped chan struct{}
|
||||
}
|
||||
|
||||
func newPeerConfig() *peerConfig {
|
||||
@ -53,7 +52,6 @@ func (cfg *peerConfig) Reload(r io.Reader) error {
|
||||
FailTimeout: cfg.FailTimeout,
|
||||
},
|
||||
&gost.InvalidFilter{},
|
||||
gost.NewFastestFilter(0, cfg.FastestCount),
|
||||
),
|
||||
gost.WithStrategy(gost.NewStrategy(cfg.Strategy)),
|
||||
)
|
||||
@ -85,7 +83,7 @@ func (cfg *peerConfig) Reload(r io.Reader) error {
|
||||
}
|
||||
|
||||
func (cfg *peerConfig) parse(r io.Reader) error {
|
||||
data, err := io.ReadAll(r)
|
||||
data, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -128,8 +126,6 @@ func (cfg *peerConfig) parse(r io.Reader) error {
|
||||
cfg.Strategy = ss[1]
|
||||
case "max_fails":
|
||||
cfg.MaxFails, _ = strconv.Atoi(ss[1])
|
||||
case "fastest_count":
|
||||
cfg.FastestCount, _ = strconv.Atoi(ss[1])
|
||||
case "fail_timeout":
|
||||
cfg.FailTimeout, _ = time.ParseDuration(ss[1])
|
||||
case "reload":
|
||||
|
@ -3,14 +3,12 @@ package main
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ginuerzh/gost"
|
||||
"github.com/go-log/log"
|
||||
@ -30,15 +28,11 @@ type route struct {
|
||||
ServeNodes stringList
|
||||
ChainNodes stringList
|
||||
Retries int
|
||||
Mark int
|
||||
Interface string
|
||||
}
|
||||
|
||||
func (r *route) parseChain() (*gost.Chain, error) {
|
||||
chain := gost.NewChain()
|
||||
chain.Retries = r.Retries
|
||||
chain.Mark = r.Mark
|
||||
chain.Interface = r.Interface
|
||||
gid := 1 // group ID
|
||||
|
||||
for _, ns := range r.ChainNodes {
|
||||
@ -66,7 +60,6 @@ func (r *route) parseChain() (*gost.Chain, error) {
|
||||
FailTimeout: nodes[0].GetDuration("fail_timeout"),
|
||||
},
|
||||
&gost.InvalidFilter{},
|
||||
gost.NewFastestFilter(0, nodes[0].GetInt("fastest_count")),
|
||||
),
|
||||
gost.WithStrategy(gost.NewStrategy(nodes[0].Get("strategy"))),
|
||||
)
|
||||
@ -135,35 +128,6 @@ func parseChainNode(ns string) (nodes []gost.Node, err error) {
|
||||
InsecureSkipVerify: !node.GetBool("secure"),
|
||||
RootCAs: rootCAs,
|
||||
}
|
||||
|
||||
// If the argument `ca` is given, but not open `secure`, we verify the
|
||||
// certificate manually.
|
||||
if rootCAs != nil && !node.GetBool("secure") {
|
||||
tlsCfg.VerifyConnection = func(state tls.ConnectionState) error {
|
||||
opts := x509.VerifyOptions{
|
||||
Roots: rootCAs,
|
||||
CurrentTime: time.Now(),
|
||||
DNSName: "",
|
||||
Intermediates: x509.NewCertPool(),
|
||||
}
|
||||
|
||||
certs := state.PeerCertificates
|
||||
for i, cert := range certs {
|
||||
if i == 0 {
|
||||
continue
|
||||
}
|
||||
opts.Intermediates.AddCert(cert)
|
||||
}
|
||||
|
||||
_, err = certs[0].Verify(opts)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if cert, err := tls.LoadX509KeyPair(node.Get("cert"), node.Get("key")); err == nil {
|
||||
tlsCfg.Certificates = []tls.Certificate{cert}
|
||||
}
|
||||
|
||||
wsOpts := &gost.WSOptions{}
|
||||
wsOpts.EnableCompression = node.GetBool("compression")
|
||||
wsOpts.ReadBufferSize = node.GetInt("rbuf")
|
||||
@ -213,12 +177,6 @@ func parseChainNode(ns string) (nodes []gost.Node, err error) {
|
||||
Timeout: timeout,
|
||||
IdleTimeout: node.GetDuration("idle"),
|
||||
}
|
||||
if config.KeepAlive {
|
||||
config.KeepAlivePeriod = node.GetDuration("ttl")
|
||||
if config.KeepAlivePeriod == 0 {
|
||||
config.KeepAlivePeriod = 10 * time.Second
|
||||
}
|
||||
}
|
||||
|
||||
if cipher := node.Get("cipher"); cipher != "" {
|
||||
sum := sha256.Sum256([]byte(cipher))
|
||||
@ -242,8 +200,6 @@ func parseChainNode(ns string) (nodes []gost.Node, err error) {
|
||||
tr = gost.FakeTCPTransporter()
|
||||
case "udp":
|
||||
tr = gost.UDPTransporter()
|
||||
case "vsock":
|
||||
tr = gost.VSOCKTransporter()
|
||||
default:
|
||||
tr = gost.TCPTransporter()
|
||||
}
|
||||
@ -278,14 +234,8 @@ func parseChainNode(ns string) (nodes []gost.Node, err error) {
|
||||
connector = gost.AutoConnector(node.User)
|
||||
}
|
||||
|
||||
host := node.Get("host")
|
||||
if host == "" {
|
||||
host = node.Host
|
||||
}
|
||||
|
||||
node.DialOptions = append(node.DialOptions,
|
||||
gost.TimeoutDialOption(timeout),
|
||||
gost.HostDialOption(host),
|
||||
)
|
||||
|
||||
node.ConnectOptions = []gost.ConnectOption{
|
||||
@ -294,6 +244,11 @@ func parseChainNode(ns string) (nodes []gost.Node, err error) {
|
||||
gost.NoDelayConnectOption(node.GetBool("nodelay")),
|
||||
}
|
||||
|
||||
host := node.Get("host")
|
||||
if host == "" {
|
||||
host = node.Host
|
||||
}
|
||||
|
||||
sshConfig := &gost.SSHConfig{}
|
||||
if s := node.Get("ssh_key"); s != "" {
|
||||
key, err := gost.ParseSSHKeyFile(s)
|
||||
@ -387,7 +342,7 @@ func (r *route) GenRouters() ([]router, error) {
|
||||
}
|
||||
}
|
||||
certFile, keyFile := node.Get("cert"), node.Get("key")
|
||||
tlsCfg, err := tlsConfig(certFile, keyFile, node.Get("ca"))
|
||||
tlsCfg, err := tlsConfig(certFile, keyFile)
|
||||
if err != nil && certFile != "" && keyFile != "" {
|
||||
return nil, err
|
||||
}
|
||||
@ -467,12 +422,6 @@ func (r *route) GenRouters() ([]router, error) {
|
||||
Timeout: timeout,
|
||||
IdleTimeout: node.GetDuration("idle"),
|
||||
}
|
||||
if config.KeepAlive {
|
||||
config.KeepAlivePeriod = node.GetDuration("ttl")
|
||||
if config.KeepAlivePeriod == 0 {
|
||||
config.KeepAlivePeriod = 10 * time.Second
|
||||
}
|
||||
}
|
||||
if cipher := node.Get("cipher"); cipher != "" {
|
||||
sum := sha256.Sum256([]byte(cipher))
|
||||
config.Key = sum[:]
|
||||
@ -492,8 +441,6 @@ func (r *route) GenRouters() ([]router, error) {
|
||||
chain.Nodes()[len(chain.Nodes())-1].Client.Transporter = gost.SSHForwardTransporter()
|
||||
}
|
||||
ln, err = gost.TCPListener(node.Addr)
|
||||
case "vsock":
|
||||
ln, err = gost.VSOCKListener(node.Addr)
|
||||
case "udp":
|
||||
ln, err = gost.UDPListener(node.Addr, &gost.UDPListenConfig{
|
||||
TTL: ttl,
|
||||
@ -669,8 +616,6 @@ func (r *route) GenRouters() ([]router, error) {
|
||||
gost.IPsHandlerOption(ips),
|
||||
gost.TCPModeHandlerOption(node.GetBool("tcp")),
|
||||
gost.IPRoutesHandlerOption(tunRoutes...),
|
||||
gost.ProxyAgentHandlerOption(node.Get("proxyAgent")),
|
||||
gost.HTTPTunnelHandlerOption(node.GetBool("httpTunnel")),
|
||||
)
|
||||
|
||||
rt := router{
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@ -35,7 +36,7 @@ func init() {
|
||||
|
||||
var (
|
||||
httpTestHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
data, _ := io.ReadAll(r.Body)
|
||||
data, _ := ioutil.ReadAll(r.Body)
|
||||
if len(data) == 0 {
|
||||
data = []byte("Hello World!")
|
||||
}
|
||||
@ -86,7 +87,7 @@ func httpRoundtrip(conn net.Conn, targetURL string, data []byte) (err error) {
|
||||
return errors.New(resp.Status)
|
||||
}
|
||||
|
||||
recv, err := io.ReadAll(resp.Body)
|
||||
recv, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
3
dns.go
3
dns.go
@ -7,6 +7,7 @@ import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
@ -266,7 +267,7 @@ func (l *dnsListener) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
buf, err = io.ReadAll(r.Body)
|
||||
buf, err = ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-gost/gosocks5"
|
||||
"github.com/ginuerzh/gosocks5"
|
||||
ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
||||
)
|
||||
|
||||
|
12
forward.go
12
forward.go
@ -10,9 +10,9 @@ import (
|
||||
|
||||
"fmt"
|
||||
|
||||
"github.com/go-gost/gosocks5"
|
||||
"github.com/ginuerzh/gosocks5"
|
||||
"github.com/go-log/log"
|
||||
smux "github.com/xtaci/smux"
|
||||
smux "gopkg.in/xtaci/smux.v1"
|
||||
)
|
||||
|
||||
type forwardConnector struct {
|
||||
@ -131,7 +131,6 @@ func (h *tcpDirectForwardHandler) Handle(conn net.Conn) {
|
||||
cc, err = h.options.Chain.Dial(node.Addr,
|
||||
RetryChainOption(h.options.Retries),
|
||||
TimeoutChainOption(h.options.Timeout),
|
||||
ResolverChainOption(h.options.Resolver),
|
||||
)
|
||||
if err != nil {
|
||||
log.Logf("[tcp] %s -> %s : %s", conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||
@ -198,12 +197,7 @@ func (h *udpDirectForwardHandler) Handle(conn net.Conn) {
|
||||
}
|
||||
}
|
||||
|
||||
cc, err := h.options.Chain.DialContext(
|
||||
context.Background(),
|
||||
"udp",
|
||||
node.Addr,
|
||||
ResolverChainOption(h.options.Resolver),
|
||||
)
|
||||
cc, err := h.options.Chain.DialContext(context.Background(), "udp", node.Addr)
|
||||
if err != nil {
|
||||
node.MarkDead()
|
||||
log.Logf("[udp] %s - %s : %s", conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||
|
93
go.mod
93
go.mod
@ -1,60 +1,49 @@
|
||||
module github.com/ginuerzh/gost
|
||||
|
||||
go 1.22
|
||||
|
||||
replace github.com/templexxx/cpu v0.0.7 => github.com/templexxx/cpu v0.0.10-0.20211111114238-98168dcec14a
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
git.torproject.org/pluggable-transports/goptlib.git v1.3.0
|
||||
git.torproject.org/pluggable-transports/goptlib.git v0.0.0-20180321061416-7d56ec4f381e
|
||||
git.torproject.org/pluggable-transports/obfs4.git v0.0.0-20181103133120-08f4d470188e
|
||||
github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2
|
||||
github.com/go-gost/gosocks4 v0.0.1
|
||||
github.com/go-gost/gosocks5 v0.3.0
|
||||
github.com/go-gost/relay v0.1.1-0.20211123134818-8ef7fd81ffd7
|
||||
github.com/go-gost/tls-dissector v0.0.2-0.20220408131628-aac992c27451
|
||||
github.com/go-log/log v0.2.0
|
||||
github.com/Yawning/chacha20 v0.0.0-20170904085104-e3b1f968fc63 // indirect
|
||||
github.com/bifurcation/mint v0.0.0-20181105071958-a14404e9a861 // indirect
|
||||
github.com/cheekybits/genny v1.0.0 // indirect
|
||||
github.com/coreos/go-iptables v0.4.5 // indirect
|
||||
github.com/dchest/siphash v1.2.1 // indirect
|
||||
github.com/docker/libcontainer v2.2.1+incompatible
|
||||
github.com/ginuerzh/gosocks4 v0.0.1
|
||||
github.com/ginuerzh/gosocks5 v0.2.0
|
||||
github.com/ginuerzh/tls-dissector v0.0.2-0.20200224064855-24ab2b3a3796
|
||||
github.com/go-gost/relay v0.1.0
|
||||
github.com/go-log/log v0.1.0
|
||||
github.com/gobwas/glob v0.2.3
|
||||
github.com/gorilla/websocket v1.5.1
|
||||
github.com/klauspost/compress v1.17.6
|
||||
github.com/mdlayher/vsock v1.2.1
|
||||
github.com/miekg/dns v1.1.58
|
||||
github.com/quic-go/quic-go v0.45.0
|
||||
github.com/ryanuber/go-glob v1.0.0
|
||||
github.com/shadowsocks/go-shadowsocks2 v0.1.5
|
||||
github.com/shadowsocks/shadowsocks-go v0.0.0-20200409064450-3e585ff90601
|
||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8
|
||||
github.com/xtaci/kcp-go/v5 v5.6.7
|
||||
github.com/xtaci/smux v1.5.24
|
||||
github.com/golang/mock v1.2.0 // indirect
|
||||
github.com/google/gopacket v1.1.17 // indirect
|
||||
github.com/gorilla/websocket v1.4.0 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.0 // indirect
|
||||
github.com/klauspost/compress v1.4.1
|
||||
github.com/klauspost/cpuid v1.2.0 // indirect
|
||||
github.com/klauspost/reedsolomon v1.7.0 // indirect
|
||||
github.com/lucas-clemente/aes12 v0.0.0-20171027163421-cd47fb39b79f // indirect
|
||||
github.com/lucas-clemente/quic-go v0.10.0
|
||||
github.com/lucas-clemente/quic-go-certificates v0.0.0-20160823095156-d2f86524cced // indirect
|
||||
github.com/miekg/dns v1.1.27
|
||||
github.com/milosgajdos83/tenus v0.0.0-20190415114537-1f3ed00ae7d8
|
||||
github.com/onsi/ginkgo v1.7.0 // indirect
|
||||
github.com/onsi/gomega v1.4.3 // indirect
|
||||
github.com/pkg/errors v0.8.1 // indirect
|
||||
github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735
|
||||
github.com/shadowsocks/go-shadowsocks2 v0.1.0
|
||||
github.com/shadowsocks/shadowsocks-go v0.0.0-20170121203516-97a5c71f80ba
|
||||
github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b
|
||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect
|
||||
github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b // indirect
|
||||
github.com/tjfoc/gmsm v1.0.1 // indirect
|
||||
github.com/xtaci/tcpraw v1.2.25
|
||||
gitlab.com/yawning/obfs4.git v0.0.0-20220204003609-77af0cba934d
|
||||
golang.org/x/crypto v0.24.0
|
||||
golang.org/x/net v0.26.0
|
||||
)
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.0.0-rc.1.0.20210721174708-390f27c3be20 // indirect
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
|
||||
github.com/coreos/go-iptables v0.6.0 // indirect
|
||||
github.com/dchest/siphash v1.2.2 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/google/gopacket v1.1.19 // indirect
|
||||
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
||||
github.com/klauspost/reedsolomon v1.12.0 // indirect
|
||||
github.com/mdlayher/socket v0.4.1 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.19.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||
github.com/templexxx/cpu v0.1.0 // indirect
|
||||
github.com/templexxx/xorsimd v0.4.2 // indirect
|
||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 // indirect
|
||||
gitlab.com/yawning/edwards25519-extra.git v0.0.0-20211229043746-2f91fcc9fbdb // indirect
|
||||
go.uber.org/mock v0.4.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 // indirect
|
||||
golang.org/x/mod v0.18.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.21.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
golang.org/x/tools v0.22.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478
|
||||
gopkg.in/gorilla/websocket.v1 v1.4.0
|
||||
gopkg.in/xtaci/kcp-go.v4 v4.3.2
|
||||
gopkg.in/xtaci/smux.v1 v1.0.7
|
||||
)
|
||||
|
307
go.sum
307
go.sum
@ -1,204 +1,145 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
filippo.io/edwards25519 v1.0.0-rc.1.0.20210721174708-390f27c3be20 h1:iJoUgXvhagsNMrJrvavw7vu1eG8+hm6jLOxlLFcoODw=
|
||||
filippo.io/edwards25519 v1.0.0-rc.1.0.20210721174708-390f27c3be20/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
|
||||
git.torproject.org/pluggable-transports/goptlib.git v1.0.0/go.mod h1:YT4XMSkuEXbtqlydr9+OxqFAyspUv0Gr9qhM3B++o/Q=
|
||||
git.torproject.org/pluggable-transports/goptlib.git v1.3.0 h1:G+iuRUblCCC2xnO+0ag1/4+aaM98D5mjWP1M0v9s8a0=
|
||||
git.torproject.org/pluggable-transports/goptlib.git v1.3.0/go.mod h1:4PBMl1dg7/3vMWSoWb46eGWlrxkUyn/CAJmxhDLAlDs=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
git.torproject.org/pluggable-transports/goptlib.git v0.0.0-20180321061416-7d56ec4f381e h1:PYcONLFUhr00kGrq7Mf14JRtoXHG7BOSKIfIha0Hu5Q=
|
||||
git.torproject.org/pluggable-transports/goptlib.git v0.0.0-20180321061416-7d56ec4f381e/go.mod h1:YT4XMSkuEXbtqlydr9+OxqFAyspUv0Gr9qhM3B++o/Q=
|
||||
git.torproject.org/pluggable-transports/obfs4.git v0.0.0-20181103133120-08f4d470188e h1:c8h60PKrRxEB5debIHBmP7T+s/EUNXTklXqlmJfYiJQ=
|
||||
git.torproject.org/pluggable-transports/obfs4.git v0.0.0-20181103133120-08f4d470188e/go.mod h1:jRZbfRcLIgFQoCw6tRmsnETVyIj54jOmXhHCYYa0jbs=
|
||||
github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed h1:eqa6queieK8SvoszxCu0WwH7lSVeL4/N/f1JwOMw1G4=
|
||||
github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed/go.mod h1:rA52xkgZwql9LRZXWb2arHEFP6qSR48KY2xOfWzEciQ=
|
||||
github.com/Yawning/chacha20 v0.0.0-20170904085104-e3b1f968fc63 h1:I6/SJSN9wJMJ+ZyQaCHUlzoTA4ypU5Bb44YWR1wTY/0=
|
||||
github.com/Yawning/chacha20 v0.0.0-20170904085104-e3b1f968fc63/go.mod h1:nf+Komq6fVP4SwmKEaVGxHTyQGKREVlwjQKpvOV39yE=
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk=
|
||||
github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
|
||||
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/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7ISrnJIXKzwaspym5BTKGx93EI=
|
||||
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0=
|
||||
github.com/bifurcation/mint v0.0.0-20181105071958-a14404e9a861 h1:x17NvoJaphEzay72TFej4OSSsgu3xRYBLkbIwdofS/4=
|
||||
github.com/bifurcation/mint v0.0.0-20181105071958-a14404e9a861/go.mod h1:zVt7zX3K/aDCk9Tj+VM7YymsX66ERvzCJzw8rFCX2JU=
|
||||
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
|
||||
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
||||
github.com/coreos/go-iptables v0.4.5 h1:DpHb9vJrZQEFMcVLFKAAGMUVX0XoRC0ptCthinRYm38=
|
||||
github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
|
||||
github.com/dchest/siphash v1.2.0 h1:YWOShuhvg0GqbQpMa60QlCGtEyf7O7HC1Jf0VjdQ60M=
|
||||
github.com/dchest/siphash v1.2.0/go.mod h1:q+IRvb2gOSrUnYoPqHiyHXS0FOBBOdl6tONBlVnOnt4=
|
||||
github.com/dchest/siphash v1.2.1 h1:4cLinnzVJDKxTCl9B01807Yiy+W7ZzVHj/KIroQRvT4=
|
||||
github.com/dchest/siphash v1.2.1/go.mod h1:q+IRvb2gOSrUnYoPqHiyHXS0FOBBOdl6tONBlVnOnt4=
|
||||
github.com/dchest/siphash v1.2.2 h1:9DFz8tQwl9pTVt5iok/9zKyzA1Q6bRGiF3HPiEEVr9I=
|
||||
github.com/dchest/siphash v1.2.2/go.mod h1:q+IRvb2gOSrUnYoPqHiyHXS0FOBBOdl6tONBlVnOnt4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/go-gost/gosocks4 v0.0.1 h1:+k1sec8HlELuQV7rWftIkmy8UijzUt2I6t+iMPlGB2s=
|
||||
github.com/go-gost/gosocks4 v0.0.1/go.mod h1:3B6L47HbU/qugDg4JnoFPHgJXE43Inz8Bah1QaN9qCc=
|
||||
github.com/go-gost/gosocks5 v0.3.0 h1:Hkmp9YDRBSCJd7xywW6dBPT6B9aQTkuWd+3WCheJiJA=
|
||||
github.com/go-gost/gosocks5 v0.3.0/go.mod h1:1G6I7HP7VFVxveGkoK8mnprnJqSqJjdcASKsdUn4Pp4=
|
||||
github.com/go-gost/relay v0.1.1-0.20211123134818-8ef7fd81ffd7 h1:itaaJhQJ19kUXEB4Igb0EbY8m+1Py2AaNNSBds/9gk4=
|
||||
github.com/go-gost/relay v0.1.1-0.20211123134818-8ef7fd81ffd7/go.mod h1:lcX+23LCQ3khIeASBo+tJ/WbwXFO32/N5YN6ucuYTG8=
|
||||
github.com/go-gost/tls-dissector v0.0.2-0.20220408131628-aac992c27451 h1:xj8gUZGYO3nb5+6Bjw9+tsFkA9sYynrOvDvvC4uDV2I=
|
||||
github.com/go-gost/tls-dissector v0.0.2-0.20220408131628-aac992c27451/go.mod h1:/9QfdewqmHdaE362Hv5nDaSWLx3pCmtD870d6GaquXs=
|
||||
github.com/go-log/log v0.2.0 h1:z8i91GBudxD5L3RmF0KVpetCbcGWAV7q1Tw1eRwQM9Q=
|
||||
github.com/go-log/log v0.2.0/go.mod h1:xzCnwajcues/6w7lne3yK2QU7DBPW7kqbgPGG5AF65U=
|
||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/docker/libcontainer v2.2.1+incompatible h1:++SbbkCw+X8vAd4j2gOCzZ2Nn7s2xFALTf7LZKmM1/0=
|
||||
github.com/docker/libcontainer v2.2.1+incompatible/go.mod h1:osvj61pYsqhNCMLGX31xr7klUBhHb/ZBuXS0o1Fvwbw=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ginuerzh/gosocks4 v0.0.1 h1:ojDKUyz+uaEeRm2usY1cyQiXTqJqrKxfeE6SVBXq4m0=
|
||||
github.com/ginuerzh/gosocks4 v0.0.1/go.mod h1:8SdwBMKjfJ9+BfP2vDJM1jcrgWUbWV6qxBPHHVrwptY=
|
||||
github.com/ginuerzh/gosocks5 v0.2.0 h1:K0Ua23U9LU3BZrf3XpGDcs0mP8DiEpa6PJE4TA/MU3s=
|
||||
github.com/ginuerzh/gosocks5 v0.2.0/go.mod h1:qp22mr6tH/prEoaN0pFukq76LlScIE+F2rP2ZP5ZHno=
|
||||
github.com/ginuerzh/tls-dissector v0.0.1 h1:yF6fIt78TO4CdjiLLn6R8r0XajQJE1Lbnuq6rP8mGW8=
|
||||
github.com/ginuerzh/tls-dissector v0.0.1/go.mod h1:u/kbBOqIOgJv39gywuUb3VwyzdZG5DKquOqfToKE6lk=
|
||||
github.com/ginuerzh/tls-dissector v0.0.2-0.20200223041816-c0cb3da7ea91 h1:bFBTbZglO4xNVWSLwDEcVKBIurTXGL2sNKi9UuQima4=
|
||||
github.com/ginuerzh/tls-dissector v0.0.2-0.20200223041816-c0cb3da7ea91/go.mod h1:YyzP8PQrGwDH/XsfHJXwqdHLwWvBYxu77YVKm0+68f0=
|
||||
github.com/ginuerzh/tls-dissector v0.0.2-0.20200223072427-83db9c3e4eb5 h1:pmGmno31njvF5xncoDcDuM8mE1984cxrQ0DeVD4lVfA=
|
||||
github.com/ginuerzh/tls-dissector v0.0.2-0.20200223072427-83db9c3e4eb5/go.mod h1:YyzP8PQrGwDH/XsfHJXwqdHLwWvBYxu77YVKm0+68f0=
|
||||
github.com/ginuerzh/tls-dissector v0.0.2-0.20200223110639-e9c10af0eb19 h1:t/AZCq8FiVNN+Mx6UmIv7bXj3+OVThg070G8ajZ3wJw=
|
||||
github.com/ginuerzh/tls-dissector v0.0.2-0.20200223110639-e9c10af0eb19/go.mod h1:YyzP8PQrGwDH/XsfHJXwqdHLwWvBYxu77YVKm0+68f0=
|
||||
github.com/ginuerzh/tls-dissector v0.0.2-0.20200223121713-a8bf02a99d69 h1:h9lREy0OWSTrjweGxduikppA2tCjGPoUj32SVHI3dr0=
|
||||
github.com/ginuerzh/tls-dissector v0.0.2-0.20200223121713-a8bf02a99d69/go.mod h1:YyzP8PQrGwDH/XsfHJXwqdHLwWvBYxu77YVKm0+68f0=
|
||||
github.com/ginuerzh/tls-dissector v0.0.2-0.20200224064855-24ab2b3a3796 h1:VPXbYRvZUzTemsI7u0FzOnEuHeHwQuMTPXApAu8aeX4=
|
||||
github.com/ginuerzh/tls-dissector v0.0.2-0.20200224064855-24ab2b3a3796/go.mod h1:YyzP8PQrGwDH/XsfHJXwqdHLwWvBYxu77YVKm0+68f0=
|
||||
github.com/go-gost/relay v0.1.0 h1:UOf2YwAzzaUjY5mdpMuLfSw0vz62iIFYk7oJQkuhlGw=
|
||||
github.com/go-gost/relay v0.1.0/go.mod h1:YFCpddLOFE3NlIkeDWRdEs8gL/GFsqXdtaf8SV5v4YQ=
|
||||
github.com/go-log/log v0.1.0 h1:wudGTNsiGzrD5ZjgIkVZ517ugi2XRe9Q/xRCzwEO4/U=
|
||||
github.com/go-log/log v0.1.0/go.mod h1:4mBwpdRMFLiuXZDCwU2lKQFsoSCo72j3HqBK9d81N2M=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba h1:ql1qNgCyOB7iAEk8JTNM+zJrgIbnyCKX/wdlyPufP5g=
|
||||
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
|
||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
||||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
||||
github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI=
|
||||
github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
|
||||
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/klauspost/reedsolomon v1.12.0 h1:I5FEp3xSwVCcEh3F5A7dofEfhXdF/bWhQWPH+XwBFno=
|
||||
github.com/klauspost/reedsolomon v1.12.0/go.mod h1:EPLZJeh4l27pUGC3aXOjheaoh1I9yut7xTURiW3LQ9Y=
|
||||
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
|
||||
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
|
||||
github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ=
|
||||
github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE=
|
||||
github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
|
||||
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
|
||||
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
|
||||
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
|
||||
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
|
||||
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/quic-go/quic-go v0.45.0 h1:OHmkQGM37luZITyTSu6ff03HP/2IrwDX1ZFiNEhSFUE=
|
||||
github.com/quic-go/quic-go v0.45.0/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI=
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
|
||||
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
|
||||
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
|
||||
github.com/shadowsocks/go-shadowsocks2 v0.1.5 h1:PDSQv9y2S85Fl7VBeOMF9StzeXZyK1HakRm86CUbr28=
|
||||
github.com/shadowsocks/go-shadowsocks2 v0.1.5/go.mod h1:AGGpIoek4HRno4xzyFiAtLHkOpcoznZEkAccaI/rplM=
|
||||
github.com/shadowsocks/shadowsocks-go v0.0.0-20200409064450-3e585ff90601 h1:XU9hik0exChEmY92ALW4l9WnDodxLVS9yOSNh2SizaQ=
|
||||
github.com/shadowsocks/shadowsocks-go v0.0.0-20200409064450-3e585ff90601/go.mod h1:mttDPaeLm87u74HMrP+n2tugXvIKWcwff/cqSX0lehY=
|
||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8=
|
||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/templexxx/cpu v0.1.0 h1:wVM+WIJP2nYaxVxqgHPD4wGA2aJ9rvrQRV8CvFzNb40=
|
||||
github.com/templexxx/cpu v0.1.0/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk=
|
||||
github.com/templexxx/xorsimd v0.4.2 h1:ocZZ+Nvu65LGHmCLZ7OoCtg8Fx8jnHKK37SjvngUoVI=
|
||||
github.com/templexxx/xorsimd v0.4.2/go.mod h1:HgwaPoDREdi6OnULpSfxhzaiiSUY4Fi3JPn1wpt28NI=
|
||||
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||
github.com/xtaci/kcp-go/v5 v5.6.7 h1:7+rnxNFIsjEwTXQk4cSZpXM4pO0hqtpwE1UFFoJBffA=
|
||||
github.com/xtaci/kcp-go/v5 v5.6.7/go.mod h1:oE9j2NVqAkuKO5o8ByKGch3vgVX3BNf8zqP8JiGq0bM=
|
||||
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 h1:EWU6Pktpas0n8lLQwDsRyZfmkPeRbdgPtW609es+/9E=
|
||||
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37/go.mod h1:HpMP7DB2CyokmAh4lp0EQnnWhmycP/TvwBGzvuie+H0=
|
||||
github.com/xtaci/smux v1.5.24 h1:77emW9dtnOxxOQ5ltR+8BbsX1kzcOxQ5gB+aaV9hXOY=
|
||||
github.com/xtaci/smux v1.5.24/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY=
|
||||
github.com/google/gopacket v1.1.17 h1:rMrlX2ZY2UbvT+sdz3+6J+pp2z+msCq9MxTU6ymxbBY=
|
||||
github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=
|
||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/klauspost/compress v1.4.1 h1:8VMb5+0wMgdBykOV96DwNwKFQ+WTI4pzYURP99CcB9E=
|
||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/cpuid v1.2.0 h1:NMpwD2G9JSFOE1/TJjGSo5zG7Yb2bTe7eq1jH+irmeE=
|
||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/reedsolomon v1.7.0 h1:pLFmRKGko2ZieiTGyo9DahLCIuljyxm+Zzhz/fYEonE=
|
||||
github.com/klauspost/reedsolomon v1.7.0/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4=
|
||||
github.com/lucas-clemente/aes12 v0.0.0-20171027163421-cd47fb39b79f h1:sSeNEkJrs+0F9TUau0CgWTTNEwF23HST3Eq0A+QIx+A=
|
||||
github.com/lucas-clemente/aes12 v0.0.0-20171027163421-cd47fb39b79f/go.mod h1:JpH9J1c9oX6otFSgdUHwUBUizmKlrMjxWnIAjff4m04=
|
||||
github.com/lucas-clemente/quic-go v0.10.0 h1:xEF+pSHYAOcu+U10Meunf+DTtc8vhQDRqlA0BJ6hufc=
|
||||
github.com/lucas-clemente/quic-go v0.10.0/go.mod h1:wuD+2XqEx8G9jtwx5ou2BEYBsE+whgQmlj0Vz/77PrY=
|
||||
github.com/lucas-clemente/quic-go-certificates v0.0.0-20160823095156-d2f86524cced h1:zqEC1GJZFbGZA0tRyNZqRjep92K5fujFtFsu5ZW7Aug=
|
||||
github.com/lucas-clemente/quic-go-certificates v0.0.0-20160823095156-d2f86524cced/go.mod h1:NCcRLrOTZbzhZvixZLlERbJtDtYsmMw8Jc4vS8Z0g58=
|
||||
github.com/miekg/dns v1.1.27 h1:aEH/kqUzUxGJ/UHcEKdJY+ugH6WEzsEBBSPa8zuy1aM=
|
||||
github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/milosgajdos83/tenus v0.0.0-20190415114537-1f3ed00ae7d8 h1:4WFQEfEJ7zaHYViIVM2Cd6tnQOOhiEHbmQtlcV7aOpc=
|
||||
github.com/milosgajdos83/tenus v0.0.0-20190415114537-1f3ed00ae7d8/go.mod h1:G95Wwn625/q6JCCytI4VR/a5VtPwrtI0B+Q1Gi38QLA=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735 h1:7YvPJVmEeFHR1Tj9sZEYsmarJEQfMVYpd/Vyy/A8dqE=
|
||||
github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
|
||||
github.com/shadowsocks/go-shadowsocks2 v0.0.12-0.20191211020244-a57bc393e43a h1:cxYYZwo6iuuJ/5f8x1mHnya7xvSF3cDrOh8Pqh7RZ/w=
|
||||
github.com/shadowsocks/go-shadowsocks2 v0.0.12-0.20191211020244-a57bc393e43a/go.mod h1:/0aFGbhK8mtOX4J/6kTJsPLZlEs9KnzKoWCOCvjd7vk=
|
||||
github.com/shadowsocks/go-shadowsocks2 v0.1.0 h1:jQhkjAmMuOTQ7B04bnrRJ5IAoZEwoaXXkKspE7rQ6ck=
|
||||
github.com/shadowsocks/go-shadowsocks2 v0.1.0/go.mod h1:/0aFGbhK8mtOX4J/6kTJsPLZlEs9KnzKoWCOCvjd7vk=
|
||||
github.com/shadowsocks/shadowsocks-go v0.0.0-20170121203516-97a5c71f80ba h1:tJgNXb3S+RkB4kNPi6N5OmEWe3m+Y3Qs6LUMiNDAONM=
|
||||
github.com/shadowsocks/shadowsocks-go v0.0.0-20170121203516-97a5c71f80ba/go.mod h1:mttDPaeLm87u74HMrP+n2tugXvIKWcwff/cqSX0lehY=
|
||||
github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b h1:+y4hCMc/WKsDbAPsOQZgBSaSZ26uh2afyaWeVg/3s/c=
|
||||
github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E=
|
||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
|
||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
|
||||
github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b h1:mnG1fcsIB1d/3vbkBak2MM0u+vhGhlQwpeimUi7QncM=
|
||||
github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
|
||||
github.com/tjfoc/gmsm v1.0.1 h1:R11HlqhXkDospckjZEihx9SW/2VW0RgdwrykyWMFOQU=
|
||||
github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc=
|
||||
github.com/xtaci/tcpraw v1.2.25 h1:VDlqo0op17JeXBM6e2G9ocCNLOJcw9mZbobMbJjo0vk=
|
||||
github.com/xtaci/tcpraw v1.2.25/go.mod h1:dKyZ2V75s0cZ7cbgJYdxPvms7af0joIeOyx1GgJQbLk=
|
||||
gitlab.com/yawning/edwards25519-extra.git v0.0.0-20211229043746-2f91fcc9fbdb h1:qRSZHsODmAP5qDvb3YsO7Qnf3TRiVbGxNG/WYnlM4/o=
|
||||
gitlab.com/yawning/edwards25519-extra.git v0.0.0-20211229043746-2f91fcc9fbdb/go.mod h1:gvdJuZuO/tPZyhEV8K3Hmoxv/DWud5L4qEQxfYjEUTo=
|
||||
gitlab.com/yawning/obfs4.git v0.0.0-20220204003609-77af0cba934d h1:tJ8F7ABaQ3p3wjxwXiWSktVDgjZEXkvaRawd2rIq5ws=
|
||||
gitlab.com/yawning/obfs4.git v0.0.0-20220204003609-77af0cba934d/go.mod h1:9GcM8QNU9/wXtEEH2q8bVOnPI7FtIF6VVLzZ1l6Hgf8=
|
||||
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
||||
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
golang.org/x/crypto v0.0.0-20181015023909-0c41d7ab0a0e/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 h1:LoYXNGAShUG3m/ehNk4iFctuhGX/+R1ZpfJ4/ia80JM=
|
||||
golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw=
|
||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
|
||||
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67 h1:1Fzlr8kkDLQwqMP8GxrhptBLqZG/EDpiATneiZHY998=
|
||||
golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
|
||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
|
||||
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
|
||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/gorilla/websocket.v1 v1.4.0 h1:lREme3ezAGPCpxSHwjGkHhAJX+ed2B6vzAJ+kaqBEIM=
|
||||
gopkg.in/gorilla/websocket.v1 v1.4.0/go.mod h1:Ons1i8d00TjvJPdla7bJyeXFsdOacUyrTYbg9IetsIE=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/xtaci/kcp-go.v4 v4.3.2 h1:S9IF+L55Ugzl/hVA6wvuL3SuAtTUzH2cBBC88MXQxnE=
|
||||
gopkg.in/xtaci/kcp-go.v4 v4.3.2/go.mod h1:fFYTlSOHNOHDNTKfoqarZMQsu7g7oXKwJ9wq0i9lODc=
|
||||
gopkg.in/xtaci/smux.v1 v1.0.7 h1:qootIZs4ZPSx5blhvgaFpx2epdFSWkyw99xT+q0mRXI=
|
||||
gopkg.in/xtaci/smux.v1 v1.0.7/go.mod h1:NbrPjLp8lNAYN8KqTplnFr2JjIBbr7CdHBkHtHsXtWA=
|
||||
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
8
gost.go
8
gost.go
@ -20,7 +20,7 @@ import (
|
||||
)
|
||||
|
||||
// Version is the gost version.
|
||||
const Version = "2.12.0"
|
||||
const Version = "2.11.0"
|
||||
|
||||
// Debug is a flag that enables the debug log.
|
||||
var Debug bool
|
||||
@ -80,8 +80,6 @@ var (
|
||||
// DefaultUserAgent is the default HTTP User-Agent header used by HTTP and websocket.
|
||||
DefaultUserAgent = "Chrome/78.0.3904.106"
|
||||
|
||||
DefaultProxyAgent = "gost/" + Version
|
||||
|
||||
// DefaultMTU is the default mtu for tun/tap device
|
||||
DefaultMTU = 1350
|
||||
)
|
||||
@ -149,7 +147,9 @@ func (rw *readWriter) Write(p []byte) (n int, err error) {
|
||||
return rw.w.Write(p)
|
||||
}
|
||||
|
||||
var nopClientConn = &nopConn{}
|
||||
var (
|
||||
nopClientConn = &nopConn{}
|
||||
)
|
||||
|
||||
// a nop connection implements net.Conn,
|
||||
// it does nothing.
|
||||
|
20
handler.go
20
handler.go
@ -7,8 +7,8 @@ import (
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/go-gost/gosocks4"
|
||||
"github.com/go-gost/gosocks5"
|
||||
"github.com/ginuerzh/gosocks4"
|
||||
"github.com/ginuerzh/gosocks5"
|
||||
"github.com/go-log/log"
|
||||
)
|
||||
|
||||
@ -42,8 +42,6 @@ type HandlerOptions struct {
|
||||
IPs []string
|
||||
TCPMode bool
|
||||
IPRoutes []IPRoute
|
||||
ProxyAgent string
|
||||
HTTPTunnel bool
|
||||
}
|
||||
|
||||
// HandlerOption allows a common way to set handler options.
|
||||
@ -213,20 +211,6 @@ func IPRoutesHandlerOption(routes ...IPRoute) HandlerOption {
|
||||
}
|
||||
}
|
||||
|
||||
// ProxyAgentHandlerOption sets the proxy agent for http handler.
|
||||
func ProxyAgentHandlerOption(agent string) HandlerOption {
|
||||
return func(opts *HandlerOptions) {
|
||||
opts.ProxyAgent = agent
|
||||
}
|
||||
}
|
||||
|
||||
// HTTPTunnelHandlerOption sets the Tunnel mode for HTTP client used in HTTP handler.
|
||||
func HTTPTunnelHandlerOption(tunnelMode bool) HandlerOption {
|
||||
return func(opts *HandlerOptions) {
|
||||
opts.HTTPTunnel = tunnelMode
|
||||
}
|
||||
}
|
||||
|
||||
type autoHandler struct {
|
||||
options *HandlerOptions
|
||||
}
|
||||
|
84
http.go
84
http.go
@ -6,7 +6,6 @@ import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
@ -174,12 +173,7 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) {
|
||||
ProtoMinor: 1,
|
||||
Header: http.Header{},
|
||||
}
|
||||
|
||||
proxyAgent := DefaultProxyAgent
|
||||
if h.options.ProxyAgent != "" {
|
||||
proxyAgent = h.options.ProxyAgent
|
||||
}
|
||||
resp.Header.Add("Proxy-Agent", proxyAgent)
|
||||
resp.Header.Add("Proxy-Agent", "gost/"+Version)
|
||||
|
||||
if !Can("tcp", host, h.options.Whitelist, h.options.Blacklist) {
|
||||
log.Logf("[http] %s - %s : Unauthorized to tcp connect to %s",
|
||||
@ -258,9 +252,7 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) {
|
||||
|
||||
// forward http request
|
||||
lastNode := route.LastNode()
|
||||
if req.Method != http.MethodConnect &&
|
||||
lastNode.Protocol == "http" &&
|
||||
!h.options.HTTPTunnel {
|
||||
if req.Method != http.MethodConnect && lastNode.Protocol == "http" {
|
||||
err = h.forwardRequest(conn, req, route)
|
||||
if err == nil {
|
||||
return
|
||||
@ -293,65 +285,27 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) {
|
||||
}
|
||||
defer cc.Close()
|
||||
|
||||
if req.Method != http.MethodConnect {
|
||||
h.handleProxy(conn, cc, req)
|
||||
return
|
||||
}
|
||||
if req.Method == http.MethodConnect {
|
||||
b := []byte("HTTP/1.1 200 Connection established\r\n" +
|
||||
"Proxy-Agent: gost/" + Version + "\r\n\r\n")
|
||||
if Debug {
|
||||
log.Logf("[http] %s <- %s\n%s", conn.RemoteAddr(), conn.LocalAddr(), string(b))
|
||||
}
|
||||
conn.Write(b)
|
||||
} else {
|
||||
req.Header.Del("Proxy-Connection")
|
||||
|
||||
b := []byte("HTTP/1.1 200 Connection established\r\n" +
|
||||
"Proxy-Agent: " + proxyAgent + "\r\n\r\n")
|
||||
if Debug {
|
||||
log.Logf("[http] %s <- %s\n%s", conn.RemoteAddr(), conn.LocalAddr(), string(b))
|
||||
if err = req.Write(cc); err != nil {
|
||||
log.Logf("[http] %s -> %s : %s", conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||
return
|
||||
}
|
||||
}
|
||||
conn.Write(b)
|
||||
|
||||
log.Logf("[http] %s <-> %s", conn.RemoteAddr(), host)
|
||||
transport(conn, cc)
|
||||
log.Logf("[http] %s >-< %s", conn.RemoteAddr(), host)
|
||||
}
|
||||
|
||||
func (h *httpHandler) handleProxy(rw, cc io.ReadWriter, req *http.Request) (err error) {
|
||||
req.Header.Del("Proxy-Connection")
|
||||
|
||||
if err = req.Write(cc); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ch := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
ch <- copyBuffer(rw, cc)
|
||||
}()
|
||||
|
||||
for {
|
||||
err := func() error {
|
||||
req, err := http.ReadRequest(bufio.NewReader(rw))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if Debug {
|
||||
dump, _ := httputil.DumpRequest(req, false)
|
||||
log.Log(string(dump))
|
||||
}
|
||||
|
||||
req.Header.Del("Proxy-Connection")
|
||||
|
||||
if err = req.Write(cc); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}()
|
||||
ch <- err
|
||||
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return <-ch
|
||||
}
|
||||
|
||||
func (h *httpHandler) authenticate(conn net.Conn, req *http.Request, resp *http.Response) (ok bool) {
|
||||
u, p, _ := basicProxyAuth(req.Header.Get("Proxy-Authorization"))
|
||||
if Debug && (u != "" || p != "") {
|
||||
@ -409,16 +363,10 @@ func (h *httpHandler) authenticate(conn net.Conn, req *http.Request, resp *http.
|
||||
conn.RemoteAddr(), conn.LocalAddr())
|
||||
resp.StatusCode = http.StatusProxyAuthRequired
|
||||
resp.Header.Add("Proxy-Authenticate", "Basic realm=\"gost\"")
|
||||
if strings.ToLower(req.Header.Get("Proxy-Connection")) == "keep-alive" {
|
||||
// XXX libcurl will keep sending auth request in same conn
|
||||
// which we don't supported yet.
|
||||
resp.Header.Add("Connection", "close")
|
||||
resp.Header.Add("Proxy-Connection", "close")
|
||||
}
|
||||
} else {
|
||||
resp.Header = http.Header{}
|
||||
resp.Header.Set("Server", "nginx/1.14.1")
|
||||
resp.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat))
|
||||
resp.Header.Set("Date", time.Now().Format(http.TimeFormat))
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
resp.Header.Set("Connection", "keep-alive")
|
||||
}
|
||||
|
17
http2.go
17
http2.go
@ -9,6 +9,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
@ -233,7 +234,7 @@ func (tr *h2Transporter) Dial(addr string, options ...DialOption) (net.Conn, err
|
||||
|
||||
transport := http2.Transport{
|
||||
TLSClientConfig: tr.tlsConfig,
|
||||
DialTLS: func(network, adr string, cfg *tls.Config) (net.Conn, error) {
|
||||
DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
|
||||
conn, err := opts.Chain.Dial(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -255,13 +256,13 @@ func (tr *h2Transporter) Dial(addr string, options ...DialOption) (net.Conn, err
|
||||
pr, pw := io.Pipe()
|
||||
req := &http.Request{
|
||||
Method: http.MethodConnect,
|
||||
URL: &url.URL{Scheme: "https", Host: opts.Host},
|
||||
URL: &url.URL{Scheme: "https", Host: addr},
|
||||
Header: make(http.Header),
|
||||
Proto: "HTTP/2.0",
|
||||
ProtoMajor: 2,
|
||||
ProtoMinor: 0,
|
||||
Body: pr,
|
||||
Host: opts.Host,
|
||||
Host: addr,
|
||||
ContentLength: -1,
|
||||
}
|
||||
if tr.path != "" {
|
||||
@ -364,11 +365,7 @@ func (h *http2Handler) roundTrip(w http.ResponseWriter, r *http.Request) {
|
||||
log.Logf("[http2] %s - %s\n%s", r.RemoteAddr, laddr, string(dump))
|
||||
}
|
||||
|
||||
proxyAgent := DefaultProxyAgent
|
||||
if h.options.ProxyAgent != "" {
|
||||
proxyAgent = h.options.ProxyAgent
|
||||
}
|
||||
w.Header().Set("Proxy-Agent", proxyAgent)
|
||||
w.Header().Set("Proxy-Agent", "gost/"+Version)
|
||||
|
||||
if !Can("tcp", host, h.options.Whitelist, h.options.Blacklist) {
|
||||
log.Logf("[http2] %s - %s : Unauthorized to tcp connect to %s",
|
||||
@ -388,7 +385,7 @@ func (h *http2Handler) roundTrip(w http.ResponseWriter, r *http.Request) {
|
||||
ProtoMajor: 2,
|
||||
ProtoMinor: 0,
|
||||
Header: http.Header{},
|
||||
Body: io.NopCloser(bytes.NewReader([]byte{})),
|
||||
Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
|
||||
}
|
||||
|
||||
if !h.authenticate(w, r, resp) {
|
||||
@ -538,7 +535,7 @@ func (h *http2Handler) authenticate(w http.ResponseWriter, r *http.Request, resp
|
||||
} else {
|
||||
resp.Header = http.Header{}
|
||||
resp.Header.Set("Server", "nginx/1.14.1")
|
||||
resp.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat))
|
||||
resp.Header.Set("Date", time.Now().Format(http.TimeFormat))
|
||||
if resp.ContentLength > 0 {
|
||||
resp.Header.Set("Content-Type", "text/html")
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@ -997,7 +997,7 @@ func TestHTTP2ProxyWithWebProbeResist(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
recv, _ := io.ReadAll(conn)
|
||||
recv, _ := ioutil.ReadAll(conn)
|
||||
if !bytes.Equal(recv, []byte("Hello World!")) {
|
||||
t.Error("data not equal")
|
||||
}
|
||||
@ -1053,7 +1053,7 @@ func TestHTTP2ProxyWithHostProbeResist(t *testing.T) {
|
||||
Proto: "HTTP/2.0",
|
||||
ProtoMajor: 2,
|
||||
ProtoMinor: 0,
|
||||
Body: io.NopCloser(bytes.NewReader(sendData)),
|
||||
Body: ioutil.NopCloser(bytes.NewReader(sendData)),
|
||||
Host: "github.com:443",
|
||||
ContentLength: int64(len(sendData)),
|
||||
}
|
||||
@ -1068,7 +1068,7 @@ func TestHTTP2ProxyWithHostProbeResist(t *testing.T) {
|
||||
t.Error("got non-200 status:", resp.Status)
|
||||
}
|
||||
|
||||
recv, _ := io.ReadAll(resp.Body)
|
||||
recv, _ := ioutil.ReadAll(resp.Body)
|
||||
if !bytes.Equal(sendData, recv) {
|
||||
t.Error("data not equal")
|
||||
}
|
||||
@ -1105,7 +1105,7 @@ func TestHTTP2ProxyWithFileProbeResist(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
recv, _ := io.ReadAll(conn)
|
||||
recv, _ := ioutil.ReadAll(conn)
|
||||
if !bytes.Equal(recv, []byte("Hello World!")) {
|
||||
t.Error("data not equal")
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@ -249,7 +249,7 @@ func TestHTTPProxyWithWebProbeResist(t *testing.T) {
|
||||
t.Error("got status:", resp.Status)
|
||||
}
|
||||
|
||||
recv, _ := io.ReadAll(resp.Body)
|
||||
recv, _ := ioutil.ReadAll(resp.Body)
|
||||
if !bytes.Equal(recv, []byte("Hello World!")) {
|
||||
t.Error("data not equal")
|
||||
}
|
||||
@ -296,7 +296,7 @@ func TestHTTPProxyWithHostProbeResist(t *testing.T) {
|
||||
t.Error("got status:", resp.Status)
|
||||
}
|
||||
|
||||
recv, _ := io.ReadAll(resp.Body)
|
||||
recv, _ := ioutil.ReadAll(resp.Body)
|
||||
if !bytes.Equal(sendData, recv) {
|
||||
t.Error("data not equal")
|
||||
}
|
||||
@ -332,7 +332,7 @@ func TestHTTPProxyWithFileProbeResist(t *testing.T) {
|
||||
t.Error("got status:", resp.Status)
|
||||
}
|
||||
|
||||
recv, _ := io.ReadAll(resp.Body)
|
||||
recv, _ := ioutil.ReadAll(resp.Body)
|
||||
if !bytes.Equal(recv, []byte("Hello World!")) {
|
||||
t.Error("data not equal, got:", string(recv))
|
||||
}
|
||||
|
42
kcp.go
42
kcp.go
@ -15,9 +15,9 @@ import (
|
||||
|
||||
"github.com/go-log/log"
|
||||
"github.com/klauspost/compress/snappy"
|
||||
"github.com/xtaci/kcp-go/v5"
|
||||
"github.com/xtaci/smux"
|
||||
"github.com/xtaci/tcpraw"
|
||||
"gopkg.in/xtaci/kcp-go.v4"
|
||||
"gopkg.in/xtaci/smux.v1"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -43,9 +43,6 @@ type KCPConfig struct {
|
||||
Resend int `json:"resend"`
|
||||
NoCongestion int `json:"nc"`
|
||||
SockBuf int `json:"sockbuf"`
|
||||
SmuxBuf int `json:"smuxbuf"`
|
||||
StreamBuf int `json:"streambuf"`
|
||||
SmuxVer int `json:"smuxver"`
|
||||
KeepAlive int `json:"keepalive"`
|
||||
SnmpLog string `json:"snmplog"`
|
||||
SnmpPeriod int `json:"snmpperiod"`
|
||||
@ -65,16 +62,6 @@ func (c *KCPConfig) Init() {
|
||||
case "fast3":
|
||||
c.NoDelay, c.Interval, c.Resend, c.NoCongestion = 1, 10, 2, 1
|
||||
}
|
||||
if c.SmuxVer <= 0 {
|
||||
c.SmuxVer = 1
|
||||
}
|
||||
if c.SmuxBuf <= 0 {
|
||||
c.SmuxBuf = c.SockBuf
|
||||
}
|
||||
if c.StreamBuf <= 0 {
|
||||
c.StreamBuf = c.SockBuf / 2
|
||||
}
|
||||
log.Logf("%#v", c)
|
||||
}
|
||||
|
||||
var (
|
||||
@ -96,9 +83,6 @@ var (
|
||||
Resend: 0,
|
||||
NoCongestion: 0,
|
||||
SockBuf: 4194304,
|
||||
SmuxVer: 1,
|
||||
SmuxBuf: 4194304,
|
||||
StreamBuf: 2097152,
|
||||
KeepAlive: 10,
|
||||
SnmpLog: "",
|
||||
SnmpPeriod: 60,
|
||||
@ -247,14 +231,8 @@ func (tr *kcpTransporter) initSession(addr string, conn net.Conn, config *KCPCon
|
||||
|
||||
// stream multiplex
|
||||
smuxConfig := smux.DefaultConfig()
|
||||
smuxConfig.Version = config.SmuxVer
|
||||
smuxConfig.MaxReceiveBuffer = config.SmuxBuf
|
||||
smuxConfig.MaxStreamBuffer = config.StreamBuf
|
||||
smuxConfig.MaxReceiveBuffer = config.SockBuf
|
||||
smuxConfig.KeepAliveInterval = time.Duration(config.KeepAlive) * time.Second
|
||||
if err := smux.VerifyConfig(smuxConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var cc net.Conn = kcpconn
|
||||
if !config.NoComp {
|
||||
cc = newCompStreamConn(kcpconn)
|
||||
@ -354,9 +332,7 @@ func (l *kcpListener) listenLoop() {
|
||||
|
||||
func (l *kcpListener) mux(conn net.Conn) {
|
||||
smuxConfig := smux.DefaultConfig()
|
||||
smuxConfig.Version = l.config.SmuxVer
|
||||
smuxConfig.MaxReceiveBuffer = l.config.SmuxBuf
|
||||
smuxConfig.MaxStreamBuffer = l.config.StreamBuf
|
||||
smuxConfig.MaxReceiveBuffer = l.config.SockBuf
|
||||
smuxConfig.KeepAliveInterval = time.Duration(l.config.KeepAlive) * time.Second
|
||||
|
||||
log.Logf("[kcp] %s - %s", conn.RemoteAddr(), l.Addr())
|
||||
@ -497,13 +473,9 @@ func (c *compStreamConn) Read(b []byte) (n int, err error) {
|
||||
}
|
||||
|
||||
func (c *compStreamConn) Write(b []byte) (n int, err error) {
|
||||
if _, err = c.w.Write(b); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err = c.w.Flush(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(b), err
|
||||
n, err = c.w.Write(b)
|
||||
err = c.w.Flush()
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (c *compStreamConn) Close() error {
|
||||
|
2
mux.go
2
mux.go
@ -3,7 +3,7 @@ package gost
|
||||
import (
|
||||
"net"
|
||||
|
||||
smux "github.com/xtaci/smux"
|
||||
smux "gopkg.in/xtaci/smux.v1"
|
||||
)
|
||||
|
||||
type muxStreamConn struct {
|
||||
|
1
node.go
1
node.go
@ -90,7 +90,6 @@ func ParseNode(s string) (node Node, err error) {
|
||||
case "ftcp": // fake TCP
|
||||
case "dns":
|
||||
case "redu", "redirectu": // UDP tproxy
|
||||
case "vsock":
|
||||
default:
|
||||
node.Transport = "tcp"
|
||||
}
|
||||
|
175
obfs.go
175
obfs.go
@ -20,9 +20,9 @@ import (
|
||||
"github.com/go-log/log"
|
||||
|
||||
pt "git.torproject.org/pluggable-transports/goptlib.git"
|
||||
dissector "github.com/go-gost/tls-dissector"
|
||||
"gitlab.com/yawning/obfs4.git/transports/base"
|
||||
"gitlab.com/yawning/obfs4.git/transports/obfs4"
|
||||
"git.torproject.org/pluggable-transports/obfs4.git/transports/base"
|
||||
"git.torproject.org/pluggable-transports/obfs4.git/transports/obfs4"
|
||||
dissector "github.com/ginuerzh/tls-dissector"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -313,31 +313,8 @@ var (
|
||||
0x0601, 0x0602, 0x0603, 0x0501, 0x0502, 0x0503, 0x0401, 0x0402,
|
||||
0x0403, 0x0301, 0x0302, 0x0303, 0x0201, 0x0202, 0x0203,
|
||||
}
|
||||
|
||||
tlsRecordTypes = []uint8{0x16, 0x14, 0x16, 0x17}
|
||||
tlsVersionMinors = []uint8{0x01, 0x03, 0x03, 0x03}
|
||||
|
||||
ErrBadType = errors.New("bad type")
|
||||
ErrBadMajorVersion = errors.New("bad major version")
|
||||
ErrBadMinorVersion = errors.New("bad minor version")
|
||||
ErrMaxDataLen = errors.New("bad tls data len")
|
||||
)
|
||||
|
||||
const (
|
||||
tlsRecordStateType = iota
|
||||
tlsRecordStateVersion0
|
||||
tlsRecordStateVersion1
|
||||
tlsRecordStateLength0
|
||||
tlsRecordStateLength1
|
||||
tlsRecordStateData
|
||||
)
|
||||
|
||||
type obfsTLSParser struct {
|
||||
step uint8
|
||||
state uint8
|
||||
length uint16
|
||||
}
|
||||
|
||||
type obfsTLSConn struct {
|
||||
net.Conn
|
||||
rbuf bytes.Buffer
|
||||
@ -345,96 +322,15 @@ type obfsTLSConn struct {
|
||||
host string
|
||||
isServer bool
|
||||
handshaked chan struct{}
|
||||
parser *obfsTLSParser
|
||||
handshakeMutex sync.Mutex
|
||||
}
|
||||
|
||||
func (r *obfsTLSParser) Parse(b []byte) (int, error) {
|
||||
i := 0
|
||||
last := 0
|
||||
length := len(b)
|
||||
|
||||
for i < length {
|
||||
ch := b[i]
|
||||
switch r.state {
|
||||
case tlsRecordStateType:
|
||||
if tlsRecordTypes[r.step] != ch {
|
||||
return 0, ErrBadType
|
||||
}
|
||||
r.state = tlsRecordStateVersion0
|
||||
i++
|
||||
case tlsRecordStateVersion0:
|
||||
if ch != 0x03 {
|
||||
return 0, ErrBadMajorVersion
|
||||
}
|
||||
r.state = tlsRecordStateVersion1
|
||||
i++
|
||||
case tlsRecordStateVersion1:
|
||||
if ch != tlsVersionMinors[r.step] {
|
||||
return 0, ErrBadMinorVersion
|
||||
}
|
||||
r.state = tlsRecordStateLength0
|
||||
i++
|
||||
case tlsRecordStateLength0:
|
||||
r.length = uint16(ch) << 8
|
||||
r.state = tlsRecordStateLength1
|
||||
i++
|
||||
case tlsRecordStateLength1:
|
||||
r.length |= uint16(ch)
|
||||
if r.step == 0 {
|
||||
r.length = 91
|
||||
} else if r.step == 1 {
|
||||
r.length = 1
|
||||
} else if r.length > maxTLSDataLen {
|
||||
return 0, ErrMaxDataLen
|
||||
}
|
||||
if r.length > 0 {
|
||||
r.state = tlsRecordStateData
|
||||
} else {
|
||||
r.state = tlsRecordStateType
|
||||
r.step++
|
||||
}
|
||||
i++
|
||||
case tlsRecordStateData:
|
||||
left := uint16(length - i)
|
||||
if left > r.length {
|
||||
left = r.length
|
||||
}
|
||||
if r.step >= 2 {
|
||||
skip := i - last
|
||||
copy(b[last:], b[i:length])
|
||||
length -= int(skip)
|
||||
last += int(left)
|
||||
i = last
|
||||
} else {
|
||||
i += int(left)
|
||||
}
|
||||
r.length -= left
|
||||
if r.length == 0 {
|
||||
if r.step < 3 {
|
||||
r.step++
|
||||
}
|
||||
r.state = tlsRecordStateType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if last == 0 {
|
||||
return 0, nil
|
||||
} else if last < length {
|
||||
length -= last
|
||||
}
|
||||
|
||||
return length, nil
|
||||
}
|
||||
|
||||
// ClientObfsTLSConn creates a connection for obfs-tls client.
|
||||
func ClientObfsTLSConn(conn net.Conn, host string) net.Conn {
|
||||
return &obfsTLSConn{
|
||||
Conn: conn,
|
||||
host: host,
|
||||
handshaked: make(chan struct{}),
|
||||
parser: &obfsTLSParser{},
|
||||
}
|
||||
}
|
||||
|
||||
@ -520,6 +416,32 @@ func (c *obfsTLSConn) clientHandshake(payload []byte) error {
|
||||
if _, err := record.WriteTo(c.Conn); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// server hello handshake message
|
||||
if _, err := record.ReadFrom(c.Conn); err != nil {
|
||||
return err
|
||||
}
|
||||
if record.Type != dissector.Handshake {
|
||||
return dissector.ErrBadType
|
||||
}
|
||||
|
||||
// change cipher spec message
|
||||
if _, err := record.ReadFrom(c.Conn); err != nil {
|
||||
return err
|
||||
}
|
||||
if record.Type != dissector.ChangeCipherSpec {
|
||||
return dissector.ErrBadType
|
||||
}
|
||||
|
||||
// encrypted handshake message
|
||||
if _, err := record.ReadFrom(c.Conn); err != nil {
|
||||
return err
|
||||
}
|
||||
if record.Type != dissector.Handshake {
|
||||
return dissector.ErrBadType
|
||||
}
|
||||
|
||||
_, err = c.rbuf.Write(record.Opaque)
|
||||
return err
|
||||
}
|
||||
|
||||
@ -599,30 +521,19 @@ func (c *obfsTLSConn) Read(b []byte) (n int, err error) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
case <-c.handshaked:
|
||||
}
|
||||
|
||||
if c.isServer {
|
||||
if c.rbuf.Len() > 0 {
|
||||
return c.rbuf.Read(b)
|
||||
}
|
||||
record := &dissector.Record{}
|
||||
if _, err = record.ReadFrom(c.Conn); err != nil {
|
||||
return
|
||||
}
|
||||
n = copy(b, record.Opaque)
|
||||
_, err = c.rbuf.Write(record.Opaque[n:])
|
||||
} else {
|
||||
n, err = c.Conn.Read(b)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if n > 0 {
|
||||
n, err = c.parser.Parse(b[:n])
|
||||
}
|
||||
if c.rbuf.Len() > 0 {
|
||||
return c.rbuf.Read(b)
|
||||
}
|
||||
record := &dissector.Record{}
|
||||
if _, err = record.ReadFrom(c.Conn); err != nil {
|
||||
return
|
||||
}
|
||||
n = copy(b, record.Opaque)
|
||||
_, err = c.rbuf.Write(record.Opaque[n:])
|
||||
return
|
||||
}
|
||||
|
||||
@ -804,16 +715,6 @@ func Obfs4Listener(addr string) (Listener, error) {
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// TempError satisfies the net.Error interface and presents itself
|
||||
// as temporary to make sure that it gets retried by the Accept loop
|
||||
// in server.go.
|
||||
type TempError struct {
|
||||
error
|
||||
}
|
||||
|
||||
func (e TempError) Timeout() bool { return false }
|
||||
func (e TempError) Temporary() bool { return true }
|
||||
|
||||
func (l *obfs4Listener) Accept() (net.Conn, error) {
|
||||
conn, err := l.Listener.Accept()
|
||||
if err != nil {
|
||||
@ -822,7 +723,7 @@ func (l *obfs4Listener) Accept() (net.Conn, error) {
|
||||
cc, err := obfs4ServerConn(l.addr, conn)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, TempError{err}
|
||||
return nil, err
|
||||
}
|
||||
return cc, nil
|
||||
}
|
||||
|
163
quic.go
163
quic.go
@ -1,7 +1,6 @@
|
||||
package gost
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
@ -13,15 +12,16 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/go-log/log"
|
||||
quic "github.com/quic-go/quic-go"
|
||||
quic "github.com/lucas-clemente/quic-go"
|
||||
)
|
||||
|
||||
type quicSession struct {
|
||||
session quic.EarlyConnection
|
||||
conn net.Conn
|
||||
session quic.Session
|
||||
}
|
||||
|
||||
func (session *quicSession) GetConn() (*quicConn, error) {
|
||||
stream, err := session.session.OpenStreamSync(context.Background())
|
||||
stream, err := session.session.OpenStreamSync()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -33,7 +33,7 @@ func (session *quicSession) GetConn() (*quicConn, error) {
|
||||
}
|
||||
|
||||
func (session *quicSession) Close() error {
|
||||
return session.session.CloseWithError(quic.ApplicationErrorCode(0), "closed")
|
||||
return session.session.Close()
|
||||
}
|
||||
|
||||
type quicTransporter struct {
|
||||
@ -59,71 +59,100 @@ func (tr *quicTransporter) Dial(addr string, options ...DialOption) (conn net.Co
|
||||
option(opts)
|
||||
}
|
||||
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tr.sessionMutex.Lock()
|
||||
defer tr.sessionMutex.Unlock()
|
||||
|
||||
session, ok := tr.sessions[addr]
|
||||
if !ok {
|
||||
var pc net.PacketConn
|
||||
pc, err = net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
|
||||
var cc *net.UDPConn
|
||||
cc, err = net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
conn = cc
|
||||
|
||||
if tr.config != nil && tr.config.Key != nil {
|
||||
pc = &quicCipherConn{PacketConn: pc, key: tr.config.Key}
|
||||
conn = &quicCipherConn{UDPConn: cc, key: tr.config.Key}
|
||||
}
|
||||
|
||||
session, err = tr.initSession(udpAddr, pc)
|
||||
if err != nil {
|
||||
pc.Close()
|
||||
return nil, err
|
||||
}
|
||||
session = &quicSession{conn: conn}
|
||||
tr.sessions[addr] = session
|
||||
}
|
||||
|
||||
conn, err = session.GetConn()
|
||||
if err != nil {
|
||||
session.Close()
|
||||
delete(tr.sessions, addr)
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
return session.conn, nil
|
||||
}
|
||||
|
||||
func (tr *quicTransporter) Handshake(conn net.Conn, options ...HandshakeOption) (net.Conn, error) {
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (tr *quicTransporter) initSession(addr net.Addr, conn net.PacketConn) (*quicSession, error) {
|
||||
opts := &HandshakeOptions{}
|
||||
for _, option := range options {
|
||||
option(opts)
|
||||
}
|
||||
config := tr.config
|
||||
if config == nil {
|
||||
config = &QUICConfig{}
|
||||
if opts.QUICConfig != nil {
|
||||
config = opts.QUICConfig
|
||||
}
|
||||
if config.TLSConfig == nil {
|
||||
config.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
}
|
||||
|
||||
tr.sessionMutex.Lock()
|
||||
defer tr.sessionMutex.Unlock()
|
||||
|
||||
timeout := opts.Timeout
|
||||
if timeout <= 0 {
|
||||
timeout = HandshakeTimeout
|
||||
}
|
||||
conn.SetDeadline(time.Now().Add(timeout))
|
||||
defer conn.SetDeadline(time.Time{})
|
||||
|
||||
session, ok := tr.sessions[opts.Addr]
|
||||
if session != nil && session.conn != conn {
|
||||
conn.Close()
|
||||
return nil, errors.New("quic: unrecognized connection")
|
||||
}
|
||||
if !ok || session.session == nil {
|
||||
s, err := tr.initSession(opts.Addr, conn, config)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
delete(tr.sessions, opts.Addr)
|
||||
return nil, err
|
||||
}
|
||||
session = s
|
||||
tr.sessions[opts.Addr] = session
|
||||
}
|
||||
cc, err := session.GetConn()
|
||||
if err != nil {
|
||||
session.Close()
|
||||
delete(tr.sessions, opts.Addr)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cc, nil
|
||||
}
|
||||
|
||||
func (tr *quicTransporter) initSession(addr string, conn net.Conn, config *QUICConfig) (*quicSession, error) {
|
||||
udpConn, ok := conn.(net.PacketConn)
|
||||
if !ok {
|
||||
return nil, errors.New("quic: wrong connection type")
|
||||
}
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
quicConfig := &quic.Config{
|
||||
HandshakeIdleTimeout: config.Timeout,
|
||||
MaxIdleTimeout: config.IdleTimeout,
|
||||
KeepAlivePeriod: config.KeepAlivePeriod,
|
||||
HandshakeTimeout: config.Timeout,
|
||||
KeepAlive: config.KeepAlive,
|
||||
IdleTimeout: config.IdleTimeout,
|
||||
Versions: []quic.VersionNumber{
|
||||
quic.Version1,
|
||||
quic.Version2,
|
||||
quic.VersionGQUIC43,
|
||||
quic.VersionGQUIC39,
|
||||
},
|
||||
}
|
||||
session, err := quic.DialEarly(context.Background(), conn, addr, tlsConfigQUICALPN(config.TLSConfig), quicConfig)
|
||||
session, err := quic.Dial(udpConn, udpAddr, addr, config.TLSConfig, quicConfig)
|
||||
if err != nil {
|
||||
log.Logf("quic dial %s: %v", addr, err)
|
||||
return nil, err
|
||||
}
|
||||
return &quicSession{session: session}, nil
|
||||
return &quicSession{conn: conn, session: session}, nil
|
||||
}
|
||||
|
||||
func (tr *quicTransporter) Multiplex() bool {
|
||||
@ -132,16 +161,15 @@ func (tr *quicTransporter) Multiplex() bool {
|
||||
|
||||
// QUICConfig is the config for QUIC client and server
|
||||
type QUICConfig struct {
|
||||
TLSConfig *tls.Config
|
||||
Timeout time.Duration
|
||||
KeepAlive bool
|
||||
KeepAlivePeriod time.Duration
|
||||
IdleTimeout time.Duration
|
||||
Key []byte
|
||||
TLSConfig *tls.Config
|
||||
Timeout time.Duration
|
||||
KeepAlive bool
|
||||
IdleTimeout time.Duration
|
||||
Key []byte
|
||||
}
|
||||
|
||||
type quicListener struct {
|
||||
ln quic.EarlyListener
|
||||
ln quic.Listener
|
||||
connChan chan net.Conn
|
||||
errChan chan error
|
||||
}
|
||||
@ -152,41 +180,39 @@ func QUICListener(addr string, config *QUICConfig) (Listener, error) {
|
||||
config = &QUICConfig{}
|
||||
}
|
||||
quicConfig := &quic.Config{
|
||||
HandshakeIdleTimeout: config.Timeout,
|
||||
KeepAlivePeriod: config.KeepAlivePeriod,
|
||||
MaxIdleTimeout: config.IdleTimeout,
|
||||
Versions: []quic.VersionNumber{
|
||||
quic.Version1,
|
||||
quic.Version2,
|
||||
},
|
||||
HandshakeTimeout: config.Timeout,
|
||||
KeepAlive: config.KeepAlive,
|
||||
IdleTimeout: config.IdleTimeout,
|
||||
}
|
||||
|
||||
tlsConfig := config.TLSConfig
|
||||
if tlsConfig == nil {
|
||||
tlsConfig = DefaultTLSConfig
|
||||
}
|
||||
|
||||
var conn net.PacketConn
|
||||
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn, err = net.ListenUDP("udp", udpAddr)
|
||||
lconn, err := net.ListenUDP("udp", udpAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn = lconn
|
||||
|
||||
if config.Key != nil {
|
||||
conn = &quicCipherConn{PacketConn: conn, key: config.Key}
|
||||
conn = &quicCipherConn{UDPConn: lconn, key: config.Key}
|
||||
}
|
||||
|
||||
ln, err := quic.ListenEarly(conn, tlsConfigQUICALPN(tlsConfig), quicConfig)
|
||||
ln, err := quic.Listen(conn, tlsConfig, quicConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
l := &quicListener{
|
||||
ln: *ln,
|
||||
ln: ln,
|
||||
connChan: make(chan net.Conn, 1024),
|
||||
errChan: make(chan error, 1),
|
||||
}
|
||||
@ -197,7 +223,7 @@ func QUICListener(addr string, config *QUICConfig) (Listener, error) {
|
||||
|
||||
func (l *quicListener) listenLoop() {
|
||||
for {
|
||||
session, err := l.ln.Accept(context.Background())
|
||||
session, err := l.ln.Accept()
|
||||
if err != nil {
|
||||
log.Log("[quic] accept:", err)
|
||||
l.errChan <- err
|
||||
@ -208,15 +234,15 @@ func (l *quicListener) listenLoop() {
|
||||
}
|
||||
}
|
||||
|
||||
func (l *quicListener) sessionLoop(session quic.Connection) {
|
||||
func (l *quicListener) sessionLoop(session quic.Session) {
|
||||
log.Logf("[quic] %s <-> %s", session.RemoteAddr(), session.LocalAddr())
|
||||
defer log.Logf("[quic] %s >-< %s", session.RemoteAddr(), session.LocalAddr())
|
||||
|
||||
for {
|
||||
stream, err := session.AcceptStream(context.Background())
|
||||
stream, err := session.AcceptStream()
|
||||
if err != nil {
|
||||
log.Log("[quic] accept stream:", err)
|
||||
session.CloseWithError(quic.ApplicationErrorCode(0), "closed")
|
||||
session.Close()
|
||||
return
|
||||
}
|
||||
|
||||
@ -265,12 +291,12 @@ func (c *quicConn) RemoteAddr() net.Addr {
|
||||
}
|
||||
|
||||
type quicCipherConn struct {
|
||||
net.PacketConn
|
||||
*net.UDPConn
|
||||
key []byte
|
||||
}
|
||||
|
||||
func (conn *quicCipherConn) ReadFrom(data []byte) (n int, addr net.Addr, err error) {
|
||||
n, addr, err = conn.PacketConn.ReadFrom(data)
|
||||
n, addr, err = conn.UDPConn.ReadFrom(data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -290,7 +316,7 @@ func (conn *quicCipherConn) WriteTo(data []byte, addr net.Addr) (n int, err erro
|
||||
return
|
||||
}
|
||||
|
||||
_, err = conn.PacketConn.WriteTo(b, addr)
|
||||
_, err = conn.UDPConn.WriteTo(b, addr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -336,12 +362,3 @@ func (conn *quicCipherConn) decrypt(data []byte) ([]byte, error) {
|
||||
nonce, ciphertext := data[:nonceSize], data[nonceSize:]
|
||||
return gcm.Open(nil, nonce, ciphertext, nil)
|
||||
}
|
||||
|
||||
func tlsConfigQUICALPN(tlsConfig *tls.Config) *tls.Config {
|
||||
if tlsConfig == nil {
|
||||
panic("quic: tlsconfig is nil")
|
||||
}
|
||||
tlsConfigQUIC := tlsConfig.Clone()
|
||||
tlsConfigQUIC.NextProtos = []string{"http/3", "quic/v1"}
|
||||
return tlsConfigQUIC
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package gost
|
||||
|
@ -1,4 +1,3 @@
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package gost
|
||||
@ -36,7 +35,8 @@ func (h *tcpRedirectHandler) Handle(c net.Conn) {
|
||||
c.Close()
|
||||
}
|
||||
|
||||
type udpRedirectHandler struct{}
|
||||
type udpRedirectHandler struct {
|
||||
}
|
||||
|
||||
// UDPRedirectHandler creates a server Handler for UDP transparent server.
|
||||
func UDPRedirectHandler(opts ...HandlerOption) Handler {
|
||||
|
31
relay.go
31
relay.go
@ -84,7 +84,7 @@ func (c *relayConnector) ConnectContext(ctx context.Context, conn net.Conn, netw
|
||||
atype = relay.AddrIPv4
|
||||
}
|
||||
|
||||
req.Features = append(req.Features, &relay.AddrFeature{
|
||||
req.Features = append(req.Features, &relay.TargetAddrFeature{
|
||||
AType: atype,
|
||||
Host: host,
|
||||
Port: uint16(nport),
|
||||
@ -155,8 +155,8 @@ func (h *relayHandler) Handle(conn net.Conn) {
|
||||
feature := f.(*relay.UserAuthFeature)
|
||||
user, pass = feature.Username, feature.Password
|
||||
}
|
||||
if f.Type() == relay.FeatureAddr {
|
||||
feature := f.(*relay.AddrFeature)
|
||||
if f.Type() == relay.FeatureTargetAddr {
|
||||
feature := f.(*relay.TargetAddrFeature)
|
||||
raddr = net.JoinHostPort(feature.Host, strconv.Itoa(int(feature.Port)))
|
||||
}
|
||||
}
|
||||
@ -203,13 +203,6 @@ func (h *relayHandler) Handle(conn net.Conn) {
|
||||
if udp {
|
||||
network = "udp"
|
||||
}
|
||||
if !Can(network, raddr, h.options.Whitelist, h.options.Blacklist) {
|
||||
resp.Status = relay.StatusForbidden
|
||||
resp.WriteTo(conn)
|
||||
log.Logf("[relay] %s -> %s : relay to %s is forbidden",
|
||||
conn.RemoteAddr(), conn.LocalAddr(), raddr)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.TODO()
|
||||
var cc net.Conn
|
||||
@ -264,11 +257,10 @@ func (h *relayHandler) Handle(conn net.Conn) {
|
||||
|
||||
type relayConn struct {
|
||||
net.Conn
|
||||
isServer bool
|
||||
udp bool
|
||||
wbuf bytes.Buffer
|
||||
once sync.Once
|
||||
headerSent bool
|
||||
isServer bool
|
||||
udp bool
|
||||
wbuf bytes.Buffer
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
func (c *relayConn) Read(b []byte) (n int, err error) {
|
||||
@ -331,7 +323,6 @@ func (c *relayConn) Write(b []byte) (n int, err error) {
|
||||
var bb [2]byte
|
||||
binary.BigEndian.PutUint16(bb[:2], uint16(len(b)))
|
||||
c.wbuf.Write(bb[:])
|
||||
c.headerSent = true
|
||||
}
|
||||
c.wbuf.Write(b) // append the data to the cached header
|
||||
// _, err = c.Conn.Write(c.wbuf.Bytes())
|
||||
@ -343,13 +334,7 @@ func (c *relayConn) Write(b []byte) (n int, err error) {
|
||||
if !c.udp {
|
||||
return c.Conn.Write(b)
|
||||
}
|
||||
if !c.headerSent {
|
||||
c.headerSent = true
|
||||
b2 := make([]byte, len(b)+2)
|
||||
copy(b2, b)
|
||||
_, err = c.Conn.Write(b2)
|
||||
return
|
||||
}
|
||||
|
||||
nsize := 2 + len(b)
|
||||
var buf []byte
|
||||
if nsize <= mediumBufferSize {
|
||||
|
33
resolver.go
33
resolver.go
@ -8,6 +8,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@ -262,7 +263,9 @@ func (r *resolver) copyServers() []NameServer {
|
||||
defer r.mux.RUnlock()
|
||||
|
||||
servers := make([]NameServer, len(r.servers))
|
||||
copy(servers, r.servers)
|
||||
for i := range r.servers {
|
||||
servers[i] = r.servers[i]
|
||||
}
|
||||
|
||||
return servers
|
||||
}
|
||||
@ -309,28 +312,17 @@ func (r *resolver) resolve(ctx context.Context, ex Exchanger, host string) (ips
|
||||
r.mux.RUnlock()
|
||||
|
||||
if prefer == "ipv6" { // prefer ipv6
|
||||
if ips, err = r.resolve6(ctx, ex, host); len(ips) > 0 {
|
||||
mq := &dns.Msg{}
|
||||
mq.SetQuestion(dns.Fqdn(host), dns.TypeAAAA)
|
||||
ips, err = r.resolveIPs(ctx, ex, mq)
|
||||
if err != nil || len(ips) > 0 {
|
||||
return
|
||||
}
|
||||
return r.resolve4(ctx, ex, host)
|
||||
}
|
||||
|
||||
if ips, err = r.resolve4(ctx, ex, host); len(ips) > 0 {
|
||||
return
|
||||
}
|
||||
return r.resolve6(ctx, ex, host)
|
||||
}
|
||||
|
||||
func (r *resolver) resolve4(ctx context.Context, ex Exchanger, host string) (ips []net.IP, err error) {
|
||||
mq := dns.Msg{}
|
||||
mq := &dns.Msg{}
|
||||
mq.SetQuestion(dns.Fqdn(host), dns.TypeA)
|
||||
return r.resolveIPs(ctx, ex, &mq)
|
||||
}
|
||||
|
||||
func (r *resolver) resolve6(ctx context.Context, ex Exchanger, host string) (ips []net.IP, err error) {
|
||||
mq := dns.Msg{}
|
||||
mq.SetQuestion(dns.Fqdn(host), dns.TypeAAAA)
|
||||
return r.resolveIPs(ctx, ex, &mq)
|
||||
return r.resolveIPs(ctx, ex, mq)
|
||||
}
|
||||
|
||||
func (r *resolver) resolveIPs(ctx context.Context, ex Exchanger, mq *dns.Msg) (ips []net.IP, err error) {
|
||||
@ -717,8 +709,7 @@ func (ex *dnsExchanger) Exchange(ctx context.Context, query []byte) ([]byte, err
|
||||
defer c.Close()
|
||||
|
||||
conn := &dns.Conn{
|
||||
Conn: c,
|
||||
UDPSize: 1024,
|
||||
Conn: c,
|
||||
}
|
||||
if _, err = conn.Write(query); err != nil {
|
||||
return nil, err
|
||||
@ -914,7 +905,7 @@ func (ex *dohExchanger) Exchange(ctx context.Context, query []byte) ([]byte, err
|
||||
}
|
||||
|
||||
// Read wireformat response from the body
|
||||
buf, err := io.ReadAll(resp.Body)
|
||||
buf, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read the response body: %s", err)
|
||||
}
|
||||
|
93
selector.go
93
selector.go
@ -4,18 +4,15 @@ import (
|
||||
"errors"
|
||||
"math/rand"
|
||||
"net"
|
||||
"sort"
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/go-log/log"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNoneAvailable indicates there is no node available.
|
||||
ErrNoneAvailable = errors.New("none node available")
|
||||
ErrNoneAvailable = errors.New("none available")
|
||||
)
|
||||
|
||||
// NodeSelector as a mechanism to pick nodes and mark their status.
|
||||
@ -208,94 +205,6 @@ func (f *FailFilter) String() string {
|
||||
return "fail"
|
||||
}
|
||||
|
||||
// FastestFilter filter the fastest node
|
||||
type FastestFilter struct {
|
||||
mu sync.Mutex
|
||||
|
||||
pinger *net.Dialer
|
||||
pingResult map[int]int
|
||||
pingResultTTL map[int]int64
|
||||
|
||||
topCount int
|
||||
}
|
||||
|
||||
func NewFastestFilter(pingTimeOut int, topCount int) *FastestFilter {
|
||||
if pingTimeOut == 0 {
|
||||
pingTimeOut = 3000 // 3s
|
||||
}
|
||||
return &FastestFilter{
|
||||
mu: sync.Mutex{},
|
||||
pinger: &net.Dialer{Timeout: time.Millisecond * time.Duration(pingTimeOut)},
|
||||
pingResult: make(map[int]int, 0),
|
||||
pingResultTTL: make(map[int]int64, 0),
|
||||
topCount: topCount,
|
||||
}
|
||||
}
|
||||
|
||||
func (f *FastestFilter) Filter(nodes []Node) []Node {
|
||||
// disabled
|
||||
if f.topCount == 0 {
|
||||
return nodes
|
||||
}
|
||||
|
||||
// get latency with ttl cache
|
||||
now := time.Now().Unix()
|
||||
|
||||
var getNodeLatency = func(node Node) int {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
|
||||
if f.pingResultTTL[node.ID] < now {
|
||||
f.pingResultTTL[node.ID] = now + 5 // tmp
|
||||
|
||||
// get latency
|
||||
go func(node Node) {
|
||||
latency := f.doTcpPing(node.Addr)
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
ttl := 300 - int64(120*r.Float64())
|
||||
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
|
||||
f.pingResult[node.ID] = latency
|
||||
f.pingResultTTL[node.ID] = now + ttl
|
||||
}(node)
|
||||
}
|
||||
return f.pingResult[node.ID]
|
||||
}
|
||||
|
||||
// sort
|
||||
sort.Slice(nodes, func(i, j int) bool {
|
||||
return getNodeLatency(nodes[i]) < getNodeLatency(nodes[j])
|
||||
})
|
||||
|
||||
// split
|
||||
if len(nodes) <= f.topCount {
|
||||
return nodes
|
||||
}
|
||||
|
||||
return nodes[0:f.topCount]
|
||||
}
|
||||
|
||||
func (f *FastestFilter) String() string {
|
||||
return "fastest"
|
||||
}
|
||||
|
||||
// doTcpPing
|
||||
func (f *FastestFilter) doTcpPing(address string) int {
|
||||
start := time.Now()
|
||||
conn, err := f.pinger.Dial("tcp", address)
|
||||
elapsed := time.Since(start)
|
||||
|
||||
if err == nil {
|
||||
_ = conn.Close()
|
||||
}
|
||||
|
||||
latency := int(elapsed.Milliseconds())
|
||||
log.Logf("pingDoTCP: %s, latency: %d", address, latency)
|
||||
return latency
|
||||
}
|
||||
|
||||
// InvalidFilter filters the invalid node.
|
||||
// A node is invalid if its port is invalid (negative or zero value).
|
||||
type InvalidFilter struct{}
|
||||
|
@ -127,30 +127,6 @@ func TestFailFilter(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFastestFilter(t *testing.T) {
|
||||
nodes := []Node{
|
||||
Node{ID: 1, marker: &failMarker{}, Addr: "1.0.0.1:80"},
|
||||
Node{ID: 2, marker: &failMarker{}, Addr: "1.0.0.2:80"},
|
||||
Node{ID: 3, marker: &failMarker{}, Addr: "1.0.0.3:80"},
|
||||
}
|
||||
filter := NewFastestFilter(0, 2)
|
||||
|
||||
var print = func(nodes []Node) []string {
|
||||
var rows []string
|
||||
for _, node := range nodes {
|
||||
rows = append(rows, node.Addr)
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
result1 := filter.Filter(nodes)
|
||||
t.Logf("result 1: %+v", print(result1))
|
||||
|
||||
time.Sleep(time.Second)
|
||||
result2 := filter.Filter(nodes)
|
||||
t.Logf("result 2: %+v", print(result2))
|
||||
}
|
||||
|
||||
func TestSelector(t *testing.T) {
|
||||
nodes := []Node{
|
||||
Node{ID: 1, marker: &failMarker{}},
|
||||
|
@ -112,11 +112,11 @@ func transport(rw1, rw2 io.ReadWriter) error {
|
||||
errc <- copyBuffer(rw2, rw1)
|
||||
}()
|
||||
|
||||
if err := <-errc; err != nil && err != io.EOF {
|
||||
return err
|
||||
err := <-errc
|
||||
if err != nil && err == io.EOF {
|
||||
err = nil
|
||||
}
|
||||
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
func copyBuffer(dst io.Writer, src io.Reader) error {
|
||||
|
@ -1,4 +1,3 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package gost
|
||||
@ -9,7 +8,7 @@ import (
|
||||
"syscall"
|
||||
|
||||
"github.com/go-log/log"
|
||||
"github.com/xtaci/kcp-go/v5"
|
||||
"gopkg.in/xtaci/kcp-go.v4"
|
||||
)
|
||||
|
||||
func kcpSigHandler() {
|
||||
|
@ -1,34 +0,0 @@
|
||||
name: gost
|
||||
base: core20
|
||||
version: '2.12.0'
|
||||
summary: A simple security tunnel written in golang
|
||||
description: |
|
||||
Project: https://github.com/ginuerzh/gost
|
||||
Wiki: https://v2.gost.run
|
||||
icon: gost.png
|
||||
website: https://v2.gost.run
|
||||
license: MIT
|
||||
|
||||
|
||||
confinement: strict
|
||||
grade: stable
|
||||
|
||||
parts:
|
||||
gost:
|
||||
plugin: go
|
||||
go-channel: latest/stable
|
||||
source: https://github.com/ginuerzh/gost
|
||||
source-subdir: cmd/gost
|
||||
source-type: git
|
||||
source-tag: v2.12.0
|
||||
build-packages:
|
||||
- gcc
|
||||
|
||||
apps:
|
||||
gost:
|
||||
command: bin/gost
|
||||
plugs:
|
||||
- home
|
||||
- network
|
||||
- network-bind
|
||||
|
43
snapcraft.yaml
Normal file
43
snapcraft.yaml
Normal file
@ -0,0 +1,43 @@
|
||||
name: gost
|
||||
type: app
|
||||
version: '2.11.0'
|
||||
title: GO Simple Tunnel
|
||||
summary: A simple security tunnel written in golang
|
||||
description: |
|
||||
https://github.com/ginuerzh/gost
|
||||
confinement: strict
|
||||
grade: stable
|
||||
base: core18
|
||||
license: MIT
|
||||
parts:
|
||||
gost:
|
||||
plugin: nil
|
||||
build-snaps: [go/1.13/stable]
|
||||
source: https://github.com/ginuerzh/gost.git
|
||||
source-subdir: cmd/gost
|
||||
source-type: git
|
||||
source-branch: '2'
|
||||
build-packages:
|
||||
- build-essential
|
||||
override-build: |
|
||||
set -ex
|
||||
|
||||
echo "Starting override-build:"
|
||||
pwd
|
||||
cd $SNAPCRAFT_PART_BUILD
|
||||
GO111MODULE=on CGO_ENABLED=0 go build --ldflags="-s -w"
|
||||
./gost -V
|
||||
|
||||
echo "Installing to ${SNAPCRAFT_PART_INSTALL}..."
|
||||
install -d $SNAPCRAFT_PART_INSTALL/bin
|
||||
cp -v gost $SNAPCRAFT_PART_INSTALL/bin/
|
||||
|
||||
echo "Override-build done!"
|
||||
apps:
|
||||
gost:
|
||||
command: bin/gost
|
||||
plugs:
|
||||
- home
|
||||
- network
|
||||
- network-bind
|
||||
|
7
sni.go
7
sni.go
@ -17,8 +17,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/asaskevich/govalidator"
|
||||
dissector "github.com/go-gost/tls-dissector"
|
||||
dissector "github.com/ginuerzh/tls-dissector"
|
||||
"github.com/go-log/log"
|
||||
)
|
||||
|
||||
@ -87,10 +86,6 @@ func (h *sniHandler) Handle(conn net.Conn) {
|
||||
return
|
||||
}
|
||||
|
||||
if !req.URL.IsAbs() && govalidator.IsDNSName(req.Host) {
|
||||
req.URL.Scheme = "http"
|
||||
}
|
||||
|
||||
handler := &httpHandler{options: h.options}
|
||||
handler.Init()
|
||||
handler.handleRequest(conn, req)
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
@ -69,7 +69,7 @@ func sniRoundtrip(client *Client, server *Server, targetURL string, data []byte)
|
||||
return errors.New(resp.Status)
|
||||
}
|
||||
|
||||
recv, err := io.ReadAll(resp.Body)
|
||||
recv, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -1,11 +0,0 @@
|
||||
package gost
|
||||
|
||||
import "syscall"
|
||||
|
||||
func setSocketMark(fd int, value int) (e error) {
|
||||
return syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_MARK, value)
|
||||
}
|
||||
|
||||
func setSocketInterface(fd int, value string) (e error) {
|
||||
return syscall.SetsockoptString(fd, syscall.SOL_SOCKET, syscall.SO_BINDTODEVICE, value)
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package gost
|
||||
|
||||
func setSocketMark(fd int, value int) (e error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func setSocketInterface(fd int, value string) (e error) {
|
||||
return nil
|
||||
}
|
18
socks.go
18
socks.go
@ -10,14 +10,13 @@ import (
|
||||
"net"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/go-gost/gosocks4"
|
||||
"github.com/go-gost/gosocks5"
|
||||
"github.com/ginuerzh/gosocks4"
|
||||
"github.com/ginuerzh/gosocks5"
|
||||
"github.com/go-log/log"
|
||||
smux "github.com/xtaci/smux"
|
||||
smux "gopkg.in/xtaci/smux.v1"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -1125,7 +1124,7 @@ func (h *socks5Handler) handleUDPRelay(conn net.Conn, req *gosocks5.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
relay, err := net.ListenUDP("udp", &net.UDPAddr{IP: conn.LocalAddr().(*net.TCPAddr).IP, Port: 0}) // use out-going interface's IP
|
||||
relay, err := net.ListenUDP("udp", nil)
|
||||
if err != nil {
|
||||
log.Logf("[socks5-udp] %s -> %s : %s", conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||
reply := gosocks5.NewReply(gosocks5.Failure, nil)
|
||||
@ -1138,6 +1137,7 @@ func (h *socks5Handler) handleUDPRelay(conn net.Conn, req *gosocks5.Request) {
|
||||
defer relay.Close()
|
||||
|
||||
socksAddr := toSocksAddr(relay.LocalAddr())
|
||||
socksAddr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String()) // replace the IP to the out-going interface's
|
||||
reply := gosocks5.NewReply(gosocks5.Succeeded, socksAddr)
|
||||
if err := reply.Write(conn); err != nil {
|
||||
log.Logf("[socks5-udp] %s <- %s : %s", conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||
@ -1630,21 +1630,17 @@ func (h *socks5Handler) muxBindOn(conn net.Conn, addr string) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: support domain
|
||||
// TODO: support ipv6 and domain
|
||||
func toSocksAddr(addr net.Addr) *gosocks5.Addr {
|
||||
host := "0.0.0.0"
|
||||
port := 0
|
||||
addrType := gosocks5.AddrIPv4
|
||||
if addr != nil {
|
||||
h, p, _ := net.SplitHostPort(addr.String())
|
||||
host = h
|
||||
port, _ = strconv.Atoi(p)
|
||||
if strings.Count(host, ":") > 0 {
|
||||
addrType = gosocks5.AddrIPv6
|
||||
}
|
||||
}
|
||||
return &gosocks5.Addr{
|
||||
Type: addrType,
|
||||
Type: gosocks5.AddrIPv4,
|
||||
Host: host,
|
||||
Port: uint16(port),
|
||||
}
|
||||
|
4
ss.go
4
ss.go
@ -10,7 +10,7 @@ import (
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/go-gost/gosocks5"
|
||||
"github.com/ginuerzh/gosocks5"
|
||||
"github.com/go-log/log"
|
||||
"github.com/shadowsocks/go-shadowsocks2/core"
|
||||
ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
||||
@ -580,7 +580,7 @@ func (c *shadowCipher) StreamConn(conn net.Conn) net.Conn {
|
||||
}
|
||||
|
||||
func (c *shadowCipher) PacketConn(conn net.PacketConn) net.PacketConn {
|
||||
return ss.NewSecurePacketConn(conn, c.cipher.Copy())
|
||||
return ss.NewSecurePacketConn(conn, c.cipher.Copy(), false)
|
||||
}
|
||||
|
||||
func initShadowCipher(info *url.Userinfo) (cipher core.Cipher) {
|
||||
|
20
ssh.go
20
ssh.go
@ -6,8 +6,8 @@ import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -27,20 +27,20 @@ const (
|
||||
GostSSHTunnelRequest = "gost-tunnel" // extended request type for ssh tunnel
|
||||
)
|
||||
|
||||
var errSessionDead = errors.New("session is dead")
|
||||
var (
|
||||
errSessionDead = errors.New("session is dead")
|
||||
)
|
||||
|
||||
// ParseSSHKeyFile parses ssh key file.
|
||||
func ParseSSHKeyFile(fp string) (ssh.Signer, error) {
|
||||
key, err := os.ReadFile(fp)
|
||||
key, err := ioutil.ReadFile(fp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ssh.ParsePrivateKey(key)
|
||||
}
|
||||
|
||||
// ParseSSHAuthorizedKeysFile parses ssh Authorized Keys file.
|
||||
func ParseSSHAuthorizedKeysFile(fp string) (map[string]bool, error) {
|
||||
authorizedKeysBytes, err := os.ReadFile(fp)
|
||||
authorizedKeysBytes, err := ioutil.ReadFile(fp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -57,7 +57,8 @@ func ParseSSHAuthorizedKeysFile(fp string) (map[string]bool, error) {
|
||||
return authorizedKeysMap, nil
|
||||
}
|
||||
|
||||
type sshDirectForwardConnector struct{}
|
||||
type sshDirectForwardConnector struct {
|
||||
}
|
||||
|
||||
// SSHDirectForwardConnector creates a Connector for SSH TCP direct port forwarding.
|
||||
func SSHDirectForwardConnector() Connector {
|
||||
@ -100,7 +101,8 @@ func (c *sshDirectForwardConnector) ConnectContext(ctx context.Context, conn net
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
type sshRemoteForwardConnector struct{}
|
||||
type sshRemoteForwardConnector struct {
|
||||
}
|
||||
|
||||
// SSHRemoteForwardConnector creates a Connector for SSH TCP remote port forwarding.
|
||||
func SSHRemoteForwardConnector() Connector {
|
||||
@ -646,7 +648,7 @@ func (h *sshForwardHandler) tcpipForwardRequest(sshConn ssh.Conn, req *ssh.Reque
|
||||
return
|
||||
}
|
||||
|
||||
ln, err := net.Listen("tcp", addr) // tie to the client connection
|
||||
ln, err := net.Listen("tcp", addr) //tie to the client connection
|
||||
if err != nil {
|
||||
log.Log("[ssh-rtcp]", err)
|
||||
req.Reply(false, nil)
|
||||
|
57
tls.go
57
tls.go
@ -2,6 +2,7 @@ package gost
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"net"
|
||||
"sync"
|
||||
@ -9,7 +10,7 @@ import (
|
||||
|
||||
"github.com/go-log/log"
|
||||
|
||||
smux "github.com/xtaci/smux"
|
||||
smux "gopkg.in/xtaci/smux.v1"
|
||||
)
|
||||
|
||||
type tlsTransporter struct {
|
||||
@ -289,40 +290,36 @@ func wrapTLSClient(conn net.Conn, tlsConfig *tls.Config, timeout time.Duration)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// We can do this in `tls.Config.VerifyConnection`, which effective for
|
||||
// other TLS protocols such as WebSocket. See `route.go:parseChainNode`
|
||||
/*
|
||||
// If crypto/tls is doing verification, there's no need to do our own.
|
||||
if tlsConfig.InsecureSkipVerify == false {
|
||||
return tlsConn, nil
|
||||
}
|
||||
// If crypto/tls is doing verification, there's no need to do our own.
|
||||
if tlsConfig.InsecureSkipVerify == false {
|
||||
return tlsConn, nil
|
||||
}
|
||||
|
||||
// Similarly if we use host's CA, we can do full handshake
|
||||
if tlsConfig.RootCAs == nil {
|
||||
return tlsConn, nil
|
||||
}
|
||||
// Similarly if we use host's CA, we can do full handshake
|
||||
if tlsConfig.RootCAs == nil {
|
||||
return tlsConn, nil
|
||||
}
|
||||
|
||||
opts := x509.VerifyOptions{
|
||||
Roots: tlsConfig.RootCAs,
|
||||
CurrentTime: time.Now(),
|
||||
DNSName: "",
|
||||
Intermediates: x509.NewCertPool(),
|
||||
}
|
||||
opts := x509.VerifyOptions{
|
||||
Roots: tlsConfig.RootCAs,
|
||||
CurrentTime: time.Now(),
|
||||
DNSName: "",
|
||||
Intermediates: x509.NewCertPool(),
|
||||
}
|
||||
|
||||
certs := tlsConn.ConnectionState().PeerCertificates
|
||||
for i, cert := range certs {
|
||||
if i == 0 {
|
||||
continue
|
||||
}
|
||||
opts.Intermediates.AddCert(cert)
|
||||
certs := tlsConn.ConnectionState().PeerCertificates
|
||||
for i, cert := range certs {
|
||||
if i == 0 {
|
||||
continue
|
||||
}
|
||||
opts.Intermediates.AddCert(cert)
|
||||
}
|
||||
|
||||
_, err = certs[0].Verify(opts)
|
||||
if err != nil {
|
||||
tlsConn.Close()
|
||||
return nil, err
|
||||
}
|
||||
*/
|
||||
_, err = certs[0].Verify(opts)
|
||||
if err != nil {
|
||||
tlsConn.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tlsConn, err
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"github.com/go-log/log"
|
||||
"github.com/shadowsocks/go-shadowsocks2/core"
|
||||
"github.com/shadowsocks/go-shadowsocks2/shadowaead"
|
||||
"github.com/shadowsocks/go-shadowsocks2/shadowstream"
|
||||
"github.com/songgao/water"
|
||||
"github.com/songgao/water/waterutil"
|
||||
"github.com/xtaci/tcpraw"
|
||||
@ -339,7 +340,7 @@ func (h *tunHandler) transportTun(tun net.Conn, conn net.PacketConn, raddr net.A
|
||||
|
||||
n, addr, err := conn.ReadFrom(b)
|
||||
if err != nil &&
|
||||
err != shadowaead.ErrShortPacket {
|
||||
err != shadowaead.ErrShortPacket && err != shadowstream.ErrShortPacket {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -701,7 +702,7 @@ func (h *tapHandler) transportTap(tap net.Conn, conn net.PacketConn, raddr net.A
|
||||
|
||||
n, addr, err := conn.ReadFrom(b)
|
||||
if err != nil &&
|
||||
err != shadowaead.ErrShortPacket {
|
||||
err != shadowaead.ErrShortPacket && err != shadowstream.ErrShortPacket {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -3,15 +3,15 @@ package gost
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/libcontainer/netlink"
|
||||
"github.com/go-log/log"
|
||||
"github.com/milosgajdos83/tenus"
|
||||
"github.com/songgao/water"
|
||||
)
|
||||
|
||||
func createTun(cfg TunConfig) (conn net.Conn, itf *net.Interface, err error) {
|
||||
ip, _, err := net.ParseCIDR(cfg.Addr)
|
||||
ip, ipNet, err := net.ParseCIDR(cfg.Addr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -26,21 +26,35 @@ func createTun(cfg TunConfig) (conn net.Conn, itf *net.Interface, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
link, err := tenus.NewLinkFrom(ifce.Name())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
mtu := cfg.MTU
|
||||
if mtu <= 0 {
|
||||
mtu = DefaultMTU
|
||||
}
|
||||
|
||||
if err = exeCmd(fmt.Sprintf("ip link set dev %s mtu %d", ifce.Name(), mtu)); err != nil {
|
||||
log.Log(err)
|
||||
cmd := fmt.Sprintf("ip link set dev %s mtu %d", ifce.Name(), mtu)
|
||||
log.Log("[tun]", cmd)
|
||||
if er := link.SetLinkMTU(mtu); er != nil {
|
||||
err = fmt.Errorf("%s: %v", cmd, er)
|
||||
return
|
||||
}
|
||||
|
||||
if err = exeCmd(fmt.Sprintf("ip address add %s dev %s", cfg.Addr, ifce.Name())); err != nil {
|
||||
log.Log(err)
|
||||
cmd = fmt.Sprintf("ip address add %s dev %s", cfg.Addr, ifce.Name())
|
||||
log.Log("[tun]", cmd)
|
||||
if er := link.SetLinkIp(ip, ipNet); er != nil {
|
||||
err = fmt.Errorf("%s: %v", cmd, er)
|
||||
return
|
||||
}
|
||||
|
||||
if err = exeCmd(fmt.Sprintf("ip link set dev %s up", ifce.Name())); err != nil {
|
||||
log.Log(err)
|
||||
cmd = fmt.Sprintf("ip link set dev %s up", ifce.Name())
|
||||
log.Log("[tun]", cmd)
|
||||
if er := link.SetLinkUp(); er != nil {
|
||||
err = fmt.Errorf("%s: %v", cmd, er)
|
||||
return
|
||||
}
|
||||
|
||||
if err = addTunRoutes(ifce.Name(), cfg.Routes...); err != nil {
|
||||
@ -61,8 +75,9 @@ func createTun(cfg TunConfig) (conn net.Conn, itf *net.Interface, err error) {
|
||||
|
||||
func createTap(cfg TapConfig) (conn net.Conn, itf *net.Interface, err error) {
|
||||
var ip net.IP
|
||||
var ipNet *net.IPNet
|
||||
if cfg.Addr != "" {
|
||||
ip, _, err = net.ParseCIDR(cfg.Addr)
|
||||
ip, ipNet, err = net.ParseCIDR(cfg.Addr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -78,23 +93,37 @@ func createTap(cfg TapConfig) (conn net.Conn, itf *net.Interface, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
link, err := tenus.NewLinkFrom(ifce.Name())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
mtu := cfg.MTU
|
||||
if mtu <= 0 {
|
||||
mtu = DefaultMTU
|
||||
}
|
||||
|
||||
if err = exeCmd(fmt.Sprintf("ip link set dev %s mtu %d", ifce.Name(), mtu)); err != nil {
|
||||
log.Log(err)
|
||||
cmd := fmt.Sprintf("ip link set dev %s mtu %d", ifce.Name(), mtu)
|
||||
log.Log("[tap]", cmd)
|
||||
if er := link.SetLinkMTU(mtu); er != nil {
|
||||
err = fmt.Errorf("%s: %v", cmd, er)
|
||||
return
|
||||
}
|
||||
|
||||
if cfg.Addr != "" {
|
||||
if err = exeCmd(fmt.Sprintf("ip address add %s dev %s", cfg.Addr, ifce.Name())); err != nil {
|
||||
log.Log(err)
|
||||
cmd = fmt.Sprintf("ip address add %s dev %s", cfg.Addr, ifce.Name())
|
||||
log.Log("[tap]", cmd)
|
||||
if er := link.SetLinkIp(ip, ipNet); er != nil {
|
||||
err = fmt.Errorf("%s: %v", cmd, er)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err = exeCmd(fmt.Sprintf("ip link set dev %s up", ifce.Name())); err != nil {
|
||||
log.Log(err)
|
||||
cmd = fmt.Sprintf("ip link set dev %s up", ifce.Name())
|
||||
log.Log("[tap]", cmd)
|
||||
if er := link.SetLinkUp(); er != nil {
|
||||
err = fmt.Errorf("%s: %v", cmd, er)
|
||||
return
|
||||
}
|
||||
|
||||
if err = addTapRoutes(ifce.Name(), cfg.Gateway, cfg.Routes...); err != nil {
|
||||
@ -120,10 +149,8 @@ func addTunRoutes(ifName string, routes ...IPRoute) error {
|
||||
}
|
||||
cmd := fmt.Sprintf("ip route add %s dev %s", route.Dest.String(), ifName)
|
||||
log.Logf("[tun] %s", cmd)
|
||||
|
||||
args := strings.Split(cmd, " ")
|
||||
if er := exec.Command(args[0], args[1:]...).Run(); er != nil {
|
||||
log.Logf("[tun] %s: %v", cmd, er)
|
||||
if err := netlink.AddRoute(route.Dest.String(), "", "", ifName); err != nil {
|
||||
return fmt.Errorf("%s: %v", cmd, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@ -136,22 +163,9 @@ func addTapRoutes(ifName string, gw string, routes ...string) error {
|
||||
}
|
||||
cmd := fmt.Sprintf("ip route add %s via %s dev %s", route, gw, ifName)
|
||||
log.Logf("[tap] %s", cmd)
|
||||
|
||||
args := strings.Split(cmd, " ")
|
||||
if er := exec.Command(args[0], args[1:]...).Run(); er != nil {
|
||||
log.Logf("[tap] %s: %v", cmd, er)
|
||||
if err := netlink.AddRoute(route, "", gw, ifName); err != nil {
|
||||
return fmt.Errorf("%s: %v", cmd, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func exeCmd(cmd string) error {
|
||||
log.Log(cmd)
|
||||
|
||||
args := strings.Split(cmd, " ")
|
||||
if err := exec.Command(args[0], args[1:]...).Run(); err != nil {
|
||||
return fmt.Errorf("%s: %v", cmd, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
//go:build !linux && !windows && !darwin
|
||||
// +build !linux,!windows,!darwin
|
||||
|
||||
package gost
|
||||
|
@ -28,7 +28,7 @@ func createTun(cfg TunConfig) (conn net.Conn, itf *net.Interface, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
cmd := fmt.Sprintf("netsh interface ip set address name=\"%s\" "+
|
||||
cmd := fmt.Sprintf("netsh interface ip set address name=%s "+
|
||||
"source=static addr=%s mask=%s gateway=none",
|
||||
ifce.Name(), ip.String(), ipMask(ipNet.Mask))
|
||||
log.Log("[tun]", cmd)
|
||||
@ -70,7 +70,7 @@ func createTap(cfg TapConfig) (conn net.Conn, itf *net.Interface, err error) {
|
||||
}
|
||||
|
||||
if ip != nil && ipNet != nil {
|
||||
cmd := fmt.Sprintf("netsh interface ip set address name=\"%s\" "+
|
||||
cmd := fmt.Sprintf("netsh interface ip set address name=%s "+
|
||||
"source=static addr=%s mask=%s gateway=none",
|
||||
ifce.Name(), ip.String(), ipMask(ipNet.Mask))
|
||||
log.Log("[tap]", cmd)
|
||||
@ -105,7 +105,7 @@ func addTunRoutes(ifName string, gw string, routes ...IPRoute) error {
|
||||
|
||||
deleteRoute(ifName, route.Dest.String())
|
||||
|
||||
cmd := fmt.Sprintf("netsh interface ip add route prefix=%s interface=\"%s\" store=active",
|
||||
cmd := fmt.Sprintf("netsh interface ip add route prefix=%s interface=%s store=active",
|
||||
route.Dest.String(), ifName)
|
||||
if gw != "" {
|
||||
cmd += " nexthop=" + gw
|
||||
@ -127,7 +127,7 @@ func addTapRoutes(ifName string, gw string, routes ...string) error {
|
||||
|
||||
deleteRoute(ifName, route)
|
||||
|
||||
cmd := fmt.Sprintf("netsh interface ip add route prefix=%s interface=\"%s\" store=active",
|
||||
cmd := fmt.Sprintf("netsh interface ip add route prefix=%s interface=%s store=active",
|
||||
route, ifName)
|
||||
if gw != "" {
|
||||
cmd += " nexthop=" + gw
|
||||
@ -142,7 +142,7 @@ func addTapRoutes(ifName string, gw string, routes ...string) error {
|
||||
}
|
||||
|
||||
func deleteRoute(ifName string, route string) error {
|
||||
cmd := fmt.Sprintf("netsh interface ip delete route prefix=%s interface=\"%s\" store=active",
|
||||
cmd := fmt.Sprintf("netsh interface ip delete route prefix=%s interface=%s store=active",
|
||||
route, ifName)
|
||||
args := strings.Split(cmd, " ")
|
||||
return exec.Command(args[0], args[1:]...).Run()
|
||||
|
76
vsock.go
76
vsock.go
@ -1,76 +0,0 @@
|
||||
package gost
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/mdlayher/vsock"
|
||||
)
|
||||
|
||||
// vsockTransporter is a raw VSOCK transporter.
|
||||
type vsockTransporter struct{}
|
||||
|
||||
// VSOCKTransporter creates a raw VSOCK client.
|
||||
func VSOCKTransporter() Transporter {
|
||||
return &vsockTransporter{}
|
||||
}
|
||||
|
||||
func (tr *vsockTransporter) Dial(addr string, options ...DialOption) (net.Conn, error) {
|
||||
opts := &DialOptions{}
|
||||
for _, option := range options {
|
||||
option(opts)
|
||||
}
|
||||
if opts.Chain == nil {
|
||||
vAddr, err := parseAddr(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return vsock.Dial(vAddr.ContextID, vAddr.Port, nil)
|
||||
}
|
||||
return opts.Chain.Dial(addr)
|
||||
}
|
||||
|
||||
func parseUint32(s string) (uint32, error ) {
|
||||
n, err := strconv.ParseUint(s, 10, 32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint32(n), nil
|
||||
}
|
||||
|
||||
func parseAddr(addr string) (*vsock.Addr, error) {
|
||||
hostStr, portStr, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
host := uint32(0)
|
||||
if hostStr != "" {
|
||||
host, err = parseUint32(hostStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
port, err := parseUint32(portStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &vsock.Addr{ContextID: host, Port: port}, nil
|
||||
}
|
||||
|
||||
func (tr *vsockTransporter) Handshake(conn net.Conn, options ...HandshakeOption) (net.Conn, error) {
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (tr *vsockTransporter) Multiplex() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// VSOCKListener creates a Listener for VSOCK proxy server.
|
||||
func VSOCKListener(addr string) (Listener, error) {
|
||||
vAddr, err := parseAddr(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return vsock.Listen(vAddr.Port, nil)
|
||||
}
|
Loading…
Reference in New Issue
Block a user