Full Code of ginuerzh/gost for AI

master 1d516e35e654 cached
115 files
696.7 KB
233.6k tokens
1448 symbols
1 requests
Download .txt
Showing preview only (730K chars total). Download the full file or copy to clipboard to get everything.
Repository: ginuerzh/gost
Branch: master
Commit: 1d516e35e654
Files: 115
Total size: 696.7 KB

Directory structure:
gitextract_oys45pca/

├── .config/
│   ├── bypass.txt
│   ├── dns.txt
│   ├── gost.json
│   ├── hosts.txt
│   ├── kcp.json
│   ├── peer.txt
│   ├── probe_resist.txt
│   └── secrets.txt
├── .dockerignore
├── .github/
│   └── workflows/
│       ├── buildx.yml
│       └── release.yml
├── .gitignore
├── .goreleaser.yaml
├── .travis.yml
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── README_en.md
├── auth.go
├── auth_test.go
├── bypass.go
├── bypass_test.go
├── chain.go
├── client.go
├── cmd/
│   └── gost/
│       ├── .ssl/
│       │   ├── README.md
│       │   ├── localhost.crt
│       │   ├── localhost.csr
│       │   ├── localhost.key
│       │   ├── rootCA.crt
│       │   ├── rootCA.key
│       │   └── rootCA.srl
│       ├── cfg.go
│       ├── main.go
│       ├── peer.go
│       └── route.go
├── common_test.go
├── dns.go
├── examples/
│   ├── bench/
│   │   ├── cli.go
│   │   └── srv.go
│   ├── forward/
│   │   ├── direct/
│   │   │   ├── client.go
│   │   │   └── server.go
│   │   ├── remote/
│   │   │   ├── client.go
│   │   │   └── server.go
│   │   └── udp/
│   │       ├── cli.go
│   │       ├── direct.go
│   │       ├── remote.go
│   │       └── srv.go
│   ├── http2/
│   │   └── http2.go
│   ├── quic/
│   │   ├── quicc.go
│   │   └── quics.go
│   ├── ssh/
│   │   ├── sshc.go
│   │   └── sshd.go
│   └── ssu/
│       └── ssu.go
├── forward.go
├── forward_test.go
├── ftcp.go
├── go.mod
├── go.sum
├── gost.go
├── handler.go
├── handler_test.go
├── hosts.go
├── hosts_test.go
├── http.go
├── http2.go
├── http2_test.go
├── http_test.go
├── kcp.go
├── kcp_test.go
├── log.go
├── mux.go
├── node.go
├── node_test.go
├── obfs.go
├── obfs_test.go
├── permissions.go
├── permissions_test.go
├── quic.go
├── quic_test.go
├── redirect.go
├── redirect_other.go
├── relay.go
├── reload.go
├── resolver.go
├── resolver_test.go
├── selector.go
├── selector_test.go
├── server.go
├── signal.go
├── signal_unix.go
├── snap/
│   └── snapcraft.yaml
├── sni.go
├── sni_test.go
├── sockopts_linux.go
├── sockopts_other.go
├── socks.go
├── socks_test.go
├── ss.go
├── ss_test.go
├── ssh.go
├── ssh_test.go
├── tcp.go
├── tls.go
├── tls_test.go
├── tuntap.go
├── tuntap_darwin.go
├── tuntap_linux.go
├── tuntap_unix.go
├── tuntap_windows.go
├── udp.go
├── vsock.go
├── ws.go
├── ws_test.go
└── wss_test.go

================================================
FILE CONTENTS
================================================

================================================
FILE: .config/bypass.txt
================================================
# period for live reloading
reload      10s

# matcher reversed
 reverse     true

*.example.com

# this will match example.org and *.example.org
.example.org

# From IANA IPv4 Special-Purpose Address Registry
# http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml

0.0.0.0/8           # RFC1122: "This host on this network"
10.0.0.0/8          # RFC1918: Private-Use
100.64.0.0/10       # RFC6598: Shared Address Space
127.0.0.0/8         # RFC1122: Loopback
169.254.0.0/16      # RFC3927: Link Local
172.16.0.0/12       # RFC1918: Private-Use
192.0.0.0/24        # RFC6890: IETF Protocol Assignments
192.0.2.0/24        # RFC5737: Documentation (TEST-NET-1)
192.88.99.0/24      # RFC3068: 6to4 Relay Anycast
192.168.0.0/16      # RFC1918: Private-Use
198.18.0.0/15       # RFC2544: Benchmarking
198.51.100.0/24     # RFC5737: Documentation (TEST-NET-2)
203.0.113.0/24      # RFC5737: Documentation (TEST-NET-3)
240.0.0.0/4         # RFC1112: Reserved
255.255.255.255/32  # RFC0919: Limited Broadcast

# From IANA Multicast Address Space Registry
# http://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml

224.0.0.0/4         # RFC5771: Multicast/Reserved


================================================
FILE: .config/dns.txt
================================================
# resolver timeout, default 30s.
timeout     10s

# resolver cache TTL, 
# minus value means that cache is disabled,
# default to the TTL in DNS server response.
# ttl         300s

# period for live reloading
reload      10s

# ip[:port]  [protocol]  [hostname]

https://1.0.0.1/dns-query
1.1.1.1:853 tls     cloudflare-dns.com
8.8.8.8
8.8.8.8     tcp
1.1.1.1     udp
1.1.1.1:53  tcp

================================================
FILE: .config/gost.json
================================================
{
    "Retries": 1,
    "Debug": false,
    "ServeNodes": [
        ":12345"
    ],
    "ChainNodes": [
        "http://:8080"
    ],

    "Routes": [
        {
            "Retries": 1,
            "ServeNodes": [
                "ws://:1443"
            ],
            "ChainNodes": [
                "socks://:192.168.1.1:1080"
            ]
        },
        {
            "Retries": 3,
            "ServeNodes": [
                "quic://:443"
            ]
        }
    ]
}

================================================
FILE: .config/hosts.txt
================================================
# period for live reloading
reload      10s

# The following lines are desirable for IPv4 capable hosts
127.0.0.1       localhost

# 127.0.1.1 is often used for the FQDN of the machine
127.0.1.1       thishost.mydomain.org  thishost
192.168.1.10    foo.mydomain.org       foo
192.168.1.13    bar.mydomain.org       bar
146.82.138.7    master.debian.org      master
209.237.226.90  www.opensource.org

# The following lines are desirable for IPv6 capable hosts
::1             localhost ip6-localhost ip6-loopback
ff02::1         ip6-allnodes
ff02::2         ip6-allrouters


================================================
FILE: .config/kcp.json
================================================
{
	"key": "it's a secrect",
	"crypt": "aes",
	"mode": "fast",
	"mtu" : 1350,
	"sndwnd": 1024,
	"rcvwnd": 1024,
	"datashard": 10,
	"parityshard": 3,
	"dscp": 0,
	"nocomp": false,
	"acknodelay": false,
	"nodelay": 0,
	"interval": 40,
	"resend": 0,
	"nc": 0,
	"sockbuf": 4194304,
	"keepalive": 10,
	"snmplog": "",
	"snmpperiod": 60
}

================================================
FILE: .config/peer.txt
================================================
# strategy for node selecting
strategy        random

max_fails       1

fail_timeout    30s

# period for live reloading
reload          10s

# peers
peer    http://:18080
peer    socks://:11080
peer    ss://chacha20:123456@:18338

================================================
FILE: .config/probe_resist.txt
================================================
Hello World!

================================================
FILE: .config/secrets.txt
================================================
# period for live reloading
reload          3s

# username password

$test.admin$ $123456$
@test.admin@ @123456@
test.admin# #123456#
test.admin\admin 123456
test001 123456
test002 12345678

================================================
FILE: .dockerignore
================================================
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so

# Folders
_obj
_test
release
debian
docs

*.exe
*.test

*.bak

.git
.gitignore
LICENSE
VERSION
README.md
Changelog.md
Makefile
docker-compose.yml

================================================
FILE: .github/workflows/buildx.yml
================================================
# 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 }}

================================================
FILE: .github/workflows/release.yml
================================================
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 }}


================================================
FILE: .gitignore
================================================
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so

# Folders
_obj
_test
release
debian
bin
dist/

# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out

*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*

_testmain.go

*.swp
*.swo

*.exe
*.test

*.bak

.vscode/
cmd/gost/gost


================================================
FILE: .goreleaser.yaml
================================================
# 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


================================================
FILE: .travis.yml
================================================
language: go
sudo: false
go:
  - 1.x

install: true
script:
  - go test -race -v -coverprofile=coverage.txt -covermode=atomic
  - cd cmd/gost && go build

after_success:
  - bash <(curl -s https://codecov.io/bash)


================================================
FILE: Dockerfile
================================================
FROM --platform=$BUILDPLATFORM tonistiigi/xx:1.5.0 AS xx

FROM --platform=$BUILDPLATFORM golang:1.23-alpine3.20 AS builder

COPY --from=xx / /

ARG TARGETPLATFORM

RUN xx-info env

ENV CGO_ENABLED=0

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

WORKDIR /bin/

COPY --from=builder /app/cmd/gost/gost .

ENTRYPOINT ["/bin/gost"]

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2016 ginuerzh

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: Makefile
================================================
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

PLATFORM_LIST = \
	darwin-amd64 \
	darwin-arm64 \
	linux-386 \
	linux-amd64 \
	linux-armv5 \
	linux-armv6 \
	linux-armv7 \
	linux-armv8 \
	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_ARCH_LIST = \
	windows-386 \
	windows-amd64 \
	windows-arm64

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)

linux-amd64:
	GOARCH=amd64 GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)

linux-armv5:
	GOARCH=arm GOOS=linux GOARM=5 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)

linux-armv6:
	GOARCH=arm GOOS=linux GOARM=6 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)

linux-armv7:
	GOARCH=arm GOOS=linux GOARM=7 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)

linux-armv8:
	GOARCH=arm64 GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)

linux-mips-softfloat:
	GOARCH=mips GOMIPS=softfloat GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)

linux-mips-hardfloat:
	GOARCH=mips GOMIPS=hardfloat GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)

linux-mipsle-softfloat:
	GOARCH=mipsle GOMIPS=softfloat GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)

linux-mipsle-hardfloat:
	GOARCH=mipsle GOMIPS=hardfloat GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)

linux-mips64:
	GOARCH=mips64 GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)

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)

freebsd-amd64:
	GOARCH=amd64 GOOS=freebsd $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(GOFILES)

windows-386:
	GOARCH=386 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe $(GOFILES)

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))

$(gz_releases): %.gz : %
	chmod +x $(BINDIR)/$(NAME)-$(basename $@)
	gzip -f -S -$(VERSION).gz $(BINDIR)/$(NAME)-$(basename $@)

$(zip_releases): %.zip : %
	zip -m -j $(BINDIR)/$(NAME)-$(basename $@)-$(VERSION).zip $(BINDIR)/$(NAME)-$(basename $@).exe

all-arch: $(PLATFORM_LIST) $(WINDOWS_ARCH_LIST)

releases: $(gz_releases) $(zip_releases)
clean:
	rm $(BINDIR)/*


================================================
FILE: README.md
================================================
GO Simple Tunnel
======

### GO语言实现的安全隧道

[![GoDoc](https://godoc.org/github.com/ginuerzh/gost?status.svg)](https://godoc.org/github.com/ginuerzh/gost)
[![Go Report Card](https://goreportcard.com/badge/github.com/ginuerzh/gost)](https://goreportcard.com/report/github.com/ginuerzh/gost)
[![codecov](https://codecov.io/gh/ginuerzh/gost/branch/master/graphs/badge.svg)](https://codecov.io/gh/ginuerzh/gost/branch/master)
[![GitHub release](https://img.shields.io/github/release/ginuerzh/gost.svg)](https://github.com/ginuerzh/gost/releases/latest)
[![Docker](https://img.shields.io/docker/pulls/ginuerzh/gost.svg)](https://hub.docker.com/r/ginuerzh/gost/)
[![gost](https://snapcraft.io/gost/badge.svg)](https://snapcraft.io/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/)

Wiki站点: [v2.gost.run](https://v2.gost.run)

Telegram讨论群: <https://t.me/gogost>

Google讨论组: <https://groups.google.com/d/forum/go-gost>

GOST v3 <https://gost.run>

安装
------

#### 二进制文件

<https://github.com/ginuerzh/gost/releases>

#### 源码编译

```bash
git clone https://github.com/ginuerzh/gost.git
cd gost/cmd/gost
go build
```

#### Docker

```bash
docker run --rm ginuerzh/gost -V
```

#### Homebrew

```bash
brew install gost
```

#### Ubuntu商店


```bash
sudo snap install core
sudo snap install gost
```

快速上手
------

#### 不设置转发代理

<img src="https://ginuerzh.github.io/images/gost_01.png" />

* 作为标准HTTP/SOCKS5代理

```bash
gost -L=:8080
```

* 设置代理认证信息

```bash
gost -L=admin:123456@localhost:8080
```

* 多端口监听

```bash
gost -L=http2://:443 -L=socks5://:1080 -L=ss://aes-128-cfb:123456@:8338
```

#### 设置转发代理

<img src="https://ginuerzh.github.io/images/gost_02.png" />

```bash
gost -L=:8080 -F=192.168.1.1:8081
```

* 转发代理认证

```bash
gost -L=:8080 -F=http://admin:123456@192.168.1.1:8081
```

#### 设置多级转发代理(代理链)

<img src="https://ginuerzh.github.io/images/gost_03.png" />

```bash
gost -L=:8080 -F=quic://192.168.1.1:6121 -F=socks5+wss://192.168.1.2:1080 -F=http2://192.168.1.3:443 ... -F=a.b.c.d:NNNN
```

gost按照-F设置的顺序通过代理链将请求最终转发给a.b.c.d:NNNN处理,每一个转发代理可以是任意HTTP/HTTPS/HTTP2/SOCKS4/SOCKS5/Shadowsocks类型代理。

#### 本地端口转发(TCP)

```bash
gost -L=tcp://:2222/192.168.1.1:22 [-F=...]
```

将本地TCP端口2222上的数据(通过代理链)转发到192.168.1.1:22上。当代理链末端(最后一个-F参数)为SSH转发通道类型时,gost会直接使用SSH的本地端口转发功能:

```bash
gost -L=tcp://:2222/192.168.1.1:22 -F forward+ssh://:2222
```

#### 本地端口转发(UDP)

```bash
gost -L=udp://:5353/192.168.1.1:53?ttl=60 [-F=...]
```

将本地UDP端口5353上的数据(通过代理链)转发到192.168.1.1:53上。
每条转发通道都有超时时间,当超过此时间,且在此时间段内无任何数据交互,则此通道将关闭。可以通过`ttl`参数来设置超时时间,默认值为60秒。

**注:** 转发UDP数据时,如果有代理链,则代理链的末端(最后一个-F参数)必须是gost SOCKS5类型代理,gost会使用UDP over TCP方式进行转发。

#### 远程端口转发(TCP)

```bash
gost -L=rtcp://:2222/192.168.1.1:22 [-F=... -F=socks5://172.24.10.1:1080]
```
将172.24.10.1:2222上的数据(通过代理链)转发到192.168.1.1:22上。当代理链末端(最后一个-F参数)为SSH转发通道类型时,gost会直接使用SSH的远程端口转发功能:

```bash
gost -L=rtcp://:2222/192.168.1.1:22 -F forward+ssh://:2222
```

#### 远程端口转发(UDP)

```bash
gost -L=rudp://:5353/192.168.1.1:53?ttl=60 [-F=... -F=socks5://172.24.10.1:1080]
```
将172.24.10.1:5353上的数据(通过代理链)转发到192.168.1.1:53上。
每条转发通道都有超时时间,当超过此时间,且在此时间段内无任何数据交互,则此通道将关闭。可以通过`ttl`参数来设置超时时间,默认值为60秒。

**注:** 转发UDP数据时,如果有代理链,则代理链的末端(最后一个-F参数)必须是GOST SOCKS5类型代理,gost会使用UDP-over-TCP方式进行转发。

#### HTTP2

gost的HTTP2支持两种模式:
* 作为标准的HTTP2代理,并向下兼容HTTPS代理。
* 作为通道传输其他协议。

##### 代理模式
服务端:
```bash
gost -L=http2://:443
```
客户端:
```bash
gost -L=:8080 -F=http2://server_ip:443
```

##### 通道模式
服务端:
```bash
gost -L=h2://:443
```
客户端:
```bash
gost -L=:8080 -F=h2://server_ip:443
```

#### QUIC
gost对QUIC的支持是基于[quic-go](https://github.com/quic-go/quic-go)库。

服务端:
```bash
gost -L=quic://:6121
```

客户端:
```bash
gost -L=:8080 -F=quic://server_ip:6121
```

**注:** QUIC模式只能作为代理链的第一个节点。

#### KCP
gost对KCP的支持是基于[kcp-go](https://github.com/xtaci/kcp-go)和[kcptun](https://github.com/xtaci/kcptun)库。

服务端:
```bash
gost -L=kcp://:8388
```

客户端:
```bash
gost -L=:8080 -F=kcp://server_ip:8388
```

gost会自动加载当前工作目录中的kcp.json(如果存在)配置文件,或者可以手动通过参数指定配置文件路径:
```bash
gost -L=kcp://:8388?c=/path/to/conf/file
```

**注:** KCP模式只能作为代理链的第一个节点。

#### SSH

gost的SSH支持两种模式:
* 作为转发通道,配合本地/远程TCP端口转发使用。
* 作为通道传输其他协议。

##### 转发模式
服务端:
```bash
gost -L=forward+ssh://:2222
```
客户端:
```bash
gost -L=rtcp://:1222/:22 -F=forward+ssh://server_ip:2222
```

##### 通道模式
服务端:
```bash
gost -L=ssh://:2222
```
客户端:
```bash
gost -L=:8080 -F=ssh://server_ip:2222?ping=60
```

可以通过`ping`参数设置心跳包发送周期,单位为秒。默认不发送心跳包。


#### 透明代理
基于iptables的透明代理。

```bash
gost -L=redirect://:12345 -F=http2://server_ip:443
```

#### obfs4
此功能由[@isofew](https://github.com/isofew)贡献。

服务端:
```bash
gost -L=obfs4://:443
```

当服务端运行后会在控制台打印出连接地址供客户端使用:
```
obfs4://:443/?cert=4UbQjIfjJEQHPOs8vs5sagrSXx1gfrDCGdVh2hpIPSKH0nklv1e4f29r7jb91VIrq4q5Jw&iat-mode=0
```

客户端:
```
gost -L=:8888 -F='obfs4://server_ip:443?cert=4UbQjIfjJEQHPOs8vs5sagrSXx1gfrDCGdVh2hpIPSKH0nklv1e4f29r7jb91VIrq4q5Jw&iat-mode=0'
```

加密机制
------

#### HTTP

对于HTTP可以使用TLS加密整个通讯过程,即HTTPS代理:

服务端:

```bash
gost -L=https://:443
```
客户端:

```bash
gost -L=:8080 -F=http+tls://server_ip:443
```

#### HTTP2

gost的HTTP2代理模式仅支持使用TLS加密的HTTP2协议,不支持明文HTTP2传输。

gost的HTTP2通道模式支持加密(h2)和明文(h2c)两种模式。

#### SOCKS5

gost支持标准SOCKS5协议的no-auth(0x00)和user/pass(0x02)方法,并在此基础上扩展了两个:tls(0x80)和tls-auth(0x82),用于数据加密。

服务端:

```bash
gost -L=socks5://:1080
```

客户端:

```bash
gost -L=:8080 -F=socks5://server_ip:1080
```

如果两端都是gost(如上)则数据传输会被加密(协商使用tls或tls-auth方法),否则使用标准SOCKS5进行通讯(no-auth或user/pass方法)。

#### Shadowsocks
gost对shadowsocks的支持是基于[shadowsocks-go](https://github.com/shadowsocks/shadowsocks-go)库。

服务端:

```bash
gost -L=ss://chacha20:123456@:8338
```
客户端:

```bash
gost -L=:8080 -F=ss://chacha20:123456@server_ip:8338
```

##### Shadowsocks UDP relay

目前仅服务端支持UDP Relay。

服务端:

```bash
gost -L=ssu://chacha20:123456@:8338
```

#### TLS
gost内置了TLS证书,如果需要使用其他TLS证书,有两种方法:
* 在gost运行目录放置cert.pem(公钥)和key.pem(私钥)两个文件即可,gost会自动加载运行目录下的cert.pem和key.pem文件。
* 使用参数指定证书文件路径:
```bash
gost -L="http2://:443?cert=/path/to/my/cert/file&key=/path/to/my/key/file"
```

对于客户端可以通过`secure`参数开启服务器证书和域名校验:
```bash
gost -L=:8080 -F="http2://server_domain_name:443?secure=true"
```

对于客户端可以指定CA证书进行[证书锁定](https://en.wikipedia.org/wiki/Transport_Layer_Security#Certificate_pinning)(Certificate Pinning):
```bash
gost -L=:8080 -F="http2://:443?ca=ca.pem"
```
证书锁定功能由[@sheerun](https://github.com/sheerun)贡献


================================================
FILE: README_en.md
================================================
gost - GO Simple Tunnel
======
 
### A simple security tunnel written in Golang

[![GoDoc](https://godoc.org/github.com/ginuerzh/gost?status.svg)](https://godoc.org/github.com/ginuerzh/gost)
[![Go Report Card](https://goreportcard.com/badge/github.com/ginuerzh/gost)](https://goreportcard.com/report/github.com/ginuerzh/gost)
[![codecov](https://codecov.io/gh/ginuerzh/gost/branch/master/graphs/badge.svg)](https://codecov.io/gh/ginuerzh/gost/branch/master)
[![GitHub release](https://img.shields.io/github/release/ginuerzh/gost.svg)](https://github.com/ginuerzh/gost/releases/latest)
[![Docker](https://img.shields.io/docker/pulls/ginuerzh/gost.svg)](https://hub.docker.com/r/ginuerzh/gost/)
[![gost](https://snapcraft.io/gost/badge.svg)](https://snapcraft.io/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/)

Wiki: [v2.gost.run](https://v2.gost.run/en/)

Telegram group: <https://t.me/gogost>

Google group: <https://groups.google.com/d/forum/go-gost>

GOST v3: <https://gost.run>

Installation
------

#### Binary files

<https://github.com/ginuerzh/gost/releases>

#### From source

```bash
git clone https://github.com/ginuerzh/gost.git
cd gost/cmd/gost
go build
```

#### Docker

```bash
docker run --rm ginuerzh/gost -V
```

#### Homebrew

```bash
brew install gost
```

#### Ubuntu store

```bash
sudo snap install core
sudo snap install gost
```

Getting started
------

#### No forward proxy

<img src="https://ginuerzh.github.io/images/gost_01.png" />

* Standard HTTP/SOCKS5 proxy

```bash
gost -L=:8080
```

* Proxy authentication

```bash
gost -L=admin:123456@localhost:8080
```

* Multiple sets of authentication information

```bash
gost -L=localhost:8080?secrets=secrets.txt
```

The secrets parameter allows you to set multiple authentication information for HTTP/SOCKS5 proxies, the format is:

```plain
# username password

test001 123456
test002 12345678
```

* Listen on multiple ports

```bash
gost -L=http2://:443 -L=socks5://:1080 -L=ss://aes-128-cfb:123456@:8338
```

#### Forward proxy

<img src="https://ginuerzh.github.io/images/gost_02.png" />

```bash
gost -L=:8080 -F=192.168.1.1:8081
```

* Forward proxy authentication

```bash
gost -L=:8080 -F=http://admin:123456@192.168.1.1:8081
```

#### Multi-level forward proxy

<img src="https://ginuerzh.github.io/images/gost_03.png" />

```bash
gost -L=:8080 -F=quic://192.168.1.1:6121 -F=socks5+wss://192.168.1.2:1080 -F=http2://192.168.1.3:443 ... -F=a.b.c.d:NNNN
```

Gost forwards the request to a.b.c.d:NNNN through the proxy chain in the order set by -F, 
each forward proxy can be any HTTP/HTTPS/HTTP2/SOCKS4/SOCKS5/Shadowsocks type.

#### Local TCP port forwarding

```bash
gost -L=tcp://:2222/192.168.1.1:22 [-F=...]
```

The data on the local TCP port 2222 is forwarded to 192.168.1.1:22 (through the proxy chain). If the last node of the chain (the last -F parameter) is a SSH forwad tunnel, then gost will use the local port forwarding function of SSH directly:

```bash
gost -L=tcp://:2222/192.168.1.1:22 -F forward+ssh://:2222
```

#### Local UDP port forwarding

```bash
gost -L=udp://:5353/192.168.1.1:53?ttl=60 [-F=...]
```

The data on the local UDP port 5353 is forwarded to 192.168.1.1:53 (through the proxy chain). 
Each forwarding channel has a timeout period. When this time is exceeded and there is no data interaction during this time period, the channel will be closed. The timeout value can be set by the `ttl` parameter. The default value is 60 seconds.

**NOTE:** When forwarding UDP data, if there is a proxy chain, the end of the chain (the last -F parameter) must be gost SOCKS5 proxy, gost will use UDP-over-TCP to forward data.

#### Remote TCP port forwarding

```bash
gost -L=rtcp://:2222/192.168.1.1:22 [-F=... -F=socks5://172.24.10.1:1080]
```

The data on 172.24.10.1:2222 is forwarded to 192.168.1.1:22 (through the proxy chain). If the last node of the chain (the last -F parameter) is a SSH tunnel, then gost will use the remote port forwarding function of SSH directly:

```bash
gost -L=rtcp://:2222/192.168.1.1:22 -F forward+ssh://:2222
```

#### Remote UDP port forwarding

```bash
gost -L=rudp://:5353/192.168.1.1:53?ttl=60 [-F=... -F=socks5://172.24.10.1:1080]
```

The data on 172.24.10.1:5353 is forwarded to 192.168.1.1:53 (through the proxy chain).
Each forwarding channel has a timeout period. When this time is exceeded and there is no data interaction during this time period, the channel will be closed. The timeout value can be set by the `ttl` parameter. The default value is 60 seconds.

**NOTE:** When forwarding UDP data, if there is a proxy chain, the end of the chain (the last -F parameter) must be gost SOCKS5 proxy, gost will use UDP-over-TCP to forward data.

#### HTTP2

Gost HTTP2 supports two modes:

* As a standard HTTP2 proxy, and backwards-compatible with the HTTPS proxy.

* As a transport tunnel.

##### Standard proxy

Server:

```bash
gost -L=http2://:443
```

Client:

```bash
gost -L=:8080 -F=http2://server_ip:443?ping=30
```

##### Tunnel 

Server:

```bash
gost -L=h2://:443
```

Client:

```bash
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).

Server:

```bash
gost -L=quic://:6121
```

Client:

```bash
gost -L=:8080 -F=quic://server_ip:6121
```

**NOTE:** QUIC node can only be used as the first node of the proxy chain.

#### KCP
Support for KCP is based on libraries [kcp-go](https://github.com/xtaci/kcp-go) and [kcptun](https://github.com/xtaci/kcptun).

Server:

```bash
gost -L=kcp://:8388
```

Client:

```bash
gost -L=:8080 -F=kcp://server_ip:8388
```

Gost will automatically load kcp.json configuration file from current working directory if exists, 
or you can use the parameter to specify the path to the file.

```bash
gost -L=kcp://:8388?c=/path/to/conf/file
```

**NOTE:** KCP node can only be used as the first node of the proxy chain.

#### SSH

Gost SSH supports two modes:

* As a forward tunnel, used by local/remote TCP port forwarding.

* As a transport tunnel.


##### Forward tunnel

Server:

```bash
gost -L=forward+ssh://:2222
```

Client:

```bash
gost -L=rtcp://:1222/:22 -F=forward+ssh://server_ip:2222
```

##### Transport tunnel
Server:

```bash
gost -L=ssh://:2222
```
Client:

```bash
gost -L=:8080 -F=ssh://server_ip:2222?ping=60
```

The client supports the ping parameter to enable heartbeat detection (which is disabled by default). Parameter value represents heartbeat interval seconds.

#### Transparent proxy
Iptables-based transparent proxy

```bash
gost -L=redirect://:12345 -F=http2://server_ip:443
```


#### obfs4
Contributed by [@isofew](https://github.com/isofew).

Server:

```bash
gost -L=obfs4://:443
```

When the server is running normally, the console prints out the connection address for the client to use:

```bash
obfs4://:443/?cert=4UbQjIfjJEQHPOs8vs5sagrSXx1gfrDCGdVh2hpIPSKH0nklv1e4f29r7jb91VIrq4q5Jw&iat-mode=0
```

Client:

```bash
gost -L=:8888 -F='obfs4://server_ip:443?cert=4UbQjIfjJEQHPOs8vs5sagrSXx1gfrDCGdVh2hpIPSKH0nklv1e4f29r7jb91VIrq4q5Jw&iat-mode=0'
```

Encryption Mechanism
------

#### HTTP

For HTTP, you can use TLS to encrypt the entire communication process, the HTTPS proxy:

Server:

```bash
gost -L=http+tls://:443
```

Client:

```bash
gost -L=:8080 -F=http+tls://server_ip:443
```

#### HTTP2

Gost HTTP2 proxy mode only supports the use of TLS encrypted HTTP2 protocol, does not support plaintext HTTP2.

Gost HTTP2 tunnel mode supports both encryption (h2) and plaintext (h2c) modes.

#### SOCKS5

Gost supports the standard SOCKS5 protocol methods: no-auth (0x00) and user/pass (0x02), 
and extends two methods for data encryption: tls(0x80) and tls-auth(0x82).

Server:

```bash
gost -L=socks://:1080
```

Client:

```bash
gost -L=:8080 -F=socks://server_ip:1080
```

If both ends are gosts (as example above), the data transfer will be encrypted (using tls or tls-auth). 
Otherwise, use standard SOCKS5 for communication (no-auth or user/pass).

#### Shadowsocks
Support for shadowsocks is based on library [shadowsocks-go](https://github.com/shadowsocks/shadowsocks-go).

Server:

```bash
gost -L=ss://aes-128-cfb:123456@:8338
```

Client:

```bash
gost -L=:8080 -F=ss://aes-128-cfb:123456@server_ip:8338
```

##### Shadowsocks UDP relay

Currently, only the server supports UDP Relay.

Server:

```bash
gost -L=ssu://aes-128-cfb:123456@:8338
```

#### TLS
There is built-in TLS certificate in gost, if you need to use other TLS certificate, there are two ways:

* Place two files cert.pem (public key) and key.pem (private key) in the current working directory, gost will automatically load them.

* Use the parameter to specify the path to the certificate file:

```bash
gost -L="http2://:443?cert=/path/to/my/cert/file&key=/path/to/my/key/file"
```

Client can specify `secure` parameter to perform server's certificate chain and host name verification:

```bash
gost -L=:8080 -F="http2://server_domain_name:443?secure=true"
```

Client can specify a CA certificate to allow for [Certificate Pinning](https://en.wikipedia.org/wiki/Transport_Layer_Security#Certificate_pinning):

```bash
gost -L=:8080 -F="http2://:443?ca=ca.pem"
```

Certificate Pinning is contributed by [@sheerun](https://github.com/sheerun).


================================================
FILE: auth.go
================================================
package gost

import (
	"bufio"
	"io"
	"strings"
	"sync"
	"time"
)

// Authenticator is an interface for user authentication.
type Authenticator interface {
	Authenticate(user, password string) bool
}

// LocalAuthenticator is an Authenticator that authenticates client by local key-value pairs.
type LocalAuthenticator struct {
	kvs     map[string]string
	period  time.Duration
	stopped chan struct{}
	mux     sync.RWMutex
}

// NewLocalAuthenticator creates an Authenticator that authenticates client by local infos.
func NewLocalAuthenticator(kvs map[string]string) *LocalAuthenticator {
	return &LocalAuthenticator{
		kvs:     kvs,
		stopped: make(chan struct{}),
	}
}

// Authenticate checks the validity of the provided user-password pair.
func (au *LocalAuthenticator) Authenticate(user, password string) bool {
	if au == nil {
		return true
	}

	au.mux.RLock()
	defer au.mux.RUnlock()

	if len(au.kvs) == 0 {
		return true
	}

	v, ok := au.kvs[user]
	return ok && (v == "" || password == v)
}

// Add adds a key-value pair to the Authenticator.
func (au *LocalAuthenticator) Add(k, v string) {
	au.mux.Lock()
	defer au.mux.Unlock()
	if au.kvs == nil {
		au.kvs = make(map[string]string)
	}
	au.kvs[k] = v
}

// Reload parses config from r, then live reloads the Authenticator.
func (au *LocalAuthenticator) Reload(r io.Reader) error {
	var period time.Duration
	kvs := make(map[string]string)

	if r == nil || au.Stopped() {
		return nil
	}

	// splitLine splits a line text by white space.
	// A line started with '#' will be ignored, otherwise it is valid.
	split := func(line string) []string {
		if line == "" {
			return nil
		}
		line = strings.Replace(line, "\t", " ", -1)
		line = strings.TrimSpace(line)

		if strings.IndexByte(line, '#') == 0 {
			return nil
		}

		var ss []string
		for _, s := range strings.Split(line, " ") {
			if s = strings.TrimSpace(s); s != "" {
				ss = append(ss, s)
			}
		}
		return ss
	}

	scanner := bufio.NewScanner(r)
	for scanner.Scan() {
		line := scanner.Text()
		ss := split(line)
		if len(ss) == 0 {
			continue
		}

		switch ss[0] {
		case "reload": // reload option
			if len(ss) > 1 {
				period, _ = time.ParseDuration(ss[1])
			}
		default:
			var k, v string
			k = ss[0]
			if len(ss) > 1 {
				v = ss[1]
			}
			kvs[k] = v
		}
	}

	if err := scanner.Err(); err != nil {
		return err
	}

	au.mux.Lock()
	defer au.mux.Unlock()

	au.period = period
	au.kvs = kvs

	return nil
}

// Period returns the reload period.
func (au *LocalAuthenticator) Period() time.Duration {
	if au.Stopped() {
		return -1
	}

	au.mux.RLock()
	defer au.mux.RUnlock()

	return au.period
}

// Stop stops reloading.
func (au *LocalAuthenticator) Stop() {
	select {
	case <-au.stopped:
	default:
		close(au.stopped)
	}
}

// Stopped checks whether the reloader is stopped.
func (au *LocalAuthenticator) Stopped() bool {
	select {
	case <-au.stopped:
		return true
	default:
		return false
	}
}


================================================
FILE: auth_test.go
================================================
package gost

import (
	"bytes"
	"fmt"
	"io"
	"net/url"
	"testing"
	"time"
)

var localAuthenticatorTests = []struct {
	clientUser  *url.Userinfo
	serverUsers []*url.Userinfo
	valid       bool
}{
	{nil, nil, true},
	{nil, []*url.Userinfo{url.User("admin")}, false},
	{nil, []*url.Userinfo{url.UserPassword("", "123456")}, false},
	{nil, []*url.Userinfo{url.UserPassword("admin", "123456")}, false},

	{url.User("admin"), nil, true},
	{url.User("admin"), []*url.Userinfo{url.User("admin")}, true},
	{url.User("admin"), []*url.Userinfo{url.User("test")}, false},
	{url.User("admin"), []*url.Userinfo{url.UserPassword("test", "123456")}, false},
	{url.User("admin"), []*url.Userinfo{url.UserPassword("admin", "123456")}, false},
	{url.User("admin"), []*url.Userinfo{url.UserPassword("admin", "")}, true},
	{url.User("admin"), []*url.Userinfo{url.UserPassword("", "123456")}, false},

	{url.UserPassword("", ""), nil, true},
	{url.UserPassword("", "123456"), nil, true},
	{url.UserPassword("", "123456"), []*url.Userinfo{url.UserPassword("", "123456")}, true},
	{url.UserPassword("", "123456"), []*url.Userinfo{url.UserPassword("admin", "")}, false},
	{url.UserPassword("", "123456"), []*url.Userinfo{url.UserPassword("admin", "123456")}, false},

	{url.UserPassword("admin", "123456"), nil, true},
	{url.UserPassword("admin", "123456"), []*url.Userinfo{url.User("admin")}, true},
	{url.UserPassword("admin", "123456"), []*url.Userinfo{url.User("test")}, false},
	{url.UserPassword("admin", "123456"), []*url.Userinfo{url.UserPassword("admin", "")}, true},
	{url.UserPassword("admin", "123456"), []*url.Userinfo{url.UserPassword("", "123456")}, false},
	{url.UserPassword("admin", "123456"), []*url.Userinfo{url.UserPassword("admin", "123")}, false},
	{url.UserPassword("admin", "123456"), []*url.Userinfo{url.UserPassword("test", "123456")}, false},
	{url.UserPassword("admin", "123456"), []*url.Userinfo{url.UserPassword("admin", "123456")}, true},

	{url.UserPassword("admin", "123456"), []*url.Userinfo{
		url.UserPassword("test", "123"),
		url.UserPassword("admin", "123456"),
	}, true},
}

func TestLocalAuthenticator(t *testing.T) {
	for i, tc := range localAuthenticatorTests {
		tc := tc
		t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
			au := NewLocalAuthenticator(nil)
			for _, u := range tc.serverUsers {
				if u != nil {
					p, _ := u.Password()
					au.Add(u.Username(), p)
				}
			}

			var u, p string
			if tc.clientUser != nil {
				u = tc.clientUser.Username()
				p, _ = tc.clientUser.Password()
			}
			if au.Authenticate(u, p) != tc.valid {
				t.Error("authenticate result should be", tc.valid)
			}
		})
	}
}

var localAuthenticatorReloadTests = []struct {
	r       io.Reader
	period  time.Duration
	kvs     map[string]string
	stopped bool
}{
	{
		r:      nil,
		period: 0,
		kvs:    nil,
	},
	{
		r:      bytes.NewBufferString(""),
		period: 0,
	},
	{
		r:      bytes.NewBufferString("reload 10s"),
		period: 10 * time.Second,
	},
	{
		r: bytes.NewBufferString("# reload 10s\n"),
	},
	{
		r:      bytes.NewBufferString("reload 10s\n#admin"),
		period: 10 * time.Second,
	},
	{
		r:      bytes.NewBufferString("reload 10s\nadmin"),
		period: 10 * time.Second,
		kvs: map[string]string{
			"admin": "",
		},
	},
	{
		r: bytes.NewBufferString("# reload 10s\nadmin"),
		kvs: map[string]string{
			"admin": "",
		},
	},
	{
		r: bytes.NewBufferString("# reload 10s\nadmin #123456"),
		kvs: map[string]string{
			"admin": "#123456",
		},
		stopped: true,
	},
	{
		r: bytes.NewBufferString("admin \t #123456\n\n\ntest \t 123456"),
		kvs: map[string]string{
			"admin": "#123456",
			"test":  "123456",
		},
		stopped: true,
	},
	{
		r: bytes.NewBufferString(`
		$test.admin$ $123456$
		@test.admin@ @123456@
		test.admin# #123456#
		test.admin\admin 123456
		`),
		kvs: map[string]string{
			"$test.admin$":      "$123456$",
			"@test.admin@":      "@123456@",
			"test.admin#":       "#123456#",
			"test.admin\\admin": "123456",
		},
		stopped: true,
	},
}

func TestLocalAuthenticatorReload(t *testing.T) {
	isEquals := func(a, b map[string]string) bool {
		if len(a) == 0 && len(b) == 0 {
			return true
		}
		if len(a) != len(b) {
			return false
		}

		for k, v := range a {
			if b[k] != v {
				return false
			}
		}
		return true
	}
	for i, tc := range localAuthenticatorReloadTests {
		tc := tc
		t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
			au := NewLocalAuthenticator(nil)

			if err := au.Reload(tc.r); err != nil {
				t.Error(err)
			}
			if au.Period() != tc.period {
				t.Errorf("#%d test failed: period value should be %v, got %v",
					i, tc.period, au.Period())
			}
			if !isEquals(au.kvs, tc.kvs) {
				t.Errorf("#%d test failed: %v, %s", i, au.kvs, tc.kvs)
			}

			if tc.stopped {
				au.Stop()
				if au.Period() >= 0 {
					t.Errorf("period of the stopped reloader should be minus value")
				}
				au.Stop()
			}
			if au.Stopped() != tc.stopped {
				t.Errorf("#%d test failed: stopped value should be %v, got %v",
					i, tc.stopped, au.Stopped())
			}
		})
	}
}


================================================
FILE: bypass.go
================================================
package gost

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"net"
	"strconv"
	"strings"
	"sync"
	"time"

	glob "github.com/gobwas/glob"
)

// Matcher is a generic pattern matcher,
// it gives the match result of the given pattern for specific v.
type Matcher interface {
	Match(v string) bool
	String() string
}

// NewMatcher creates a Matcher for the given pattern.
// The acutal Matcher depends on the pattern:
// IP Matcher if pattern is a valid IP address.
// CIDR Matcher if pattern is a valid CIDR address.
// Domain Matcher if both of the above are not.
func NewMatcher(pattern string) Matcher {
	if pattern == "" {
		return nil
	}
	if ip := net.ParseIP(pattern); ip != nil {
		return IPMatcher(ip)
	}
	if _, inet, err := net.ParseCIDR(pattern); err == nil {
		return CIDRMatcher(inet)
	}
	return DomainMatcher(pattern)
}

type ipMatcher struct {
	ip net.IP
}

// IPMatcher creates a Matcher for a specific IP address.
func IPMatcher(ip net.IP) Matcher {
	return &ipMatcher{
		ip: ip,
	}
}

func (m *ipMatcher) Match(ip string) bool {
	if m == nil {
		return false
	}
	return m.ip.Equal(net.ParseIP(ip))
}

func (m *ipMatcher) String() string {
	return "ip " + m.ip.String()
}

type cidrMatcher struct {
	ipNet *net.IPNet
}

// CIDRMatcher creates a Matcher for a specific CIDR notation IP address.
func CIDRMatcher(inet *net.IPNet) Matcher {
	return &cidrMatcher{
		ipNet: inet,
	}
}

func (m *cidrMatcher) Match(ip string) bool {
	if m == nil || m.ipNet == nil {
		return false
	}
	return m.ipNet.Contains(net.ParseIP(ip))
}

func (m *cidrMatcher) String() string {
	return "cidr " + m.ipNet.String()
}

type domainMatcher struct {
	pattern string
	glob    glob.Glob
}

// DomainMatcher creates a Matcher for a specific domain pattern,
// the pattern can be a plain domain such as 'example.com',
// a wildcard such as '*.exmaple.com' or a special wildcard '.example.com'.
func DomainMatcher(pattern string) Matcher {
	p := pattern
	if strings.HasPrefix(pattern, ".") {
		p = pattern[1:] // trim the prefix '.'
		pattern = "*" + p
	}
	return &domainMatcher{
		pattern: p,
		glob:    glob.MustCompile(pattern),
	}
}

func (m *domainMatcher) Match(domain string) bool {
	if m == nil || m.glob == nil {
		return false
	}

	if domain == m.pattern {
		return true
	}
	return m.glob.Match(domain)
}

func (m *domainMatcher) String() string {
	return "domain " + m.pattern
}

// Bypass is a filter for address (IP or domain).
// It contains a list of matchers.
type Bypass struct {
	matchers []Matcher
	period   time.Duration // the period for live reloading
	reversed bool
	stopped  chan struct{}
	mux      sync.RWMutex
}

// NewBypass creates and initializes a new Bypass using matchers as its match rules.
// The rules will be reversed if the reversed is true.
func NewBypass(reversed bool, matchers ...Matcher) *Bypass {
	return &Bypass{
		matchers: matchers,
		reversed: reversed,
		stopped:  make(chan struct{}),
	}
}

// NewBypassPatterns creates and initializes a new Bypass using matcher patterns as its match rules.
// The rules will be reversed if the reverse is true.
func NewBypassPatterns(reversed bool, patterns ...string) *Bypass {
	var matchers []Matcher
	for _, pattern := range patterns {
		if m := NewMatcher(pattern); m != nil {
			matchers = append(matchers, m)
		}
	}
	bp := NewBypass(reversed)
	bp.AddMatchers(matchers...)
	return bp
}

// Contains reports whether the bypass includes addr.
func (bp *Bypass) Contains(addr string) bool {
	if bp == nil || addr == "" {
		return false
	}

	// try to strip the port
	if host, port, _ := net.SplitHostPort(addr); host != "" && port != "" {
		if p, _ := strconv.Atoi(port); p > 0 { // port is valid
			addr = host
		}
	}

	bp.mux.RLock()
	defer bp.mux.RUnlock()

	if len(bp.matchers) == 0 {
		return false
	}

	var matched bool
	for _, matcher := range bp.matchers {
		if matcher == nil {
			continue
		}
		if matcher.Match(addr) {
			matched = true
			break
		}
	}
	return !bp.reversed && matched ||
		bp.reversed && !matched
}

// AddMatchers appends matchers to the bypass matcher list.
func (bp *Bypass) AddMatchers(matchers ...Matcher) {
	bp.mux.Lock()
	defer bp.mux.Unlock()

	bp.matchers = append(bp.matchers, matchers...)
}

// Matchers return the bypass matcher list.
func (bp *Bypass) Matchers() []Matcher {
	bp.mux.RLock()
	defer bp.mux.RUnlock()

	return bp.matchers
}

// Reversed reports whether the rules of the bypass are reversed.
func (bp *Bypass) Reversed() bool {
	bp.mux.RLock()
	defer bp.mux.RUnlock()

	return bp.reversed
}

// Reload parses config from r, then live reloads the bypass.
func (bp *Bypass) Reload(r io.Reader) error {
	var matchers []Matcher
	var period time.Duration
	var reversed bool

	if r == nil || bp.Stopped() {
		return nil
	}

	scanner := bufio.NewScanner(r)
	for scanner.Scan() {
		line := scanner.Text()
		ss := splitLine(line)
		if len(ss) == 0 {
			continue
		}
		switch ss[0] {
		case "reload": // reload option
			if len(ss) > 1 {
				period, _ = time.ParseDuration(ss[1])
			}
		case "reverse": // reverse option
			if len(ss) > 1 {
				reversed, _ = strconv.ParseBool(ss[1])
			}
		default:
			matchers = append(matchers, NewMatcher(ss[0]))
		}
	}

	if err := scanner.Err(); err != nil {
		return err
	}

	bp.mux.Lock()
	defer bp.mux.Unlock()

	bp.matchers = matchers
	bp.period = period
	bp.reversed = reversed

	return nil
}

// Period returns the reload period.
func (bp *Bypass) Period() time.Duration {
	if bp.Stopped() {
		return -1
	}

	bp.mux.RLock()
	defer bp.mux.RUnlock()

	return bp.period
}

// Stop stops reloading.
func (bp *Bypass) Stop() {
	select {
	case <-bp.stopped:
	default:
		close(bp.stopped)
	}
}

// Stopped checks whether the reloader is stopped.
func (bp *Bypass) Stopped() bool {
	select {
	case <-bp.stopped:
		return true
	default:
		return false
	}
}

func (bp *Bypass) String() string {
	b := &bytes.Buffer{}
	fmt.Fprintf(b, "reversed: %v\n", bp.Reversed())
	fmt.Fprintf(b, "reload: %v\n", bp.Period())
	for _, m := range bp.Matchers() {
		b.WriteString(m.String())
		b.WriteByte('\n')
	}
	return b.String()
}


================================================
FILE: bypass_test.go
================================================
package gost

import (
	"bytes"
	"fmt"
	"io"
	"testing"
	"time"
)

var bypassContainTests = []struct {
	patterns []string
	reversed bool
	addr     string
	bypassed bool
}{
	// empty pattern
	{[]string{""}, false, "", false},
	{[]string{""}, false, "192.168.1.1", false},
	{[]string{""}, true, "", false},
	{[]string{""}, true, "192.168.1.1", false},

	// IP address
	{[]string{"192.168.1.1"}, false, "192.168.1.1", true},
	{[]string{"192.168.1.1"}, true, "192.168.1.1", false},
	{[]string{"192.168.1.1"}, false, "192.168.1.2", false},
	{[]string{"192.168.1.1"}, true, "192.168.1.2", true},
	{[]string{"0.0.0.0"}, false, "0.0.0.0", true},
	{[]string{"0.0.0.0"}, true, "0.0.0.0", false},

	// CIDR address
	{[]string{"192.168.1.0/0"}, false, "1.2.3.4", true},
	{[]string{"192.168.1.0/0"}, true, "1.2.3.4", false},
	{[]string{"192.168.1.0/8"}, false, "192.1.0.255", true},
	{[]string{"192.168.1.0/8"}, true, "192.1.0.255", false},
	{[]string{"192.168.1.0/8"}, false, "191.1.0.255", false},
	{[]string{"192.168.1.0/8"}, true, "191.1.0.255", true},
	{[]string{"192.168.1.0/16"}, false, "192.168.0.255", true},
	{[]string{"192.168.1.0/16"}, true, "192.168.0.255", false},
	{[]string{"192.168.1.0/16"}, false, "192.0.1.255", false},
	{[]string{"192.168.1.0/16"}, true, "192.0.0.255", true},
	{[]string{"192.168.1.0/24"}, false, "192.168.1.255", true},
	{[]string{"192.168.1.0/24"}, true, "192.168.1.255", false},
	{[]string{"192.168.1.0/24"}, false, "192.168.0.255", false},
	{[]string{"192.168.1.0/24"}, true, "192.168.0.255", true},
	{[]string{"192.168.1.1/32"}, false, "192.168.1.1", true},
	{[]string{"192.168.1.1/32"}, true, "192.168.1.1", false},
	{[]string{"192.168.1.1/32"}, false, "192.168.1.2", false},
	{[]string{"192.168.1.1/32"}, true, "192.168.1.2", true},

	// plain domain
	{[]string{"www.example.com"}, false, "www.example.com", true},
	{[]string{"www.example.com"}, true, "www.example.com", false},
	{[]string{"http://www.example.com"}, false, "http://www.example.com", true},
	{[]string{"http://www.example.com"}, true, "http://www.example.com", false},
	{[]string{"http://www.example.com"}, false, "http://example.com", false},
	{[]string{"http://www.example.com"}, true, "http://example.com", true},
	{[]string{"www.example.com"}, false, "example.com", false},
	{[]string{"www.example.com"}, true, "example.com", true},

	// host:port
	{[]string{"192.168.1.1"}, false, "192.168.1.1:80", true},
	{[]string{"192.168.1.1"}, true, "192.168.1.1:80", false},
	{[]string{"192.168.1.1:80"}, false, "192.168.1.1", false},
	{[]string{"192.168.1.1:80"}, true, "192.168.1.1", true},
	{[]string{"192.168.1.1:80"}, false, "192.168.1.1:80", false},
	{[]string{"192.168.1.1:80"}, true, "192.168.1.1:80", true},
	{[]string{"192.168.1.1:80"}, false, "192.168.1.1:8080", false},
	{[]string{"192.168.1.1:80"}, true, "192.168.1.1:8080", true},

	{[]string{"example.com"}, false, "example.com:80", true},
	{[]string{"example.com"}, true, "example.com:80", false},
	{[]string{"example.com:80"}, false, "example.com", false},
	{[]string{"example.com:80"}, true, "example.com", true},
	{[]string{"example.com:80"}, false, "example.com:80", false},
	{[]string{"example.com:80"}, true, "example.com:80", true},
	{[]string{"example.com:80"}, false, "example.com:8080", false},
	{[]string{"example.com:80"}, true, "example.com:8080", true},

	// domain wildcard

	{[]string{"*"}, false, "", false},
	{[]string{"*"}, false, "192.168.1.1", true},
	{[]string{"*"}, false, "192.168.0.0/16", true},
	{[]string{"*"}, false, "http://example.com", true},
	{[]string{"*"}, false, "example.com:80", true},
	{[]string{"*"}, true, "", false},
	{[]string{"*"}, true, "192.168.1.1", false},
	{[]string{"*"}, true, "192.168.0.0/16", false},
	{[]string{"*"}, true, "http://example.com", false},
	{[]string{"*"}, true, "example.com:80", false},

	// sub-domain
	{[]string{"*.example.com"}, false, "example.com", false},
	{[]string{"*.example.com"}, false, "http://example.com", false},
	{[]string{"*.example.com"}, false, "www.example.com", true},
	{[]string{"*.example.com"}, false, "http://www.example.com", true},
	{[]string{"*.example.com"}, false, "abc.def.example.com", true},

	{[]string{"*.*.example.com"}, false, "example.com", false},
	{[]string{"*.*.example.com"}, false, "www.example.com", false},
	{[]string{"*.*.example.com"}, false, "abc.def.example.com", true},
	{[]string{"*.*.example.com"}, false, "abc.def.ghi.example.com", true},

	{[]string{"**.example.com"}, false, "example.com", false},
	{[]string{"**.example.com"}, false, "www.example.com", true},
	{[]string{"**.example.com"}, false, "abc.def.ghi.example.com", true},

	// prefix wildcard
	{[]string{"*example.com"}, false, "example.com", true},
	{[]string{"*example.com"}, false, "www.example.com", true},
	{[]string{"*example.com"}, false, "abc.defexample.com", true},
	{[]string{"*example.com"}, false, "abc.def-example.com", true},
	{[]string{"*example.com"}, false, "abc.def.example.com", true},
	{[]string{"*example.com"}, false, "http://www.example.com", true},
	{[]string{"*example.com"}, false, "e-xample.com", false},

	{[]string{"http://*.example.com"}, false, "example.com", false},
	{[]string{"http://*.example.com"}, false, "http://example.com", false},
	{[]string{"http://*.example.com"}, false, "http://www.example.com", true},
	{[]string{"http://*.example.com"}, false, "https://www.example.com", false},
	{[]string{"http://*.example.com"}, false, "http://abc.def.example.com", true},

	{[]string{"www.*.com"}, false, "www.example.com", true},
	{[]string{"www.*.com"}, false, "www.abc.def.com", true},

	{[]string{"www.*.*.com"}, false, "www.example.com", false},
	{[]string{"www.*.*.com"}, false, "www.abc.def.com", true},
	{[]string{"www.*.*.com"}, false, "www.abc.def.ghi.com", true},

	{[]string{"www.*example*.com"}, false, "www.example.com", true},
	{[]string{"www.*example*.com"}, false, "www.abc.example.def.com", true},
	{[]string{"www.*example*.com"}, false, "www.e-xample.com", false},

	{[]string{"www.example.*"}, false, "www.example.com", true},
	{[]string{"www.example.*"}, false, "www.example.io", true},
	{[]string{"www.example.*"}, false, "www.example.com.cn", true},

	{[]string{".example.com"}, false, "www.example.com", true},
	{[]string{".example.com"}, false, "example.com", true},
	{[]string{".example.com"}, false, "www.example.com.cn", false},

	{[]string{"example.com*"}, false, "example.com", true},
	{[]string{"example.com:*"}, false, "example.com", false},
	{[]string{"example.com:*"}, false, "example.com:80", false},
	{[]string{"example.com:*"}, false, "example.com:8080", false},
	{[]string{"example.com:*"}, false, "example.com:http", true},
	{[]string{"example.com:*"}, false, "http://example.com:80", false},

	{[]string{"*example.com*"}, false, "example.com:80", true},
	{[]string{"*example.com:*"}, false, "example.com:80", false},

	{[]string{".example.com:*"}, false, "www.example.com", false},
	{[]string{".example.com:*"}, false, "http://www.example.com", false},
	{[]string{".example.com:*"}, false, "example.com:80", false},
	{[]string{".example.com:*"}, false, "www.example.com:8080", false},
	{[]string{".example.com:*"}, false, "http://www.example.com:80", true},
}

func TestBypassContains(t *testing.T) {
	for i, tc := range bypassContainTests {
		tc := tc
		t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
			bp := NewBypassPatterns(tc.reversed, tc.patterns...)
			if bp.Contains(tc.addr) != tc.bypassed {
				t.Errorf("#%d test failed: %v, %s", i, tc.patterns, tc.addr)
			}
		})
	}
}

var bypassReloadTests = []struct {
	r io.Reader

	reversed bool
	period   time.Duration

	addr     string
	bypassed bool
	stopped  bool
}{
	{
		r:        nil,
		reversed: false,
		period:   0,
		addr:     "192.168.1.1",
		bypassed: false,
		stopped:  false,
	},
	{
		r:        bytes.NewBufferString(""),
		reversed: false,
		period:   0,
		addr:     "192.168.1.1",
		bypassed: false,
		stopped:  false,
	},
	{
		r:        bytes.NewBufferString("reverse true\nreload 10s"),
		reversed: true,
		period:   10 * time.Second,
		addr:     "192.168.1.1",
		bypassed: false,
		stopped:  false,
	},
	{
		r:        bytes.NewBufferString("reverse false\nreload 10s\n192.168.1.1"),
		reversed: false,
		period:   10 * time.Second,
		addr:     "192.168.1.1",
		bypassed: true,
		stopped:  false,
	},
	{
		r:        bytes.NewBufferString("#reverse true\n#reload 10s\n192.168.0.0/16"),
		reversed: false,
		period:   0,
		addr:     "192.168.10.2",
		bypassed: true,
		stopped:  true,
	},
	{
		r:        bytes.NewBufferString("#reverse true\n#reload 10s\n192.168.1.0/24 #comment"),
		reversed: false,
		period:   0,
		addr:     "192.168.10.2",
		bypassed: false,
		stopped:  true,
	},
	{
		r:        bytes.NewBufferString("reverse false\nreload 10s\n192.168.1.1\n#example.com"),
		reversed: false,
		period:   10 * time.Second,
		addr:     "example.com",
		bypassed: false,
		stopped:  false,
	},
	{
		r:        bytes.NewBufferString("#reverse true\n#reload 10s\n192.168.1.1\n#example.com"),
		reversed: false,
		period:   0,
		addr:     "192.168.1.1",
		bypassed: true,
		stopped:  true,
	},
	{
		r:        bytes.NewBufferString("#reverse true\n#reload 10s\nexample.com #comment"),
		reversed: false,
		period:   0,
		addr:     "example.com",
		bypassed: true,
		stopped:  true,
	},
	{
		r:        bytes.NewBufferString("#reverse true\n#reload 10s\n.example.com"),
		reversed: false,
		period:   0,
		addr:     "example.com",
		bypassed: true,
		stopped:  true,
	},
	{
		r:        bytes.NewBufferString("#reverse true\n#reload 10s\n*.example.com"),
		reversed: false,
		period:   0,
		addr:     "example.com",
		bypassed: false,
		stopped:  true,
	},
}

func TestByapssReload(t *testing.T) {
	for i, tc := range bypassReloadTests {
		bp := NewBypass(false)
		if err := bp.Reload(tc.r); err != nil {
			t.Error(err)
		}
		t.Log(bp.String())

		if bp.Reversed() != tc.reversed {
			t.Errorf("#%d test failed: reversed value should be %v, got %v",
				i, tc.reversed, bp.reversed)
		}
		if bp.Period() != tc.period {
			t.Errorf("#%d test failed: period value should be %v, got %v",
				i, tc.period, bp.Period())
		}
		if bp.Contains(tc.addr) != tc.bypassed {
			t.Errorf("#%d test failed: %v, %s", i, bp.reversed, tc.addr)
		}
		if tc.stopped {
			bp.Stop()
			if bp.Period() >= 0 {
				t.Errorf("period of the stopped reloader should be minus value")
			}
			bp.Stop()
		}
		if bp.Stopped() != tc.stopped {
			t.Errorf("#%d test failed: stopped value should be %v, got %v",
				i, tc.stopped, bp.Stopped())
		}
	}
}


================================================
FILE: chain.go
================================================
package gost

import (
	"context"
	"errors"
	"fmt"
	"net"
	"syscall"
	"time"

	"github.com/go-log/log"
)

var (
	// ErrEmptyChain is an error that implies the chain is empty.
	ErrEmptyChain = errors.New("empty chain")
)

// Chain is a proxy chain that holds a list of proxy node groups.
type Chain struct {
	isRoute    bool
	Retries    int
	Mark       int
	Interface  string
	nodeGroups []*NodeGroup
	route      []Node // nodes in the selected route
}

// NewChain creates a proxy chain with a list of proxy nodes.
// It creates the node groups automatically, one group per node.
func NewChain(nodes ...Node) *Chain {
	chain := &Chain{}
	for _, node := range nodes {
		chain.nodeGroups = append(chain.nodeGroups, NewNodeGroup(node))
	}
	return 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
}

// Nodes returns the proxy nodes that the chain holds.
// The first node in each group will be returned.
func (c *Chain) Nodes() (nodes []Node) {
	for _, group := range c.nodeGroups {
		if ns := group.Nodes(); len(ns) > 0 {
			nodes = append(nodes, ns[0])
		}
	}
	return
}

// NodeGroups returns the list of node group.
func (c *Chain) NodeGroups() []*NodeGroup {
	return c.nodeGroups
}

// LastNode returns the last node of the node list.
// If the chain is empty, an empty node will be returned.
// If the last node is a node group, the first node in the group will be returned.
func (c *Chain) LastNode() Node {
	if c.IsEmpty() {
		return Node{}
	}
	group := c.nodeGroups[len(c.nodeGroups)-1]
	return group.GetNode(0)
}

// LastNodeGroup returns the last group of the group list.
func (c *Chain) LastNodeGroup() *NodeGroup {
	if c.IsEmpty() {
		return nil
	}
	return c.nodeGroups[len(c.nodeGroups)-1]
}

// AddNode appends the node(s) to the chain.
func (c *Chain) AddNode(nodes ...Node) {
	if c == nil {
		return
	}
	for _, node := range nodes {
		c.nodeGroups = append(c.nodeGroups, NewNodeGroup(node))
	}
}

// AddNodeGroup appends the group(s) to the chain.
func (c *Chain) AddNodeGroup(groups ...*NodeGroup) {
	if c == nil {
		return
	}
	for _, group := range groups {
		c.nodeGroups = append(c.nodeGroups, group)
	}
}

// IsEmpty checks if the chain is empty.
// An empty chain means that there is no proxy node or node group in the chain.
func (c *Chain) IsEmpty() bool {
	return c == nil || len(c.nodeGroups) == 0
}

// Dial connects to the target TCP address addr through the chain.
// Deprecated: use DialContext instead.
func (c *Chain) Dial(address string, opts ...ChainOption) (conn net.Conn, err error) {
	return c.DialContext(context.Background(), "tcp", address, opts...)
}

// DialContext connects to the address on the named network using the provided context.
func (c *Chain) DialContext(ctx context.Context, network, address string, opts ...ChainOption) (conn net.Conn, err error) {
	options := &ChainOptions{}
	for _, opt := range opts {
		opt(options)
	}

	retries := 1
	if c != nil && c.Retries > 0 {
		retries = c.Retries
	}
	if options.Retries > 0 {
		retries = options.Retries
	}

	for i := 0; i < retries; i++ {
		conn, err = c.dialWithOptions(ctx, network, address, options)
		if err == nil {
			break
		}
	}
	return
}

func (c *Chain) dialWithOptions(ctx context.Context, network, address string, options *ChainOptions) (net.Conn, error) {
	if options == nil {
		options = &ChainOptions{}
	}
	if c == nil {
		c = &Chain{}
	}
	route, err := c.selectRouteFor(address)
	if err != nil {
		return nil, err
	}

	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
	if timeout <= 0 {
		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":
			if address == "" {
				return net.ListenUDP(network, nil)
			}
		default:
		}
		d := &net.Dialer{
			Timeout: timeout,
			Control: controlFunction,
			// LocalAddr: laddr, // TODO: optional local address
		}
		return d.DialContext(ctx, network, ipAddr)
	}

	conn, err := route.getConn(ctx)
	if err != nil {
		return nil, err
	}

	cOpts := append([]ConnectOption{AddrConnectOption(address)}, route.LastNode().ConnectOptions...)
	cc, err := route.LastNode().Client.ConnectContext(ctx, conn, network, ipAddr, cOpts...)
	if err != nil {
		conn.Close()
		return nil, err
	}
	return cc, nil
}

func (*Chain) resolve(addr string, resolver Resolver, hosts *Hosts) string {
	host, port, err := net.SplitHostPort(addr)
	if err != nil {
		return addr
	}

	if ip := hosts.Lookup(host); ip != nil {
		return net.JoinHostPort(ip.String(), port)
	}
	if resolver != nil {
		ips, err := resolver.Resolve(host)
		if err != nil {
			log.Logf("[resolver] %s: %v", host, err)
		}
		if len(ips) == 0 {
			log.Logf("[resolver] %s: domain does not exists", host)
			return ""
		}
		return net.JoinHostPort(ips[0].String(), port)
	}
	return addr
}

// Conn obtains a handshaked connection to the last node of the chain.
func (c *Chain) Conn(opts ...ChainOption) (conn net.Conn, err error) {
	options := &ChainOptions{}
	for _, opt := range opts {
		opt(options)
	}

	ctx := context.Background()

	retries := 1
	if c != nil && c.Retries > 0 {
		retries = c.Retries
	}
	if options.Retries > 0 {
		retries = options.Retries
	}

	for i := 0; i < retries; i++ {
		var route *Chain
		route, err = c.selectRoute()
		if err != nil {
			continue
		}
		conn, err = route.getConn(ctx)
		if err == nil {
			break
		}
	}
	return
}

// getConn obtains a connection to the last node of the chain.
func (c *Chain) getConn(ctx context.Context) (conn net.Conn, err error) {
	if c.IsEmpty() {
		err = ErrEmptyChain
		return
	}
	nodes := c.Nodes()
	node := nodes[0]

	cc, err := node.Client.Dial(node.Addr, node.DialOptions...)
	if err != nil {
		node.MarkDead()
		return
	}

	cn, err := node.Client.Handshake(cc, node.HandshakeOptions...)
	if err != nil {
		cc.Close()
		node.MarkDead()
		return
	}
	node.ResetDead()

	preNode := node
	for _, node := range nodes[1:] {
		var cc net.Conn
		cc, err = preNode.Client.ConnectContext(ctx, cn, "tcp", node.Addr, preNode.ConnectOptions...)
		if err != nil {
			cn.Close()
			node.MarkDead()
			return
		}
		cc, err = node.Client.Handshake(cc, node.HandshakeOptions...)
		if err != nil {
			cn.Close()
			node.MarkDead()
			return
		}
		node.ResetDead()

		cn = cc
		preNode = node
	}

	conn = cn
	return
}

func (c *Chain) selectRoute() (route *Chain, err error) {
	return c.selectRouteFor("")
}

// selectRouteFor selects route with bypass testing.
func (c *Chain) selectRouteFor(addr string) (route *Chain, err error) {
	if c.IsEmpty() {
		return c.newRoute(), nil
	}
	if c.isRoute {
		return c, nil
	}

	route = c.newRoute()
	var nl []Node

	for _, group := range c.nodeGroups {
		var node Node
		node, err = group.Next()
		if err != nil {
			return
		}

		if node.Bypass.Contains(addr) {
			break
		}

		if node.Client.Transporter.Multiplex() {
			node.DialOptions = append(node.DialOptions,
				ChainDialOption(route),
			)
			route = c.newRoute() // cutoff the chain for multiplex node.
		}

		route.AddNode(node)
		nl = append(nl, node)
	}

	route.route = nl

	return
}

// ChainOptions holds options for Chain.
type ChainOptions struct {
	Retries  int
	Timeout  time.Duration
	Hosts    *Hosts
	Resolver Resolver
	Mark     int
}

// ChainOption allows a common way to set chain options.
type ChainOption func(opts *ChainOptions)

// RetryChainOption specifies the times of retry used by Chain.Dial.
func RetryChainOption(retries int) ChainOption {
	return func(opts *ChainOptions) {
		opts.Retries = retries
	}
}

// TimeoutChainOption specifies the timeout used by Chain.Dial.
func TimeoutChainOption(timeout time.Duration) ChainOption {
	return func(opts *ChainOptions) {
		opts.Timeout = timeout
	}
}

// HostsChainOption specifies the hosts used by Chain.Dial.
func HostsChainOption(hosts *Hosts) ChainOption {
	return func(opts *ChainOptions) {
		opts.Hosts = hosts
	}
}

// ResolverChainOption specifies the Resolver used by Chain.Dial.
func ResolverChainOption(resolver Resolver) ChainOption {
	return func(opts *ChainOptions) {
		opts.Resolver = resolver
	}
}


================================================
FILE: client.go
================================================
package gost

import (
	"context"
	"crypto/tls"
	"net"
	"net/url"
	"time"

	"github.com/go-gost/gosocks5"
)

// Client is a proxy client.
// A client is divided into two layers: connector and transporter.
// Connector is responsible for connecting to the destination address through this proxy.
// Transporter performs a handshake with this proxy.
type Client struct {
	Connector
	Transporter
}

// DefaultClient is a standard HTTP proxy client.
var DefaultClient = &Client{Connector: HTTPConnector(nil), Transporter: TCPTransporter()}

// Dial connects to the address addr via the DefaultClient.
func Dial(addr string, options ...DialOption) (net.Conn, error) {
	return DefaultClient.Dial(addr, options...)
}

// Handshake performs a handshake via the DefaultClient.
func Handshake(conn net.Conn, options ...HandshakeOption) (net.Conn, error) {
	return DefaultClient.Handshake(conn, options...)
}

// Connect connects to the address addr via the DefaultClient.
func Connect(conn net.Conn, addr string) (net.Conn, error) {
	return DefaultClient.Connect(conn, addr)
}

// Connector is responsible for connecting to the destination address.
type Connector interface {
	// Deprecated: use ConnectContext instead.
	Connect(conn net.Conn, address string, options ...ConnectOption) (net.Conn, error)
	ConnectContext(ctx context.Context, conn net.Conn, network, address string, options ...ConnectOption) (net.Conn, error)
}

type autoConnector struct {
	User *url.Userinfo
}

// AutoConnector is a Connector.
func AutoConnector(user *url.Userinfo) Connector {
	return &autoConnector{
		User: user,
	}
}

func (c *autoConnector) Connect(conn net.Conn, address string, options ...ConnectOption) (net.Conn, error) {
	return c.ConnectContext(context.Background(), conn, "tcp", address, options...)
}

func (c *autoConnector) ConnectContext(ctx context.Context, conn net.Conn, network, address string, options ...ConnectOption) (net.Conn, error) {
	var cnr Connector
	switch network {
	case "tcp", "tcp4", "tcp6":
		cnr = &httpConnector{User: c.User}
	default:
		cnr = &socks5UDPTunConnector{User: c.User}
	}

	return cnr.ConnectContext(ctx, conn, network, address, options...)
}

// Transporter is responsible for handshaking with the proxy server.
type Transporter interface {
	Dial(addr string, options ...DialOption) (net.Conn, error)
	Handshake(conn net.Conn, options ...HandshakeOption) (net.Conn, error)
	// Indicate that the Transporter supports multiplex
	Multiplex() bool
}

// DialOptions describes the options for Transporter.Dial.
type DialOptions struct {
	Timeout time.Duration
	Chain   *Chain
	Host    string
}

// DialOption allows a common way to set DialOptions.
type DialOption func(opts *DialOptions)

// TimeoutDialOption specifies the timeout used by Transporter.Dial
func TimeoutDialOption(timeout time.Duration) DialOption {
	return func(opts *DialOptions) {
		opts.Timeout = timeout
	}
}

// ChainDialOption specifies a chain used by Transporter.Dial
func ChainDialOption(chain *Chain) DialOption {
	return func(opts *DialOptions) {
		opts.Chain = chain
	}
}

// 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
	Host       string
	User       *url.Userinfo
	Timeout    time.Duration
	Interval   time.Duration
	Retry      int
	TLSConfig  *tls.Config
	WSOptions  *WSOptions
	KCPConfig  *KCPConfig
	QUICConfig *QUICConfig
	SSHConfig  *SSHConfig
}

// HandshakeOption allows a common way to set HandshakeOptions.
type HandshakeOption func(opts *HandshakeOptions)

// AddrHandshakeOption specifies the server address
func AddrHandshakeOption(addr string) HandshakeOption {
	return func(opts *HandshakeOptions) {
		opts.Addr = addr
	}
}

// HostHandshakeOption specifies the hostname
func HostHandshakeOption(host string) HandshakeOption {
	return func(opts *HandshakeOptions) {
		opts.Host = host
	}
}

// UserHandshakeOption specifies the user used by Transporter.Handshake
func UserHandshakeOption(user *url.Userinfo) HandshakeOption {
	return func(opts *HandshakeOptions) {
		opts.User = user
	}
}

// TimeoutHandshakeOption specifies the timeout used by Transporter.Handshake
func TimeoutHandshakeOption(timeout time.Duration) HandshakeOption {
	return func(opts *HandshakeOptions) {
		opts.Timeout = timeout
	}
}

// IntervalHandshakeOption specifies the interval time used by Transporter.Handshake
func IntervalHandshakeOption(interval time.Duration) HandshakeOption {
	return func(opts *HandshakeOptions) {
		opts.Interval = interval
	}
}

// RetryHandshakeOption specifies the times of retry used by Transporter.Handshake
func RetryHandshakeOption(retry int) HandshakeOption {
	return func(opts *HandshakeOptions) {
		opts.Retry = retry
	}
}

// TLSConfigHandshakeOption specifies the TLS config used by Transporter.Handshake
func TLSConfigHandshakeOption(config *tls.Config) HandshakeOption {
	return func(opts *HandshakeOptions) {
		opts.TLSConfig = config
	}
}

// WSOptionsHandshakeOption specifies the websocket options used by websocket handshake
func WSOptionsHandshakeOption(options *WSOptions) HandshakeOption {
	return func(opts *HandshakeOptions) {
		opts.WSOptions = options
	}
}

// KCPConfigHandshakeOption specifies the KCP config used by KCP handshake
func KCPConfigHandshakeOption(config *KCPConfig) HandshakeOption {
	return func(opts *HandshakeOptions) {
		opts.KCPConfig = config
	}
}

// QUICConfigHandshakeOption specifies the QUIC config used by QUIC handshake
func QUICConfigHandshakeOption(config *QUICConfig) HandshakeOption {
	return func(opts *HandshakeOptions) {
		opts.QUICConfig = config
	}
}

// SSHConfigHandshakeOption specifies the ssh config used by SSH client handshake.
func SSHConfigHandshakeOption(config *SSHConfig) HandshakeOption {
	return func(opts *HandshakeOptions) {
		opts.SSHConfig = config
	}
}

// ConnectOptions describes the options for Connector.Connect.
type ConnectOptions struct {
	Addr      string
	Timeout   time.Duration
	User      *url.Userinfo
	Selector  gosocks5.Selector
	UserAgent string
	NoTLS     bool
	NoDelay   bool
}

// ConnectOption allows a common way to set ConnectOptions.
type ConnectOption func(opts *ConnectOptions)

// AddrConnectOption specifies the corresponding address of the target.
func AddrConnectOption(addr string) ConnectOption {
	return func(opts *ConnectOptions) {
		opts.Addr = addr
	}
}

// TimeoutConnectOption specifies the timeout for connecting to target.
func TimeoutConnectOption(timeout time.Duration) ConnectOption {
	return func(opts *ConnectOptions) {
		opts.Timeout = timeout
	}
}

// UserConnectOption specifies the user info for authentication.
func UserConnectOption(user *url.Userinfo) ConnectOption {
	return func(opts *ConnectOptions) {
		opts.User = user
	}
}

// SelectorConnectOption specifies the SOCKS5 client selector.
func SelectorConnectOption(s gosocks5.Selector) ConnectOption {
	return func(opts *ConnectOptions) {
		opts.Selector = s
	}
}

// UserAgentConnectOption specifies the HTTP user-agent header.
func UserAgentConnectOption(ua string) ConnectOption {
	return func(opts *ConnectOptions) {
		opts.UserAgent = ua
	}
}

// NoTLSConnectOption specifies the SOCKS5 method without TLS.
func NoTLSConnectOption(b bool) ConnectOption {
	return func(opts *ConnectOptions) {
		opts.NoTLS = b
	}
}

// NoDelayConnectOption specifies the NoDelay option for ss.Connect.
func NoDelayConnectOption(b bool) ConnectOption {
	return func(opts *ConnectOptions) {
		opts.NoDelay = b
	}
}


================================================
FILE: cmd/gost/.ssl/README.md
================================================
[//]: <> (https://gist.github.com/fntlnz/cf14feb5a46b2eda428e000157447309)

# Create Root CA (Done once)

## Create Root Key

**Attention:** this is the key used to sign the certificate requests, anyone holding this can sign certificates on your behalf. So keep it in a safe place!

```bash
openssl genrsa -des3 -out rootCA.key 4096
```

If you want a non password protected key just remove the `-des3` option


## Create and self sign the Root Certificate

```bash
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.crt
```

Here we used our root key to create the root certificate that needs to be distributed in all the computers that have to trust us.


# Create a certificate (Done for each server)

This procedure needs to be followed for each server/appliance that needs a trusted certificate from our CA

## Create the certificate key

```
openssl genrsa -out mydomain.com.key 2048
```

## Create the signing request

**Important:** Please mind that while creating the signign request is important to specify the `Common Name` providing the IP address or URL for the service, otherwise the certificate
cannot be verified

```
openssl req -new -key mydomain.com.key -out mydomain.com.csr
```

## Generate the certificate using the `mydomain` csr and key along with the CA Root key

```
openssl x509 -req -in mydomain.com.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out mydomain.com.crt -days 500 -sha256
```


================================================
FILE: cmd/gost/.ssl/localhost.crt
================================================
-----BEGIN CERTIFICATE-----
MIIDvjCCAaYCCQC0XjV3wljvnjANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls
b2NhbGhvc3QwHhcNMTgwNzA4MDQ1MzIyWhcNMTkxMTIwMDQ1MzIyWjAuMQswCQYD
VQQGEwJDTjELMAkGA1UEBwwCU0gxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMOKgzWil/KjyRy2Axb3XlLB1nMwLFJC
pC6r8yb+1Kq/ldZghJZvymuFVjn+bihvJqvZiOv4KRtnM8gD55AhaQp6Ese5M9b+
47HLB//SkfJsQREsmnrHfHxjmUQjhMy7jrpcf9OnDOXQ5zk3v6AWEIqMtAiZ99ku
AQvyJJ07+VpwZrMuzbSGfFBCKEbbqP7yKHjSUm3QDTpTiK4AnBmzlVeThUIA68oa
XZKQVXX/8U2i6H4eq5eNpyUsKSnnuK+cryHpAIK4vNMzw96vATTfEmuWASEzkHhW
3KtfXE0CIH0GsK5zueGDo9ygnO7hjtx60SWynlGf6c6edxPwNvEmTZcCAwEAATAN
BgkqhkiG9w0BAQsFAAOCAgEApLkdhnDzErgBljY6qRaR0JlouTpqJXwi5BRi7F1P
bx5ukrZAVSOsZ7ncEkZuxkIX+ktBVFBL8twkvMEl+sMQ24R+F+TrlHWN2xPR/pez
9V19hq26yMIlYLqSq3KZ0W9ZlT2ge+3sTvY+gAJhZ6nOz9WGRJ1mi+pN/ok678QX
KdOJXcePzYr5iKqMq/5cJ2sA1xYwVl+0xrvfRVTFkp4yR6wzGODtjquB+scZ9S64
GWnFTjHAJvUKYxpeoLAt9lZHsESDqGq7hA4z1uVjhNEDJHKnXW4OhXxMB8Gk2hY8
3k4zbnKsouNNW0a7jijCMpXOem/vgQF4GK5ecp0S+Ml/AunsPoi6rGgOCX8XXmti
6DfQhsxxgn1co/JKNxhgsnQftXFwKivh73JFctSh+bMLsewfXsvq+b0K3EuuV9bV
EttVCgbUaCDYdA6IDkqD2PRx9tsotne76r+cX+ah+NjnA6XN+XY2bJgV1UaiKTrP
moNHglw+xoUqOJ7FlGJcVC7uIFPhMviNkpSZh6WxX+OSS4fPO25kxxNpldql6I+3
xb5XEHLpPCEI4PyK0rYnsjk764Loqff8YBMFRQSXIUz9ot5SgGs/FY1vsQap5OeD
Hw2usWhCvkSzr7kiXI+30BvJKK2r9GOAM7mtO9dfkM9MMKKnMzd+O2XE4r6PNLrg
Rds=
-----END CERTIFICATE-----


================================================
FILE: cmd/gost/.ssl/localhost.csr
================================================
-----BEGIN CERTIFICATE REQUEST-----
MIICczCCAVsCAQAwLjELMAkGA1UEBhMCQ04xCzAJBgNVBAcMAlNIMRIwEAYDVQQD
DAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDioM1
opfyo8kctgMW915SwdZzMCxSQqQuq/Mm/tSqv5XWYISWb8prhVY5/m4obyar2Yjr
+CkbZzPIA+eQIWkKehLHuTPW/uOxywf/0pHybEERLJp6x3x8Y5lEI4TMu466XH/T
pwzl0Oc5N7+gFhCKjLQImffZLgEL8iSdO/lacGazLs20hnxQQihG26j+8ih40lJt
0A06U4iuAJwZs5VXk4VCAOvKGl2SkFV1//FNouh+HquXjaclLCkp57ivnK8h6QCC
uLzTM8PerwE03xJrlgEhM5B4VtyrX1xNAiB9BrCuc7nhg6PcoJzu4Y7cetElsp5R
n+nOnncT8DbxJk2XAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAr+AkYRAPulBU
B5HR3pAreYrf3Y2fvGLSNo4hvsJkmXJxDgMZnGsjVzW1IZLF8szn4v050y6Qm/Ne
qupabYP5zpj0vKkACYGJ2zadnowmwlTzwlxEOv27uQykC/IuRcjdloAD7ZwhNwmO
dLNjdiXn63GUeSL/JK0UHyXTqvpmiHq+6TAOdl3vmsRFCQDChRtViK2fwSeX2y87
hLicSVQyNOe0gUx7IvE9B2QPNhdzaMVPYeN8I/cayNeUKhiWxEGKhwPAaievuSXJ
fUsz11XYBYW+kjFsTqkV1OjkG0mxvwaiq5W3CRx8365w71IMdKV5t5xhc0n0TXp7
cT27XN7cdw==
-----END CERTIFICATE REQUEST-----


================================================
FILE: cmd/gost/.ssl/localhost.key
================================================
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAw4qDNaKX8qPJHLYDFvdeUsHWczAsUkKkLqvzJv7Uqr+V1mCE
lm/Ka4VWOf5uKG8mq9mI6/gpG2czyAPnkCFpCnoSx7kz1v7jscsH/9KR8mxBESya
esd8fGOZRCOEzLuOulx/06cM5dDnOTe/oBYQioy0CJn32S4BC/IknTv5WnBmsy7N
tIZ8UEIoRtuo/vIoeNJSbdANOlOIrgCcGbOVV5OFQgDryhpdkpBVdf/xTaLofh6r
l42nJSwpKee4r5yvIekAgri80zPD3q8BNN8Sa5YBITOQeFbcq19cTQIgfQawrnO5
4YOj3KCc7uGO3HrRJbKeUZ/pzp53E/A28SZNlwIDAQABAoIBAGx1pMeYMw3L2R5K
urX/aVsf1xI3My5Bdo3IpGsJx+4ZrEOnb4N96FnxMF2kiXd2B44kb/TqxepEOQ2F
VOi2D2xXP5l2WZGz+ZnBUuOL6ZX8g67B/cGCasMX/4gy51Mj6UvnSKOeMeI7GDW9
fVWPR4eB+c4XkMju4ne8zKBGBs4pN4KoxTWSnZSM4p+q/Jb/DMa+kVhFfRjkqfWc
vCpDgHs1uMcHvPBNYO9flDaC2Jgk4cvV9mX0TolXAvaNo8aN0joM7WH3fvw7NCD9
LCkqCmpjOxJIqJQT1twIkSy42q7VaFi7ApyIaMfXlmnj4UTlVTe5bBO+2AgwLYtC
cKgDMjECgYEA8JPm3Pc80EsYB6d4qp/Qmy2VrnlaxZwvaRwh63Pssqthg4SZkIp5
yjXOT4MDlJdrEzMtATRZUXTCRxGFSs0tolNY2KQ2WvYRhISlN8UBkGuMEkRGLuct
p++qpPcSZJcox25kT82CKin1nQYb48k33JAOMUOWIBJO56G35sfPj28CgYEA0BOE
pa+FYj/WxZS79YT1ZbsajeuUKlNUtAIxKJ2cKSQyfFuPM+xZG3H+iroRfR8HCVai
2+Oz9/TlxZOPR7+P+2fpS8W2tT+Qkmiyz8QJAULd+Irw5XIdatkpVm343XxMx3Pa
2qtBmgj6RINvsWTWRotMqhcuDRirxqm1IIQhkFkCgYBLNmIhyOXpVODRW8k8xrQI
H6tBHc2EJD0qRlJQczCX9z6ISIdeCfzjfAjhENuos+IU4ZX7X2thLPikEVUzuou+
yQHo0QXxUCbP4Exq8Bt6FDV5bIDonvvGGgamhlvouN1V5CxWSrCcD/wquEM15q2h
NiRJwJCJvE+Q2R1OeD9q3wKBgFWDkAJf7luAjQ3KoKy4pfnXOYSWCuCSOr94Hyfo
DmPCIpWFM4dNXRmwccIl0kYv2D54QppILJB9L2lRyZLdIZlbDUA802gN5aamLMbC
dEj2aC9bOsGxcnGVKi4BKEQub4eRD6LKuz1I70H1GpQ3MvDvEuTcfeqX9xDAclYY
t4qRAoGBAI6YSTs97DUe7Zwk7q+S3PBU5uct4Dwtmy2XWZdgHwl5aP8apSLciL5Y
PMkpcTMzkuC+QFaPZ8wFcI7GLg0bOs91hkrqscDKEg4nGB9fJkU82iOQZNL4Hv1u
wO7uIGa2kcpNtQOLNO88y45WFyrn5a+T6VhDmIuc+F+TU1ZzdYdH
-----END RSA PRIVATE KEY-----


================================================
FILE: cmd/gost/.ssl/rootCA.crt
================================================
-----BEGIN CERTIFICATE-----
MIIEpDCCAowCCQDwV08QFUCcSzANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls
b2NhbGhvc3QwHhcNMTgwNzA4MDQ1MzE3WhcNMjEwNDI3MDQ1MzE3WjAUMRIwEAYD
VQQDDAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDE
+71yX9vQY3l52C31e04ACvm2oNMLSCrLOXGewOTFpv9yXjinMC0Ab6Xa4yB4MPtd
ujWDSEq9gkKCkILoalVX7R4gtLDN+EdoVadBw/WHbrGB4sHnFOWwpUbjiiwwPSU5
qXjcqIqR2sA1BgoAv6c1qHq7V4bgbEjtGL71KkDoQZSIgNyJlXe1mcUKqmqeAnro
0WfwrNXyYt66L3PmCy9MIpWRxf9sa8PDsgT3SQEN4BHb70Z8hNj6RXfVGDZcpfcI
iwbrL//YnK7waRKaKD4LoLOodE0cx3fowSWYvlwUAoYx8wFKOcdtM1zaUp+QDAug
xT5g5ghU150XuqhDU6Wq1An8dLgcDU1D4cxhLk/W8OXtIk4k7yny6eUJi2zHziMm
8jfHd3M6SwohUrE3LsQI5gpvu4sAVFLMkRxaWZ95XhsVMmIsE/L5FHwDfqid0dvx
bafOKT+fI3N3BaUPJlVHCNqSzSZIW59+ufnDwBV7SmJj4KMlvixEU+EFfPFdGiCA
Lr0dSG5+Scx1aClaMUeVccCljp2f99IEa9wI+xwMPDStkOmnhVuqG1aEogggQZkD
/5yh04wrn8EwYCAiasNNUXTV7AoqIt2bgeFbGo2Qr7LdsYuUmaWEzTm0KsHogkkg
Ibd3RPBLDr/WfWI13oHMdsz8jjbXG/D1AhrcdozYDQIDAQABMA0GCSqGSIb3DQEB
CwUAA4ICAQC1EeQqn2AwrS+UVc5fKRpHzV9ZMiDpxFMRLsDWBP5kNr1nSA72yYcR
WgxvdqG/rGRds6lvRbvIaWD0zeujPkR3iCpb1V5oRXQ6lWOlY44pZEwCdnDd2M8I
yQ7BLZCHHmlCN7a51n2o0D78HeILIeeTCQlKFDc5r51qrZbZR5DZmrp9jaZ+3eCg
LQ3Onfj0WEmQFuMFGQrbJ2oaCC1GvuZWEbRh+lrxjRKOyCaRQFTY4Efe8tIwMm6J
1iyMtqK7BxminQCfizQrstB67wMljydYeUf+wwbgkiKGYc9VGopckrO3lntzKycu
9l0BmlZYkmCFt3cv23BcqAbcLdyLXh3yASwVMXaLZ4iVSaslRm4uX+gbKFCBABLa
vqu7JQHfAPOeYj7zCrN12EHejPxdCjSImBeAbe56vax4uFGAodXxDGcepRItSzax
qPKJd8U/8e3JDn+wmZNKwD9UGLZPbiuYOg7X+EWhjki0J6ZjgLc8dMleeD2rO+j2
P/Wgv1gMr6J1svUlqkNf1Ng9eSbl/nMhuOBVOGcPnK7+wCLxM7ByaR0QgeH6/9VO
4urq53/vspBC679BHsZx3gIhcg4VefmOM2cZnTRM4izPstq1JBQkbuvz+5XuT7Yj
5Fk1/xkapCUifntKYSoslkkbNHRYxAInqkc0txn3qNBI8GAQFksz5g==
-----END CERTIFICATE-----


================================================
FILE: cmd/gost/.ssl/rootCA.key
================================================
-----BEGIN RSA PRIVATE KEY-----
MIIJKAIBAAKCAgEAxPu9cl/b0GN5edgt9XtOAAr5tqDTC0gqyzlxnsDkxab/cl44
pzAtAG+l2uMgeDD7Xbo1g0hKvYJCgpCC6GpVV+0eILSwzfhHaFWnQcP1h26xgeLB
5xTlsKVG44osMD0lOal43KiKkdrANQYKAL+nNah6u1eG4GxI7Ri+9SpA6EGUiIDc
iZV3tZnFCqpqngJ66NFn8KzV8mLeui9z5gsvTCKVkcX/bGvDw7IE90kBDeAR2+9G
fITY+kV31Rg2XKX3CIsG6y//2Jyu8GkSmig+C6CzqHRNHMd36MElmL5cFAKGMfMB
SjnHbTNc2lKfkAwLoMU+YOYIVNedF7qoQ1OlqtQJ/HS4HA1NQ+HMYS5P1vDl7SJO
JO8p8unlCYtsx84jJvI3x3dzOksKIVKxNy7ECOYKb7uLAFRSzJEcWlmfeV4bFTJi
LBPy+RR8A36ondHb8W2nzik/nyNzdwWlDyZVRwjaks0mSFuffrn5w8AVe0piY+Cj
Jb4sRFPhBXzxXRoggC69HUhufknMdWgpWjFHlXHApY6dn/fSBGvcCPscDDw0rZDp
p4VbqhtWhKIIIEGZA/+codOMK5/BMGAgImrDTVF01ewKKiLdm4HhWxqNkK+y3bGL
lJmlhM05tCrB6IJJICG3d0TwSw6/1n1iNd6BzHbM/I421xvw9QIa3HaM2A0CAwEA
AQKCAgBXbeSH/0PxGjWwfuLnMfNM0ZJEHN2PBFj6GmTzsWnY0GZQvMEoc5mFuAhF
PsoKjrMCxsM5obyKoGYkzT9NKOT4QaY9nfVbdfc7t8ikx/USR29B1wN5LS1FWhY8
p/c08e6zySR7y9K1KgJlhmiqLGZqynyu6gpTUbyMf49CAZ8Ndw4WCBvadRzM3ZM3
SKxJtZAYBdm8WPocuwVgXe9zC0PS5wa7zMWxuaMKGNlbaGuvXOSQWYNPgSdM7chi
LHz0YjVi9VH80TEdU23SBtDa20Gup4UWH4iaXW47QH8PbG4x82zcfp7z8vEw5rsv
q7xmkvIWSXWGTJMmFQ0EmzRTray5fj38Oo2ZtwHvkJQ1WkiFNFiWFZXnoS3z6h5q
1lX6ZUhCoobUJRRlDYCwNDV6dMYKXK2NNeD1MPvzUoUIpoQnoxnNF+VYMMENax3e
YuEiT6xbBXzB/WE0bFVAtSPzf1vPVw+8MP5BhaH3lQb6XA89FiEZg+u95rNpf2SA
gFWvz0VZsGab+LwYhbYdicmKPRH+2Pzpt5MdWt8jyo066Lv0NP5xpH9IUv/u2RX7
Ycw0Bu1HWKLoEzovoH6OEa0n1A7H+PNOhABzrLvbU8GMp4kEQpXACxR43KruxE7S
QgotUAb7teCP54yEHTVAe06YIaq4JPk5xqnmMVvaeuy5rvssAQKCAQEA5d4NUONV
/An+bAf31HicZfRH6Pf1N3JUdjYz2l1y60Pf7dzlDI2fjOWlccp24+efXLM1sMeK
GXQZsAnYJevZktQxodM67CsgEFgdGhH2s5Ey3Dp5bt3uS/SaFv4sT1x9awYdYtKp
6fGovjB1Qp/eMuZNJVl9RwegFVzzrrSMxucNzUuL4v4L911ypR4wz4s1ptqI31/U
56B1VRKjwZntqJaNO2Plt/yY0s+ganhzdKBynoOKzTpYHCqZhHdqvqfc1qC0W1xI
E/b3Nf0J+GqjjT7JDbWgqNty5ipDfCdIeems96U1Gu9oeKGDzvCgtImZNFMyHzLM
MhO0v6GA6zkuVQKCAQEA22Cls2AAUuugi2tdZR/krHokrUMPaKvi9RIQpqHpoKqL
E3rKX9aWyIMhktch7VsnDF52R8CMUhgc7PfL4wsWA5cCq26x4E57aJUH5mxc5va5
n5Sxb3C99Ytr6GpCkG4Y3pzO93ihgfuW+mQREYLpFYd/c/1SH/e4Wx5nGKx6YocY
6b/AbxWcRMlihC2gK7JFgSZMqaL+wn68oKJ7j8RUN+ykZEzBXBWL2l4oKWm+qBDx
pOFSQODeQ0CQhPWovD4dVNmyrh5TcDUlJQ3+iU2hRkXe13mLTkGpSM53kwkrfVn+
4SmVLEm5YhNcHG14A1yDqs6SY//8l5xfUeZyrPBK2QKCAQEAqIsRLm8SG9RkFWge
Qk8RNfxQQbSVu0r8PRTvHjyIx5Ij/e+KjpLFGvVDQtUWKXMquTi5tF4KlzE2qIn/
T4bIKE2n+qS7vnC8eN9yryvevLlJFotVgIH/ePfnh9ZkPOhvGWsJXu1iIqPLe3Bi
ejBoJuAQTsN4BP3FVgSqtD20Px8pUo8DCbQGqCB/sCwb1AGZnDb+RvKoVBGmFnOt
WIX56TRCZ/qOdEIk9+W/FHIvDaObhziiLGqMMlLV73fz78l7Nm/s7lQSkXjyuEZJ
6jiepTEVEBVNsKH/dF4mz0CqdqFs7sPW1WIXMuQSlkh/PQDrMZ+Sz6daa5lhXWUY
9uAdZQKCAQBrDzRuYIhn7yPPRlsy0ai4X3dsstBfRZsh/Gnx2Ax64x+yJveCY+f7
/LqyvZiKDDT3PVY92ALiwW/EWX2/1JYutFCSNxhJniNtu2U6l2GTOY8HCPq6puud
XCgSKWFIuOIcKax7avxuwchBc/o8cIWtgw25HkQo46ytkx2/FdU4JjQLRw/zZjl3
/Eu+s8F58asnxvgcxTXM1yrYvdLNK4PqMutbI3YtqToyHEc/RqLLxFEZJPkOPm9Z
pLWinXx2OV35HbCsdpJDrTvuZHD2stLkx45j26YXT8X8iP4j3JLDvtq7KZ7qGSSG
b2pBWU77XPfIsL0SXkf3+VEvV+ZY7X+pAoIBABV6Mu5Yr4UxI+ZgsaKgcK8aKoyD
5GDshxkxs8R3K1i7eCF0mEjxkV25r11KX10qFvG+hPJqizKQDBOCQC2w3noqz42p
QVUeBNXpDVGoImD1/4DqUvQMivTwHWS+wSAi/wYAODJ6/bWP5Kil/7iDOwCPp0WD
mLd0ujjwkOw3Xksn2Gd01pXeiT4FZpkYnyh5ddWGf1TihRFATW5+vpi6t+6KX3LR
hwd9zi6soSwju/n986NUfGfeewBb6/fnh6hM/vfS2a0Blvk/7yM1k2P0uN+TzLYf
skhRay10UoMwtXak+q/DBzrrAbW3EwuIdV66H4dx1AV5NMq6kAAtfDXc728=
-----END RSA PRIVATE KEY-----


================================================
FILE: cmd/gost/.ssl/rootCA.srl
================================================
B45E3577C258EF9E


================================================
FILE: cmd/gost/cfg.go
================================================
package main

import (
	"bufio"
	"crypto/tls"
	"crypto/x509"
	"encoding/json"
	"fmt"
	"net"
	"net/url"
	"os"
	"strings"

	"github.com/ginuerzh/gost"
)

var (
	routers []router
)

type baseConfig struct {
	route
	Routes []route
	Debug  bool
}

func parseBaseConfig(s string) (*baseConfig, error) {
	file, err := os.Open(s)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	if err := json.NewDecoder(file).Decode(baseCfg); err != nil {
		return nil, err
	}

	return baseCfg, nil
}

var (
	defaultCertFile = "cert.pem"
	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) {
	if certFile == "" || keyFile == "" {
		certFile, keyFile = defaultCertFile, defaultKeyFile
	}

	cert, err := tls.LoadX509KeyPair(certFile, keyFile)
	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
}

func loadCA(caFile string) (cp *x509.CertPool, err error) {
	if caFile == "" {
		return
	}
	cp = x509.NewCertPool()
	data, err := os.ReadFile(caFile)
	if err != nil {
		return nil, err
	}
	if !cp.AppendCertsFromPEM(data) {
		return nil, fmt.Errorf("loadCA %s: AppendCertsFromPEM failed", caFile)
	}
	return
}

func parseKCPConfig(configFile string) (*gost.KCPConfig, error) {
	if configFile == "" {
		return nil, nil
	}
	file, err := os.Open(configFile)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	config := &gost.KCPConfig{}
	if err = json.NewDecoder(file).Decode(config); err != nil {
		return nil, err
	}
	return config, nil
}

func parseUsers(authFile string) (users []*url.Userinfo, err error) {
	if authFile == "" {
		return
	}

	file, err := os.Open(authFile)
	if err != nil {
		return
	}
	defer file.Close()
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if line == "" || strings.HasPrefix(line, "#") {
			continue
		}

		s := strings.SplitN(line, " ", 2)
		if len(s) == 1 {
			users = append(users, url.User(strings.TrimSpace(s[0])))
		} else if len(s) == 2 {
			users = append(users, url.UserPassword(strings.TrimSpace(s[0]), strings.TrimSpace(s[1])))
		}
	}

	err = scanner.Err()
	return
}

func parseAuthenticator(s string) (gost.Authenticator, error) {
	if s == "" {
		return nil, nil
	}
	f, err := os.Open(s)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	au := gost.NewLocalAuthenticator(nil)
	au.Reload(f)

	go gost.PeriodReload(au, s)

	return au, nil
}

func parseIP(s string, port string) (ips []string) {
	if s == "" {
		return
	}
	if port == "" {
		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))
			}

		}
		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))
	}
	return
}

func parseBypass(s string) *gost.Bypass {
	if s == "" {
		return nil
	}
	var matchers []gost.Matcher
	var reversed bool
	if strings.HasPrefix(s, "~") {
		reversed = true
		s = strings.TrimLeft(s, "~")
	}

	f, err := os.Open(s)
	if err != nil {
		for _, s := range strings.Split(s, ",") {
			s = strings.TrimSpace(s)
			if s == "" {
				continue
			}
			matchers = append(matchers, gost.NewMatcher(s))
		}
		return gost.NewBypass(reversed, matchers...)
	}
	defer f.Close()

	bp := gost.NewBypass(reversed)
	bp.Reload(f)
	go gost.PeriodReload(bp, s)

	return bp
}

func parseResolver(cfg string) gost.Resolver {
	if cfg == "" {
		return nil
	}
	var nss []gost.NameServer

	f, err := os.Open(cfg)
	if err != nil {
		for _, s := range strings.Split(cfg, ",") {
			s = strings.TrimSpace(s)
			if s == "" {
				continue
			}
			if strings.HasPrefix(s, "https") {
				p := "https"
				u, _ := url.Parse(s)
				if u == nil || u.Scheme == "" {
					continue
				}
				if u.Scheme == "https-chain" {
					p = u.Scheme
				}
				ns := gost.NameServer{
					Addr:     s,
					Protocol: p,
				}
				nss = append(nss, ns)
				continue
			}

			ss := strings.Split(s, "/")
			if len(ss) == 1 {
				ns := gost.NameServer{
					Addr: ss[0],
				}
				nss = append(nss, ns)
			}
			if len(ss) == 2 {
				ns := gost.NameServer{
					Addr:     ss[0],
					Protocol: ss[1],
				}
				nss = append(nss, ns)
			}
		}
		return gost.NewResolver(0, nss...)
	}
	defer f.Close()

	resolver := gost.NewResolver(0)
	resolver.Reload(f)

	go gost.PeriodReload(resolver, cfg)

	return resolver
}

func parseHosts(s string) *gost.Hosts {
	f, err := os.Open(s)
	if err != nil {
		return nil
	}
	defer f.Close()

	hosts := gost.NewHosts()
	hosts.Reload(f)

	go gost.PeriodReload(hosts, s)

	return hosts
}

func parseIPRoutes(s string) (routes []gost.IPRoute) {
	if s == "" {
		return
	}

	file, err := os.Open(s)
	if err != nil {
		ss := strings.Split(s, ",")
		for _, s := range ss {
			if _, inet, _ := net.ParseCIDR(strings.TrimSpace(s)); inet != nil {
				routes = append(routes, gost.IPRoute{Dest: inet})
			}
		}
		return
	}

	defer file.Close()
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := strings.Replace(scanner.Text(), "\t", " ", -1)
		line = strings.TrimSpace(line)
		if line == "" || strings.HasPrefix(line, "#") {
			continue
		}

		var route gost.IPRoute
		var ss []string
		for _, s := range strings.Split(line, " ") {
			if s = strings.TrimSpace(s); s != "" {
				ss = append(ss, s)
			}
		}
		if len(ss) > 0 && ss[0] != "" {
			_, route.Dest, _ = net.ParseCIDR(strings.TrimSpace(ss[0]))
			if route.Dest == nil {
				continue
			}
		}
		if len(ss) > 1 && ss[1] != "" {
			route.Gateway = net.ParseIP(ss[1])
		}
		routes = append(routes, route)
	}
	return routes
}


================================================
FILE: cmd/gost/main.go
================================================
package main

import (
	"crypto/tls"
	"errors"
	"flag"
	"fmt"
	"net/http"
	"os"
	"runtime"

	_ "net/http/pprof"

	"github.com/ginuerzh/gost"
	"github.com/go-log/log"
)

var (
	configureFile string
	baseCfg       = &baseConfig{}
	pprofAddr     string
	pprofEnabled  = os.Getenv("PROFILING") != ""
)

func init() {
	gost.SetLogger(&gost.LogLogger{})

	var (
		printVersion bool
	)

	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 {
		flag.StringVar(&pprofAddr, "P", ":6060", "profiling HTTP server address")
	}
	flag.Parse()

	if printVersion {
		fmt.Fprintf(os.Stdout, "gost %s (%s %s/%s)\n",
			gost.Version, runtime.Version(), runtime.GOOS, runtime.GOARCH)
		os.Exit(0)
	}

	if configureFile != "" {
		_, err := parseBaseConfig(configureFile)
		if err != nil {
			log.Log(err)
			os.Exit(1)
		}
	}
	if flag.NFlag() == 0 {
		flag.PrintDefaults()
		os.Exit(0)
	}
}

func main() {
	if pprofEnabled {
		go func() {
			log.Log("profiling server on", pprofAddr)
			log.Log(http.ListenAndServe(pprofAddr, nil))
		}()
	}

	// NOTE: as of 2.6, you can use custom cert/key files to initialize the default certificate.
	tlsConfig, err := tlsConfig(defaultCertFile, defaultKeyFile, "")
	if err != nil {
		// generate random self-signed certificate.
		cert, err := gost.GenCertificate()
		if err != nil {
			log.Log(err)
			os.Exit(1)
		}
		tlsConfig = &tls.Config{
			Certificates: []tls.Certificate{cert},
		}
	} else {
		log.Log("load TLS certificate files OK")
	}

	gost.DefaultTLSConfig = tlsConfig

	if err := start(); err != nil {
		log.Log(err)
		os.Exit(1)
	}

	select {}
}

func start() error {
	gost.Debug = baseCfg.Debug

	var routers []router
	rts, err := baseCfg.route.GenRouters()
	if err != nil {
		return err
	}
	routers = append(routers, rts...)

	for _, route := range baseCfg.Routes {
		rts, err := route.GenRouters()
		if err != nil {
			return err
		}
		routers = append(routers, rts...)
	}

	if len(routers) == 0 {
		return errors.New("invalid config")
	}
	for i := range routers {
		go routers[i].Serve()
	}

	return nil
}


================================================
FILE: cmd/gost/peer.go
================================================
package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"io"
	"strconv"
	"strings"
	"time"

	"github.com/ginuerzh/gost"
)

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{}
}

func newPeerConfig() *peerConfig {
	return &peerConfig{
		stopped: make(chan struct{}),
	}
}

func (cfg *peerConfig) Validate() {
}

func (cfg *peerConfig) Reload(r io.Reader) error {
	if cfg.Stopped() {
		return nil
	}

	if err := cfg.parse(r); err != nil {
		return err
	}
	cfg.Validate()

	group := cfg.group
	group.SetSelector(
		nil,
		gost.WithFilter(
			&gost.FailFilter{
				MaxFails:    cfg.MaxFails,
				FailTimeout: cfg.FailTimeout,
			},
			&gost.InvalidFilter{},
			gost.NewFastestFilter(0, cfg.FastestCount),
		),
		gost.WithStrategy(gost.NewStrategy(cfg.Strategy)),
	)

	gNodes := cfg.baseNodes
	nid := len(gNodes) + 1
	for _, s := range cfg.Nodes {
		nodes, err := parseChainNode(s)
		if err != nil {
			return err
		}

		for i := range nodes {
			nodes[i].ID = nid
			nid++
		}

		gNodes = append(gNodes, nodes...)
	}

	nodes := group.SetNodes(gNodes...)
	for _, node := range nodes[len(cfg.baseNodes):] {
		if node.Bypass != nil {
			node.Bypass.Stop() // clear the old nodes
		}
	}

	return nil
}

func (cfg *peerConfig) parse(r io.Reader) error {
	data, err := io.ReadAll(r)
	if err != nil {
		return err
	}

	// compatible with JSON format
	if err := json.NewDecoder(bytes.NewReader(data)).Decode(cfg); err == nil {
		return nil
	}

	split := func(line string) []string {
		if line == "" {
			return nil
		}
		if n := strings.IndexByte(line, '#'); n >= 0 {
			line = line[:n]
		}
		line = strings.Replace(line, "\t", " ", -1)
		line = strings.TrimSpace(line)

		var ss []string
		for _, s := range strings.Split(line, " ") {
			if s = strings.TrimSpace(s); s != "" {
				ss = append(ss, s)
			}
		}
		return ss
	}

	cfg.Nodes = nil
	scanner := bufio.NewScanner(bytes.NewReader(data))
	for scanner.Scan() {
		line := scanner.Text()
		ss := split(line)
		if len(ss) < 2 {
			continue
		}

		switch ss[0] {
		case "strategy":
			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":
			cfg.period, _ = time.ParseDuration(ss[1])
		case "peer":
			cfg.Nodes = append(cfg.Nodes, ss[1])
		}
	}

	return scanner.Err()
}

func (cfg *peerConfig) Period() time.Duration {
	if cfg.Stopped() {
		return -1
	}
	return cfg.period
}

// Stop stops reloading.
func (cfg *peerConfig) Stop() {
	select {
	case <-cfg.stopped:
	default:
		close(cfg.stopped)
	}
}

// Stopped checks whether the reloader is stopped.
func (cfg *peerConfig) Stopped() bool {
	select {
	case <-cfg.stopped:
		return true
	default:
		return false
	}
}


================================================
FILE: cmd/gost/route.go
================================================
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"
)

type stringList []string

func (l *stringList) String() string {
	return fmt.Sprintf("%s", *l)
}
func (l *stringList) Set(value string) error {
	*l = append(*l, value)
	return nil
}

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 {
		ngroup := gost.NewNodeGroup()
		ngroup.ID = gid
		gid++

		// parse the base nodes
		nodes, err := parseChainNode(ns)
		if err != nil {
			return nil, err
		}

		nid := 1 // node ID
		for i := range nodes {
			nodes[i].ID = nid
			nid++
		}
		ngroup.AddNode(nodes...)

		ngroup.SetSelector(nil,
			gost.WithFilter(
				&gost.FailFilter{
					MaxFails:    nodes[0].GetInt("max_fails"),
					FailTimeout: nodes[0].GetDuration("fail_timeout"),
				},
				&gost.InvalidFilter{},
				gost.NewFastestFilter(0, nodes[0].GetInt("fastest_count")),
			),
			gost.WithStrategy(gost.NewStrategy(nodes[0].Get("strategy"))),
		)

		if cfg := nodes[0].Get("peer"); cfg != "" {
			f, err := os.Open(cfg)
			if err != nil {
				return nil, err
			}

			peerCfg := newPeerConfig()
			peerCfg.group = ngroup
			peerCfg.baseNodes = nodes
			peerCfg.Reload(f)
			f.Close()

			go gost.PeriodReload(peerCfg, cfg)
		}

		chain.AddNodeGroup(ngroup)
	}

	return chain, nil
}

func parseChainNode(ns string) (nodes []gost.Node, err error) {
	node, err := gost.ParseNode(ns)
	if err != nil {
		return
	}

	if auth := node.Get("auth"); auth != "" && node.User == nil {
		c, err := base64.StdEncoding.DecodeString(auth)
		if err != nil {
			return nil, err
		}
		cs := string(c)
		s := strings.IndexByte(cs, ':')
		if s < 0 {
			node.User = url.User(cs)
		} else {
			node.User = url.UserPassword(cs[:s], cs[s+1:])
		}
	}
	if node.User == nil {
		users, err := parseUsers(node.Get("secrets"))
		if err != nil {
			return nil, err
		}
		if len(users) > 0 {
			node.User = users[0]
		}
	}

	serverName, sport, _ := net.SplitHostPort(node.Addr)
	if serverName == "" {
		serverName = "localhost" // default server name
	}

	rootCAs, err := loadCA(node.Get("ca"))
	if err != nil {
		return
	}
	tlsCfg := &tls.Config{
		ServerName:         serverName,
		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")
	wsOpts.WriteBufferSize = node.GetInt("wbuf")
	wsOpts.UserAgent = node.Get("agent")
	wsOpts.Path = node.Get("path")

	timeout := node.GetDuration("timeout")

	var tr gost.Transporter
	switch node.Transport {
	case "tls":
		tr = gost.TLSTransporter()
	case "mtls":
		tr = gost.MTLSTransporter()
	case "ws":
		tr = gost.WSTransporter(wsOpts)
	case "mws":
		tr = gost.MWSTransporter(wsOpts)
	case "wss":
		tr = gost.WSSTransporter(wsOpts)
	case "mwss":
		tr = gost.MWSSTransporter(wsOpts)
	case "kcp":
		config, err := parseKCPConfig(node.Get("c"))
		if err != nil {
			return nil, err
		}
		if config == nil {
			conf := gost.DefaultKCPConfig
			if node.GetBool("tcp") {
				conf.TCP = true
			}
			config = &conf
		}
		tr = gost.KCPTransporter(config)
	case "ssh":
		if node.Protocol == "direct" || node.Protocol == "remote" {
			tr = gost.SSHForwardTransporter()
		} else {
			tr = gost.SSHTunnelTransporter()
		}
	case "quic":
		config := &gost.QUICConfig{
			TLSConfig:   tlsCfg,
			KeepAlive:   node.GetBool("keepalive"),
			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[:]
		}

		tr = gost.QUICTransporter(config)
	case "http2":
		tr = gost.HTTP2Transporter(tlsCfg)
	case "h2":
		tr = gost.H2Transporter(tlsCfg, node.Get("path"))
	case "h2c":
		tr = gost.H2CTransporter(node.Get("path"))
	case "obfs4":
		tr = gost.Obfs4Transporter()
	case "ohttp":
		tr = gost.ObfsHTTPTransporter()
	case "otls":
		tr = gost.ObfsTLSTransporter()
	case "ftcp":
		tr = gost.FakeTCPTransporter()
	case "udp":
		tr = gost.UDPTransporter()
	case "vsock":
		tr = gost.VSOCKTransporter()
	default:
		tr = gost.TCPTransporter()
	}

	var connector gost.Connector
	switch node.Protocol {
	case "http2":
		connector = gost.HTTP2Connector(node.User)
	case "socks", "socks5":
		connector = gost.SOCKS5Connector(node.User)
	case "socks4":
		connector = gost.SOCKS4Connector()
	case "socks4a":
		connector = gost.SOCKS4AConnector()
	case "ss":
		connector = gost.ShadowConnector(node.User)
	case "ssu":
		connector = gost.ShadowUDPConnector(node.User)
	case "direct":
		connector = gost.SSHDirectForwardConnector()
	case "remote":
		connector = gost.SSHRemoteForwardConnector()
	case "forward":
		connector = gost.ForwardConnector()
	case "sni":
		connector = gost.SNIConnector(node.Get("host"))
	case "http":
		connector = gost.HTTPConnector(node.User)
	case "relay":
		connector = gost.RelayConnector(node.User)
	default:
		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{
		gost.UserAgentConnectOption(node.Get("agent")),
		gost.NoTLSConnectOption(node.GetBool("notls")),
		gost.NoDelayConnectOption(node.GetBool("nodelay")),
	}

	sshConfig := &gost.SSHConfig{}
	if s := node.Get("ssh_key"); s != "" {
		key, err := gost.ParseSSHKeyFile(s)
		if err != nil {
			return nil, err
		}
		sshConfig.Key = key
	}
	handshakeOptions := []gost.HandshakeOption{
		gost.AddrHandshakeOption(node.Addr),
		gost.HostHandshakeOption(host),
		gost.UserHandshakeOption(node.User),
		gost.TLSConfigHandshakeOption(tlsCfg),
		gost.IntervalHandshakeOption(node.GetDuration("ping")),
		gost.TimeoutHandshakeOption(timeout),
		gost.RetryHandshakeOption(node.GetInt("retry")),
		gost.SSHConfigHandshakeOption(sshConfig),
	}

	node.Client = &gost.Client{
		Connector:   connector,
		Transporter: tr,
	}

	node.Bypass = parseBypass(node.Get("bypass"))

	ips := parseIP(node.Get("ip"), sport)
	for _, ip := range ips {
		nd := node.Clone()
		nd.Addr = ip
		// override the default node address
		nd.HandshakeOptions = append(handshakeOptions, gost.AddrHandshakeOption(ip))
		// One node per IP
		nodes = append(nodes, nd)
	}
	if len(ips) == 0 {
		node.HandshakeOptions = handshakeOptions
		nodes = []gost.Node{node}
	}

	if node.Transport == "obfs4" {
		for i := range nodes {
			if err := gost.Obfs4Init(nodes[i], false); err != nil {
				return nil, err
			}
		}
	}

	return
}

func (r *route) GenRouters() ([]router, error) {
	chain, err := r.parseChain()
	if err != nil {
		return nil, err
	}

	var rts []router

	for _, ns := range r.ServeNodes {
		node, err := gost.ParseNode(ns)
		if err != nil {
			return nil, err
		}

		if auth := node.Get("auth"); auth != "" && node.User == nil {
			c, err := base64.StdEncoding.DecodeString(auth)
			if err != nil {
				return nil, err
			}
			cs := string(c)
			s := strings.IndexByte(cs, ':')
			if s < 0 {
				node.User = url.User(cs)
			} else {
				node.User = url.UserPassword(cs[:s], cs[s+1:])
			}
		}
		authenticator, err := parseAuthenticator(node.Get("secrets"))
		if err != nil {
			return nil, err
		}
		if authenticator == nil && node.User != nil {
			kvs := make(map[string]string)
			kvs[node.User.Username()], _ = node.User.Password()
			authenticator = gost.NewLocalAuthenticator(kvs)
		}
		if node.User == nil {
			if users, _ := parseUsers(node.Get("secrets")); len(users) > 0 {
				node.User = users[0]
			}
		}
		certFile, keyFile := node.Get("cert"), node.Get("key")
		tlsCfg, err := tlsConfig(certFile, keyFile, node.Get("ca"))
		if err != nil && certFile != "" && keyFile != "" {
			return nil, err
		}

		wsOpts := &gost.WSOptions{}
		wsOpts.EnableCompression = node.GetBool("compression")
		wsOpts.ReadBufferSize = node.GetInt("rbuf")
		wsOpts.WriteBufferSize = node.GetInt("wbuf")
		wsOpts.Path = node.Get("path")

		ttl := node.GetDuration("ttl")
		timeout := node.GetDuration("timeout")

		tunRoutes := parseIPRoutes(node.Get("route"))
		gw := net.ParseIP(node.Get("gw")) // default gateway
		for i := range tunRoutes {
			if tunRoutes[i].Gateway == nil {
				tunRoutes[i].Gateway = gw
			}
		}

		var ln gost.Listener
		switch node.Transport {
		case "tls":
			ln, err = gost.TLSListener(node.Addr, tlsCfg)
		case "mtls":
			ln, err = gost.MTLSListener(node.Addr, tlsCfg)
		case "ws":
			ln, err = gost.WSListener(node.Addr, wsOpts)
		case "mws":
			ln, err = gost.MWSListener(node.Addr, wsOpts)
		case "wss":
			ln, err = gost.WSSListener(node.Addr, tlsCfg, wsOpts)
		case "mwss":
			ln, err = gost.MWSSListener(node.Addr, tlsCfg, wsOpts)
		case "kcp":
			config, er := parseKCPConfig(node.Get("c"))
			if er != nil {
				return nil, er
			}
			if config == nil {
				conf := gost.DefaultKCPConfig
				if node.GetBool("tcp") {
					conf.TCP = true
				}
				config = &conf
			}
			ln, err = gost.KCPListener(node.Addr, config)
		case "ssh":
			config := &gost.SSHConfig{
				Authenticator: authenticator,
				TLSConfig:     tlsCfg,
			}
			if s := node.Get("ssh_key"); s != "" {
				key, err := gost.ParseSSHKeyFile(s)
				if err != nil {
					return nil, err
				}
				config.Key = key
			}
			if s := node.Get("ssh_authorized_keys"); s != "" {
				keys, err := gost.ParseSSHAuthorizedKeysFile(s)
				if err != nil {
					return nil, err
				}
				config.AuthorizedKeys = keys
			}
			if node.Protocol == "forward" {
				ln, err = gost.TCPListener(node.Addr)
			} else {
				ln, err = gost.SSHTunnelListener(node.Addr, config)
			}
		case "quic":
			config := &gost.QUICConfig{
				TLSConfig:   tlsCfg,
				KeepAlive:   node.GetBool("keepalive"),
				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[:]
			}

			ln, err = gost.QUICListener(node.Addr, config)
		case "http2":
			ln, err = gost.HTTP2Listener(node.Addr, tlsCfg)
		case "h2":
			ln, err = gost.H2Listener(node.Addr, tlsCfg, node.Get("path"))
		case "h2c":
			ln, err = gost.H2CListener(node.Addr, node.Get("path"))
		case "tcp":
			// Directly use SSH port forwarding if the last chain node is forward+ssh
			if chain.LastNode().Protocol == "forward" && chain.LastNode().Transport == "ssh" {
				chain.Nodes()[len(chain.Nodes())-1].Client.Connector = gost.SSHDirectForwardConnector()
				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,
				Backlog:   node.GetInt("backlog"),
				QueueSize: node.GetInt("queue"),
			})
		case "rtcp":
			// Directly use SSH port forwarding if the last chain node is forward+ssh
			if chain.LastNode().Protocol == "forward" && chain.LastNode().Transport == "ssh" {
				chain.Nodes()[len(chain.Nodes())-1].Client.Connector = gost.SSHRemoteForwardConnector()
				chain.Nodes()[len(chain.Nodes())-1].Client.Transporter = gost.SSHForwardTransporter()
			}
			ln, err = gost.TCPRemoteForwardListener(node.Addr, chain)
		case "rudp":
			ln, err = gost.UDPRemoteForwardListener(node.Addr,
				chain,
				&gost.UDPListenConfig{
					TTL:       ttl,
					Backlog:   node.GetInt("backlog"),
					QueueSize: node.GetInt("queue"),
				})
		case "obfs4":
			if err = gost.Obfs4Init(node, true); err != nil {
				return nil, err
			}
			ln, err = gost.Obfs4Listener(node.Addr)
		case "ohttp":
			ln, err = gost.ObfsHTTPListener(node.Addr)
		case "otls":
			ln, err = gost.ObfsTLSListener(node.Addr)
		case "tun":
			cfg := gost.TunConfig{
				Name:    node.Get("name"),
				Addr:    node.Get("net"),
				Peer:    node.Get("peer"),
				MTU:     node.GetInt("mtu"),
				Routes:  tunRoutes,
				Gateway: node.Get("gw"),
			}
			ln, err = gost.TunListener(cfg)
		case "tap":
			cfg := gost.TapConfig{
				Name:    node.Get("name"),
				Addr:    node.Get("net"),
				MTU:     node.GetInt("mtu"),
				Routes:  strings.Split(node.Get("route"), ","),
				Gateway: node.Get("gw"),
			}
			ln, err = gost.TapListener(cfg)
		case "ftcp":
			ln, err = gost.FakeTCPListener(
				node.Addr,
				&gost.FakeTCPListenConfig{
					TTL:       ttl,
					Backlog:   node.GetInt("backlog"),
					QueueSize: node.GetInt("queue"),
				},
			)
		case "dns":
			ln, err = gost.DNSListener(
				node.Addr,
				&gost.DNSOptions{
					Mode:      node.Get("mode"),
					TLSConfig: tlsCfg,
				},
			)
		case "redu", "redirectu":
			ln, err = gost.UDPRedirectListener(node.Addr, &gost.UDPListenConfig{
				TTL:       ttl,
				Backlog:   node.GetInt("backlog"),
				QueueSize: node.GetInt("queue"),
			})
		default:
			ln, err = gost.TCPListener(node.Addr)
		}
		if err != nil {
			return nil, err
		}

		var handler gost.Handler
		switch node.Protocol {
		case "http2":
			handler = gost.HTTP2Handler()
		case "socks", "socks5":
			handler = gost.SOCKS5Handler()
		case "socks4", "socks4a":
			handler = gost.SOCKS4Handler()
		case "ss":
			handler = gost.ShadowHandler()
		case "http":
			handler = gost.HTTPHandler()
		case "tcp":
			handler = gost.TCPDirectForwardHandler(node.Remote)
		case "rtcp":
			handler = gost.TCPRemoteForwardHandler(node.Remote)
		case "udp":
			handler = gost.UDPDirectForwardHandler(node.Remote)
		case "rudp":
			handler = gost.UDPRemoteForwardHandler(node.Remote)
		case "forward":
			handler = gost.SSHForwardHandler()
		case "red", "redirect":
			handler = gost.TCPRedirectHandler()
		case "redu", "redirectu":
			handler = gost.UDPRedirectHandler()
		case "ssu":
			handler = gost.ShadowUDPHandler()
		case "sni":
			handler = gost.SNIHandler()
		case "tun":
			handler = gost.TunHandler()
		case "tap":
			handler = gost.TapHandler()
		case "dns":
			handler = gost.DNSHandler(node.Remote)
		case "relay":
			handler = gost.RelayHandler(node.Remote)
		default:
			// start from 2.5, if remote is not empty, then we assume that it is a forward tunnel.
			if node.Remote != "" {
				handler = gost.TCPDirectForwardHandler(node.Remote)
			} else {
				handler = gost.AutoHandler()
			}
		}

		var whitelist, blacklist *gost.Permissions
		if node.Values.Get("whitelist") != "" {
			if whitelist, err = gost.ParsePermissions(node.Get("whitelist")); err != nil {
				return nil, err
			}
		}
		if node.Values.Get("blacklist") != "" {
			if blacklist, err = gost.ParsePermissions(node.Get("blacklist")); err != nil {
				return nil, err
			}
		}

		node.Bypass = parseBypass(node.Get("bypass"))
		hosts := parseHosts(node.Get("hosts"))
		ips := parseIP(node.Get("ip"), "")

		resolver := parseResolver(node.Get("dns"))
		if resolver != nil {
			resolver.Init(
				gost.ChainResolverOption(chain),
				gost.TimeoutResolverOption(timeout),
				gost.TTLResolverOption(ttl),
				gost.PreferResolverOption(node.Get("prefer")),
				gost.SrcIPResolverOption(net.ParseIP(node.Get("ip"))),
			)
		}

		handler.Init(
			gost.AddrHandlerOption(ln.Addr().String()),
			gost.ChainHandlerOption(chain),
			gost.UsersHandlerOption(node.User),
			gost.AuthenticatorHandlerOption(authenticator),
			gost.TLSConfigHandlerOption(tlsCfg),
			gost.WhitelistHandlerOption(whitelist),
			gost.BlacklistHandlerOption(blacklist),
			gost.StrategyHandlerOption(gost.NewStrategy(node.Get("strategy"))),
			gost.MaxFailsHandlerOption(node.GetInt("max_fails")),
			gost.FailTimeoutHandlerOption(node.GetDuration("fail_timeout")),
			gost.BypassHandlerOption(node.Bypass),
			gost.ResolverHandlerOption(resolver),
			gost.HostsHandlerOption(hosts),
			gost.RetryHandlerOption(node.GetInt("retry")), // override the global retry option.
			gost.TimeoutHandlerOption(timeout),
			gost.ProbeResistHandlerOption(node.Get("probe_resist")),
			gost.KnockingHandlerOption(node.Get("knock")),
			gost.NodeHandlerOption(node),
			gost.IPsHandlerOption(ips),
			gost.TCPModeHandlerOption(node.GetBool("tcp")),
			gost.IPRoutesHandlerOption(tunRoutes...),
			gost.ProxyAgentHandlerOption(node.Get("proxyAgent")),
			gost.HTTPTunnelHandlerOption(node.GetBool("httpTunnel")),
		)

		rt := router{
			node:     node,
			server:   &gost.Server{Listener: ln},
			handler:  handler,
			chain:    chain,
			resolver: resolver,
			hosts:    hosts,
		}
		rts = append(rts, rt)
	}

	return rts, nil
}

type router struct {
	node     gost.Node
	server   *gost.Server
	handler  gost.Handler
	chain    *gost.Chain
	resolver gost.Resolver
	hosts    *gost.Hosts
}

func (r *router) Serve() error {
	log.Logf("%s on %s", r.node.String(), r.server.Addr())
	return r.server.Serve(r.handler)
}

func (r *router) Close() error {
	if r == nil || r.server == nil {
		return nil
	}
	return r.server.Close()
}


================================================
FILE: common_test.go
================================================
package gost

import (
	"bufio"
	"bytes"
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/url"
	"sync"
	"time"

	"github.com/go-log/log"
)

func init() {
	SetLogger(&NopLogger{})
	// SetLogger(&LogLogger{})
	Debug = true
	DialTimeout = 1000 * time.Millisecond
	HandshakeTimeout = 1000 * time.Millisecond
	ConnectTimeout = 1000 * time.Millisecond

	cert, err := GenCertificate()
	if err != nil {
		panic(err)
	}
	DefaultTLSConfig = &tls.Config{
		Certificates: []tls.Certificate{cert},
	}
}

var (
	httpTestHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		data, _ := io.ReadAll(r.Body)
		if len(data) == 0 {
			data = []byte("Hello World!")
		}
		io.Copy(w, bytes.NewReader(data))
	})

	udpTestHandler = udpHandlerFunc(func(w io.Writer, r *udpRequest) {
		io.Copy(w, r.Body)
	})
)

// proxyConn obtains a connection to the proxy server.
func proxyConn(client *Client, server *Server) (net.Conn, error) {
	conn, err := client.Dial(server.Addr().String())
	if err != nil {
		return nil, err
	}

	cc, err := client.Handshake(conn, AddrHandshakeOption(server.Addr().String()))
	if err != nil {
		conn.Close()
		return nil, err
	}

	return cc, nil
}

// httpRoundtrip does a HTTP request-response roundtrip, and checks the data received.
func httpRoundtrip(conn net.Conn, targetURL string, data []byte) (err error) {
	req, err := http.NewRequest(
		http.MethodGet,
		targetURL,
		bytes.NewReader(data),
	)
	if err != nil {
		return
	}
	if err = req.Write(conn); err != nil {
		return
	}
	resp, err := http.ReadResponse(bufio.NewReader(conn), req)
	if err != nil {
		return
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return errors.New(resp.Status)
	}

	recv, err := io.ReadAll(resp.Body)
	if err != nil {
		return
	}

	if !bytes.Equal(data, recv) {
		return fmt.Errorf("data not equal")
	}
	return
}

func udpRoundtrip(logger log.Logger, client *Client, server *Server, host string, data []byte) (err error) {
	conn, err := proxyConn(client, server)
	if err != nil {
		return
	}
	defer conn.Close()

	conn, err = client.Connect(conn, host)
	if err != nil {
		return
	}

	conn.SetDeadline(time.Now().Add(1 * time.Second))
	defer conn.SetDeadline(time.Time{})

	if _, err = conn.Write(data); err != nil {
		logger.Logf("write to %s via %s: %s", host, server.Addr(), err)
		return
	}

	recv := make([]byte, len(data))
	if _, err = conn.Read(recv); err != nil {
		logger.Logf("read from %s via %s: %s", host, server.Addr(), err)
		return
	}

	if !bytes.Equal(data, recv) {
		return fmt.Errorf("data not equal")
	}

	return
}

func proxyRoundtrip(client *Client, server *Server, targetURL string, data []byte) (err error) {
	conn, err := proxyConn(client, server)
	if err != nil {
		return err
	}
	defer conn.Close()

	u, err := url.Parse(targetURL)
	if err != nil {
		return
	}

	conn, err = client.Connect(conn, u.Host)
	if err != nil {
		return
	}

	conn.SetDeadline(time.Now().Add(1000 * time.Millisecond))
	defer conn.SetDeadline(time.Time{})

	return httpRoundtrip(conn, targetURL, data)
}

type udpRequest struct {
	Body       io.Reader
	RemoteAddr string
}

type udpResponseWriter struct {
	conn net.PacketConn
	addr net.Addr
}

func (w *udpResponseWriter) Write(p []byte) (int, error) {
	return w.conn.WriteTo(p, w.addr)
}

type udpHandlerFunc func(w io.Writer, r *udpRequest)

// udpTestServer is a UDP server for test.
type udpTestServer struct {
	ln        net.PacketConn
	handler   udpHandlerFunc
	wg        sync.WaitGroup
	mu        sync.Mutex // guards closed and conns
	closed    bool
	startChan chan struct{}
	exitChan  chan struct{}
}

func newUDPTestServer(handler udpHandlerFunc) *udpTestServer {
	laddr, _ := net.ResolveUDPAddr("udp", "127.0.0.1:0")
	ln, err := net.ListenUDP("udp", laddr)
	if err != nil {
		panic(fmt.Sprintf("udptest: failed to listen on a port: %v", err))
	}

	return &udpTestServer{
		ln:        ln,
		handler:   handler,
		startChan: make(chan struct{}),
		exitChan:  make(chan struct{}),
	}
}

func (s *udpTestServer) Start() {
	go s.serve()
	<-s.startChan
}

func (s *udpTestServer) serve() {
	select {
	case <-s.startChan:
		return
	default:
		close(s.startChan)
	}

	for {
		data := make([]byte, 32*1024)
		n, raddr, err := s.ln.ReadFrom(data)
		if err != nil {
			break
		}
		if s.handler != nil {
			s.wg.Add(1)
			go func() {
				defer s.wg.Done()
				w := &udpResponseWriter{
					conn: s.ln,
					addr: raddr,
				}
				r := &udpRequest{
					Body:       bytes.NewReader(data[:n]),
					RemoteAddr: raddr.String(),
				}
				s.handler(w, r)
			}()
		}
	}

	// signal the listener has been exited.
	close(s.exitChan)
}

func (s *udpTestServer) Addr() string {
	return s.ln.LocalAddr().String()
}

func (s *udpTestServer) Close() error {
	s.mu.Lock()

	if s.closed {
		s.mu.Unlock()
		return nil
	}

	err := s.ln.Close()
	s.closed = true
	s.mu.Unlock()

	<-s.exitChan

	s.wg.Wait()

	return err
}


================================================
FILE: dns.go
================================================
package gost

import (
	"bytes"
	"context"
	"crypto/tls"
	"encoding/base64"
	"errors"
	"io"
	"net"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/go-log/log"
	"github.com/miekg/dns"
)

var (
	defaultResolver Resolver
)

func init() {
	defaultResolver = NewResolver(
		DefaultResolverTimeout,
		NameServer{
			Addr:     "127.0.0.1:53",
			Protocol: "udp",
		})
	defaultResolver.Init()
}

type dnsHandler struct {
	options *HandlerOptions
}

// DNSHandler creates a Handler for DNS server.
func DNSHandler(raddr string, opts ...HandlerOption) Handler {
	h := &dnsHandler{}

	for _, opt := range opts {
		opt(h.options)
	}
	return h
}

func (h *dnsHandler) Init(opts ...HandlerOption) {
	if h.options == nil {
		h.options = &HandlerOptions{}
	}

	for _, opt := range opts {
		opt(h.options)
	}
}

func (h *dnsHandler) Handle(conn net.Conn) {
	defer conn.Close()

	b := mPool.Get().([]byte)
	defer mPool.Put(b)

	n, err := conn.Read(b)
	if err != nil {
		log.Logf("[dns] %s - %s: %v", conn.RemoteAddr(), conn.LocalAddr(), err)
	}

	mq := &dns.Msg{}
	if err = mq.Unpack(b[:n]); err != nil {
		log.Logf("[dns] %s - %s request unpack: %v", conn.RemoteAddr(), conn.LocalAddr(), err)
		return
	}
	log.Logf("[dns] %s -> %s: %s", conn.RemoteAddr(), conn.LocalAddr(), h.dumpMsgHeader(mq))
	if Debug {
		log.Logf("[dns] %s >>> %s: %s", conn.RemoteAddr(), conn.LocalAddr(), mq.String())
	}

	start := time.Now()

	resolver := h.options.Resolver
	if resolver == nil {
		resolver = defaultResolver
	}
	reply, err := resolver.Exchange(context.Background(), b[:n])
	if err != nil {
		log.Logf("[dns] %s - %s exchange: %v", conn.RemoteAddr(), conn.LocalAddr(), err)
		return
	}

	rtt := time.Since(start)

	mr := &dns.Msg{}
	if err = mr.Unpack(reply); err != nil {
		log.Logf("[dns] %s - %s reply unpack: %v", conn.RemoteAddr(), conn.LocalAddr(), err)
		return
	}
	log.Logf("[dns] %s <- %s: %s [%s]",
		conn.RemoteAddr(), conn.LocalAddr(), h.dumpMsgHeader(mr), rtt)
	if Debug {
		log.Logf("[dns] %s <<< %s: %s", conn.RemoteAddr(), conn.LocalAddr(), mr.String())
	}

	if _, err = conn.Write(reply); err != nil {
		log.Logf("[dns] %s - %s reply unpack: %v", conn.RemoteAddr(), conn.LocalAddr(), err)
	}
}

func (h *dnsHandler) dumpMsgHeader(m *dns.Msg) string {
	buf := new(bytes.Buffer)
	buf.WriteString(m.MsgHdr.String() + " ")
	buf.WriteString("QUERY: " + strconv.Itoa(len(m.Question)) + ", ")
	buf.WriteString("ANSWER: " + strconv.Itoa(len(m.Answer)) + ", ")
	buf.WriteString("AUTHORITY: " + strconv.Itoa(len(m.Ns)) + ", ")
	buf.WriteString("ADDITIONAL: " + strconv.Itoa(len(m.Extra)))
	return buf.String()
}

// DNSOptions is options for DNS Listener.
type DNSOptions struct {
	Mode         string
	UDPSize      int
	ReadTimeout  time.Duration
	WriteTimeout time.Duration
	TLSConfig    *tls.Config
}

type dnsListener struct {
	addr     net.Addr
	server   dnsServer
	connChan chan net.Conn
	errc     chan error
}

// DNSListener creates a Listener for DNS proxy server.
func DNSListener(addr string, options *DNSOptions) (Listener, error) {
	if options == nil {
		options = &DNSOptions{}
	}

	tlsConfig := options.TLSConfig
	if tlsConfig == nil {
		tlsConfig = DefaultTLSConfig
	}

	ln := &dnsListener{
		connChan: make(chan net.Conn, 128),
		errc:     make(chan error, 1),
	}

	var srv dnsServer
	var err error
	switch strings.ToLower(options.Mode) {
	case "tcp":
		srv = &dns.Server{
			Net:          "tcp",
			Addr:         addr,
			Handler:      ln,
			ReadTimeout:  options.ReadTimeout,
			WriteTimeout: options.WriteTimeout,
		}
	case "tls":
		srv = &dns.Server{
			Net:          "tcp-tls",
			Addr:         addr,
			Handler:      ln,
			TLSConfig:    tlsConfig,
			ReadTimeout:  options.ReadTimeout,
			WriteTimeout: options.WriteTimeout,
		}
	case "https":
		srv = &dohServer{
			addr:      addr,
			tlsConfig: tlsConfig,
			server: &http.Server{
				Handler:      ln,
				ReadTimeout:  options.ReadTimeout,
				WriteTimeout: options.WriteTimeout,
			},
		}

	default:
		ln.addr, err = net.ResolveTCPAddr("tcp", addr)
		srv = &dns.Server{
			Net:          "udp",
			Addr:         addr,
			Handler:      ln,
			UDPSize:      options.UDPSize,
			ReadTimeout:  options.ReadTimeout,
			WriteTimeout: options.WriteTimeout,
		}
	}
	if err != nil {
		return nil, err
	}

	if ln.addr == nil {
		ln.addr, err = net.ResolveTCPAddr("tcp", addr)
		if err != nil {
			return nil, err
		}
	}

	ln.server = srv

	go func() {
		if err := ln.server.ListenAndServe(); err != nil {
			ln.errc <- err
			return
		}
	}()

	select {
	case err := <-ln.errc:
		return nil, err
	default:
	}

	return ln, nil
}

func (l *dnsListener) serve(w dnsResponseWriter, mq []byte) (err error) {
	conn := newDNSServerConn(l.addr, w.RemoteAddr())
	conn.mq <- mq

	select {
	case l.connChan <- conn:
	default:
		return errors.New("connection queue is full")
	}

	select {
	case mr := <-conn.mr:
		_, err = w.Write(mr)
	case <-conn.cclose:
		err = io.EOF
	}
	return
}

func (l *dnsListener) ServeDNS(w dns.ResponseWriter, m *dns.Msg) {
	b, err := m.Pack()
	if err != nil {
		log.Logf("[dns] %s: %v", l.addr, err)
		return
	}
	if err := l.serve(w, b); err != nil {
		log.Logf("[dns] %s: %v", l.addr, err)
	}
}

// Based on https://github.com/semihalev/sdns
func (l *dnsListener) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	var buf []byte
	var err error
	switch r.Method {
	case http.MethodGet:
		buf, err = base64.RawURLEncoding.DecodeString(r.URL.Query().Get("dns"))
		if len(buf) == 0 || err != nil {
			http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
			return
		}
	case http.MethodPost:
		if r.Header.Get("Content-Type") != "application/dns-message" {
			http.Error(w, http.StatusText(http.StatusUnsupportedMediaType), http.StatusUnsupportedMediaType)
			return
		}

		buf, err = io.ReadAll(r.Body)
		if err != nil {
			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
			return
		}
	default:
		http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
		return
	}

	mq := &dns.Msg{}
	if err := mq.Unpack(buf); err != nil {
		http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
		return
	}

	w.Header().Set("Server", "SDNS")
	w.Header().Set("Content-Type", "application/dns-message")

	raddr, _ := net.ResolveTCPAddr("tcp", r.RemoteAddr)
	if err := l.serve(newDoHResponseWriter(raddr, w), buf); err != nil {
		log.Logf("[dns] %s: %v", l.addr, err)
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
	}
}

func (l *dnsListener) Accept() (conn net.Conn, err error) {
	select {
	case conn = <-l.connChan:
	case err = <-l.errc:
	}
	return
}

func (l *dnsListener) Close() error {
	return l.server.Shutdown()
}

func (l *dnsListener) Addr() net.Addr {
	return l.addr
}

type dnsServer interface {
	ListenAndServe() error
	Shutdown() error
}

type dohServer struct {
	addr      string
	tlsConfig *tls.Config
	server    *http.Server
}

func (s *dohServer) ListenAndServe() error {
	ln, err := net.Listen("tcp", s.addr)
	if err != nil {
		return err
	}
	ln = tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, s.tlsConfig)
	return s.server.Serve(ln)
}

func (s *dohServer) Shutdown() error {
	return s.server.Shutdown(context.Background())
}

type dnsServerConn struct {
	mq           chan []byte
	mr           chan []byte
	cclose       chan struct{}
	laddr, raddr net.Addr
}

func newDNSServerConn(laddr, raddr net.Addr) *dnsServerConn {
	return &dnsServerConn{
		mq:     make(chan []byte, 1),
		mr:     make(chan []byte, 1),
		laddr:  laddr,
		raddr:  raddr,
		cclose: make(chan struct{}),
	}
}

func (c *dnsServerConn) Read(b []byte) (n int, err error) {
	select {
	case mb := <-c.mq:
		n = copy(b, mb)
	case <-c.cclose:
		err = errors.New("connection is closed")
	}
	return
}

func (c *dnsServerConn) Write(b []byte) (n int, err error) {
	select {
	case c.mr <- b:
		n = len(b)
	case <-c.cclose:
		err = errors.New("broken pipe")
	}

	return
}

func (c *dnsServerConn) Close() error {
	select {
	case <-c.cclose:
	default:
		close(c.cclose)
	}
	return nil
}

func (c *dnsServerConn) LocalAddr() net.Addr {
	return c.laddr
}

func (c *dnsServerConn) RemoteAddr() net.Addr {
	return c.raddr
}

func (c *dnsServerConn) SetDeadline(t time.Time) error {
	return &net.OpError{Op: "set", Net: "dns", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
}

func (c *dnsServerConn) SetReadDeadline(t time.Time) error {
	return &net.OpError{Op: "set", Net: "dns", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
}

func (c *dnsServerConn) SetWriteDeadline(t time.Time) error {
	return &net.OpError{Op: "set", Net: "dns", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
}

type dnsResponseWriter interface {
	io.Writer
	RemoteAddr() net.Addr
}

type dohResponseWriter struct {
	raddr net.Addr
	http.ResponseWriter
}

func newDoHResponseWriter(raddr net.Addr, w http.ResponseWriter) dnsResponseWriter {
	return &dohResponseWriter{
		raddr:          raddr,
		ResponseWriter: w,
	}
}

func (w *dohResponseWriter) RemoteAddr() net.Addr {
	return w.raddr
}


================================================
FILE: examples/bench/cli.go
================================================
package main

import (
	"bufio"
	"flag"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"sync"
	"time"

	"github.com/ginuerzh/gost"
	"golang.org/x/net/http2"
)

var (
	requests, concurrency int
	quiet                 bool
	swg, ewg              sync.WaitGroup
)

func init() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	flag.IntVar(&requests, "n", 1, "Number of requests to perform")
	flag.IntVar(&concurrency, "c", 1, "Number of multiple requests to make at a time")
	flag.BoolVar(&quiet, "q", false, "quiet mode")
	flag.BoolVar(&http2.VerboseLogs, "v", false, "HTTP2 verbose logs")
	flag.BoolVar(&gost.Debug, "d", false, "debug mode")
	flag.Parse()

	if quiet {
		gost.SetLogger(&gost.NopLogger{})
	}
}

func main() {
	chain := gost.NewChain(

		/*
			// http+tcp
			gost.Node{
				Addr: "127.0.0.1:18080",
				Client: gost.NewClient(
					gost.HTTPConnector(url.UserPassword("admin", "123456")),
					gost.TCPTransporter(),
				),
			},
		*/

		/*
			// socks5+tcp
			gost.Node{
				Addr: "127.0.0.1:11080",
				Client: gost.NewClient(
					gost.SOCKS5Connector(url.UserPassword("admin", "123456")),
					gost.TCPTransporter(),
				),
			},
		*/

		/*
			// ss+tcp
			gost.Node{
				Addr: "127.0.0.1:18338",
				Client: gost.NewClient(
					gost.ShadowConnector(url.UserPassword("chacha20", "123456")),
					gost.TCPTransporter(),
				),
			},
		*/

		/*
			// http+ws
			gost.Node{
				Addr: "127.0.0.1:18000",
				Client: gost.NewClient(
					gost.HTTPConnector(url.UserPassword("admin", "123456")),
					gost.WSTransporter(nil),
				),
			},
		*/

		/*
			// http+wss
			gost.Node{
				Addr: "127.0.0.1:18443",
				Client: gost.NewClient(
					gost.HTTPConnector(url.UserPassword("admin", "123456")),
					gost.WSSTransporter(nil),
				),
			},
		*/

		/*
			// http+tls
			gost.Node{
				Addr: "127.0.0.1:11443",
				Client: gost.NewClient(
					gost.HTTPConnector(url.UserPassword("admin", "123456")),
					gost.TLSTransporter(),
				),
			},
		*/

		/*
			// http2
			gost.Node{
				Addr: "127.0.0.1:1443",
				Client: &gost.Client{
					Connector:   gost.HTTP2Connector(url.UserPassword("admin", "123456")),
					Transporter: gost.HTTP2Transporter(nil),
				},
			},
		*/

		/*
			// http+kcp
			gost.Node{
				Addr: "127.0.0.1:18388",
				Client: gost.NewClient(
					gost.HTTPConnector(nil),
					gost.KCPTransporter(nil),
				),
			},
		*/

		/*
			// http+ssh
			gost.Node{
				Addr: "127.0.0.1:12222",
				Client: gost.NewClient(
					gost.HTTPConnector(url.UserPassword("admin", "123456")),
					gost.SSHTunnelTransporter(),
				),
			},
		*/

		/*
			// http+quic
			gost.Node{
				Addr: "localhost:6121",
				Client: &gost.Client{
					Connector:   gost.HTTPConnector(url.UserPassword("admin", "123456")),
					Transporter: gost.QUICTransporter(nil),
				},
			},
		*/
		// socks5+h2
		gost.Node{
			Addr: "localhost:8443",
			Client: &gost.Client{
				// Connector: gost.HTTPConnector(url.UserPassword("admin", "123456")),
				Connector: gost.SOCKS5Connector(url.UserPassword("admin", "123456")),
				// Transporter: gost.H2CTransporter(), // HTTP2 h2c mode
				Transporter: gost.H2Transporter(nil), // HTTP2 h2
			},
		},
	)

	total := 0
	for total < requests {
		if total+concurrency > requests {
			concurrency = requests - total
		}
		startChan := make(chan struct{})
		for i := 0; i < concurrency; i++ {
			swg.Add(1)
			ewg.Add(1)
			go request(chain, startChan)
		}

		start := time.Now()
		swg.Wait()       // wait for workers ready
		close(startChan) // start signal
		ewg.Wait()       // wait for workers done

		duration := time.Since(start)
		total += concurrency
		log.Printf("%d/%d/%d requests done (%v/%v)", total, requests, concurrency, duration, duration/time.Duration(concurrency))
	}
}

func request(chain *gost.Chain, start <-chan struct{}) {
	defer ewg.Done()

	swg.Done()
	<-start

	conn, err := chain.Dial("localhost:18888")
	if err != nil {
		log.Println(err)
		return
	}
	defer conn.Close()
	//conn = tls.Client(conn, &tls.Config{InsecureSkipVerify: true})
	req, err := http.NewRequest(http.MethodGet, "http://localhost:18888", nil)
	if err != nil {
		log.Println(err)
		return
	}
	if err := req.Write(conn); err != nil {
		log.Println(err)
		return
	}
	resp, err := http.ReadResponse(bufio.NewReader(conn), req)
	if err != nil {
		log.Println(err)
		return
	}
	defer resp.Body.Close()

	if gost.Debug {
		rb, _ := httputil.DumpRequest(req, true)
		log.Println(string(rb))
		rb, _ = httputil.DumpResponse(resp, true)
		log.Println(string(rb))
	}
}


================================================
FILE: examples/bench/srv.go
================================================
package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"time"

	"github.com/ginuerzh/gost"
	"golang.org/x/net/http2"
)

var (
	quiet bool
)

func init() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	flag.BoolVar(&quiet, "q", false, "quiet mode")
	flag.BoolVar(&gost.Debug, "d", false, "debug mode")
	flag.BoolVar(&http2.VerboseLogs, "v", false, "HTTP2 verbose logs")
	flag.Parse()

	if quiet {
		gost.SetLogger(&gost.NopLogger{})
	}
}

func main() {
	go httpServer()
	go socks5Server()
	go tlsServer()
	go shadowServer()
	go wsServer()
	go wssServer()
	go kcpServer()
	go tcpForwardServer()
	go tcpRemoteForwardServer()
	// go rudpForwardServer()
	// go tcpRedirectServer()
	go sshTunnelServer()
	go http2Server()
	go http2TunnelServer()
	go quicServer()
	go shadowUDPServer()
	go testServer()
	select {}
}

func httpServer() {
	ln, err := gost.TCPListener(":18080")
	if err != nil {
		log.Fatal(err)
	}
	h := gost.HTTPHandler(
		gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
	)
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}

func socks5Server() {
	ln, err := gost.TCPListener(":11080")
	if err != nil {
		log.Fatal(err)
	}
	h := gost.SOCKS5Handler(
		gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
		gost.TLSConfigHandlerOption(tlsConfig()),
	)
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}

func shadowServer() {
	ln, err := gost.TCPListener(":18338")
	if err != nil {
		log.Fatal(err)
	}
	h := gost.ShadowHandler(
		gost.UsersHandlerOption(url.UserPassword("chacha20", "123456")),
	)
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}

func tlsServer() {
	ln, err := gost.TLSListener(":11443", tlsConfig())
	if err != nil {
		log.Fatal(err)
	}
	h := gost.HTTPHandler(
		gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
	)
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}

func wsServer() {
	ln, err := gost.WSListener(":18000", nil)
	if err != nil {
		log.Fatal(err)
	}
	h := gost.HTTPHandler(
		gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
	)
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}

func wssServer() {
	ln, err := gost.WSSListener(":18443", tlsConfig(), nil)
	if err != nil {
		log.Fatal(err)
	}
	h := gost.HTTPHandler(
		gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
	)
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}

func kcpServer() {
	ln, err := gost.KCPListener(":18388", nil)
	if err != nil {
		log.Fatal(err)
	}
	h := gost.HTTPHandler()
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}

func tcpForwardServer() {
	ln, err := gost.TCPListener(":2222")
	if err != nil {
		log.Fatal(err)
	}
	h := gost.TCPDirectForwardHandler("localhost:22")
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}

func tcpRemoteForwardServer() {
	ln, err := gost.TCPRemoteForwardListener(
		":1222",
		/*
			gost.NewChain(
				gost.Node{
					Protocol:  "socks5",
					Transport: "tcp",
					Addr:      "localhost:12345",
					User:      url.UserPassword("admin", "123456"),
					Client: &gost.Client{
						Connector:   gost.SOCKS5Connector(url.UserPassword("admin", "123456")),
						Transporter: gost.TCPTransporter(),
					},
				},
			),
		*/
		nil,
	)
	if err != nil {
		log.Fatal()
	}
	h := gost.TCPRemoteForwardHandler(
		":22",
		//gost.AddrHandlerOption("127.0.0.1:22"),
	)
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}

func rudpForwardServer() {
	ln, err := gost.UDPRemoteForwardListener(
		":10053",
		gost.NewChain(
			gost.Node{
				Protocol:  "socks5",
				Transport: "tcp",
				Addr:      "localhost:12345",
				User:      url.UserPassword("admin", "123456"),
				Client: &gost.Client{
					Connector:   gost.SOCKS5Connector(url.UserPassword("admin", "123456")),
					Transporter: gost.TCPTransporter(),
				},
			},
		),
		30*time.Second,
	)
	if err != nil {
		log.Fatal()
	}
	h := gost.UDPRemoteForwardHandler("localhost:53")
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}

func tcpRedirectServer() {
	ln, err := gost.TCPListener(":8008")
	if err != nil {
		log.Fatal(err)
	}
	h := gost.TCPRedirectHandler()
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}

func sshTunnelServer() {
	ln, err := gost.SSHTunnelListener(":12222", &gost.SSHConfig{TLSConfig: tlsConfig()})
	if err != nil {
		log.Fatal(err)
	}
	h := gost.HTTPHandler(
		gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
	)
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}

func http2Server() {
	// http2.VerboseLogs = true

	ln, err := gost.HTTP2Listener(":1443", tlsConfig())
	if err != nil {
		log.Fatal(err)
	}
	h := gost.HTTP2Handler(
		gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
	)
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}

func http2TunnelServer() {
	ln, err := gost.H2Listener(":8443", tlsConfig()) // HTTP2 h2 mode
	// ln, err := gost.H2CListener(":8443") // HTTP2 h2c mode
	if err != nil {
		log.Fatal(err)
	}
	// h := gost.HTTPHandler(
	// 	gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
	// )
	h := gost.SOCKS5Handler(
		gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
		gost.TLSConfigHandlerOption(tlsConfig()),
	)
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}

func quicServer() {
	ln, err := gost.QUICListener("localhost:6121", &gost.QUICConfig{TLSConfig: tlsConfig()})
	if err != nil {
		log.Fatal(err)
	}
	h := gost.HTTPHandler(
		gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
	)
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}

func shadowUDPServer() {
	ln, err := gost.ShadowUDPListener(":18338", url.UserPassword("chacha20", "123456"), 30*time.Second)
	if err != nil {
		log.Fatal(err)
	}
	h := gost.ShadowUDPdHandler(
	/*
		gost.ChainHandlerOption(gost.NewChain(
			gost.Node{
				Protocol:  "socks5",
				Transport: "tcp",
				Addr:      "localhost:11080",
				User:      url.UserPassword("admin", "123456"),
				Client: &gost.Client{
					Connector:   gost.SOCKS5Connector(url.UserPassword("admin", "123456")),
					Transporter: gost.TCPTransporter(),
				},
			},
		)),
	*/
	)
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}

var (
	rawCert = []byte(`-----BEGIN CERTIFICATE-----
MIIC+jCCAeKgAwIBAgIRAMlREhz8Miu1FQozsxbeqyMwDQYJKoZIhvcNAQELBQAw
EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNzA1MTkwNTM5MDJaFw0xODA1MTkwNTM5
MDJaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQCyfqvv0kDriciEAVIW6JaWYFCL9a19jj1wmAGmVGxV3kNsr01kpa6N
0EBqnrcy7WknhCt1d43CqhKtTcXgJ/J9phZVxlizb8sUB85hm+MvP0N3HCg3f0Jw
hLuMrPijS6xjyw0fKCK/p6OUYMIfo5cdqeZid2WV4Ozts5uRd6Dmy2kyBe8Zg1F4
8YJGuTWZmL2L7uZUiPY4T3q9+1iucq3vUpxymVRi1BTXnTpx+C0GS8NNgeEmevHv
482vHM5DNflAQ+mvGZvBVduq/AfirCDnt2DIZm1DcZXLrY9F3EPrlRZexmAhCDGR
LIKnMmoGicBM11Aw1fDIfJAHynk43tjPAgMBAAGjSzBJMA4GA1UdDwEB/wQEAwIF
oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuC
CWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEAAx8Lna8DcQv0bRB3L9i2+KRN
l/UhPCoFagxk1cZore4p0w+1m7OgigOoTpg5jh78DzVDhScZlgJ0bBVYp5rojeJS
cBDC9lCDcaXQfFmT5LykCAwIgw/gs+rw5Aq0y3D0m8CcqKosyZa9wnZ2cVy/+45w
emcSdboc65ueZScv38/W7aTUoVRcjyRUv0jv0zW0EPnnDlluVkeZo9spBhiTTwoj
b3zGODs6alTNIJwZIHNxxyOmfJPpVVp8BzGbMk7YBixSlZ/vbrrYV34TcSiy7J57
lNNoVWM+OwiVk1+AEZfQDwaQfef5tsIkAZBUyITkkDKRhygtwM2110dejbEsgg==
-----END CERTIFICATE-----`)
	rawKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAsn6r79JA64nIhAFSFuiWlmBQi/WtfY49cJgBplRsVd5DbK9N
ZKWujdBAap63Mu1pJ4QrdXeNwqoSrU3F4CfyfaYWVcZYs2/LFAfOYZvjLz9Ddxwo
N39CcIS7jKz4o0usY8sNHygiv6ejlGDCH6OXHanmYndlleDs7bObkXeg5stpMgXv
GYNRePGCRrk1mZi9i+7mVIj2OE96vftYrnKt71KccplUYtQU1506cfgtBkvDTYHh
Jnrx7+PNrxzOQzX5QEPprxmbwVXbqvwH4qwg57dgyGZtQ3GVy62PRdxD65UWXsZg
IQgxkSyCpzJqBonATNdQMNXwyHyQB8p5ON7YzwIDAQABAoIBAQCG4doj3Apa8z+n
IShbT1+cOyQi34A+xOIA151Hh7xmFxN0afRd/iWt3JUQ/OcLgQRZbDM7DSD+3W5H
r+G7xfQkpwFxx/T3g58+f7ehYx+GcJQWyhxJ88zNIkBnyb4KCAE5WBOOW9IGajPe
yE9pgUGMlPsXpYoKfHIOHg+NGY1pWUGBfBNR2kGrbkpZMmyy5bGa8dyrwAFBFRru
kcmmKvate8UlbRspFtd4nR/GQLTBrcDJ1k1i1Su/4BpDuDeK6LPI8ZRePGqbdcxk
TS30lsdYozuGfjZ5Zu8lSIJ//+7RjfDg8r684dpWjpalq8Quen60ZrIs01CSbfyU
k8gOzTHhAoGBAOKhp41wXveegq+WylSXFyngm4bzF4dVdTRsSbJVk7NaOx1vCU6o
/xIHoGEQyLI6wF+EaHmY89/Qu6tSV97XyBbiKeskopv5iXS/BsWTHJ1VbCA1ZLmK
HgGllEkS0xfc9AdB7b6/K7LxAAQVKP3DtN6+6pSDZh9Sv2M1j0DbhkNbAoGBAMmg
HcMfExaaeskjHqyLudtKX+znwaIoumleOGuavohR4R+Fpk8Yv8Xhb5U7Yr4gk0vY
CFmhp1WAi6QMZ/8jePlKKXl3Ney827luoKiMczp2DoYE0t0u2Kw3LfkNKfjADZ7d
JI6xPJV9/X1erwjq+4UdKqrpOf05SY4nkBMcvr6dAoGAXzisvbDJNiFTp5Mj0Abr
pJzKvBjHegVeCXi2PkfWlzUCQYu1zWcURO8PY7k5mik1SuzHONAbJ578Oy+N3AOt
/m9oTXRHHmHqbzMUFU+KZlDN7XqBp7NwiCCZ/Vn7d7tOjP4Wdl68baL07sI1RupD
xJNS3LOY5PBPmc+XMRkLgKECgYEAgBNDlJSCrZMHeAjlDTncn53I/VXiPD2e3BvL
vx6W9UT9ueZN1GSmPO6M0MDeYmOS7VSXSUhUYQ28pkJzNTC1QbWITu4YxP7anBnX
1/kPoQ0pAJzDzVharlqGy3M/PBHTFRzogfO3xkY35ZFlokaR6uayGcr42Q+w16nt
7RYPXEkCgYEA3GQYirHnGZuQ952jMvduqnpgkJiSnr0fa+94Rwa1pAhxHLFMo5s4
fqZOtqKPj2s5X1JR0VCey1ilCcaAhWeb3tXCpbYLZSbMtjtqwA6LUeGY+Xdupsjw
cfWIcOfHsIm2kP+RCxEnZf1XwiN9wyJeiUKlE0dqmx9j7F0Bm+7YDhI=
-----END RSA PRIVATE KEY-----`)
)

func tlsConfig() *tls.Config {
	cert, err := tls.X509KeyPair(rawCert, rawKey)
	if err != nil {
		panic(err)
	}
	return &tls.Config{
		Certificates:             []tls.Certificate{cert},
		PreferServerCipherSuites: true,
	}
}

func testServer() {
	s := &http.Server{
		Addr: ":18888",
		Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			fmt.Fprintln(w, "abcdefghijklmnopqrstuvwxyz")
		}),
	}
	log.Fatal(s.ListenAndServe())
}


================================================
FILE: examples/forward/direct/client.go
================================================
package main

import (
	"log"

	"github.com/ginuerzh/gost"
)

func main() {
	tcpForward()
}

func tcpForward() {
	chain := gost.NewChain(
		gost.Node{
			Addr: "localhost:11222",
			Client: &gost.Client{
				Connector:   gost.SSHDirectForwardConnector(),
				Transporter: gost.SSHForwardTransporter(),
			},
		},
	)

	ln, err := gost.TCPListener(":11800")
	if err != nil {
		log.Fatal(err)
	}
	h := gost.TCPDirectForwardHandler(
		"localhost:22",
		gost.ChainHandlerOption(chain),
	)
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}


================================================
FILE: examples/forward/direct/server.go
================================================
package main

import (
	"crypto/tls"
	"log"

	"github.com/ginuerzh/gost"
)

func main() {
	sshForwardServer()
}

func sshForwardServer() {
	ln, err := gost.TCPListener(":11222")
	if err != nil {
		log.Fatal(err)
	}
	h := gost.SSHForwardHandler(
		gost.AddrHandlerOption(":11222"),
		// gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
		gost.TLSConfigHandlerOption(tlsConfig()),
	)
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}

var (
	rawCert = []byte(`-----BEGIN CERTIFICATE-----
MIIC+jCCAeKgAwIBAgIRAMlREhz8Miu1FQozsxbeqyMwDQYJKoZIhvcNAQELBQAw
EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNzA1MTkwNTM5MDJaFw0xODA1MTkwNTM5
MDJaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQCyfqvv0kDriciEAVIW6JaWYFCL9a19jj1wmAGmVGxV3kNsr01kpa6N
0EBqnrcy7WknhCt1d43CqhKtTcXgJ/J9phZVxlizb8sUB85hm+MvP0N3HCg3f0Jw
hLuMrPijS6xjyw0fKCK/p6OUYMIfo5cdqeZid2WV4Ozts5uRd6Dmy2kyBe8Zg1F4
8YJGuTWZmL2L7uZUiPY4T3q9+1iucq3vUpxymVRi1BTXnTpx+C0GS8NNgeEmevHv
482vHM5DNflAQ+mvGZvBVduq/AfirCDnt2DIZm1DcZXLrY9F3EPrlRZexmAhCDGR
LIKnMmoGicBM11Aw1fDIfJAHynk43tjPAgMBAAGjSzBJMA4GA1UdDwEB/wQEAwIF
oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuC
CWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEAAx8Lna8DcQv0bRB3L9i2+KRN
l/UhPCoFagxk1cZore4p0w+1m7OgigOoTpg5jh78DzVDhScZlgJ0bBVYp5rojeJS
cBDC9lCDcaXQfFmT5LykCAwIgw/gs+rw5Aq0y3D0m8CcqKosyZa9wnZ2cVy/+45w
emcSdboc65ueZScv38/W7aTUoVRcjyRUv0jv0zW0EPnnDlluVkeZo9spBhiTTwoj
b3zGODs6alTNIJwZIHNxxyOmfJPpVVp8BzGbMk7YBixSlZ/vbrrYV34TcSiy7J57
lNNoVWM+OwiVk1+AEZfQDwaQfef5tsIkAZBUyITkkDKRhygtwM2110dejbEsgg==
-----END CERTIFICATE-----`)
	rawKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAsn6r79JA64nIhAFSFuiWlmBQi/WtfY49cJgBplRsVd5DbK9N
ZKWujdBAap63Mu1pJ4QrdXeNwqoSrU3F4CfyfaYWVcZYs2/LFAfOYZvjLz9Ddxwo
N39CcIS7jKz4o0usY8sNHygiv6ejlGDCH6OXHanmYndlleDs7bObkXeg5stpMgXv
GYNRePGCRrk1mZi9i+7mVIj2OE96vftYrnKt71KccplUYtQU1506cfgtBkvDTYHh
Jnrx7+PNrxzOQzX5QEPprxmbwVXbqvwH4qwg57dgyGZtQ3GVy62PRdxD65UWXsZg
IQgxkSyCpzJqBonATNdQMNXwyHyQB8p5ON7YzwIDAQABAoIBAQCG4doj3Apa8z+n
IShbT1+cOyQi34A+xOIA151Hh7xmFxN0afRd/iWt3JUQ/OcLgQRZbDM7DSD+3W5H
r+G7xfQkpwFxx/T3g58+f7ehYx+GcJQWyhxJ88zNIkBnyb4KCAE5WBOOW9IGajPe
yE9pgUGMlPsXpYoKfHIOHg+NGY1pWUGBfBNR2kGrbkpZMmyy5bGa8dyrwAFBFRru
kcmmKvate8UlbRspFtd4nR/GQLTBrcDJ1k1i1Su/4BpDuDeK6LPI8ZRePGqbdcxk
TS30lsdYozuGfjZ5Zu8lSIJ//+7RjfDg8r684dpWjpalq8Quen60ZrIs01CSbfyU
k8gOzTHhAoGBAOKhp41wXveegq+WylSXFyngm4bzF4dVdTRsSbJVk7NaOx1vCU6o
/xIHoGEQyLI6wF+EaHmY89/Qu6tSV97XyBbiKeskopv5iXS/BsWTHJ1VbCA1ZLmK
HgGllEkS0xfc9AdB7b6/K7LxAAQVKP3DtN6+6pSDZh9Sv2M1j0DbhkNbAoGBAMmg
HcMfExaaeskjHqyLudtKX+znwaIoumleOGuavohR4R+Fpk8Yv8Xhb5U7Yr4gk0vY
CFmhp1WAi6QMZ/8jePlKKXl3Ney827luoKiMczp2DoYE0t0u2Kw3LfkNKfjADZ7d
JI6xPJV9/X1erwjq+4UdKqrpOf05SY4nkBMcvr6dAoGAXzisvbDJNiFTp5Mj0Abr
pJzKvBjHegVeCXi2PkfWlzUCQYu1zWcURO8PY7k5mik1SuzHONAbJ578Oy+N3AOt
/m9oTXRHHmHqbzMUFU+KZlDN7XqBp7NwiCCZ/Vn7d7tOjP4Wdl68baL07sI1RupD
xJNS3LOY5PBPmc+XMRkLgKECgYEAgBNDlJSCrZMHeAjlDTncn53I/VXiPD2e3BvL
vx6W9UT9ueZN1GSmPO6M0MDeYmOS7VSXSUhUYQ28pkJzNTC1QbWITu4YxP7anBnX
1/kPoQ0pAJzDzVharlqGy3M/PBHTFRzogfO3xkY35ZFlokaR6uayGcr42Q+w16nt
7RYPXEkCgYEA3GQYirHnGZuQ952jMvduqnpgkJiSnr0fa+94Rwa1pAhxHLFMo5s4
fqZOtqKPj2s5X1JR0VCey1ilCcaAhWeb3tXCpbYLZSbMtjtqwA6LUeGY+Xdupsjw
cfWIcOfHsIm2kP+RCxEnZf1XwiN9wyJeiUKlE0dqmx9j7F0Bm+7YDhI=
-----END RSA PRIVATE KEY-----`)
)

func tlsConfig() *tls.Config {
	cert, err := tls.X509KeyPair(rawCert, rawKey)
	if err != nil {
		panic(err)
	}
	return &tls.Config{Certificates: []tls.Certificate{cert}}
}


================================================
FILE: examples/forward/remote/client.go
================================================
package main

import (
	"log"

	"github.com/ginuerzh/gost"
)

func main() {
	sshRemoteForward()
}

func sshRemoteForward() {
	chain := gost.NewChain(
		gost.Node{
			Protocol:  "forward",
			Transport: "ssh",
			Addr:      "localhost:11222",
			Client: &gost.Client{
				Connector:   gost.SSHRemoteForwardConnector(),
				Transporter: gost.SSHForwardTransporter(),
			},
		},
	)

	ln, err := gost.TCPRemoteForwardListener(":11800", chain)
	if err != nil {
		log.Fatal(err)
	}
	h := gost.TCPRemoteForwardHandler(
		"localhost:10000",
	)
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}


================================================
FILE: examples/forward/remote/server.go
================================================
package main

import (
	"crypto/tls"
	"log"

	"github.com/ginuerzh/gost"
)

func main() {
	sshRemoteForwardServer()
}

func sshRemoteForwardServer() {
	ln, err := gost.TCPListener(":11222")
	if err != nil {
		log.Fatal(err)
	}
	h := gost.SSHForwardHandler(
		gost.AddrHandlerOption(":11222"),
		// gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
		gost.TLSConfigHandlerOption(tlsConfig()),
	)
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}

var (
	rawCert = []byte(`-----BEGIN CERTIFICATE-----
MIIC+jCCAeKgAwIBAgIRAMlREhz8Miu1FQozsxbeqyMwDQYJKoZIhvcNAQELBQAw
EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNzA1MTkwNTM5MDJaFw0xODA1MTkwNTM5
MDJaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQCyfqvv0kDriciEAVIW6JaWYFCL9a19jj1wmAGmVGxV3kNsr01kpa6N
0EBqnrcy7WknhCt1d43CqhKtTcXgJ/J9phZVxlizb8sUB85hm+MvP0N3HCg3f0Jw
hLuMrPijS6xjyw0fKCK/p6OUYMIfo5cdqeZid2WV4Ozts5uRd6Dmy2kyBe8Zg1F4
8YJGuTWZmL2L7uZUiPY4T3q9+1iucq3vUpxymVRi1BTXnTpx+C0GS8NNgeEmevHv
482vHM5DNflAQ+mvGZvBVduq/AfirCDnt2DIZm1DcZXLrY9F3EPrlRZexmAhCDGR
LIKnMmoGicBM11Aw1fDIfJAHynk43tjPAgMBAAGjSzBJMA4GA1UdDwEB/wQEAwIF
oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuC
CWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEAAx8Lna8DcQv0bRB3L9i2+KRN
l/UhPCoFagxk1cZore4p0w+1m7OgigOoTpg5jh78DzVDhScZlgJ0bBVYp5rojeJS
cBDC9lCDcaXQfFmT5LykCAwIgw/gs+rw5Aq0y3D0m8CcqKosyZa9wnZ2cVy/+45w
emcSdboc65ueZScv38/W7aTUoVRcjyRUv0jv0zW0EPnnDlluVkeZo9spBhiTTwoj
b3zGODs6alTNIJwZIHNxxyOmfJPpVVp8BzGbMk7YBixSlZ/vbrrYV34TcSiy7J57
lNNoVWM+OwiVk1+AEZfQDwaQfef5tsIkAZBUyITkkDKRhygtwM2110dejbEsgg==
-----END CERTIFICATE-----`)
	rawKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAsn6r79JA64nIhAFSFuiWlmBQi/WtfY49cJgBplRsVd5DbK9N
ZKWujdBAap63Mu1pJ4QrdXeNwqoSrU3F4CfyfaYWVcZYs2/LFAfOYZvjLz9Ddxwo
N39CcIS7jKz4o0usY8sNHygiv6ejlGDCH6OXHanmYndlleDs7bObkXeg5stpMgXv
GYNRePGCRrk1mZi9i+7mVIj2OE96vftYrnKt71KccplUYtQU1506cfgtBkvDTYHh
Jnrx7+PNrxzOQzX5QEPprxmbwVXbqvwH4qwg57dgyGZtQ3GVy62PRdxD65UWXsZg
IQgxkSyCpzJqBonATNdQMNXwyHyQB8p5ON7YzwIDAQABAoIBAQCG4doj3Apa8z+n
IShbT1+cOyQi34A+xOIA151Hh7xmFxN0afRd/iWt3JUQ/OcLgQRZbDM7DSD+3W5H
r+G7xfQkpwFxx/T3g58+f7ehYx+GcJQWyhxJ88zNIkBnyb4KCAE5WBOOW9IGajPe
yE9pgUGMlPsXpYoKfHIOHg+NGY1pWUGBfBNR2kGrbkpZMmyy5bGa8dyrwAFBFRru
kcmmKvate8UlbRspFtd4nR/GQLTBrcDJ1k1i1Su/4BpDuDeK6LPI8ZRePGqbdcxk
TS30lsdYozuGfjZ5Zu8lSIJ//+7RjfDg8r684dpWjpalq8Quen60ZrIs01CSbfyU
k8gOzTHhAoGBAOKhp41wXveegq+WylSXFyngm4bzF4dVdTRsSbJVk7NaOx1vCU6o
/xIHoGEQyLI6wF+EaHmY89/Qu6tSV97XyBbiKeskopv5iXS/BsWTHJ1VbCA1ZLmK
HgGllEkS0xfc9AdB7b6/K7LxAAQVKP3DtN6+6pSDZh9Sv2M1j0DbhkNbAoGBAMmg
HcMfExaaeskjHqyLudtKX+znwaIoumleOGuavohR4R+Fpk8Yv8Xhb5U7Yr4gk0vY
CFmhp1WAi6QMZ/8jePlKKXl3Ney827luoKiMczp2DoYE0t0u2Kw3LfkNKfjADZ7d
JI6xPJV9/X1erwjq+4UdKqrpOf05SY4nkBMcvr6dAoGAXzisvbDJNiFTp5Mj0Abr
pJzKvBjHegVeCXi2PkfWlzUCQYu1zWcURO8PY7k5mik1SuzHONAbJ578Oy+N3AOt
/m9oTXRHHmHqbzMUFU+KZlDN7XqBp7NwiCCZ/Vn7d7tOjP4Wdl68baL07sI1RupD
xJNS3LOY5PBPmc+XMRkLgKECgYEAgBNDlJSCrZMHeAjlDTncn53I/VXiPD2e3BvL
vx6W9UT9ueZN1GSmPO6M0MDeYmOS7VSXSUhUYQ28pkJzNTC1QbWITu4YxP7anBnX
1/kPoQ0pAJzDzVharlqGy3M/PBHTFRzogfO3xkY35ZFlokaR6uayGcr42Q+w16nt
7RYPXEkCgYEA3GQYirHnGZuQ952jMvduqnpgkJiSnr0fa+94Rwa1pAhxHLFMo5s4
fqZOtqKPj2s5X1JR0VCey1ilCcaAhWeb3tXCpbYLZSbMtjtqwA6LUeGY+Xdupsjw
cfWIcOfHsIm2kP+RCxEnZf1XwiN9wyJeiUKlE0dqmx9j7F0Bm+7YDhI=
-----END RSA PRIVATE KEY-----`)
)

func tlsConfig() *tls.Config {
	cert, err := tls.X509KeyPair(rawCert, rawKey)
	if err != nil {
		panic(err)
	}
	return &tls.Config{Certificates: []tls.Certificate{cert}}
}


================================================
FILE: examples/forward/udp/cli.go
================================================
package main

import (
	"flag"
	"log"
	"net"
	"time"
)

var (
	concurrency int
	saddr       string
)

func init() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	flag.StringVar(&saddr, "S", ":18080", "server address")
	flag.IntVar(&concurrency, "c", 1, "Number of multiple echo to make at a time")
	flag.Parse()
}

func main() {
	for i := 0; i < concurrency; i++ {
		go udpEchoLoop()
	}
	select {}
}

func udpEchoLoop() {
	addr, err := net.ResolveUDPAddr("udp", saddr)
	if err != nil {
		log.Fatal(err)
	}
	conn, err := net.DialUDP("udp", nil, addr)
	if err != nil {
		log.Fatal(err)
	}

	msg := []byte(`abcdefghijklmnopqrstuvwxyz`)
	for {
		if _, err := conn.Write(msg); err != nil {
			log.Fatal(err)
		}
		b := make([]byte, 1024)
		_, err := conn.Read(b)
		if err != nil {
			log.Fatal(err)
		}
		// log.Println(string(b[:n]))
		time.Sleep(100 * time.Millisecond)
	}
}


================================================
FILE: examples/forward/udp/direct.go
================================================
package main

import (
	"flag"
	"log"
	"time"

	"github.com/ginuerzh/gost"
)

var (
	laddr, faddr string
	quiet        bool
)

func init() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	flag.StringVar(&laddr, "L", ":18080", "listen address")
	flag.StringVar(&faddr, "F", ":8080", "forward address")
	flag.BoolVar(&quiet, "q", false, "quiet mode")
	flag.BoolVar(&gost.Debug, "d", false, "debug mode")
	flag.Parse()

	if quiet {
		gost.SetLogger(&gost.NopLogger{})
	}
}
func main() {
	udpDirectForwardServer()
}

func udpDirectForwardServer() {
	ln, err := gost.UDPDirectForwardListener(laddr, time.Second*30)
	if err != nil {
		log.Fatal(err)
	}
	h := gost.UDPDirectForwardHandler(
		faddr,
	/*
		gost.ChainHandlerOption(gost.NewChain(gost.Node{
			Protocol:  "socks5",
			Transport: "tcp",
			Addr:      ":11080",
			User:      url.UserPassword("admin", "123456"),
			Client: &gost.Client{
				Connector: gost.SOCKS5Connector(
					url.UserPassword("admin", "123456"),
				),
				Transporter: gost.TCPTransporter(),
			},
		})),
	*/
	)
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}


================================================
FILE: examples/forward/udp/remote.go
================================================
package main

import (
	"flag"
	"log"
	"time"

	"github.com/ginuerzh/gost"
)

var (
	laddr, faddr string
	quiet        bool
)

func init() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	flag.StringVar(&laddr, "L", ":18080", "listen address")
	flag.StringVar(&faddr, "F", ":8080", "forward address")
	flag.BoolVar(&quiet, "q", false, "quiet mode")
	flag.BoolVar(&gost.Debug, "d", false, "debug mode")
	flag.Parse()

	if quiet {
		gost.SetLogger(&gost.NopLogger{})
	}
}
func main() {
	udpRemoteForwardServer()
}

func udpRemoteForwardServer() {
	ln, err := gost.UDPRemoteForwardListener(
		laddr,
		/*
			gost.NewChain(gost.Node{
				Protocol:  "socks5",
				Transport: "tcp",
				Addr:      ":11080",
				User:      url.UserPassword("admin", "123456"),
				Client: &gost.Client{
					Connector: gost.SOCKS5Connector(
						url.UserPassword("admin", "123456"),
					),
					Transporter: gost.TCPTransporter(),
				},
			}),
		*/
		nil,
		time.Second*30)
	if err != nil {
		log.Fatal(err)
	}
	h := gost.UDPRemoteForwardHandler(
		faddr,
	)
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}


================================================
FILE: examples/forward/udp/srv.go
================================================
package main

import (
	"flag"
	"log"
	"net"
)

var (
	laddr string
)

func init() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	flag.StringVar(&laddr, "L", ":8080", "listen address")
	flag.Parse()
}
func main() {
	udpEchoServer()
}

func udpEchoServer() {
	addr, err := net.ResolveUDPAddr("udp", laddr)
	if err != nil {
		log.Fatal(err)
	}
	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		log.Fatal(err)
	}

	for {
		b := make([]byte, 1024)
		n, raddr, err := conn.ReadFromUDP(b)
		if err != nil {
			log.Fatal(err)
		}
		if _, err = conn.WriteToUDP(b[:n], raddr); err != nil {
			log.Fatal(err)
		}

	}
}


================================================
FILE: examples/http2/http2.go
================================================
package main

import (
	"crypto/tls"
	"flag"
	"log"
	"net/url"

	"golang.org/x/net/http2"

	"github.com/ginuerzh/gost"
)

var (
	quiet             bool
	keyFile, certFile string
	laddr             string
	user, passwd      string
)

func init() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	flag.StringVar(&laddr, "L", ":1443", "listen address")
	flag.StringVar(&user, "u", "", "username")
	flag.StringVar(&passwd, "p", "", "password")
	flag.BoolVar(&quiet, "q", false, "quiet mode")
	flag.BoolVar(&gost.Debug, "d", false, "debug mode")
	flag.BoolVar(&http2.VerboseLogs, "v", false, "HTTP2 verbose log")
	flag.StringVar(&keyFile, "key", "key.pem", "TLS key file")
	flag.StringVar(&certFile, "cert", "cert.pem", "TLS cert file")
	flag.Parse()

	if quiet {
		gost.SetLogger(&gost.NopLogger{})
	}
}

func main() {
	http2Server()
}

func http2Server() {
	cert, er := tls.LoadX509KeyPair(certFile, keyFile)
	if er != nil {
		log.Println(er)
		cert, er = tls.X509KeyPair(rawCert, rawKey)
		if er != nil {
			panic(er)
		}
	}

	ln, err := gost.HTTP2Listener(laddr, &tls.Config{Certificates: []tls.Certificate{cert}})
	if err != nil {
		log.Fatal(err)
	}

	var users []*url.Userinfo
	if user != "" || passwd != "" {
		users = append(users, url.UserPassword(user, passwd))
	}

	h := gost.HTTP2Handler(
		gost.UsersHandlerOption(users...),
		gost.AddrHandlerOption(laddr),
	)
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}

var (
	rawCert = []byte(`-----BEGIN CERTIFICATE-----
MIIC+jCCAeKgAwIBAgIRAMlREhz8Miu1FQozsxbeqyMwDQYJKoZIhvcNAQELBQAw
EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNzA1MTkwNTM5MDJaFw0xODA1MTkwNTM5
MDJaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQCyfqvv0kDriciEAVIW6JaWYFCL9a19jj1wmAGmVGxV3kNsr01kpa6N
0EBqnrcy7WknhCt1d43CqhKtTcXgJ/J9phZVxlizb8sUB85hm+MvP0N3HCg3f0Jw
hLuMrPijS6xjyw0fKCK/p6OUYMIfo5cdqeZid2WV4Ozts5uRd6Dmy2kyBe8Zg1F4
8YJGuTWZmL2L7uZUiPY4T3q9+1iucq3vUpxymVRi1BTXnTpx+C0GS8NNgeEmevHv
482vHM5DNflAQ+mvGZvBVduq/AfirCDnt2DIZm1DcZXLrY9F3EPrlRZexmAhCDGR
LIKnMmoGicBM11Aw1fDIfJAHynk43tjPAgMBAAGjSzBJMA4GA1UdDwEB/wQEAwIF
oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuC
CWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEAAx8Lna8DcQv0bRB3L9i2+KRN
l/UhPCoFagxk1cZore4p0w+1m7OgigOoTpg5jh78DzVDhScZlgJ0bBVYp5rojeJS
cBDC9lCDcaXQfFmT5LykCAwIgw/gs+rw5Aq0y3D0m8CcqKosyZa9wnZ2cVy/+45w
emcSdboc65ueZScv38/W7aTUoVRcjyRUv0jv0zW0EPnnDlluVkeZo9spBhiTTwoj
b3zGODs6alTNIJwZIHNxxyOmfJPpVVp8BzGbMk7YBixSlZ/vbrrYV34TcSiy7J57
lNNoVWM+OwiVk1+AEZfQDwaQfef5tsIkAZBUyITkkDKRhygtwM2110dejbEsgg==
-----END CERTIFICATE-----`)
	rawKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAsn6r79JA64nIhAFSFuiWlmBQi/WtfY49cJgBplRsVd5DbK9N
ZKWujdBAap63Mu1pJ4QrdXeNwqoSrU3F4CfyfaYWVcZYs2/LFAfOYZvjLz9Ddxwo
N39CcIS7jKz4o0usY8sNHygiv6ejlGDCH6OXHanmYndlleDs7bObkXeg5stpMgXv
GYNRePGCRrk1mZi9i+7mVIj2OE96vftYrnKt71KccplUYtQU1506cfgtBkvDTYHh
Jnrx7+PNrxzOQzX5QEPprxmbwVXbqvwH4qwg57dgyGZtQ3GVy62PRdxD65UWXsZg
IQgxkSyCpzJqBonATNdQMNXwyHyQB8p5ON7YzwIDAQABAoIBAQCG4doj3Apa8z+n
IShbT1+cOyQi34A+xOIA151Hh7xmFxN0afRd/iWt3JUQ/OcLgQRZbDM7DSD+3W5H
r+G7xfQkpwFxx/T3g58+f7ehYx+GcJQWyhxJ88zNIkBnyb4KCAE5WBOOW9IGajPe
yE9pgUGMlPsXpYoKfHIOHg+NGY1pWUGBfBNR2kGrbkpZMmyy5bGa8dyrwAFBFRru
kcmmKvate8UlbRspFtd4nR/GQLTBrcDJ1k1i1Su/4BpDuDeK6LPI8ZRePGqbdcxk
TS30lsdYozuGfjZ5Zu8lSIJ//+7RjfDg8r684dpWjpalq8Quen60ZrIs01CSbfyU
k8gOzTHhAoGBAOKhp41wXveegq+WylSXFyngm4bzF4dVdTRsSbJVk7NaOx1vCU6o
/xIHoGEQyLI6wF+EaHmY89/Qu6tSV97XyBbiKeskopv5iXS/BsWTHJ1VbCA1ZLmK
HgGllEkS0xfc9AdB7b6/K7LxAAQVKP3DtN6+6pSDZh9Sv2M1j0DbhkNbAoGBAMmg
HcMfExaaeskjHqyLudtKX+znwaIoumleOGuavohR4R+Fpk8Yv8Xhb5U7Yr4gk0vY
CFmhp1WAi6QMZ/8jePlKKXl3Ney827luoKiMczp2DoYE0t0u2Kw3LfkNKfjADZ7d
JI6xPJV9/X1erwjq+4UdKqrpOf05SY4nkBMcvr6dAoGAXzisvbDJNiFTp5Mj0Abr
pJzKvBjHegVeCXi2PkfWlzUCQYu1zWcURO8PY7k5mik1SuzHONAbJ578Oy+N3AOt
/m9oTXRHHmHqbzMUFU+KZlDN7XqBp7NwiCCZ/Vn7d7tOjP4Wdl68baL07sI1RupD
xJNS3LOY5PBPmc+XMRkLgKECgYEAgBNDlJSCrZMHeAjlDTncn53I/VXiPD2e3BvL
vx6W9UT9ueZN1GSmPO6M0MDeYmOS7VSXSUhUYQ28pkJzNTC1QbWITu4YxP7anBnX
1/kPoQ0pAJzDzVharlqGy3M/PBHTFRzogfO3xkY35ZFlokaR6uayGcr42Q+w16nt
7RYPXEkCgYEA3GQYirHnGZuQ952jMvduqnpgkJiSnr0fa+94Rwa1pAhxHLFMo5s4
fqZOtqKPj2s5X1JR0VCey1ilCcaAhWeb3tXCpbYLZSbMtjtqwA6LUeGY+Xdupsjw
cfWIcOfHsIm2kP+RCxEnZf1XwiN9wyJeiUKlE0dqmx9j7F0Bm+7YDhI=
-----END RSA PRIVATE KEY-----`)
)

func tlsConfig() *tls.Config {
	cert, err := tls.X509KeyPair(rawCert, rawKey)
	if err != nil {
		panic(err)
	}
	return &tls.Config{Certificates: []tls.Certificate{cert}}
}


================================================
FILE: examples/quic/quicc.go
================================================
package main

import (
	"crypto/tls"
	"flag"
	"log"
	"time"

	"github.com/ginuerzh/gost"
)

var (
	laddr, faddr string
	quiet        bool
)

func init() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	flag.StringVar(&laddr, "L", ":18080", "listen address")
	flag.StringVar(&faddr, "F", "localhost:6121", "forward address")
	flag.BoolVar(&quiet, "q", false, "quiet mode")
	flag.BoolVar(&gost.Debug, "d", false, "debug mode")
	flag.Parse()

	if quiet {
		gost.SetLogger(&gost.NopLogger{})
	}
}

func main() {
	chain := gost.NewChain(
		gost.Node{
			Protocol:  "socks5",
			Transport: "quic",
			Addr:      faddr,
			Client: &gost.Client{
				Connector:   gost.SOCKS5Connector(nil),
				Transporter: gost.QUICTransporter(&gost.QUICConfig{Timeout: 30 * time.Second, KeepAlive: true}),
			},
		},
	)

	ln, err := gost.TCPListener(laddr)
	if err != nil {
		log.Fatal(err)
	}
	h := gost.SOCKS5Handler(
		gost.ChainHandlerOption(chain),
		gost.TLSConfigHandlerOption(tlsConfig()),
	)
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}

var (
	rawCert = []byte(`-----BEGIN CERTIFICATE-----
MIIC+jCCAeKgAwIBAgIRAMlREhz8Miu1FQozsxbeqyMwDQYJKoZIhvcNAQELBQAw
EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNzA1MTkwNTM5MDJaFw0xODA1MTkwNTM5
MDJaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQCyfqvv0kDriciEAVIW6JaWYFCL9a19jj1wmAGmVGxV3kNsr01kpa6N
0EBqnrcy7WknhCt1d43CqhKtTcXgJ/J9phZVxlizb8sUB85hm+MvP0N3HCg3f0Jw
hLuMrPijS6xjyw0fKCK/p6OUYMIfo5cdqeZid2WV4Ozts5uRd6Dmy2kyBe8Zg1F4
8YJGuTWZmL2L7uZUiPY4T3q9+1iucq3vUpxymVRi1BTXnTpx+C0GS8NNgeEmevHv
482vHM5DNflAQ+mvGZvBVduq/AfirCDnt2DIZm1DcZXLrY9F3EPrlRZexmAhCDGR
LIKnMmoGicBM11Aw1fDIfJAHynk43tjPAgMBAAGjSzBJMA4GA1UdDwEB/wQEAwIF
oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuC
CWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEAAx8Lna8DcQv0bRB3L9i2+KRN
l/UhPCoFagxk1cZore4p0w+1m7OgigOoTpg5jh78DzVDhScZlgJ0bBVYp5rojeJS
cBDC9lCDcaXQfFmT5LykCAwIgw/gs+rw5Aq0y3D0m8CcqKosyZa9wnZ2cVy/+45w
emcSdboc65ueZScv38/W7aTUoVRcjyRUv0jv0zW0EPnnDlluVkeZo9spBhiTTwoj
b3zGODs6alTNIJwZIHNxxyOmfJPpVVp8BzGbMk7YBixSlZ/vbrrYV34TcSiy7J57
lNNoVWM+OwiVk1+AEZfQDwaQfef5tsIkAZBUyITkkDKRhygtwM2110dejbEsgg==
-----END CERTIFICATE-----`)
	rawKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAsn6r79JA64nIhAFSFuiWlmBQi/WtfY49cJgBplRsVd5DbK9N
ZKWujdBAap63Mu1pJ4QrdXeNwqoSrU3F4CfyfaYWVcZYs2/LFAfOYZvjLz9Ddxwo
N39CcIS7jKz4o0usY8sNHygiv6ejlGDCH6OXHanmYndlleDs7bObkXeg5stpMgXv
GYNRePGCRrk1mZi9i+7mVIj2OE96vftYrnKt71KccplUYtQU1506cfgtBkvDTYHh
Jnrx7+PNrxzOQzX5QEPprxmbwVXbqvwH4qwg57dgyGZtQ3GVy62PRdxD65UWXsZg
IQgxkSyCpzJqBonATNdQMNXwyHyQB8p5ON7YzwIDAQABAoIBAQCG4doj3Apa8z+n
IShbT1+cOyQi34A+xOIA151Hh7xmFxN0afRd/iWt3JUQ/OcLgQRZbDM7DSD+3W5H
r+G7xfQkpwFxx/T3g58+f7ehYx+GcJQWyhxJ88zNIkBnyb4KCAE5WBOOW9IGajPe
yE9pgUGMlPsXpYoKfHIOHg+NGY1pWUGBfBNR2kGrbkpZMmyy5bGa8dyrwAFBFRru
kcmmKvate8UlbRspFtd4nR/GQLTBrcDJ1k1i1Su/4BpDuDeK6LPI8ZRePGqbdcxk
TS30lsdYozuGfjZ5Zu8lSIJ//+7RjfDg8r684dpWjpalq8Quen60ZrIs01CSbfyU
k8gOzTHhAoGBAOKhp41wXveegq+WylSXFyngm4bzF4dVdTRsSbJVk7NaOx1vCU6o
/xIHoGEQyLI6wF+EaHmY89/Qu6tSV97XyBbiKeskopv5iXS/BsWTHJ1VbCA1ZLmK
HgGllEkS0xfc9AdB7b6/K7LxAAQVKP3DtN6+6pSDZh9Sv2M1j0DbhkNbAoGBAMmg
HcMfExaaeskjHqyLudtKX+znwaIoumleOGuavohR4R+Fpk8Yv8Xhb5U7Yr4gk0vY
CFmhp1WAi6QMZ/8jePlKKXl3Ney827luoKiMczp2DoYE0t0u2Kw3LfkNKfjADZ7d
JI6xPJV9/X1erwjq+4UdKqrpOf05SY4nkBMcvr6dAoGAXzisvbDJNiFTp5Mj0Abr
pJzKvBjHegVeCXi2PkfWlzUCQYu1zWcURO8PY7k5mik1SuzHONAbJ578Oy+N3AOt
/m9oTXRHHmHqbzMUFU+KZlDN7XqBp7NwiCCZ/Vn7d7tOjP4Wdl68baL07sI1RupD
xJNS3LOY5PBPmc+XMRkLgKECgYEAgBNDlJSCrZMHeAjlDTncn53I/VXiPD2e3BvL
vx6W9UT9ueZN1GSmPO6M0MDeYmOS7VSXSUhUYQ28pkJzNTC1QbWITu4YxP7anBnX
1/kPoQ0pAJzDzVharlqGy3M/PBHTFRzogfO3xkY35ZFlokaR6uayGcr42Q+w16nt
7RYPXEkCgYEA3GQYirHnGZuQ952jMvduqnpgkJiSnr0fa+94Rwa1pAhxHLFMo5s4
fqZOtqKPj2s5X1JR0VCey1ilCcaAhWeb3tXCpbYLZSbMtjtqwA6LUeGY+Xdupsjw
cfWIcOfHsIm2kP+RCxEnZf1XwiN9wyJeiUKlE0dqmx9j7F0Bm+7YDhI=
-----END RSA PRIVATE KEY-----`)
)

func tlsConfig() *tls.Config {
	cert, err := tls.X509KeyPair(rawCert, rawKey)
	if err != nil {
		panic(err)
	}
	return &tls.Config{Certificates: []tls.Certificate{cert}}
}


================================================
FILE: examples/quic/quics.go
================================================
package main

import (
	"crypto/tls"
	"flag"
	"log"

	"github.com/ginuerzh/gost"
)

var (
	laddr string
	quiet bool
)

func init() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	flag.StringVar(&laddr, "L", ":6121", "listen address")
	flag.BoolVar(&quiet, "q", false, "quiet mode")
	flag.BoolVar(&gost.Debug, "d", false, "debug mode")

	flag.Parse()

	if quiet {
		gost.SetLogger(&gost.NopLogger{})
	}
}

func main() {
	quicServer()
}

func quicServer() {
	ln, err := gost.QUICListener(laddr, &gost.QUICConfig{TLSConfig: tlsConfig()})
	if err != nil {
		log.Fatal(err)
	}
	h := gost.SOCKS5Handler(gost.TLSConfigHandlerOption(tlsConfig()))
	log.Println("server listen on", laddr)

	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}

var (
	rawCert = []byte(`-----BEGIN CERTIFICATE-----
MIIC+jCCAeKgAwIBAgIRAMlREhz8Miu1FQozsxbeqyMwDQYJKoZIhvcNAQELBQAw
EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNzA1MTkwNTM5MDJaFw0xODA1MTkwNTM5
MDJaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQCyfqvv0kDriciEAVIW6JaWYFCL9a19jj1wmAGmVGxV3kNsr01kpa6N
0EBqnrcy7WknhCt1d43CqhKtTcXgJ/J9phZVxlizb8sUB85hm+MvP0N3HCg3f0Jw
hLuMrPijS6xjyw0fKCK/p6OUYMIfo5cdqeZid2WV4Ozts5uRd6Dmy2kyBe8Zg1F4
8YJGuTWZmL2L7uZUiPY4T3q9+1iucq3vUpxymVRi1BTXnTpx+C0GS8NNgeEmevHv
482vHM5DNflAQ+mvGZvBVduq/AfirCDnt2DIZm1DcZXLrY9F3EPrlRZexmAhCDGR
LIKnMmoGicBM11Aw1fDIfJAHynk43tjPAgMBAAGjSzBJMA4GA1UdDwEB/wQEAwIF
oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuC
CWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEAAx8Lna8DcQv0bRB3L9i2+KRN
l/UhPCoFagxk1cZore4p0w+1m7OgigOoTpg5jh78DzVDhScZlgJ0bBVYp5rojeJS
cBDC9lCDcaXQfFmT5LykCAwIgw/gs+rw5Aq0y3D0m8CcqKosyZa9wnZ2cVy/+45w
emcSdboc65ueZScv38/W7aTUoVRcjyRUv0jv0zW0EPnnDlluVkeZo9spBhiTTwoj
b3zGODs6alTNIJwZIHNxxyOmfJPpVVp8BzGbMk7YBixSlZ/vbrrYV34TcSiy7J57
lNNoVWM+OwiVk1+AEZfQDwaQfef5tsIkAZBUyITkkDKRhygtwM2110dejbEsgg==
-----END CERTIFICATE-----`)
	rawKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAsn6r79JA64nIhAFSFuiWlmBQi/WtfY49cJgBplRsVd5DbK9N
ZKWujdBAap63Mu1pJ4QrdXeNwqoSrU3F4CfyfaYWVcZYs2/LFAfOYZvjLz9Ddxwo
N39CcIS7jKz4o0usY8sNHygiv6ejlGDCH6OXHanmYndlleDs7bObkXeg5stpMgXv
GYNRePGCRrk1mZi9i+7mVIj2OE96vftYrnKt71KccplUYtQU1506cfgtBkvDTYHh
Jnrx7+PNrxzOQzX5QEPprxmbwVXbqvwH4qwg57dgyGZtQ3GVy62PRdxD65UWXsZg
IQgxkSyCpzJqBonATNdQMNXwyHyQB8p5ON7YzwIDAQABAoIBAQCG4doj3Apa8z+n
IShbT1+cOyQi34A+xOIA151Hh7xmFxN0afRd/iWt3JUQ/OcLgQRZbDM7DSD+3W5H
r+G7xfQkpwFxx/T3g58+f7ehYx+GcJQWyhxJ88zNIkBnyb4KCAE5WBOOW9IGajPe
yE9pgUGMlPsXpYoKfHIOHg+NGY1pWUGBfBNR2kGrbkpZMmyy5bGa8dyrwAFBFRru
kcmmKvate8UlbRspFtd4nR/GQLTBrcDJ1k1i1Su/4BpDuDeK6LPI8ZRePGqbdcxk
TS30lsdYozuGfjZ5Zu8lSIJ//+7RjfDg8r684dpWjpalq8Quen60ZrIs01CSbfyU
k8gOzTHhAoGBAOKhp41wXveegq+WylSXFyngm4bzF4dVdTRsSbJVk7NaOx1vCU6o
/xIHoGEQyLI6wF+EaHmY89/Qu6tSV97XyBbiKeskopv5iXS/BsWTHJ1VbCA1ZLmK
HgGllEkS0xfc9AdB7b6/K7LxAAQVKP3DtN6+6pSDZh9Sv2M1j0DbhkNbAoGBAMmg
HcMfExaaeskjHqyLudtKX+znwaIoumleOGuavohR4R+Fpk8Yv8Xhb5U7Yr4gk0vY
CFmhp1WAi6QMZ/8jePlKKXl3Ney827luoKiMczp2DoYE0t0u2Kw3LfkNKfjADZ7d
JI6xPJV9/X1erwjq+4UdKqrpOf05SY4nkBMcvr6dAoGAXzisvbDJNiFTp5Mj0Abr
pJzKvBjHegVeCXi2PkfWlzUCQYu1zWcURO8PY7k5mik1SuzHONAbJ578Oy+N3AOt
/m9oTXRHHmHqbzMUFU+KZlDN7XqBp7NwiCCZ/Vn7d7tOjP4Wdl68baL07sI1RupD
xJNS3LOY5PBPmc+XMRkLgKECgYEAgBNDlJSCrZMHeAjlDTncn53I/VXiPD2e3BvL
vx6W9UT9ueZN1GSmPO6M0MDeYmOS7VSXSUhUYQ28pkJzNTC1QbWITu4YxP7anBnX
1/kPoQ0pAJzDzVharlqGy3M/PBHTFRzogfO3xkY35ZFlokaR6uayGcr42Q+w16nt
7RYPXEkCgYEA3GQYirHnGZuQ952jMvduqnpgkJiSnr0fa+94Rwa1pAhxHLFMo5s4
fqZOtqKPj2s5X1JR0VCey1ilCcaAhWeb3tXCpbYLZSbMtjtqwA6LUeGY+Xdupsjw
cfWIcOfHsIm2kP+RCxEnZf1XwiN9wyJeiUKlE0dqmx9j7F0Bm+7YDhI=
-----END RSA PRIVATE KEY-----`)
)

func tlsConfig() *tls.Config {
	cert, err := tls.X509KeyPair(rawCert, rawKey)
	if err != nil {
		panic(err)
	}
	return &tls.Config{Certificates: []tls.Certificate{cert}}
}


================================================
FILE: examples/ssh/sshc.go
================================================
package main

import (
	"crypto/tls"
	"flag"
	"log"
	"time"

	"github.com/ginuerzh/gost"
)

var (
	laddr, faddr string
	quiet        bool
)

func init() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	flag.StringVar(&laddr, "L", ":18080", "listen address")
	flag.StringVar(&faddr, "F", ":12222", "forward address")
	flag.BoolVar(&quiet, "q", false, "quiet mode")
	flag.BoolVar(&gost.Debug, "d", false, "debug mode")
	flag.Parse()

	if quiet {
		gost.SetLogger(&gost.NopLogger{})
	}
}

func main() {
	chain := gost.NewChain(
		gost.Node{
			Protocol:  "socks5",
			Transport: "ssh",
			Addr:      faddr,
			HandshakeOptions: []gost.HandshakeOption{
				gost.IntervalHandshakeOption(30 * time.Second),
			},
			Client: &gost.Client{
				Connector:   gost.SOCKS5Connector(nil),
				Transporter: gost.SSHTunnelTransporter(),
			},
		},
	)

	ln, err := gost.TCPListener(laddr)
	if err != nil {
		log.Fatal(err)
	}
	h := gost.SOCKS5Handler(
		gost.ChainHandlerOption(chain),
		gost.TLSConfigHandlerOption(tlsConfig()),
	)
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}

var (
	rawCert = []byte(`-----BEGIN CERTIFICATE-----
MIIC+jCCAeKgAwIBAgIRAMlREhz8Miu1FQozsxbeqyMwDQYJKoZIhvcNAQELBQAw
EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNzA1MTkwNTM5MDJaFw0xODA1MTkwNTM5
MDJaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQCyfqvv0kDriciEAVIW6JaWYFCL9a19jj1wmAGmVGxV3kNsr01kpa6N
0EBqnrcy7WknhCt1d43CqhKtTcXgJ/J9phZVxlizb8sUB85hm+MvP0N3HCg3f0Jw
hLuMrPijS6xjyw0fKCK/p6OUYMIfo5cdqeZid2WV4Ozts5uRd6Dmy2kyBe8Zg1F4
8YJGuTWZmL2L7uZUiPY4T3q9+1iucq3vUpxymVRi1BTXnTpx+C0GS8NNgeEmevHv
482vHM5DNflAQ+mvGZvBVduq/AfirCDnt2DIZm1DcZXLrY9F3EPrlRZexmAhCDGR
LIKnMmoGicBM11Aw1fDIfJAHynk43tjPAgMBAAGjSzBJMA4GA1UdDwEB/wQEAwIF
oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuC
CWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEAAx8Lna8DcQv0bRB3L9i2+KRN
l/UhPCoFagxk1cZore4p0w+1m7OgigOoTpg5jh78DzVDhScZlgJ0bBVYp5rojeJS
cBDC9lCDcaXQfFmT5LykCAwIgw/gs+rw5Aq0y3D0m8CcqKosyZa9wnZ2cVy/+45w
emcSdboc65ueZScv38/W7aTUoVRcjyRUv0jv0zW0EPnnDlluVkeZo9spBhiTTwoj
b3zGODs6alTNIJwZIHNxxyOmfJPpVVp8BzGbMk7YBixSlZ/vbrrYV34TcSiy7J57
lNNoVWM+OwiVk1+AEZfQDwaQfef5tsIkAZBUyITkkDKRhygtwM2110dejbEsgg==
-----END CERTIFICATE-----`)
	rawKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAsn6r79JA64nIhAFSFuiWlmBQi/WtfY49cJgBplRsVd5DbK9N
ZKWujdBAap63Mu1pJ4QrdXeNwqoSrU3F4CfyfaYWVcZYs2/LFAfOYZvjLz9Ddxwo
N39CcIS7jKz4o0usY8sNHygiv6ejlGDCH6OXHanmYndlleDs7bObkXeg5stpMgXv
GYNRePGCRrk1mZi9i+7mVIj2OE96vftYrnKt71KccplUYtQU1506cfgtBkvDTYHh
Jnrx7+PNrxzOQzX5QEPprxmbwVXbqvwH4qwg57dgyGZtQ3GVy62PRdxD65UWXsZg
IQgxkSyCpzJqBonATNdQMNXwyHyQB8p5ON7YzwIDAQABAoIBAQCG4doj3Apa8z+n
IShbT1+cOyQi34A+xOIA151Hh7xmFxN0afRd/iWt3JUQ/OcLgQRZbDM7DSD+3W5H
r+G7xfQkpwFxx/T3g58+f7ehYx+GcJQWyhxJ88zNIkBnyb4KCAE5WBOOW9IGajPe
yE9pgUGMlPsXpYoKfHIOHg+NGY1pWUGBfBNR2kGrbkpZMmyy5bGa8dyrwAFBFRru
kcmmKvate8UlbRspFtd4nR/GQLTBrcDJ1k1i1Su/4BpDuDeK6LPI8ZRePGqbdcxk
TS30lsdYozuGfjZ5Zu8lSIJ//+7RjfDg8r684dpWjpalq8Quen60ZrIs01CSbfyU
k8gOzTHhAoGBAOKhp41wXveegq+WylSXFyngm4bzF4dVdTRsSbJVk7NaOx1vCU6o
/xIHoGEQyLI6wF+EaHmY89/Qu6tSV97XyBbiKeskopv5iXS/BsWTHJ1VbCA1ZLmK
HgGllEkS0xfc9AdB7b6/K7LxAAQVKP3DtN6+6pSDZh9Sv2M1j0DbhkNbAoGBAMmg
HcMfExaaeskjHqyLudtKX+znwaIoumleOGuavohR4R+Fpk8Yv8Xhb5U7Yr4gk0vY
CFmhp1WAi6QMZ/8jePlKKXl3Ney827luoKiMczp2DoYE0t0u2Kw3LfkNKfjADZ7d
JI6xPJV9/X1erwjq+4UdKqrpOf05SY4nkBMcvr6dAoGAXzisvbDJNiFTp5Mj0Abr
pJzKvBjHegVeCXi2PkfWlzUCQYu1zWcURO8PY7k5mik1SuzHONAbJ578Oy+N3AOt
/m9oTXRHHmHqbzMUFU+KZlDN7XqBp7NwiCCZ/Vn7d7tOjP4Wdl68baL07sI1RupD
xJNS3LOY5PBPmc+XMRkLgKECgYEAgBNDlJSCrZMHeAjlDTncn53I/VXiPD2e3BvL
vx6W9UT9ueZN1GSmPO6M0MDeYmOS7VSXSUhUYQ28pkJzNTC1QbWITu4YxP7anBnX
1/kPoQ0pAJzDzVharlqGy3M/PBHTFRzogfO3xkY35ZFlokaR6uayGcr42Q+w16nt
7RYPXEkCgYEA3GQYirHnGZuQ952jMvduqnpgkJiSnr0fa+94Rwa1pAhxHLFMo5s4
fqZOtqKPj2s5X1JR0VCey1ilCcaAhWeb3tXCpbYLZSbMtjtqwA6LUeGY+Xdupsjw
cfWIcOfHsIm2kP+RCxEnZf1XwiN9wyJeiUKlE0dqmx9j7F0Bm+7YDhI=
-----END RSA PRIVATE KEY-----`)
)

func tlsConfig() *tls.Config {
	cert, err := tls.X509KeyPair(rawCert, rawKey)
	if err != nil {
		panic(err)
	}
	return &tls.Config{Certificates: []tls.Certificate{cert}}
}


================================================
FILE: examples/ssh/sshd.go
================================================
package main

import (
	"crypto/tls"
	"flag"
	"log"

	"github.com/ginuerzh/gost"
)

var (
	laddr string
	quiet bool
)

func init() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	flag.StringVar(&laddr, "L", ":12222", "listen address")
	flag.BoolVar(&quiet, "q", false, "quiet mode")
	flag.BoolVar(&gost.Debug, "d", false, "debug mode")

	flag.Parse()

	if quiet {
		gost.SetLogger(&gost.NopLogger{})
	}
}

func main() {
	sshTunnelServer()
}

func sshTunnelServer() {
	ln, err := gost.SSHTunnelListener(laddr, &gost.SSHConfig{TLSConfig: tlsConfig()})
	if err != nil {
		log.Fatal(err)
	}
	h := gost.SOCKS5Handler(gost.TLSConfigHandlerOption(tlsConfig()))
	log.Println("server listen on", laddr)
	s := &gost.Server{ln}
	log.Fatal(s.Serve(h))
}

var (
	rawCert = []byte(`-----BEGIN CERTIFICATE-----
MIIC+jCCAeKgAwIBAgIRAMlREhz8Miu1FQozsxbeqyMwDQYJKoZIhvcNAQELBQAw
EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNzA1MTkwNTM5MDJaFw0xODA1MTkwNTM5
MDJaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQCyfqvv0kDriciEAVIW6JaWYFCL9a19jj1wmAGmVGxV3kNsr01kpa6N
0EBqnrcy7WknhCt1d43CqhKtTcXgJ/J9phZVxlizb8sUB85hm+MvP0N3HCg3f0Jw
hLuMrPijS6xjyw0fKCK/p6OUYMIfo5cdqeZid2WV4Ozts5uRd6Dmy2kyBe8Zg1F4
8YJGuTWZmL2L7uZUiPY4T3q9+1iucq3vUpxymVRi1BTXnTpx+C0GS8NNgeEmevHv
482vHM5DNflAQ+mvGZvBVduq/AfirCDnt2DIZm1DcZXLrY9F3EPrlRZexmAhCDGR
LIKnMmoGicBM11Aw1fDIfJAHynk43tjPAgMBAAGjSzBJMA4GA1UdDwEB/wQEAwIF
oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuC
CWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEAAx8Lna8DcQv0bRB3L9i2+KRN
l/UhPCoFagxk1cZore4p0w+1m7OgigOoTpg5jh78DzVDhScZlgJ0bBVYp5rojeJS
cBDC9lCDcaXQfFmT5LykCAwIgw/gs+rw5Aq0y3D0m8CcqKosyZa9wnZ2cVy/+45w
emcSdboc65ueZScv38/W7aTUoVRcjyRUv0jv0zW0EPnnDlluVkeZo9spBhiTTwoj
b3zGODs6alTNIJwZIHNxxyOmfJPpVVp8BzGbMk7YBixSlZ/vbrrYV34TcSiy7J57
lNNoVWM+OwiVk1+AEZfQDwaQfef5tsIkAZBUyITkkDKRhygtwM2110dejbEsgg==
-----END CERTIFICATE-----`)
	rawKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAsn6r79JA64nIhAFSFuiWlmBQi/WtfY49cJgBplRsVd5DbK9N
ZKWujdBAap63Mu1pJ4QrdXeNwqoSrU3F4CfyfaYWVcZYs2/LFAfOYZvjLz9Ddxwo
N39CcIS7jKz4o0usY8sNHygiv6ejlGDCH6OXHanmYndlleDs7bObkXeg5stpMgXv
GYNRePGCRrk1mZi9i+7mVIj2OE96vftYrnKt71KccplUYtQU1506cfgtBkvDTYHh
Jnrx7+PNrxzOQzX5QEPprxmbwVXbqvwH4qwg57dgyGZtQ3GVy62PRdxD65UWXsZg
IQgxkSyCpzJqBonATNdQMNXwyHyQB8p5ON7YzwIDAQABAoIBAQCG4doj3Apa8z+n
IShbT1+cOyQi34A+xOIA151Hh7xmFxN0afRd/iWt3JUQ/OcLgQRZbDM7DSD+3W5H
r+G7xfQkpwFxx/T3g58+f7ehYx+GcJQWyhxJ88zNIkBnyb4KCAE5WBOOW9IGajPe
yE9pgUGMlPsXpYoKfHIOHg+NGY1pWUGBfBNR2kGrbkpZMmyy5bGa8dyrwAFBFRru
kcmmKvate8UlbRspFtd4nR/GQLTBrcDJ1k1i1Su/4BpDuDeK6LPI8ZRePGqbdcxk
TS30lsdYozuGfjZ5Zu8lSIJ//+7RjfDg8r684dpWjpalq8Quen60ZrIs01CSbfyU
k8gOzTHhAoGBAOKhp41wXveegq+WylSXFyngm4bzF4dVdTRsSbJVk7NaOx1vCU6o
/xIHoGEQyLI6wF+EaHmY89/Qu6tSV97XyBbiKeskopv5iXS/BsWTHJ1VbCA1ZLmK
HgGllEkS0xfc9AdB7b6/K7LxAAQVKP3DtN6+6pSDZh9Sv2M1j0DbhkNbAoGBAMmg
HcMfExaaeskjHqyLudtKX+znwaIoumleOGuavohR4R+Fpk8Yv8Xhb5U7Yr4gk0vY
CFmhp1WAi6QMZ/8jePlKKXl3Ney827luoKiMczp2DoYE0t0u2Kw3LfkNKfjADZ7d
JI6xPJV9/X1erwjq+4UdKqrpOf05SY4nkBMcvr6dAoGAXzisvbDJNiFTp5Mj0Abr
pJzKvBjHegVeCXi2PkfWlzUCQYu1zWcURO8PY7k5mik1SuzHONAbJ578Oy+N3AOt
/m9oTXRHHmHqbzMUFU+KZlDN7XqBp7NwiCCZ/Vn7d7tOjP4Wdl68baL07sI1RupD
xJNS3LOY5PBPmc+XMRkLgKECgYEAgBNDlJSCrZMHeAjlDTncn53I/VXiPD2e3BvL
vx6W9UT9ueZN1GSmPO6M0MDeYmOS7VSXSUhUYQ28pkJzNTC1QbWITu4YxP7anBnX
1/kPoQ0pAJzDzVharlqGy3M/PBHTFRzogfO3xkY35ZFlokaR6uayGcr42Q+w16nt
7RYPXEkCgYEA3GQYirHnGZuQ952jMvduqnpgkJiSnr0fa+94Rwa1pAhxHLFMo5s4
fqZOtqKPj2s5X1JR0VCey1ilCcaAhWeb3tXCpbYLZSbMtjtqwA6LUeGY+Xdupsjw
cfWIcOfHsIm2kP+RCxEnZf1XwiN9wyJeiUKlE0dqmx9j7F0Bm+7YDhI=
-----END RSA PRIVATE KEY-----`)
)

func tlsConfig() *tls.Config {
	cert, err := tls.X509KeyPair(rawCert, rawKey)
	if err != nil {
		panic(err)
	}
	return &tls.Config{Certificates: []tls.Certificate{cert}}
}


================================================
FILE: examples/ssu/ssu.go
================================================
package main

import (
	"bytes"
	"log"
	"net"
	"strconv"

	"github.com/go-gost/gosocks5"
	ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
)

func main() {
	ssuClient()
}

func ssuClient() {
	addr, err := net.ResolveUDPAddr("udp", ":18338")
	if err != nil {
		log.Fatal(err)
	}
	laddr, _ := net.ResolveUDPAddr("udp", ":10800")
	conn, err := net.ListenUDP("udp", laddr)
	if err != nil {
		log.Fatal(err)
	}
	cp, err := ss.NewCipher("chacha20", "123456")
	if err != nil {
		log.Fatal(err)
	}
	cc := ss.NewSecurePacketConn(conn, cp, false)

	raddr, _ := net.ResolveUDPAddr("udp", ":8080")
	msg := []byte(`abcdefghijklmnopqrstuvwxyz`)
	dgram := gosocks5.NewUDPDatagram(gosocks5.NewUDPHeader(0, 0, toSocksAddr(raddr)), msg)
	buf := bytes.Buffer{}
	dgram.Write(&buf)
	for {
		log.Printf("%# x", buf.Bytes()[3:])
		if _, err := cc.WriteTo(buf.Bytes()[3:], addr); err != nil {
			log.Fatal(err)
		}
		b := make([]byte, 1024)
		n, adr, err := cc.ReadFrom(b)
		if err != nil {
			log.Fatal(err)
		}
		log.Printf("%s: %# x", adr, b[:n])
	}
}

func toSocksAddr(addr net.Addr) *gosocks5.Addr {
	host := "0.0.0.0"
	port := 0
	if addr != nil {
		h, p, _ := net.SplitHostPort(addr.String())
		host = h
		port, _ = strconv.Atoi(p)
	}
	return &gosocks5.Addr{
		Type: gosocks5.AddrIPv4,
		Host: host,
		Port: uint16(port),
	}
}


================================================
FILE: forward.go
================================================
package gost

import (
	"context"
	"errors"
	"net"
	"strings"
	"sync"
	"time"

	"fmt"

	"github.com/go-gost/gosocks5"
	"github.com/go-log/log"
	smux "github.com/xtaci/smux"
)

type forwardConnector struct {
}

// ForwardConnector creates a Connector for data forward client.
func ForwardConnector() Connector {
	return &forwardConnector{}
}

func (c *forwardConnector) Connect(conn net.Conn, address string, options ...ConnectOption) (net.Conn, error) {
	return c.ConnectContext(context.Background(), conn, "tcp", address, options...)
}

func (c *forwardConnector) ConnectContext(ctx context.Context, conn net.Conn, network, address string, options ...ConnectOption) (net.Conn, error) {
	return conn, nil
}

type baseForwardHandler struct {
	raddr   string
	group   *NodeGroup
	options *HandlerOptions
}

func (h *baseForwardHandler) Init(options ...HandlerOption) {
	if h.options == nil {
		h.options = &HandlerOptions{}
	}

	for _, opt := range options {
		opt(h.options)
	}

	h.group = NewNodeGroup() // reset node group

	h.group.SetSelector(&defaultSelector{},
		WithStrategy(h.options.Strategy),
		WithFilter(&FailFilter{
			MaxFails:    h.options.MaxFails,
			FailTimeout: h.options.FailTimeout,
		}),
	)

	n := 1
	addrs := append(strings.Split(h.raddr, ","), h.options.IPs...)
	for _, addr := range addrs {
		if addr == "" {
			continue
		}

		// We treat the remote target server as a node, so we can put them in a group,
		// and perform the node selection for load balancing.
		h.group.AddNode(Node{
			ID:     n,
			Addr:   addr,
			Host:   addr,
			marker: &failMarker{},
		})

		n++
	}
}

type tcpDirectForwardHandler struct {
	*baseForwardHandler
}

// TCPDirectForwardHandler creates a server Handler for TCP port forwarding server.
// The raddr is the remote address that the server will forward to.
// NOTE: as of 2.6, remote address can be a comma-separated address list.
func TCPDirectForwardHandler(raddr string, opts ...HandlerOption) Handler {
	h := &tcpDirectForwardHandler{
		baseForwardHandler: &baseForwardHandler{
			raddr:   raddr,
			group:   NewNodeGroup(),
			options: &HandlerOptions{},
		},
	}

	for _, opt := range opts {
		opt(h.options)
	}

	return h
}

func (h *tcpDirectForwardHandler) Init(options ...HandlerOption) {
	h.baseForwardHandler.Init(options...)
}

func (h *tcpDirectForwardHandler) Handle(conn net.Conn) {
	defer conn.Close()

	log.Logf("[tcp] %s - %s", conn.RemoteAddr(), conn.LocalAddr())

	retries := 1
	if h.options.Chain != nil && h.options.Chain.Retries > 0 {
		retries = h.options.Chain.Retries
	}
	if h.options.Retries > 0 {
		retries = h.options.Retries
	}

	var cc net.Conn
	var node Node
	var err error
	for i := 0; i < retries; i++ {
		if len(h.group.Nodes()) > 0 {
			node, err = h.group.Next()
			if err != nil {
				log.Logf("[tcp] %s - %s : %s", conn.RemoteAddr(), conn.LocalAddr(), err)
				return
			}
		}

		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)
			node.MarkDead()
		} else {
			break
		}
	}
	if err != nil {
		return
	}

	node.ResetDead()
	defer cc.Close()

	addr := node.Addr
	if addr == "" {
		addr = conn.LocalAddr().String()
	}
	log.Logf("[tcp] %s <-> %s", conn.RemoteAddr(), addr)
	transport(conn, cc)
	log.Logf("[tcp] %s >-< %s", conn.RemoteAddr(), addr)
}

type udpDirectForwardHandler struct {
	*baseForwardHandler
}

// UDPDirectForwardHandler creates a server Handler for UDP port forwarding server.
// The raddr is the remote address that the server will forward to.
// NOTE: as of 2.6, remote address can be a comma-separated address list.
func UDPDirectForwardHandler(raddr string, opts ...HandlerOption) Handler {
	h := &udpDirectForwardHandler{
		baseForwardHandler: &baseForwardHandler{
			raddr:   raddr,
			group:   NewNodeGroup(),
			options: &HandlerOptions{},
		},
	}

	for _, opt := range opts {
		opt(h.options)
	}

	return h
}

func (h *udpDirectForwardHandler) Init(options ...HandlerOption) {
	h.baseForwardHandler.Init(options...)
}

func (h *udpDirectForwardHandler) Handle(conn net.Conn) {
	defer conn.Close()

	log.Logf("[udp] %s - %s", conn.RemoteAddr(), conn.LocalAddr())

	var node Node
	var err error
	if len(h.group.Nodes()) > 0 {
		node, err = h.group.Next()
		if err != nil {
			log.Logf("[udp] %s - %s : %s", conn.RemoteAddr(), conn.LocalAddr(), err)
			return
		}
	}

	cc, err := h.options.Chain.DialContext(
		context.Background(),
		"udp",
		node.Addr,
		ResolverChainOption(h.options.Resolver),
	)
	if err != nil {
		node.MarkDead()
		log.Logf("[udp] %s - %s : %s", conn.RemoteAddr(), conn.LocalAddr(), err)
		return
	}
	defer cc.Close()
	node.ResetDead()

	addr := node.Addr
	if addr == "" {
		addr = conn.LocalAddr().String()
	}
	log.Logf("[udp] %s <-> %s", conn.RemoteAddr(), addr)
	transport(conn, cc)
	log.Logf("[udp] %s >-< %s", conn.RemoteAddr(), addr)
}

type tcpRemoteForwardHandler struct {
	*baseForwardHandler
}

// TCPRemoteForwardHandler creates a server Handler for TCP remote port forwarding server.
// The raddr is the remote address that the server will forward to.
// NOTE: as of 2.6, remote address can be a comma-separated address list.
func TCPRemoteForwardHandler(raddr string, opts ...HandlerOption) Handler {
	h := &tcpRemoteForwardHandler{
		baseForwardHandler: &baseForwardHandler{
			raddr:   raddr,
			group:   NewNodeGroup(),
			options: &HandlerOptions{},
		},
	}

	for _, opt := range opts {
		opt(h.options)
	}

	return h
}

func (h *tcpRemoteForwardHandler) Init(options ...HandlerOption) {
	h.baseForwardHandler.Init(options...)
}

func (h *tcpRemoteForwardHandler) Handle(conn net.Conn) {
	defer conn.Close()

	retries := 1
	if h.options.Retries > 0 {
		retries = h.options.Retries
	}

	var cc net.Conn
	var node Node
	var err error
	for i := 0; i < retries; i++ {
		if len(h.group.Nodes()) > 0 {
			node, err = h.group.Next()
			if err != nil {
				log.Logf("[rtcp] %s - %s : %s", conn.LocalAddr(), h.raddr, err)
				return
			}
		}
		cc, err = net.DialTimeout("tcp", node.Addr, h.options.Timeout)
		if err != nil {
			log.Logf("[rtcp] %s -> %s : %s", conn.LocalAddr(), node.Addr, err)
			node.MarkDead()
		} else {
			break
		}
	}
	if err != nil {
		return
	}

	defer cc.Close()
	node.ResetDead()

	log.Logf("[rtcp] %s <-> %s", conn.LocalAddr(), node.Addr)
	transport(cc, conn)
	log.Logf("[rtcp] %s >-< %s", conn.LocalAddr(), node.Addr)
}

type udpRemoteForwardHandler struct {
	*baseForwardHandler
}

// UDPRemoteForwardHandler creates a server Handler for UDP remote port forwarding server.
// The raddr is the remote address that the server will forward to.
// NOTE: as of 2.6, remote address can be a comma-separated address list.
func UDPRemoteForwardHandler(raddr string, opts ...HandlerOption) Handler {
	h := &udpRemoteForwardHandler{
		baseForwardHandler: &baseForwardHandler{
			raddr:   raddr,
			group:   NewNodeGroup(),
			options: &HandlerOptions{},
		},
	}

	for _, opt := range opts {
		opt(h.options)
	}

	return h
}

func (h *udpRemoteForwardHandler) Init(options ...HandlerOption) {
	h.baseForwardHandler.Init(options...)
}

func (h *udpRemoteForwardHandler) Handle(conn net.Conn) {
	defer conn.Close()

	var node Node
	var err error
	if len(h.group.Nodes()) > 0 {
		node, err = h.group.Next()
		if err != nil {
			log.Logf("[rudp] %s - %s : %s", conn.RemoteAddr(), h.raddr, err)
			return
		}
	}

	raddr, err := net.ResolveUDPAddr("udp", node.Addr)
	if err != nil {
		node.MarkDead()
		log.Logf("[rudp] %s - %s : %s", conn.RemoteAddr(), node.Addr, err)
		return
	}
	cc, err := net.DialUDP("udp", nil, raddr)
	if err != nil {
		node.MarkDead()
		log.Logf("[rudp] %s - %s : %s", conn.RemoteAddr(), node.Addr, err)
		return
	}
	defer cc.Close()
	node.ResetDead()

	log.Logf("[rudp] %s <-> %s", conn.RemoteAddr(), node.Addr)
	transport(conn, cc)
	log.Logf("[rudp] %s >-< %s", conn.RemoteAddr(), node.Addr)
}

type tcpRemoteForwardListener struct {
	addr       net.Addr
	chain      *Chain
	connChan   chan net.Conn
	ln         net.Listener
	session    *muxSession
	sessionMux sync.Mutex
	closed     chan struct{}
	closeMux   sync.Mutex
}

// TCPRemoteForwardListener creates a Listener for TCP remote port forwarding server.
func TCPRemoteForwardListener(addr string, chain *Chain) (Listener, error) {
	laddr, err := net.ResolveTCPAddr("tcp", addr)
	if err != nil {
		return nil, err
	}

	ln := &tcpRemoteForwardListener{
		addr:     laddr,
		chain:    chain,
		connChan: make(chan net.Conn, 1024),
		closed:   make(chan struct{}),
	}

	if !ln.isChainValid() {
		ln.ln, err = net.Listen("tcp", ln.addr.String())
		return ln, err
	}

	go ln.listenLoop()

	return ln, err
}

func (l *tcpRemoteForwardListener) isChainValid() bool {
	if l.chain.IsEmpty() {
		return false
	}

	lastNode := l.chain.LastNode()
	if (lastNode.Protocol == "forward" && lastNode.Transport == "ssh") ||
		lastNode.Protocol == "socks5" || lastNode.Protocol == "" {
		return true
	}
	return false
}

func (l *tcpRemoteForwardListener) listenLoop() {
	var tempDelay time.Duration

	for {
		conn, err := l.accept()

		select {
		case <-l.closed:
			if conn != nil {
				conn.Close()
			}
			return
		default:
		}

		if err != nil {
			if tempDelay == 0 {
				tempDelay = 1000 * time.Millisecond
			} else {
				tempDelay *= 2
			}
			if max := 6 * time.Second; tempDelay > max {
				tempDelay = max
			}
			log.Logf("[rtcp] accept error: %v; retrying in %v", err, tempDelay)
			time.Sleep(tempDelay)
			continue
		}

		tempDelay = 0

		select {
		case l.connChan <- conn:
		default:
			conn.Close()
			log.Logf("[rtcp] %s - %s: connection queue is full", conn.RemoteAddr(), conn.LocalAddr())
		}
	}
}

func (l *tcpRemoteForwardListener) Accept() (conn net.Conn, err error) {
	if l.ln != nil {
		return l.ln.Accept()
	}

	select {
	case conn = <-l.connChan:
	case <-l.closed:
		err = errors.New("closed")
	}

	return
}

func (l *tcpRemoteForwardListener) accept() (conn net.Conn, err error) {
	lastNode := l.chain.LastNode()
	if lastNode.Protocol == "forward" && lastNode.Transport == "ssh" {
		return l.chain.Dial(l.addr.String())
	}

	if l.isChainValid() {
		if lastNode.GetBool("mbind") {
			return l.muxAccept() // multiplexing support for binding.
		}

		cc, er := l.chain.Conn()
		if er != nil {
			return nil, er
		}
		conn, err = l.waitConnectSOCKS5(cc)
		if err != nil {
			cc.Close()
		}
	}
	return
}

func (l *tcpRemoteForwardListener) muxAccept() (conn net.Conn, err error) {
	session, err := l.getSession()
	if err != nil {
		return nil, err
	}
	cc, err := session.Accept()
	if err != nil {
		session.Close()
		return nil, err
	}

	return cc, nil
}

func (l *tcpRemoteForwardListener) getSession() (s *muxSession, err error) {
	l.sessionMux.Lock()
	defer l.sessionMux.Unlock()

	if l.session != nil && !l.session.IsClosed() {
		return l.session, nil
	}

	conn, err := l.chain.Conn()
	if err != nil {
		return nil, err
	}

	defer func(c net.Conn) {
		if err != nil {
			c.Close()
		}
	}(conn)

	conn.SetDeadline(time.Now().Add(HandshakeTimeout))
	defer conn.SetDeadline(time.Time{})

	conn, err = socks5Handshake(conn, userSocks5HandshakeOption(l.chain.LastNode().User))
	if err != nil {
		return nil, err
	}
	req := gosocks5.NewRequest(CmdMuxBind, toSocksAddr(l.addr))
	if err := req.Write(conn); err != nil {
		log.Log("[rtcp] SOCKS5 BIND request: ", err)
		return nil, err
	}

	rep, err := gosocks5.ReadReply(conn)
	if err != nil {
		log.Log("[rtcp] SOCKS5 BIND reply: ", err)
		return nil, err
	}
	if rep.Rep != gosocks5.Succeeded {
		log.Logf("[rtcp] bind on %s failure", l.addr)
		return nil, fmt.Errorf("Bind on %s failure", l.addr.String())
	}
	log.Logf("[rtcp] BIND ON %s OK", rep.Addr)

	// Upgrade connection to multiplex stream.
	session, err := smux.Server(conn, smux.DefaultConfig())
	if err != nil {
		return nil, err
	}
	l.session = &muxSession{
		conn:    conn,
		session: session,
	}

	return l.session, nil
}

func (l *tcpRemoteForwardListener) waitConnectSOCKS5(conn net.Conn) (net.Conn, error) {
	conn, err := socks5Handshake(conn, userSocks5HandshakeOption(l.chain.LastNode().User))
	if err != nil {
		return nil, err
	}
	req := gosocks5.NewRequest(gosocks5.CmdBind, toSocksAddr(l.addr))
	if err := req.Write(conn); err != nil {
		log.Log("[rtcp] SOCKS5 BIND request: ", err)
		return nil, err
	}

	// first reply, bind status
	conn.SetReadDeadline(time.Now().Add(ReadTimeout))
	rep, err := gosocks5.ReadReply(conn)
	if err != nil {
		log.Log("[rtcp] SOCKS5 BIND reply: ", err)
		return nil, err
	}
	conn.SetReadDeadline(time.Time{})
	if rep.Rep != gosocks5.Succeeded {
		log.Logf("[rtcp] bind on %s failure", l.addr)
		return nil, fmt.Errorf("Bind on %s failure", l.addr.String())
	}
	log.Logf("[rtcp] BIND ON %s OK", rep.Addr)

	// second reply, peer connected
	rep, err = gosocks5.ReadReply(conn)
	if err != nil {
		log.Log("[rtcp]", err)
		return nil, err
	}
	if rep.Rep != gosocks5.Succeeded {
		log.Logf("[rtcp] peer connect failure: %d", rep.Rep)
		return nil, errors.New("peer connect failure")
	}

	log.Logf("[rtcp] PEER %s CONNECTED", rep.Addr)
	return conn, nil
}

func (l *tcpRemoteForwardListener) Addr() net.Addr {
	if l.ln != nil {
		return l.ln.Addr()
	}
	return l.addr
}

func (l *tcpRemoteForwardListener) Close() error {
	if l.ln != nil {
		return l.ln.Close()
	}

	l.closeMux.Lock()
	defer l.closeMux.Unlock()

	select {
	case <-l.closed:
		return nil
	default:
		close(l.closed)
	}
	return nil
}

type udpRemoteForwardListener struct {
	addr     net.Addr
	chain    *Chain
	connMap  *udpConnMap
	connChan chan net.Conn
	ln       *net.UDPConn
	ttl      time.Duration
	closed   chan struct{}
	ready    chan struct{}
	once     sync.Once
	closeMux sync.Mutex
	config   *UDPListenConfig
}

// UDPRemoteForwardListener creates a Listener for UDP remote port forwarding server.
func UDPRemoteForwardListener(addr string, chain *Chain, cfg *UDPListenConfig) (Listener, error) {
	laddr, err := net.ResolveUDPAddr("udp", addr)
	if err != nil {
		return nil, err
	}

	if cfg == nil {
		cfg = &UDPListenConfig{}
	}

	backlog := cfg.Backlog
	if backlog <= 0 {
		backlog = defaultBacklog
	}

	ln := &udpRemoteForwardListener{
		addr:     laddr,
		chain:    chain,
		connMap:  new(udpConnMap),
		connChan: make(chan net.Conn, backlog),
		ready:    make(chan struct{}),
		closed:   make(chan struct{}),
		config:   cfg,
	}

	go ln.listenLoop()

	<-ln.ready

	return ln, err
}

func (l *udpRemoteForwardListener) isChainValid() bool {
	if l.chain.IsEmpty() {
		return false
	}

	lastNode := l.chain.LastNode()
	return lastNode.Protocol == "socks5" || lastNode.Protocol == ""
}

func (l *udpRemoteForwardListener) listenLoop() {
	for {
		conn, err := l.connect()
		if err != nil {
			log.Logf("[rudp] %s : %s", l.Addr(), err)
			return
		}

		l.once.Do(func() {
			close(l.ready)
		})

		func() {
			defer conn.Close()

			for {
				b := make([]byte, mediumBufferSize)
				n, raddr, err := conn.ReadFrom(b)
				if err != nil {
					log.Logf("[rudp] %s : %s", l.Addr(), err)
					break
				}

				uc, ok := l.connMap.Get(raddr.String())
				if !ok {
					uc = newUDPServerConn(conn, raddr, &udpServerConnConfig{
						ttl:   l.config.TTL,
						qsize: l.config.QueueSize,
						onClose: func() {
							l.connMap.Delete(raddr.String())
							log.Logf("[rudp] %s closed (%d)", raddr, l.connMap.Size())
						},
					})

					select {
					case l.connChan <- uc:
						l.connMap.Set(raddr.String(), uc)
						log.Logf("[rudp] %s -> %s (%d)", raddr, l.Addr(), l.connMap.Size())
					default:
						uc.Close()
						log.Logf("[rudp] %s - %s: connection queue is full (%d)",
							raddr, l.Addr(), cap(l.connChan))
					}
				}

				select {
				case uc.rChan <- b[:n]:
					if Debug {
						log.Logf("[rudp] %s >>> %s : length %d", raddr, l.Addr(), n)
					}
				default:
					log.Logf("[rudp] %s -> %s : recv queue is full", raddr, l.Addr(), cap(uc.rChan))
				}
			}
		}()
	}
}

func (l *udpRemoteForwardListener) connect() (conn net.PacketConn, err error) {
	var tempDelay time.Duration

	for {
		select {
		case <-l.closed:
			return nil, errors.New("closed")
		default:
		}

		if l.isChainValid() {
			var cc net.Conn
			cc, err = getSocks5UDPTunnel(l.chain, l.addr)
			if err != nil {
				log.Logf("[rudp] %s : %s", l.Addr(), err)
			} else {
				conn = cc.(net.PacketConn)
			}
		} else {
			var uc *net.UDPConn
			uc, err = net.ListenUDP("udp", l.addr.(*net.UDPAddr))
			if err == nil {
				l.addr = uc.LocalAddr()
				conn = uc
			}
		}

		if err != nil {
			if tempDelay == 0 {
				tempDelay = 1000 * time.Millisecond
			} else {
				tempDelay *= 2
			}
			if max := 6 * time.Second; tempDelay > max {
				tempDelay = max
			}
			log.Logf("[rudp] Accept error: %v; retrying in %v", err, tempDelay)
			time.Sleep(tempDelay)
			continue
		}
		return
	}
}

func (l *udpRemoteForwardListener) Accept() (conn net.Conn, err error) {
	select {
	case conn = <-l.connChan:
	case <-l.closed:
		err = errors.New("accpet on closed listener")
	}
	return
}

func (l *udpRemoteForwardListener) Addr() net.Addr {
	return l.addr
}

func (l *udpRemoteForwardListener) Close() error {
	l.closeMux.Lock()
	defer l.closeMux.Unlock()

	select {
	case <-l.closed:
		return nil
	default:
		l.connMap.Range(func(k interface{}, v *udpServerConn) bool {
			v.Close()
			return true
		})
		close(l.closed)
	}

	return nil
}


================================================
FILE: forward_test.go
================================================
package gost

import (
	"crypto/rand"
	"net/http/httptest"
	"net/url"
	"testing"
)

func tcpDirectForwardRoundtrip(targetURL string, data []byte) error {
	ln, err := TCPListener("")
	if err != nil {
		return err
	}

	u, err := url.Parse(targetURL)
	if err != nil {
		return err
	}

	client := &Client{
		Connector:   ForwardConnector(),
		Transporter: TCPTransporter(),
	}

	h := TCPDirectForwardHandler(u.Host)
	h.Init()
	server := &Server{
		Listener: ln,
		Handler:  h,
	}

	go server.Run()
	defer server.Close()

	return proxyRoundtrip(client, server, targetURL, data)
}

func TestTCPDirectForward(t *testing.T) {
	httpSrv := httptest.NewServer(httpTestHandler)
	defer httpSrv.Close()

	sendData := make([]byte, 128)
	rand.Read(sendData)

	err := tcpDirectForwardRoundtrip(httpSrv.URL, sendData)
	if err != nil {
		t.Error(err)
	}
}

func BenchmarkTCPDirectForward(b *testing.B) {
	httpSrv := httptest.NewServer(httpTestHandler)
	defer httpSrv.Close()

	sendData := make([]byte, 128)
	rand.Read(sendData)

	ln, err := TCPListener("")
	if err != nil {
		b.Error(err)
	}

	client := &Client{
		Connector:   ForwardConnector(),
		Transporter: TCPTransporter(),
	}

	u, err := url.Parse(httpSrv.URL)
	if err != nil {
		b.Error(err)
	}

	h := TCPDirectForwardHandler(u.Host)
	h.Init()
	server := &Server{
		Listener: ln,
		Handler:  h,
	}
	go server.Run()
	defer server.Close()

	for i := 0; i < b.N; i++ {
		if err := proxyRoundtrip(client, server, httpSrv.URL, sendData); err != nil {
			b.Error(err)
		}
	}
}

func BenchmarkTCPDirectForwardParallel(b *testing.B) {
	httpSrv := httptest.NewServer(httpTestHandler)
	defer httpSrv.Close()

	sendData := make([]byte, 128)
	rand.Read(sendData)

	ln, err := TCPListener("")
	if err != nil {
		b.Error(err)
	}

	client := &Client{
		Connector:   ForwardConnector(),
		Transporter: TCPTransporter(),
	}

	u, err := url.Parse(httpSrv.URL)
	if err != nil {
		b.Error(err)
	}

	h := TCPDirectForwardHandler(u.Host)
	h.Init()
	server := &Server{
		Listener: ln,
		Handler:  h,
	}
	go server.Run()
	defer server.Close()

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			if err := proxyRoundtrip(client, server, httpSrv.
Download .txt
gitextract_oys45pca/

├── .config/
│   ├── bypass.txt
│   ├── dns.txt
│   ├── gost.json
│   ├── hosts.txt
│   ├── kcp.json
│   ├── peer.txt
│   ├── probe_resist.txt
│   └── secrets.txt
├── .dockerignore
├── .github/
│   └── workflows/
│       ├── buildx.yml
│       └── release.yml
├── .gitignore
├── .goreleaser.yaml
├── .travis.yml
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── README_en.md
├── auth.go
├── auth_test.go
├── bypass.go
├── bypass_test.go
├── chain.go
├── client.go
├── cmd/
│   └── gost/
│       ├── .ssl/
│       │   ├── README.md
│       │   ├── localhost.crt
│       │   ├── localhost.csr
│       │   ├── localhost.key
│       │   ├── rootCA.crt
│       │   ├── rootCA.key
│       │   └── rootCA.srl
│       ├── cfg.go
│       ├── main.go
│       ├── peer.go
│       └── route.go
├── common_test.go
├── dns.go
├── examples/
│   ├── bench/
│   │   ├── cli.go
│   │   └── srv.go
│   ├── forward/
│   │   ├── direct/
│   │   │   ├── client.go
│   │   │   └── server.go
│   │   ├── remote/
│   │   │   ├── client.go
│   │   │   └── server.go
│   │   └── udp/
│   │       ├── cli.go
│   │       ├── direct.go
│   │       ├── remote.go
│   │       └── srv.go
│   ├── http2/
│   │   └── http2.go
│   ├── quic/
│   │   ├── quicc.go
│   │   └── quics.go
│   ├── ssh/
│   │   ├── sshc.go
│   │   └── sshd.go
│   └── ssu/
│       └── ssu.go
├── forward.go
├── forward_test.go
├── ftcp.go
├── go.mod
├── go.sum
├── gost.go
├── handler.go
├── handler_test.go
├── hosts.go
├── hosts_test.go
├── http.go
├── http2.go
├── http2_test.go
├── http_test.go
├── kcp.go
├── kcp_test.go
├── log.go
├── mux.go
├── node.go
├── node_test.go
├── obfs.go
├── obfs_test.go
├── permissions.go
├── permissions_test.go
├── quic.go
├── quic_test.go
├── redirect.go
├── redirect_other.go
├── relay.go
├── reload.go
├── resolver.go
├── resolver_test.go
├── selector.go
├── selector_test.go
├── server.go
├── signal.go
├── signal_unix.go
├── snap/
│   └── snapcraft.yaml
├── sni.go
├── sni_test.go
├── sockopts_linux.go
├── sockopts_other.go
├── socks.go
├── socks_test.go
├── ss.go
├── ss_test.go
├── ssh.go
├── ssh_test.go
├── tcp.go
├── tls.go
├── tls_test.go
├── tuntap.go
├── tuntap_darwin.go
├── tuntap_linux.go
├── tuntap_unix.go
├── tuntap_windows.go
├── udp.go
├── vsock.go
├── ws.go
├── ws_test.go
└── wss_test.go
Download .txt
SYMBOL INDEX (1448 symbols across 86 files)

FILE: auth.go
  type Authenticator (line 12) | type Authenticator interface
  type LocalAuthenticator (line 17) | type LocalAuthenticator struct
    method Authenticate (line 33) | func (au *LocalAuthenticator) Authenticate(user, password string) bool {
    method Add (line 50) | func (au *LocalAuthenticator) Add(k, v string) {
    method Reload (line 60) | func (au *LocalAuthenticator) Reload(r io.Reader) error {
    method Period (line 127) | func (au *LocalAuthenticator) Period() time.Duration {
    method Stop (line 139) | func (au *LocalAuthenticator) Stop() {
    method Stopped (line 148) | func (au *LocalAuthenticator) Stopped() bool {
  function NewLocalAuthenticator (line 25) | func NewLocalAuthenticator(kvs map[string]string) *LocalAuthenticator {

FILE: auth_test.go
  function TestLocalAuthenticator (line 51) | func TestLocalAuthenticator(t *testing.T) {
  function TestLocalAuthenticatorReload (line 146) | func TestLocalAuthenticatorReload(t *testing.T) {

FILE: bypass.go
  type Matcher (line 19) | type Matcher interface
  function NewMatcher (line 29) | func NewMatcher(pattern string) Matcher {
  type ipMatcher (line 42) | type ipMatcher struct
    method Match (line 53) | func (m *ipMatcher) Match(ip string) bool {
    method String (line 60) | func (m *ipMatcher) String() string {
  function IPMatcher (line 47) | func IPMatcher(ip net.IP) Matcher {
  type cidrMatcher (line 64) | type cidrMatcher struct
    method Match (line 75) | func (m *cidrMatcher) Match(ip string) bool {
    method String (line 82) | func (m *cidrMatcher) String() string {
  function CIDRMatcher (line 69) | func CIDRMatcher(inet *net.IPNet) Matcher {
  type domainMatcher (line 86) | type domainMatcher struct
    method Match (line 106) | func (m *domainMatcher) Match(domain string) bool {
    method String (line 117) | func (m *domainMatcher) String() string {
  function DomainMatcher (line 94) | func DomainMatcher(pattern string) Matcher {
  type Bypass (line 123) | type Bypass struct
    method Contains (line 156) | func (bp *Bypass) Contains(addr string) bool {
    method AddMatchers (line 190) | func (bp *Bypass) AddMatchers(matchers ...Matcher) {
    method Matchers (line 198) | func (bp *Bypass) Matchers() []Matcher {
    method Reversed (line 206) | func (bp *Bypass) Reversed() bool {
    method Reload (line 214) | func (bp *Bypass) Reload(r io.Reader) error {
    method Period (line 259) | func (bp *Bypass) Period() time.Duration {
    method Stop (line 271) | func (bp *Bypass) Stop() {
    method Stopped (line 280) | func (bp *Bypass) Stopped() bool {
    method String (line 289) | func (bp *Bypass) String() string {
  function NewBypass (line 133) | func NewBypass(reversed bool, matchers ...Matcher) *Bypass {
  function NewBypassPatterns (line 143) | func NewBypassPatterns(reversed bool, patterns ...string) *Bypass {

FILE: bypass_test.go
  function TestBypassContains (line 160) | func TestBypassContains(t *testing.T) {
  function TestByapssReload (line 272) | func TestByapssReload(t *testing.T) {

FILE: chain.go
  type Chain (line 20) | type Chain struct
    method newRoute (line 41) | func (c *Chain) newRoute(nodes ...Node) *Chain {
    method Nodes (line 53) | func (c *Chain) Nodes() (nodes []Node) {
    method NodeGroups (line 63) | func (c *Chain) NodeGroups() []*NodeGroup {
    method LastNode (line 70) | func (c *Chain) LastNode() Node {
    method LastNodeGroup (line 79) | func (c *Chain) LastNodeGroup() *NodeGroup {
    method AddNode (line 87) | func (c *Chain) AddNode(nodes ...Node) {
    method AddNodeGroup (line 97) | func (c *Chain) AddNodeGroup(groups ...*NodeGroup) {
    method IsEmpty (line 108) | func (c *Chain) IsEmpty() bool {
    method Dial (line 114) | func (c *Chain) Dial(address string, opts ...ChainOption) (conn net.Co...
    method DialContext (line 119) | func (c *Chain) DialContext(ctx context.Context, network, address stri...
    method dialWithOptions (line 142) | func (c *Chain) dialWithOptions(ctx context.Context, network, address ...
    method resolve (line 223) | func (*Chain) resolve(addr string, resolver Resolver, hosts *Hosts) st...
    method Conn (line 247) | func (c *Chain) Conn(opts ...ChainOption) (conn net.Conn, err error) {
    method getConn (line 278) | func (c *Chain) getConn(ctx context.Context) (conn net.Conn, err error) {
    method selectRoute (line 325) | func (c *Chain) selectRoute() (route *Chain, err error) {
    method selectRouteFor (line 330) | func (c *Chain) selectRouteFor(addr string) (route *Chain, err error) {
  function NewChain (line 31) | func NewChain(nodes ...Node) *Chain {
  type ChainOptions (line 369) | type ChainOptions struct
  type ChainOption (line 378) | type ChainOption
  function RetryChainOption (line 381) | func RetryChainOption(retries int) ChainOption {
  function TimeoutChainOption (line 388) | func TimeoutChainOption(timeout time.Duration) ChainOption {
  function HostsChainOption (line 395) | func HostsChainOption(hosts *Hosts) ChainOption {
  function ResolverChainOption (line 402) | func ResolverChainOption(resolver Resolver) ChainOption {

FILE: client.go
  type Client (line 17) | type Client struct
  function Dial (line 26) | func Dial(addr string, options ...DialOption) (net.Conn, error) {
  function Handshake (line 31) | func Handshake(conn net.Conn, options ...HandshakeOption) (net.Conn, err...
  function Connect (line 36) | func Connect(conn net.Conn, addr string) (net.Conn, error) {
  type Connector (line 41) | type Connector interface
  type autoConnector (line 47) | type autoConnector struct
    method Connect (line 58) | func (c *autoConnector) Connect(conn net.Conn, address string, options...
    method ConnectContext (line 62) | func (c *autoConnector) ConnectContext(ctx context.Context, conn net.C...
  function AutoConnector (line 52) | func AutoConnector(user *url.Userinfo) Connector {
  type Transporter (line 75) | type Transporter interface
  type DialOptions (line 83) | type DialOptions struct
  type DialOption (line 90) | type DialOption
  function TimeoutDialOption (line 93) | func TimeoutDialOption(timeout time.Duration) DialOption {
  function ChainDialOption (line 100) | func ChainDialOption(chain *Chain) DialOption {
  function HostDialOption (line 107) | func HostDialOption(host string) DialOption {
  type HandshakeOptions (line 114) | type HandshakeOptions struct
  type HandshakeOption (line 129) | type HandshakeOption
  function AddrHandshakeOption (line 132) | func AddrHandshakeOption(addr string) HandshakeOption {
  function HostHandshakeOption (line 139) | func HostHandshakeOption(host string) HandshakeOption {
  function UserHandshakeOption (line 146) | func UserHandshakeOption(user *url.Userinfo) HandshakeOption {
  function TimeoutHandshakeOption (line 153) | func TimeoutHandshakeOption(timeout time.Duration) HandshakeOption {
  function IntervalHandshakeOption (line 160) | func IntervalHandshakeOption(interval time.Duration) HandshakeOption {
  function RetryHandshakeOption (line 167) | func RetryHandshakeOption(retry int) HandshakeOption {
  function TLSConfigHandshakeOption (line 174) | func TLSConfigHandshakeOption(config *tls.Config) HandshakeOption {
  function WSOptionsHandshakeOption (line 181) | func WSOptionsHandshakeOption(options *WSOptions) HandshakeOption {
  function KCPConfigHandshakeOption (line 188) | func KCPConfigHandshakeOption(config *KCPConfig) HandshakeOption {
  function QUICConfigHandshakeOption (line 195) | func QUICConfigHandshakeOption(config *QUICConfig) HandshakeOption {
  function SSHConfigHandshakeOption (line 202) | func SSHConfigHandshakeOption(config *SSHConfig) HandshakeOption {
  type ConnectOptions (line 209) | type ConnectOptions struct
  type ConnectOption (line 220) | type ConnectOption
  function AddrConnectOption (line 223) | func AddrConnectOption(addr string) ConnectOption {
  function TimeoutConnectOption (line 230) | func TimeoutConnectOption(timeout time.Duration) ConnectOption {
  function UserConnectOption (line 237) | func UserConnectOption(user *url.Userinfo) ConnectOption {
  function SelectorConnectOption (line 244) | func SelectorConnectOption(s gosocks5.Selector) ConnectOption {
  function UserAgentConnectOption (line 251) | func UserAgentConnectOption(ua string) ConnectOption {
  function NoTLSConnectOption (line 258) | func NoTLSConnectOption(b bool) ConnectOption {
  function NoDelayConnectOption (line 265) | func NoDelayConnectOption(b bool) ConnectOption {

FILE: cmd/gost/cfg.go
  type baseConfig (line 21) | type baseConfig struct
  function parseBaseConfig (line 27) | func parseBaseConfig(s string) (*baseConfig, error) {
  function tlsConfig (line 48) | func tlsConfig(certFile, keyFile, caFile string) (*tls.Config, error) {
  function loadCA (line 72) | func loadCA(caFile string) (cp *x509.CertPool, err error) {
  function parseKCPConfig (line 87) | func parseKCPConfig(configFile string) (*gost.KCPConfig, error) {
  function parseUsers (line 104) | func parseUsers(authFile string) (users []*url.Userinfo, err error) {
  function parseAuthenticator (line 133) | func parseAuthenticator(s string) (gost.Authenticator, error) {
  function parseIP (line 151) | func parseIP(s string, port string) (ips []string) {
  function parseBypass (line 195) | func parseBypass(s string) *gost.Bypass {
  function parseResolver (line 226) | func parseResolver(cfg string) gost.Resolver {
  function parseHosts (line 283) | func parseHosts(s string) *gost.Hosts {
  function parseIPRoutes (line 298) | func parseIPRoutes(s string) (routes []gost.IPRoute) {

FILE: cmd/gost/main.go
  function init (line 25) | func init() {
  function main (line 63) | func main() {
  function start (line 97) | func start() error {

FILE: cmd/gost/peer.go
  type peerConfig (line 15) | type peerConfig struct
    method Validate (line 34) | func (cfg *peerConfig) Validate() {
    method Reload (line 37) | func (cfg *peerConfig) Reload(r io.Reader) error {
    method parse (line 87) | func (cfg *peerConfig) parse(r io.Reader) error {
    method Period (line 145) | func (cfg *peerConfig) Period() time.Duration {
    method Stop (line 153) | func (cfg *peerConfig) Stop() {
    method Stopped (line 162) | func (cfg *peerConfig) Stopped() bool {
  function newPeerConfig (line 28) | func newPeerConfig() *peerConfig {

FILE: cmd/gost/route.go
  type stringList (line 19) | type stringList
    method String (line 21) | func (l *stringList) String() string {
    method Set (line 24) | func (l *stringList) Set(value string) error {
  type route (line 29) | type route struct
    method parseChain (line 37) | func (r *route) parseChain() (*gost.Chain, error) {
    method GenRouters (line 348) | func (r *route) GenRouters() ([]router, error) {
  function parseChainNode (line 95) | func parseChainNode(ns string) (nodes []gost.Node, err error) {
  type router (line 690) | type router struct
    method Serve (line 699) | func (r *router) Serve() error {
    method Close (line 704) | func (r *router) Close() error {

FILE: common_test.go
  function init (line 19) | func init() {
  function proxyConn (line 51) | func proxyConn(client *Client, server *Server) (net.Conn, error) {
  function httpRoundtrip (line 67) | func httpRoundtrip(conn net.Conn, targetURL string, data []byte) (err er...
  function udpRoundtrip (line 100) | func udpRoundtrip(logger log.Logger, client *Client, server *Server, hos...
  function proxyRoundtrip (line 133) | func proxyRoundtrip(client *Client, server *Server, targetURL string, da...
  type udpRequest (line 156) | type udpRequest struct
  type udpResponseWriter (line 161) | type udpResponseWriter struct
    method Write (line 166) | func (w *udpResponseWriter) Write(p []byte) (int, error) {
  type udpHandlerFunc (line 170) | type udpHandlerFunc
  type udpTestServer (line 173) | type udpTestServer struct
    method Start (line 198) | func (s *udpTestServer) Start() {
    method serve (line 203) | func (s *udpTestServer) serve() {
    method Addr (line 238) | func (s *udpTestServer) Addr() string {
    method Close (line 242) | func (s *udpTestServer) Close() error {
  function newUDPTestServer (line 183) | func newUDPTestServer(handler udpHandlerFunc) *udpTestServer {

FILE: dns.go
  function init (line 24) | func init() {
  type dnsHandler (line 34) | type dnsHandler struct
    method Init (line 48) | func (h *dnsHandler) Init(opts ...HandlerOption) {
    method Handle (line 58) | func (h *dnsHandler) Handle(conn net.Conn) {
    method dumpMsgHeader (line 109) | func (h *dnsHandler) dumpMsgHeader(m *dns.Msg) string {
  function DNSHandler (line 39) | func DNSHandler(raddr string, opts ...HandlerOption) Handler {
  type DNSOptions (line 120) | type DNSOptions struct
  type dnsListener (line 128) | type dnsListener struct
    method serve (line 222) | func (l *dnsListener) serve(w dnsResponseWriter, mq []byte) (err error) {
    method ServeDNS (line 241) | func (l *dnsListener) ServeDNS(w dns.ResponseWriter, m *dns.Msg) {
    method ServeHTTP (line 253) | func (l *dnsListener) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    method Accept (line 295) | func (l *dnsListener) Accept() (conn net.Conn, err error) {
    method Close (line 303) | func (l *dnsListener) Close() error {
    method Addr (line 307) | func (l *dnsListener) Addr() net.Addr {
  function DNSListener (line 136) | func DNSListener(addr string, options *DNSOptions) (Listener, error) {
  type dnsServer (line 311) | type dnsServer interface
  type dohServer (line 316) | type dohServer struct
    method ListenAndServe (line 322) | func (s *dohServer) ListenAndServe() error {
    method Shutdown (line 331) | func (s *dohServer) Shutdown() error {
  type dnsServerConn (line 335) | type dnsServerConn struct
    method Read (line 352) | func (c *dnsServerConn) Read(b []byte) (n int, err error) {
    method Write (line 362) | func (c *dnsServerConn) Write(b []byte) (n int, err error) {
    method Close (line 373) | func (c *dnsServerConn) Close() error {
    method LocalAddr (line 382) | func (c *dnsServerConn) LocalAddr() net.Addr {
    method RemoteAddr (line 386) | func (c *dnsServerConn) RemoteAddr() net.Addr {
    method SetDeadline (line 390) | func (c *dnsServerConn) SetDeadline(t time.Time) error {
    method SetReadDeadline (line 394) | func (c *dnsServerConn) SetReadDeadline(t time.Time) error {
    method SetWriteDeadline (line 398) | func (c *dnsServerConn) SetWriteDeadline(t time.Time) error {
  function newDNSServerConn (line 342) | func newDNSServerConn(laddr, raddr net.Addr) *dnsServerConn {
  type dnsResponseWriter (line 402) | type dnsResponseWriter interface
  type dohResponseWriter (line 407) | type dohResponseWriter struct
    method RemoteAddr (line 419) | func (w *dohResponseWriter) RemoteAddr() net.Addr {
  function newDoHResponseWriter (line 412) | func newDoHResponseWriter(raddr net.Addr, w http.ResponseWriter) dnsResp...

FILE: examples/bench/cli.go
  function init (line 23) | func init() {
  function main (line 38) | func main() {
  function request (line 185) | func request(chain *gost.Chain, start <-chan struct{}) {

FILE: examples/bench/srv.go
  function init (line 20) | func init() {
  function main (line 33) | func main() {
  function httpServer (line 54) | func httpServer() {
  function socks5Server (line 66) | func socks5Server() {
  function shadowServer (line 79) | func shadowServer() {
  function tlsServer (line 91) | func tlsServer() {
  function wsServer (line 103) | func wsServer() {
  function wssServer (line 115) | func wssServer() {
  function kcpServer (line 127) | func kcpServer() {
  function tcpForwardServer (line 137) | func tcpForwardServer() {
  function tcpRemoteForwardServer (line 147) | func tcpRemoteForwardServer() {
  function rudpForwardServer (line 177) | func rudpForwardServer() {
  function tcpRedirectServer (line 202) | func tcpRedirectServer() {
  function sshTunnelServer (line 212) | func sshTunnelServer() {
  function http2Server (line 224) | func http2Server() {
  function http2TunnelServer (line 238) | func http2TunnelServer() {
  function quicServer (line 255) | func quicServer() {
  function shadowUDPServer (line 267) | func shadowUDPServer() {
  function tlsConfig (line 340) | func tlsConfig() *tls.Config {
  function testServer (line 351) | func testServer() {

FILE: examples/forward/direct/client.go
  function main (line 9) | func main() {
  function tcpForward (line 13) | func tcpForward() {

FILE: examples/forward/direct/server.go
  function main (line 10) | func main() {
  function sshForwardServer (line 14) | func sshForwardServer() {
  function tlsConfig (line 76) | func tlsConfig() *tls.Config {

FILE: examples/forward/remote/client.go
  function main (line 9) | func main() {
  function sshRemoteForward (line 13) | func sshRemoteForward() {

FILE: examples/forward/remote/server.go
  function main (line 10) | func main() {
  function sshRemoteForwardServer (line 14) | func sshRemoteForwardServer() {
  function tlsConfig (line 76) | func tlsConfig() *tls.Config {

FILE: examples/forward/udp/cli.go
  function init (line 15) | func init() {
  function main (line 23) | func main() {
  function udpEchoLoop (line 30) | func udpEchoLoop() {

FILE: examples/forward/udp/direct.go
  function init (line 16) | func init() {
  function main (line 29) | func main() {
  function udpDirectForwardServer (line 33) | func udpDirectForwardServer() {

FILE: examples/forward/udp/remote.go
  function init (line 16) | func init() {
  function main (line 29) | func main() {
  function udpRemoteForwardServer (line 33) | func udpRemoteForwardServer() {

FILE: examples/forward/udp/srv.go
  function init (line 13) | func init() {
  function main (line 19) | func main() {
  function udpEchoServer (line 23) | func udpEchoServer() {

FILE: examples/http2/http2.go
  function init (line 21) | func init() {
  function main (line 39) | func main() {
  function http2Server (line 43) | func http2Server() {
  function tlsConfig (line 119) | func tlsConfig() *tls.Config {

FILE: examples/quic/quicc.go
  function init (line 17) | func init() {
  function main (line 31) | func main() {
  function tlsConfig (line 104) | func tlsConfig() *tls.Config {

FILE: examples/quic/quics.go
  function init (line 16) | func init() {
  function main (line 30) | func main() {
  function quicServer (line 34) | func quicServer() {
  function tlsConfig (line 94) | func tlsConfig() *tls.Config {

FILE: examples/ssh/sshc.go
  function init (line 17) | func init() {
  function main (line 31) | func main() {
  function tlsConfig (line 107) | func tlsConfig() *tls.Config {

FILE: examples/ssh/sshd.go
  function init (line 16) | func init() {
  function main (line 30) | func main() {
  function sshTunnelServer (line 34) | func sshTunnelServer() {
  function tlsConfig (line 93) | func tlsConfig() *tls.Config {

FILE: examples/ssu/ssu.go
  function main (line 13) | func main() {
  function ssuClient (line 17) | func ssuClient() {
  function toSocksAddr (line 52) | func toSocksAddr(addr net.Addr) *gosocks5.Addr {

FILE: forward.go
  type forwardConnector (line 18) | type forwardConnector struct
    method Connect (line 26) | func (c *forwardConnector) Connect(conn net.Conn, address string, opti...
    method ConnectContext (line 30) | func (c *forwardConnector) ConnectContext(ctx context.Context, conn ne...
  function ForwardConnector (line 22) | func ForwardConnector() Connector {
  type baseForwardHandler (line 34) | type baseForwardHandler struct
    method Init (line 40) | func (h *baseForwardHandler) Init(options ...HandlerOption) {
  type tcpDirectForwardHandler (line 79) | type tcpDirectForwardHandler struct
    method Init (line 102) | func (h *tcpDirectForwardHandler) Init(options ...HandlerOption) {
    method Handle (line 106) | func (h *tcpDirectForwardHandler) Handle(conn net.Conn) {
  function TCPDirectForwardHandler (line 86) | func TCPDirectForwardHandler(raddr string, opts ...HandlerOption) Handler {
  type udpDirectForwardHandler (line 159) | type udpDirectForwardHandler struct
    method Init (line 182) | func (h *udpDirectForwardHandler) Init(options ...HandlerOption) {
    method Handle (line 186) | func (h *udpDirectForwardHandler) Handle(conn net.Conn) {
  function UDPDirectForwardHandler (line 166) | func UDPDirectForwardHandler(raddr string, opts ...HandlerOption) Handler {
  type tcpRemoteForwardHandler (line 224) | type tcpRemoteForwardHandler struct
    method Init (line 247) | func (h *tcpRemoteForwardHandler) Init(options ...HandlerOption) {
    method Handle (line 251) | func (h *tcpRemoteForwardHandler) Handle(conn net.Conn) {
  function TCPRemoteForwardHandler (line 231) | func TCPRemoteForwardHandler(raddr string, opts ...HandlerOption) Handler {
  type udpRemoteForwardHandler (line 290) | type udpRemoteForwardHandler struct
    method Init (line 313) | func (h *udpRemoteForwardHandler) Init(options ...HandlerOption) {
    method Handle (line 317) | func (h *udpRemoteForwardHandler) Handle(conn net.Conn) {
  function UDPRemoteForwardHandler (line 297) | func UDPRemoteForwardHandler(raddr string, opts ...HandlerOption) Handler {
  type tcpRemoteForwardListener (line 350) | type tcpRemoteForwardListener struct
    method isChainValid (line 385) | func (l *tcpRemoteForwardListener) isChainValid() bool {
    method listenLoop (line 398) | func (l *tcpRemoteForwardListener) listenLoop() {
    method Accept (line 438) | func (l *tcpRemoteForwardListener) Accept() (conn net.Conn, err error) {
    method accept (line 452) | func (l *tcpRemoteForwardListener) accept() (conn net.Conn, err error) {
    method muxAccept (line 475) | func (l *tcpRemoteForwardListener) muxAccept() (conn net.Conn, err err...
    method getSession (line 489) | func (l *tcpRemoteForwardListener) getSession() (s *muxSession, err er...
    method waitConnectSOCKS5 (line 545) | func (l *tcpRemoteForwardListener) waitConnectSOCKS5(conn net.Conn) (n...
    method Addr (line 585) | func (l *tcpRemoteForwardListener) Addr() net.Addr {
    method Close (line 592) | func (l *tcpRemoteForwardListener) Close() error {
  function TCPRemoteForwardListener (line 362) | func TCPRemoteForwardListener(addr string, chain *Chain) (Listener, erro...
  type udpRemoteForwardListener (line 609) | type udpRemoteForwardListener struct
    method isChainValid (line 656) | func (l *udpRemoteForwardListener) isChainValid() bool {
    method listenLoop (line 665) | func (l *udpRemoteForwardListener) listenLoop() {
    method connect (line 723) | func (l *udpRemoteForwardListener) connect() (conn net.PacketConn, err...
    method Accept (line 767) | func (l *udpRemoteForwardListener) Accept() (conn net.Conn, err error) {
    method Addr (line 776) | func (l *udpRemoteForwardListener) Addr() net.Addr {
    method Close (line 780) | func (l *udpRemoteForwardListener) Close() error {
  function UDPRemoteForwardListener (line 624) | func UDPRemoteForwardListener(addr string, chain *Chain, cfg *UDPListenC...

FILE: forward_test.go
  function tcpDirectForwardRoundtrip (line 10) | func tcpDirectForwardRoundtrip(targetURL string, data []byte) error {
  function TestTCPDirectForward (line 39) | func TestTCPDirectForward(t *testing.T) {
  function BenchmarkTCPDirectForward (line 52) | func BenchmarkTCPDirectForward(b *testing.B) {
  function BenchmarkTCPDirectForwardParallel (line 90) | func BenchmarkTCPDirectForwardParallel(b *testing.B) {
  function udpDirectForwardRoundtrip (line 130) | func udpDirectForwardRoundtrip(t *testing.T, host string, data []byte) e...
  function TestUDPDirectForward (line 154) | func TestUDPDirectForward(t *testing.T) {
  function BenchmarkUDPDirectForward (line 167) | func BenchmarkUDPDirectForward(b *testing.B) {
  function BenchmarkUDPDirectForwardParallel (line 202) | func BenchmarkUDPDirectForwardParallel(b *testing.B) {
  function tcpRemoteForwardRoundtrip (line 239) | func tcpRemoteForwardRoundtrip(t *testing.T, targetURL string, data []by...
  function TestTCPRemoteForward (line 268) | func TestTCPRemoteForward(t *testing.T) {
  function udpRemoteForwardRoundtrip (line 281) | func udpRemoteForwardRoundtrip(t *testing.T, host string, data []byte) e...
  function TestUDPRemoteForward (line 305) | func TestUDPRemoteForward(t *testing.T) {

FILE: ftcp.go
  type fakeTCPTransporter (line 12) | type fakeTCPTransporter struct
    method Dial (line 19) | func (tr *fakeTCPTransporter) Dial(addr string, options ...DialOption)...
    method Handshake (line 40) | func (tr *fakeTCPTransporter) Handshake(conn net.Conn, options ...Hand...
    method Multiplex (line 44) | func (tr *fakeTCPTransporter) Multiplex() bool {
  function FakeTCPTransporter (line 15) | func FakeTCPTransporter() Transporter {
  type FakeTCPListenConfig (line 49) | type FakeTCPListenConfig struct
  type fakeTCPListener (line 55) | type fakeTCPListener struct
    method listenLoop (line 89) | func (l *fakeTCPListener) listenLoop() {
    method Accept (line 133) | func (l *fakeTCPListener) Accept() (conn net.Conn, err error) {
    method Addr (line 145) | func (l *fakeTCPListener) Addr() net.Addr {
    method Close (line 149) | func (l *fakeTCPListener) Close() error {
  function FakeTCPListener (line 64) | func FakeTCPListener(addr string, cfg *FakeTCPListenConfig) (Listener, e...
  type fakeTCPConn (line 159) | type fakeTCPConn struct
    method Read (line 164) | func (c *fakeTCPConn) Read(b []byte) (n int, err error) {
    method Write (line 169) | func (c *fakeTCPConn) Write(b []byte) (n int, err error) {
    method RemoteAddr (line 173) | func (c *fakeTCPConn) RemoteAddr() net.Addr {

FILE: gost.go
  constant Version (line 23) | Version = "2.12.0"
  function SetLogger (line 90) | func SetLogger(logger log.Logger) {
  function GenCertificate (line 95) | func GenCertificate() (cert tls.Certificate, err error) {
  function generateKeyPair (line 103) | func generateKeyPair() (rawCert, rawKey []byte, err error) {
  type readWriter (line 139) | type readWriter struct
    method Read (line 144) | func (rw *readWriter) Read(p []byte) (n int, err error) {
    method Write (line 148) | func (rw *readWriter) Write(p []byte) (n int, err error) {
  type nopConn (line 156) | type nopConn struct
    method Read (line 158) | func (c *nopConn) Read(b []byte) (n int, err error) {
    method Write (line 162) | func (c *nopConn) Write(b []byte) (n int, err error) {
    method Close (line 166) | func (c *nopConn) Close() error {
    method LocalAddr (line 170) | func (c *nopConn) LocalAddr() net.Addr {
    method RemoteAddr (line 174) | func (c *nopConn) RemoteAddr() net.Addr {
    method SetDeadline (line 178) | func (c *nopConn) SetDeadline(t time.Time) error {
    method SetReadDeadline (line 182) | func (c *nopConn) SetReadDeadline(t time.Time) error {
    method SetWriteDeadline (line 186) | func (c *nopConn) SetWriteDeadline(t time.Time) error {
  function splitLine (line 191) | func splitLine(line string) []string {
  function connStateCallback (line 210) | func connStateCallback(conn net.Conn, cs http.ConnState) {

FILE: handler.go
  type Handler (line 16) | type Handler interface
  type HandlerOptions (line 22) | type HandlerOptions struct
  type HandlerOption (line 50) | type HandlerOption
  function AddrHandlerOption (line 53) | func AddrHandlerOption(addr string) HandlerOption {
  function ChainHandlerOption (line 60) | func ChainHandlerOption(chain *Chain) HandlerOption {
  function UsersHandlerOption (line 67) | func UsersHandlerOption(users ...*url.Userinfo) HandlerOption {
  function AuthenticatorHandlerOption (line 84) | func AuthenticatorHandlerOption(au Authenticator) HandlerOption {
  function TLSConfigHandlerOption (line 91) | func TLSConfigHandlerOption(config *tls.Config) HandlerOption {
  function WhitelistHandlerOption (line 98) | func WhitelistHandlerOption(whitelist *Permissions) HandlerOption {
  function BlacklistHandlerOption (line 105) | func BlacklistHandlerOption(blacklist *Permissions) HandlerOption {
  function BypassHandlerOption (line 112) | func BypassHandlerOption(bypass *Bypass) HandlerOption {
  function StrategyHandlerOption (line 119) | func StrategyHandlerOption(strategy Strategy) HandlerOption {
  function MaxFailsHandlerOption (line 126) | func MaxFailsHandlerOption(n int) HandlerOption {
  function FailTimeoutHandlerOption (line 133) | func FailTimeoutHandlerOption(d time.Duration) HandlerOption {
  function RetryHandlerOption (line 140) | func RetryHandlerOption(retries int) HandlerOption {
  function TimeoutHandlerOption (line 147) | func TimeoutHandlerOption(timeout time.Duration) HandlerOption {
  function ResolverHandlerOption (line 154) | func ResolverHandlerOption(resolver Resolver) HandlerOption {
  function HostsHandlerOption (line 161) | func HostsHandlerOption(hosts *Hosts) HandlerOption {
  function ProbeResistHandlerOption (line 168) | func ProbeResistHandlerOption(pr string) HandlerOption {
  function KnockingHandlerOption (line 175) | func KnockingHandlerOption(host string) HandlerOption {
  function NodeHandlerOption (line 182) | func NodeHandlerOption(node Node) HandlerOption {
  function HostHandlerOption (line 189) | func HostHandlerOption(host string) HandlerOption {
  function IPsHandlerOption (line 196) | func IPsHandlerOption(ips []string) HandlerOption {
  function TCPModeHandlerOption (line 203) | func TCPModeHandlerOption(b bool) HandlerOption {
  function IPRoutesHandlerOption (line 210) | func IPRoutesHandlerOption(routes ...IPRoute) HandlerOption {
  function ProxyAgentHandlerOption (line 217) | func ProxyAgentHandlerOption(agent string) HandlerOption {
  function HTTPTunnelHandlerOption (line 224) | func HTTPTunnelHandlerOption(tunnelMode bool) HandlerOption {
  type autoHandler (line 230) | type autoHandler struct
    method Init (line 241) | func (h *autoHandler) Init(options ...HandlerOption) {
    method Handle (line 250) | func (h *autoHandler) Handle(conn net.Conn) {
  function AutoHandler (line 235) | func AutoHandler(opts ...HandlerOption) Handler {
  type bufferdConn (line 279) | type bufferdConn struct
    method Read (line 284) | func (c *bufferdConn) Read(b []byte) (int, error) {

FILE: handler_test.go
  function autoHTTPProxyRoundtrip (line 11) | func autoHTTPProxyRoundtrip(targetURL string, data []byte, clientInfo *u...
  function TestAutoHTTPProxy (line 34) | func TestAutoHTTPProxy(t *testing.T) {
  function autoSocks5ProxyRoundtrip (line 58) | func autoSocks5ProxyRoundtrip(targetURL string, data []byte, clientInfo ...
  function TestAutoSOCKS5Proxy (line 80) | func TestAutoSOCKS5Proxy(t *testing.T) {
  function autoSOCKS4ProxyRoundtrip (line 113) | func autoSOCKS4ProxyRoundtrip(targetURL string, data []byte, options ......
  function TestAutoSOCKS4Proxy (line 134) | func TestAutoSOCKS4Proxy(t *testing.T) {
  function autoSocks4aProxyRoundtrip (line 151) | func autoSocks4aProxyRoundtrip(targetURL string, data []byte, options .....
  function TestAutoSOCKS4AProxy (line 173) | func TestAutoSOCKS4AProxy(t *testing.T) {
  function autoSSProxyRoundtrip (line 190) | func autoSSProxyRoundtrip(targetURL string, data []byte, clientInfo *url...
  function TestAutoSSProxy (line 212) | func TestAutoSSProxy(t *testing.T) {

FILE: hosts.go
  type Host (line 14) | type Host struct
  function NewHost (line 21) | func NewHost(ip net.IP, hostname string, aliases ...string) Host {
  type Hosts (line 34) | type Hosts struct
    method AddHost (line 50) | func (h *Hosts) AddHost(host ...Host) {
    method Lookup (line 58) | func (h *Hosts) Lookup(host string) (ip net.IP) {
    method Reload (line 85) | func (h *Hosts) Reload(r io.Reader) error {
    method Period (line 132) | func (h *Hosts) Period() time.Duration {
    method Stop (line 144) | func (h *Hosts) Stop() {
    method Stopped (line 153) | func (h *Hosts) Stopped() bool {
  function NewHosts (line 42) | func NewHosts(hosts ...Host) *Hosts {

FILE: hosts_test.go
  function TestHostsLookup (line 29) | func TestHostsLookup(t *testing.T) {
  function TestHostsReload (line 105) | func TestHostsReload(t *testing.T) {

FILE: http.go
  type httpConnector (line 22) | type httpConnector struct
    method Connect (line 32) | func (c *httpConnector) Connect(conn net.Conn, address string, options...
    method ConnectContext (line 36) | func (c *httpConnector) ConnectContext(ctx context.Context, conn net.C...
  function HTTPConnector (line 28) | func HTTPConnector(user *url.Userinfo) Connector {
  type httpHandler (line 108) | type httpHandler struct
    method Init (line 119) | func (h *httpHandler) Init(options ...HandlerOption) {
    method Handle (line 128) | func (h *httpHandler) Handle(conn net.Conn) {
    method handleRequest (line 141) | func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) {
    method handleProxy (line 313) | func (h *httpHandler) handleProxy(rw, cc io.ReadWriter, req *http.Requ...
    method authenticate (line 355) | func (h *httpHandler) authenticate(conn net.Conn, req *http.Request, r...
    method forwardRequest (line 437) | func (h *httpHandler) forwardRequest(conn net.Conn, req *http.Request,...
  function HTTPHandler (line 113) | func HTTPHandler(opts ...HandlerOption) Handler {
  function basicProxyAuth (line 501) | func basicProxyAuth(proxyAuth string) (username, password string, ok boo...

FILE: http2.go
  type http2Connector (line 26) | type http2Connector struct
    method Connect (line 36) | func (c *http2Connector) Connect(conn net.Conn, address string, option...
    method ConnectContext (line 40) | func (c *http2Connector) ConnectContext(ctx context.Context, conn net....
  function HTTP2Connector (line 32) | func HTTP2Connector(user *url.Userinfo) Connector {
  type http2Transporter (line 115) | type http2Transporter struct
    method Dial (line 132) | func (tr *http2Transporter) Dial(addr string, options ...DialOption) (...
    method Handshake (line 184) | func (tr *http2Transporter) Handshake(conn net.Conn, options ...Handsh...
    method Multiplex (line 188) | func (tr *http2Transporter) Multiplex() bool {
  function HTTP2Transporter (line 122) | func HTTP2Transporter(config *tls.Config) Transporter {
  type h2Transporter (line 193) | type h2Transporter struct
    method Dial (line 220) | func (tr *h2Transporter) Dial(addr string, options ...DialOption) (net...
    method Handshake (line 299) | func (tr *h2Transporter) Handshake(conn net.Conn, options ...Handshake...
    method Multiplex (line 307) | func (tr *h2Transporter) Multiplex() bool {
  function H2Transporter (line 201) | func H2Transporter(config *tls.Config, path string) Transporter {
  function H2CTransporter (line 213) | func H2CTransporter(path string) Transporter {
  type http2Handler (line 311) | type http2Handler struct
    method Init (line 323) | func (h *http2Handler) Init(options ...HandlerOption) {
    method Handle (line 332) | func (h *http2Handler) Handle(conn net.Conn) {
    method roundTrip (line 344) | func (h *http2Handler) roundTrip(w http.ResponseWriter, r *http.Reques...
    method authenticate (line 484) | func (h *http2Handler) authenticate(w http.ResponseWriter, r *http.Req...
    method forwardRequest (line 561) | func (h *http2Handler) forwardRequest(w http.ResponseWriter, r *http.R...
    method writeResponse (line 575) | func (h *http2Handler) writeResponse(w http.ResponseWriter, resp *http...
  function HTTP2Handler (line 316) | func HTTP2Handler(opts ...HandlerOption) Handler {
  type http2Listener (line 586) | type http2Listener struct
    method handleFunc (line 629) | func (l *http2Listener) handleFunc(w http.ResponseWriter, r *http.Requ...
    method Accept (line 645) | func (l *http2Listener) Accept() (conn net.Conn, err error) {
    method Addr (line 656) | func (l *http2Listener) Addr() net.Addr {
    method Close (line 660) | func (l *http2Listener) Close() (err error) {
  function HTTP2Listener (line 594) | func HTTP2Listener(addr string, config *tls.Config) (Listener, error) {
  type h2Listener (line 671) | type h2Listener struct
    method listenLoop (line 727) | func (l *h2Listener) listenLoop() {
    method handleLoop (line 740) | func (l *h2Listener) handleLoop(conn net.Conn) {
    method handleFunc (line 760) | func (l *h2Listener) handleFunc(w http.ResponseWriter, r *http.Request) {
    method upgrade (line 784) | func (l *h2Listener) upgrade(w http.ResponseWriter, r *http.Request) (...
    method Accept (line 817) | func (l *h2Listener) Accept() (conn net.Conn, err error) {
  function H2Listener (line 681) | func H2Listener(addr string, config *tls.Config, path string) (Listener,...
  function H2CListener (line 708) | func H2CListener(addr string, path string) (Listener, error) {
  type http2Conn (line 830) | type http2Conn struct
    method Read (line 838) | func (c *http2Conn) Read(b []byte) (n int, err error) {
    method Write (line 842) | func (c *http2Conn) Write(b []byte) (n int, err error) {
    method Close (line 846) | func (c *http2Conn) Close() (err error) {
    method LocalAddr (line 862) | func (c *http2Conn) LocalAddr() net.Addr {
    method RemoteAddr (line 866) | func (c *http2Conn) RemoteAddr() net.Addr {
    method SetDeadline (line 870) | func (c *http2Conn) SetDeadline(t time.Time) error {
    method SetReadDeadline (line 874) | func (c *http2Conn) SetReadDeadline(t time.Time) error {
    method SetWriteDeadline (line 878) | func (c *http2Conn) SetWriteDeadline(t time.Time) error {
  type http2ServerConn (line 883) | type http2ServerConn struct
    method Read (line 889) | func (c *http2ServerConn) Read(b []byte) (n int, err error) {
    method Write (line 893) | func (c *http2ServerConn) Write(b []byte) (n int, err error) {
    method Close (line 897) | func (c *http2ServerConn) Close() error {
    method LocalAddr (line 906) | func (c *http2ServerConn) LocalAddr() net.Addr {
    method RemoteAddr (line 911) | func (c *http2ServerConn) RemoteAddr() net.Addr {
    method SetDeadline (line 916) | func (c *http2ServerConn) SetDeadline(t time.Time) error {
    method SetReadDeadline (line 920) | func (c *http2ServerConn) SetReadDeadline(t time.Time) error {
    method SetWriteDeadline (line 924) | func (c *http2ServerConn) SetWriteDeadline(t time.Time) error {
  type http2ClientConn (line 929) | type http2ClientConn struct
    method Close (line 936) | func (c *http2ClientConn) Close() error {
  type flushWriter (line 943) | type flushWriter struct
    method Write (line 947) | func (fw flushWriter) Write(p []byte) (n int, err error) {

FILE: http2_test.go
  function http2ProxyRoundtrip (line 16) | func http2ProxyRoundtrip(targetURL string, data []byte, clientInfo *url....
  function TestHTTP2ProxyAuth (line 40) | func TestHTTP2ProxyAuth(t *testing.T) {
  function BenchmarkHTTP2Proxy (line 64) | func BenchmarkHTTP2Proxy(b *testing.B) {
  function BenchmarkHTTP2ProxyParallel (line 97) | func BenchmarkHTTP2ProxyParallel(b *testing.B) {
  function httpOverH2Roundtrip (line 132) | func httpOverH2Roundtrip(targetURL string, data []byte, tlsConfig *tls.C...
  function TestHTTPOverH2 (line 158) | func TestHTTPOverH2(t *testing.T) {
  function BenchmarkHTTPOverH2 (line 182) | func BenchmarkHTTPOverH2(b *testing.B) {
  function BenchmarkHTTPOverH2Parallel (line 215) | func BenchmarkHTTPOverH2Parallel(b *testing.B) {
  function socks5OverH2Roundtrip (line 250) | func socks5OverH2Roundtrip(targetURL string, data []byte, tlsConfig *tls...
  function TestSOCKS5OverH2 (line 276) | func TestSOCKS5OverH2(t *testing.T) {
  function socks4OverH2Roundtrip (line 302) | func socks4OverH2Roundtrip(targetURL string, data []byte, tlsConfig *tls...
  function TestSOCKS4OverH2 (line 324) | func TestSOCKS4OverH2(t *testing.T) {
  function socks4aOverH2Roundtrip (line 338) | func socks4aOverH2Roundtrip(targetURL string, data []byte, tlsConfig *tl...
  function TestSOCKS4AOverH2 (line 360) | func TestSOCKS4AOverH2(t *testing.T) {
  function ssOverH2Roundtrip (line 374) | func ssOverH2Roundtrip(targetURL string, data []byte, tlsConfig *tls.Con...
  function TestSSOverH2 (line 400) | func TestSSOverH2(t *testing.T) {
  function sniOverH2Roundtrip (line 426) | func sniOverH2Roundtrip(targetURL string, data []byte, host string) error {
  function TestSNIOverH2 (line 453) | func TestSNIOverH2(t *testing.T) {
  function h2ForwardTunnelRoundtrip (line 491) | func h2ForwardTunnelRoundtrip(targetURL string, data []byte) error {
  function TestH2ForwardTunnel (line 519) | func TestH2ForwardTunnel(t *testing.T) {
  function httpOverH2CRoundtrip (line 532) | func httpOverH2CRoundtrip(targetURL string, data []byte,
  function TestHTTPOverH2C (line 558) | func TestHTTPOverH2C(t *testing.T) {
  function BenchmarkHTTPOverH2C (line 582) | func BenchmarkHTTPOverH2C(b *testing.B) {
  function BenchmarkHTTPOverH2CParallel (line 615) | func BenchmarkHTTPOverH2CParallel(b *testing.B) {
  function socks5OverH2CRoundtrip (line 650) | func socks5OverH2CRoundtrip(targetURL string, data []byte,
  function TestSOCKS5OverH2C (line 676) | func TestSOCKS5OverH2C(t *testing.T) {
  function socks4OverH2CRoundtrip (line 701) | func socks4OverH2CRoundtrip(targetURL string, data []byte) error {
  function TestSOCKS4OverH2C (line 723) | func TestSOCKS4OverH2C(t *testing.T) {
  function socks4aOverH2CRoundtrip (line 737) | func socks4aOverH2CRoundtrip(targetURL string, data []byte) error {
  function TestSOCKS4AOverH2C (line 759) | func TestSOCKS4AOverH2C(t *testing.T) {
  function ssOverH2CRoundtrip (line 773) | func ssOverH2CRoundtrip(targetURL string, data []byte,
  function TestSSOverH2C (line 799) | func TestSSOverH2C(t *testing.T) {
  function sniOverH2CRoundtrip (line 824) | func sniOverH2CRoundtrip(targetURL string, data []byte, host string) err...
  function TestSNIOverH2C (line 851) | func TestSNIOverH2C(t *testing.T) {
  function h2cForwardTunnelRoundtrip (line 889) | func h2cForwardTunnelRoundtrip(targetURL string, data []byte) error {
  function TestH2CForwardTunnel (line 917) | func TestH2CForwardTunnel(t *testing.T) {
  function TestHTTP2ProxyWithCodeProbeResist (line 930) | func TestHTTP2ProxyWithCodeProbeResist(t *testing.T) {
  function TestHTTP2ProxyWithWebProbeResist (line 962) | func TestHTTP2ProxyWithWebProbeResist(t *testing.T) {
  function TestHTTP2ProxyWithHostProbeResist (line 1006) | func TestHTTP2ProxyWithHostProbeResist(t *testing.T) {
  function TestHTTP2ProxyWithFileProbeResist (line 1077) | func TestHTTP2ProxyWithFileProbeResist(t *testing.T) {
  function TestHTTP2ProxyWithBypass (line 1114) | func TestHTTP2ProxyWithBypass(t *testing.T) {

FILE: http_test.go
  function httpProxyRoundtrip (line 35) | func httpProxyRoundtrip(targetURL string, data []byte, clientInfo *url.U...
  function TestHTTPProxyAuth (line 59) | func TestHTTPProxyAuth(t *testing.T) {
  function TestHTTPProxyWithInvalidRequest (line 86) | func TestHTTPProxyWithInvalidRequest(t *testing.T) {
  function BenchmarkHTTPProxy (line 120) | func BenchmarkHTTPProxy(b *testing.B) {
  function BenchmarkHTTPProxyParallel (line 153) | func BenchmarkHTTPProxyParallel(b *testing.B) {
  function TestHTTPProxyWithCodeProbeResist (line 188) | func TestHTTPProxyWithCodeProbeResist(t *testing.T) {
  function TestHTTPProxyWithWebProbeResist (line 215) | func TestHTTPProxyWithWebProbeResist(t *testing.T) {
  function TestHTTPProxyWithHostProbeResist (line 258) | func TestHTTPProxyWithHostProbeResist(t *testing.T) {
  function TestHTTPProxyWithFileProbeResist (line 305) | func TestHTTPProxyWithFileProbeResist(t *testing.T) {
  function TestHTTPProxyWithBypass (line 341) | func TestHTTPProxyWithBypass(t *testing.T) {

FILE: kcp.go
  type KCPConfig (line 29) | type KCPConfig struct
    method Init (line 57) | func (c *KCPConfig) Init() {
  type kcpTransporter (line 110) | type kcpTransporter struct
    method Dial (line 135) | func (tr *kcpTransporter) Dial(addr string, options ...DialOption) (co...
    method Handshake (line 176) | func (tr *kcpTransporter) Handshake(conn net.Conn, options ...Handshak...
    method initSession (line 216) | func (tr *kcpTransporter) initSession(addr string, conn net.Conn, conf...
    method Multiplex (line 269) | func (tr *kcpTransporter) Multiplex() bool {
  function KCPTransporter (line 117) | func KCPTransporter(config *KCPConfig) Transporter {
  type kcpListener (line 273) | type kcpListener struct
    method listenLoop (line 336) | func (l *kcpListener) listenLoop() {
    method mux (line 355) | func (l *kcpListener) mux(conn net.Conn) {
    method Accept (line 395) | func (l *kcpListener) Accept() (conn net.Conn, err error) {
    method Addr (line 406) | func (l *kcpListener) Addr() net.Addr {
    method Close (line 410) | func (l *kcpListener) Close() error {
  function KCPListener (line 281) | func KCPListener(addr string, config *KCPConfig) (Listener, error) {
  function blockCrypt (line 414) | func blockCrypt(key, crypt, salt string) (block kcp.BlockCrypt) {
  function snmpLogger (line 450) | func snmpLogger(format string, interval int) {
  type compStreamConn (line 481) | type compStreamConn struct
    method Read (line 495) | func (c *compStreamConn) Read(b []byte) (n int, err error) {
    method Write (line 499) | func (c *compStreamConn) Write(b []byte) (n int, err error) {
    method Close (line 509) | func (c *compStreamConn) Close() error {
    method LocalAddr (line 513) | func (c *compStreamConn) LocalAddr() net.Addr {
    method RemoteAddr (line 517) | func (c *compStreamConn) RemoteAddr() net.Addr {
    method SetDeadline (line 521) | func (c *compStreamConn) SetDeadline(t time.Time) error {
    method SetReadDeadline (line 525) | func (c *compStreamConn) SetReadDeadline(t time.Time) error {
    method SetWriteDeadline (line 529) | func (c *compStreamConn) SetWriteDeadline(t time.Time) error {
  function newCompStreamConn (line 487) | func newCompStreamConn(conn net.Conn) *compStreamConn {

FILE: kcp_test.go
  function httpOverKCPRoundtrip (line 11) | func httpOverKCPRoundtrip(targetURL string, data []byte,
  function TestHTTPOverKCP (line 37) | func TestHTTPOverKCP(t *testing.T) {
  function BenchmarkHTTPOverKCP (line 61) | func BenchmarkHTTPOverKCP(b *testing.B) {
  function BenchmarkHTTPOverKCPParallel (line 94) | func BenchmarkHTTPOverKCPParallel(b *testing.B) {
  function socks5OverKCPRoundtrip (line 129) | func socks5OverKCPRoundtrip(targetURL string, data []byte,
  function TestSOCKS5OverKCP (line 155) | func TestSOCKS5OverKCP(t *testing.T) {
  function socks4OverKCPRoundtrip (line 180) | func socks4OverKCPRoundtrip(targetURL string, data []byte) error {
  function TestSOCKS4OverKCP (line 202) | func TestSOCKS4OverKCP(t *testing.T) {
  function socks4aOverKCPRoundtrip (line 216) | func socks4aOverKCPRoundtrip(targetURL string, data []byte) error {
  function TestSOCKS4AOverKCP (line 238) | func TestSOCKS4AOverKCP(t *testing.T) {
  function ssOverKCPRoundtrip (line 253) | func ssOverKCPRoundtrip(targetURL string, data []byte,
  function TestSSOverKCP (line 279) | func TestSSOverKCP(t *testing.T) {
  function sniOverKCPRoundtrip (line 304) | func sniOverKCPRoundtrip(targetURL string, data []byte, host string) err...
  function TestSNIOverKCP (line 331) | func TestSNIOverKCP(t *testing.T) {
  function kcpForwardTunnelRoundtrip (line 369) | func kcpForwardTunnelRoundtrip(targetURL string, data []byte) error {
  function TestKCPForwardTunnel (line 397) | func TestKCPForwardTunnel(t *testing.T) {

FILE: log.go
  function init (line 8) | func init() {
  type LogLogger (line 13) | type LogLogger struct
    method Log (line 17) | func (l *LogLogger) Log(v ...interface{}) {
    method Logf (line 22) | func (l *LogLogger) Logf(format string, v ...interface{}) {
  type NopLogger (line 27) | type NopLogger struct
    method Log (line 31) | func (l *NopLogger) Log(v ...interface{}) {
    method Logf (line 35) | func (l *NopLogger) Logf(format string, v ...interface{}) {

FILE: mux.go
  type muxStreamConn (line 9) | type muxStreamConn struct
    method Read (line 14) | func (c *muxStreamConn) Read(b []byte) (n int, err error) {
    method Write (line 18) | func (c *muxStreamConn) Write(b []byte) (n int, err error) {
    method Close (line 22) | func (c *muxStreamConn) Close() error {
  type muxSession (line 26) | type muxSession struct
    method GetConn (line 31) | func (session *muxSession) GetConn() (net.Conn, error) {
    method Accept (line 39) | func (session *muxSession) Accept() (net.Conn, error) {
    method Close (line 47) | func (session *muxSession) Close() error {
    method IsClosed (line 54) | func (session *muxSession) IsClosed() bool {
    method NumStreams (line 61) | func (session *muxSession) NumStreams() int {

FILE: node.go
  type Node (line 19) | type Node struct
    method MarkDead (line 124) | func (node *Node) MarkDead() {
    method ResetDead (line 132) | func (node *Node) ResetDead() {
    method Clone (line 140) | func (node *Node) Clone() Node {
    method Get (line 149) | func (node *Node) Get(key string) string {
    method GetBool (line 154) | func (node *Node) GetBool(key string) bool {
    method GetInt (line 160) | func (node *Node) GetInt(key string) int {
    method GetDuration (line 166) | func (node *Node) GetDuration(key string) time.Duration {
    method String (line 174) | func (node Node) String() string {
  function ParseNode (line 40) | func ParseNode(s string) (node Node, err error) {
  type NodeGroup (line 187) | type NodeGroup struct
    method AddNode (line 203) | func (group *NodeGroup) AddNode(node ...Node) {
    method SetNodes (line 215) | func (group *NodeGroup) SetNodes(nodes ...Node) []Node {
    method SetSelector (line 229) | func (group *NodeGroup) SetSelector(selector NodeSelector, opts ...Sel...
    method Nodes (line 241) | func (group *NodeGroup) Nodes() []Node {
    method GetNode (line 253) | func (group *NodeGroup) GetNode(i int) Node {
    method Next (line 265) | func (group *NodeGroup) Next() (node Node, err error) {
  function NewNodeGroup (line 196) | func NewNodeGroup(nodes ...Node) *NodeGroup {

FILE: node_test.go
  function TestParseNode (line 33) | func TestParseNode(t *testing.T) {

FILE: obfs.go
  constant maxTLSDataLen (line 29) | maxTLSDataLen = 16384
  type obfsHTTPTransporter (line 32) | type obfsHTTPTransporter struct
    method Handshake (line 41) | func (tr *obfsHTTPTransporter) Handshake(conn net.Conn, options ...Han...
  function ObfsHTTPTransporter (line 37) | func ObfsHTTPTransporter() Transporter {
  type obfsHTTPListener (line 49) | type obfsHTTPListener struct
    method Accept (line 66) | func (l *obfsHTTPListener) Accept() (net.Conn, error) {
  function ObfsHTTPListener (line 54) | func ObfsHTTPListener(addr string) (Listener, error) {
  type obfsHTTPConn (line 75) | type obfsHTTPConn struct
    method Handshake (line 86) | func (c *obfsHTTPConn) Handshake() (err error) {
    method serverHandshake (line 107) | func (c *obfsHTTPConn) serverHandshake() (err error) {
    method clientHandshake (line 169) | func (c *obfsHTTPConn) clientHandshake() (err error) {
    method Read (line 196) | func (c *obfsHTTPConn) Read(b []byte) (n int, err error) {
    method drainHeader (line 213) | func (c *obfsHTTPConn) drainHeader() (err error) {
    method Write (line 246) | func (c *obfsHTTPConn) Write(b []byte) (n int, err error) {
  type obfsTLSTransporter (line 259) | type obfsTLSTransporter struct
    method Handshake (line 268) | func (tr *obfsTLSTransporter) Handshake(conn net.Conn, options ...Hand...
  function ObfsTLSTransporter (line 264) | func ObfsTLSTransporter() Transporter {
  type obfsTLSListener (line 276) | type obfsTLSListener struct
    method Accept (line 293) | func (l *obfsTLSListener) Accept() (net.Conn, error) {
  function ObfsTLSListener (line 281) | func ObfsTLSListener(addr string) (Listener, error) {
  constant tlsRecordStateType (line 327) | tlsRecordStateType = iota
  constant tlsRecordStateVersion0 (line 328) | tlsRecordStateVersion0
  constant tlsRecordStateVersion1 (line 329) | tlsRecordStateVersion1
  constant tlsRecordStateLength0 (line 330) | tlsRecordStateLength0
  constant tlsRecordStateLength1 (line 331) | tlsRecordStateLength1
  constant tlsRecordStateData (line 332) | tlsRecordStateData
  type obfsTLSParser (line 335) | type obfsTLSParser struct
    method Parse (line 352) | func (r *obfsTLSParser) Parse(b []byte) (int, error) {
  type obfsTLSConn (line 341) | type obfsTLSConn struct
    method Handshaked (line 451) | func (c *obfsTLSConn) Handshaked() bool {
    method Handshake (line 460) | func (c *obfsTLSConn) Handshake(payload []byte) (err error) {
    method clientHandshake (line 481) | func (c *obfsTLSConn) clientHandshake(payload []byte) error {
    method serverHandshake (line 526) | func (c *obfsTLSConn) serverHandshake() error {
    method Read (line 596) | func (c *obfsTLSConn) Read(b []byte) (n int, err error) {
    method Write (line 629) | func (c *obfsTLSConn) Write(b []byte) (n int, err error) {
  function ClientObfsTLSConn (line 432) | func ClientObfsTLSConn(conn net.Conn, host string) net.Conn {
  function ServerObfsTLSConn (line 442) | func ServerObfsTLSConn(conn net.Conn, host string) net.Conn {
  type obfs4Context (line 668) | type obfs4Context struct
  function Obfs4Init (line 678) | func Obfs4Init(node Node, isServeNode bool) error {
  function obfs4GetContext (line 720) | func obfs4GetContext(addr string) (obfs4Context, error) {
  function obfs4ServerURL (line 728) | func obfs4ServerURL(node Node) string {
  function obfs4ClientConn (line 745) | func obfs4ClientConn(addr string, conn net.Conn) (net.Conn, error) {
  function obfs4ServerConn (line 755) | func obfs4ServerConn(addr string, conn net.Conn) (net.Conn, error) {
  type obfs4Transporter (line 764) | type obfs4Transporter struct
    method Handshake (line 773) | func (tr *obfs4Transporter) Handshake(conn net.Conn, options ...Handsh...
  function Obfs4Transporter (line 769) | func Obfs4Transporter() Transporter {
  type obfs4Listener (line 789) | type obfs4Listener struct
    method Accept (line 817) | func (l *obfs4Listener) Accept() (net.Conn, error) {
  function Obfs4Listener (line 795) | func Obfs4Listener(addr string) (Listener, error) {
  type TempError (line 810) | type TempError struct
    method Timeout (line 814) | func (e TempError) Timeout() bool   { return false }
    method Temporary (line 815) | func (e TempError) Temporary() bool { return true }

FILE: obfs_test.go
  function httpOverObfsHTTPRoundtrip (line 11) | func httpOverObfsHTTPRoundtrip(targetURL string, data []byte,
  function TestHTTPOverObfsHTTP (line 37) | func TestHTTPOverObfsHTTP(t *testing.T) {
  function BenchmarkHTTPOverObfsHTTP (line 64) | func BenchmarkHTTPOverObfsHTTP(b *testing.B) {
  function BenchmarkHTTPOverObfsHTTPParallel (line 98) | func BenchmarkHTTPOverObfsHTTPParallel(b *testing.B) {
  function socks5OverObfsHTTPRoundtrip (line 133) | func socks5OverObfsHTTPRoundtrip(targetURL string, data []byte,
  function TestSOCKS5OverObfsHTTP (line 159) | func TestSOCKS5OverObfsHTTP(t *testing.T) {
  function socks4OverObfsHTTPRoundtrip (line 184) | func socks4OverObfsHTTPRoundtrip(targetURL string, data []byte) error {
  function TestSOCKS4OverObfsHTTP (line 206) | func TestSOCKS4OverObfsHTTP(t *testing.T) {
  function socks4aOverObfsHTTPRoundtrip (line 220) | func socks4aOverObfsHTTPRoundtrip(targetURL string, data []byte) error {
  function TestSOCKS4AOverObfsHTTP (line 242) | func TestSOCKS4AOverObfsHTTP(t *testing.T) {
  function ssOverObfsHTTPRoundtrip (line 257) | func ssOverObfsHTTPRoundtrip(targetURL string, data []byte,
  function TestSSOverObfsHTTP (line 283) | func TestSSOverObfsHTTP(t *testing.T) {
  function sniOverObfsHTTPRoundtrip (line 308) | func sniOverObfsHTTPRoundtrip(targetURL string, data []byte, host string...
  function TestSNIOverObfsHTTP (line 335) | func TestSNIOverObfsHTTP(t *testing.T) {
  function httpOverObfs4Roundtrip (line 373) | func httpOverObfs4Roundtrip(targetURL string, data []byte,
  function _TestHTTPOverObfs4 (line 399) | func _TestHTTPOverObfs4(t *testing.T) {

FILE: permissions.go
  type Permission (line 14) | type Permission struct
  type PortRange (line 21) | type PortRange struct
    method Contains (line 63) | func (ir *PortRange) Contains(value int) bool {
  function ParsePortRange (line 27) | func ParsePortRange(s string) (*PortRange, error) {
  type PortSet (line 68) | type PortSet
    method Contains (line 95) | func (ps *PortSet) Contains(value int) bool {
  function ParsePortSet (line 72) | func ParsePortSet(s string) (*PortSet, error) {
  type StringSet (line 106) | type StringSet
    method Contains (line 122) | func (ss *StringSet) Contains(subj string) bool {
  function ParseStringSet (line 110) | func ParseStringSet(s string) (*StringSet, error) {
  type Permissions (line 133) | type Permissions
    method Can (line 180) | func (ps *Permissions) Can(action string, host string, port int) bool {
  function ParsePermissions (line 136) | func ParsePermissions(s string) (*Permissions, error) {
  function minint (line 190) | func minint(x, y int) int {
  function maxint (line 197) | func maxint(x, y int) int {
  function Can (line 205) | func Can(action string, addr string, whitelist, blacklist *Permissions) ...

FILE: permissions_test.go
  function TestPortRangeParse (line 70) | func TestPortRangeParse(t *testing.T) {
  function TestPortRangeContains (line 81) | func TestPortRangeContains(t *testing.T) {
  function TestStringSetParse (line 93) | func TestStringSetParse(t *testing.T) {
  function TestStringSetContains (line 104) | func TestStringSetContains(t *testing.T) {
  function TestPortSetParse (line 116) | func TestPortSetParse(t *testing.T) {
  function TestPortSetContains (line 127) | func TestPortSetContains(t *testing.T) {
  function TestPermissionsParse (line 143) | func TestPermissionsParse(t *testing.T) {

FILE: quic.go
  type quicSession (line 19) | type quicSession struct
    method GetConn (line 23) | func (session *quicSession) GetConn() (*quicConn, error) {
    method Close (line 35) | func (session *quicSession) Close() error {
  type quicTransporter (line 39) | type quicTransporter struct
    method Dial (line 56) | func (tr *quicTransporter) Dial(addr string, options ...DialOption) (c...
    method Handshake (line 99) | func (tr *quicTransporter) Handshake(conn net.Conn, options ...Handsha...
    method initSession (line 103) | func (tr *quicTransporter) initSession(addr net.Addr, conn net.PacketC...
    method Multiplex (line 129) | func (tr *quicTransporter) Multiplex() bool {
  function QUICTransporter (line 46) | func QUICTransporter(config *QUICConfig) Transporter {
  type QUICConfig (line 134) | type QUICConfig struct
  type quicListener (line 143) | type quicListener struct
    method listenLoop (line 198) | func (l *quicListener) listenLoop() {
    method sessionLoop (line 211) | func (l *quicListener) sessionLoop(session quic.Connection) {
    method Accept (line 233) | func (l *quicListener) Accept() (conn net.Conn, err error) {
    method Addr (line 245) | func (l *quicListener) Addr() net.Addr {
    method Close (line 249) | func (l *quicListener) Close() error {
  function QUICListener (line 150) | func QUICListener(addr string, config *QUICConfig) (Listener, error) {
  type quicConn (line 253) | type quicConn struct
    method LocalAddr (line 259) | func (c *quicConn) LocalAddr() net.Addr {
    method RemoteAddr (line 263) | func (c *quicConn) RemoteAddr() net.Addr {
  type quicCipherConn (line 267) | type quicCipherConn struct
    method ReadFrom (line 272) | func (conn *quicCipherConn) ReadFrom(data []byte) (n int, addr net.Add...
    method WriteTo (line 287) | func (conn *quicCipherConn) WriteTo(data []byte, addr net.Addr) (n int...
    method encrypt (line 301) | func (conn *quicCipherConn) encrypt(data []byte) ([]byte, error) {
    method decrypt (line 320) | func (conn *quicCipherConn) decrypt(data []byte) ([]byte, error) {
  function tlsConfigQUICALPN (line 340) | func tlsConfigQUICALPN(tlsConfig *tls.Config) *tls.Config {

FILE: quic_test.go
  function httpOverQUICRoundtrip (line 12) | func httpOverQUICRoundtrip(targetURL string, data []byte,
  function TestHTTPOverQUIC (line 38) | func TestHTTPOverQUIC(t *testing.T) {
  function BenchmarkHTTPOverQUIC (line 62) | func BenchmarkHTTPOverQUIC(b *testing.B) {
  function BenchmarkHTTPOverQUICParallel (line 95) | func BenchmarkHTTPOverQUICParallel(b *testing.B) {
  function socks5OverQUICRoundtrip (line 130) | func socks5OverQUICRoundtrip(targetURL string, data []byte,
  function TestSOCKS5OverQUIC (line 156) | func TestSOCKS5OverQUIC(t *testing.T) {
  function socks4OverQUICRoundtrip (line 181) | func socks4OverQUICRoundtrip(targetURL string, data []byte) error {
  function TestSOCKS4OverQUIC (line 203) | func TestSOCKS4OverQUIC(t *testing.T) {
  function socks4aOverQUICRoundtrip (line 217) | func socks4aOverQUICRoundtrip(targetURL string, data []byte) error {
  function TestSOCKS4AOverQUIC (line 239) | func TestSOCKS4AOverQUIC(t *testing.T) {
  function ssOverQUICRoundtrip (line 254) | func ssOverQUICRoundtrip(targetURL string, data []byte,
  function TestSSOverQUIC (line 280) | func TestSSOverQUIC(t *testing.T) {
  function sniOverQUICRoundtrip (line 305) | func sniOverQUICRoundtrip(targetURL string, data []byte, host string) er...
  function TestSNIOverQUIC (line 332) | func TestSNIOverQUIC(t *testing.T) {
  function quicForwardTunnelRoundtrip (line 370) | func quicForwardTunnelRoundtrip(targetURL string, data []byte) error {
  function TestQUICForwardTunnel (line 398) | func TestQUICForwardTunnel(t *testing.T) {
  function httpOverCipherQUICRoundtrip (line 411) | func httpOverCipherQUICRoundtrip(targetURL string, data []byte,
  function TestHTTPOverCipherQUIC (line 441) | func TestHTTPOverCipherQUIC(t *testing.T) {

FILE: redirect.go
  type tcpRedirectHandler (line 19) | type tcpRedirectHandler struct
    method Init (line 31) | func (h *tcpRedirectHandler) Init(options ...HandlerOption) {
    method Handle (line 41) | func (h *tcpRedirectHandler) Handle(c net.Conn) {
    method getOriginalDstAddr (line 73) | func (h *tcpRedirectHandler) getOriginalDstAddr(conn *net.TCPConn) (ad...
  function TCPRedirectHandler (line 24) | func TCPRedirectHandler(opts ...HandlerOption) Handler {
  type udpRedirectHandler (line 107) | type udpRedirectHandler struct
    method Init (line 119) | func (h *udpRedirectHandler) Init(options ...HandlerOption) {
    method Handle (line 129) | func (h *udpRedirectHandler) Handle(conn net.Conn) {
  function UDPRedirectHandler (line 112) | func UDPRedirectHandler(opts ...HandlerOption) Handler {
  type udpRedirectListener (line 154) | type udpRedirectListener struct
    method Accept (line 180) | func (l *udpRedirectListener) Accept() (conn net.Conn, err error) {
    method Addr (line 209) | func (l *udpRedirectListener) Addr() net.Addr {
  function UDPRedirectListener (line 160) | func UDPRedirectListener(addr string, cfg *UDPListenConfig) (Listener, e...
  type udpRedirectServerConn (line 213) | type udpRedirectServerConn struct
    method Read (line 220) | func (c *udpRedirectServerConn) Read(b []byte) (n int, err error) {
    method Write (line 236) | func (c *udpRedirectServerConn) Write(b []byte) (n int, err error) {

FILE: redirect_other.go
  type tcpRedirectHandler (line 13) | type tcpRedirectHandler struct
    method Init (line 30) | func (h *tcpRedirectHandler) Init(options ...HandlerOption) {
    method Handle (line 34) | func (h *tcpRedirectHandler) Handle(c net.Conn) {
  function TCPRedirectHandler (line 18) | func TCPRedirectHandler(opts ...HandlerOption) Handler {
  type udpRedirectHandler (line 39) | type udpRedirectHandler struct
    method Init (line 46) | func (h *udpRedirectHandler) Init(options ...HandlerOption) {
    method Handle (line 49) | func (h *udpRedirectHandler) Handle(conn net.Conn) {
  function UDPRedirectHandler (line 42) | func UDPRedirectHandler(opts ...HandlerOption) Handler {
  function UDPRedirectListener (line 55) | func UDPRedirectListener(addr string, cfg *UDPListenConfig) (Listener, e...

FILE: relay.go
  type relayConnector (line 20) | type relayConnector struct
    method Connect (line 32) | func (c *relayConnector) Connect(conn net.Conn, address string, option...
    method ConnectContext (line 36) | func (c *relayConnector) ConnectContext(ctx context.Context, conn net....
  function RelayConnector (line 26) | func RelayConnector(user *url.Userinfo) Connector {
  type relayHandler (line 114) | type relayHandler struct
    method Init (line 133) | func (h *relayHandler) Init(options ...HandlerOption) {
    method Handle (line 137) | func (h *relayHandler) Handle(conn net.Conn) {
  function RelayHandler (line 119) | func RelayHandler(raddr string, opts ...HandlerOption) Handler {
  type relayConn (line 265) | type relayConn struct
    method Read (line 274) | func (c *relayConn) Read(b []byte) (n int, err error) {
    method ReadFrom (line 317) | func (c *relayConn) ReadFrom(b []byte) (n int, addr net.Addr, err erro...
    method Write (line 323) | func (c *relayConn) Write(b []byte) (n int, err error) {
    method WriteTo (line 367) | func (c *relayConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {

FILE: reload.go
  type Reloader (line 12) | type Reloader interface
  type Stoppable (line 18) | type Stoppable interface
  function PeriodReload (line 24) | func PeriodReload(r Reloader, configFile string) error {

FILE: resolver.go
  type nameServerOptions (line 27) | type nameServerOptions struct
  type NameServerOption (line 33) | type NameServerOption
  function TimeoutNameServerOption (line 36) | func TimeoutNameServerOption(timeout time.Duration) NameServerOption {
  function ChainNameServerOption (line 43) | func ChainNameServerOption(chain *Chain) NameServerOption {
  type NameServer (line 51) | type NameServer struct
    method Init (line 60) | func (ns *NameServer) Init(opts ...NameServerOption) error {
    method String (line 112) | func (ns *NameServer) String() string {
  type resolverOptions (line 121) | type resolverOptions struct
  type ResolverOption (line 130) | type ResolverOption
  function ChainResolverOption (line 133) | func ChainResolverOption(chain *Chain) ResolverOption {
  function TimeoutResolverOption (line 140) | func TimeoutResolverOption(timeout time.Duration) ResolverOption {
  function TTLResolverOption (line 147) | func TTLResolverOption(ttl time.Duration) ResolverOption {
  function PreferResolverOption (line 154) | func PreferResolverOption(prefer string) ResolverOption {
  function SrcIPResolverOption (line 161) | func SrcIPResolverOption(ip net.IP) ResolverOption {
  type Resolver (line 169) | type Resolver interface
  type ReloadResolver (line 180) | type ReloadResolver interface
  type resolver (line 186) | type resolver struct
    method Init (line 214) | func (r *resolver) Init(opts ...ResolverOption) error {
    method copyServers (line 260) | func (r *resolver) copyServers() []NameServer {
    method Resolve (line 270) | func (r *resolver) Resolve(host string) (ips []net.IP, err error) {
    method resolve (line 302) | func (r *resolver) resolve(ctx context.Context, ex Exchanger, host str...
    method resolve4 (line 324) | func (r *resolver) resolve4(ctx context.Context, ex Exchanger, host st...
    method resolve6 (line 330) | func (r *resolver) resolve6(ctx context.Context, ex Exchanger, host st...
    method resolveIPs (line 336) | func (r *resolver) resolveIPs(ctx context.Context, ex Exchanger, mq *d...
    method addSubnetOpt (line 360) | func (r *resolver) addSubnetOpt(m *dns.Msg) {
    method Exchange (line 382) | func (r *resolver) Exchange(ctx context.Context, query []byte) (reply ...
    method exchangeMsg (line 426) | func (r *resolver) exchangeMsg(ctx context.Context, ex Exchanger, mq *...
    method TTL (line 442) | func (r *resolver) TTL() time.Duration {
    method Reload (line 448) | func (r *resolver) Reload(rd io.Reader) error {
    method Period (line 540) | func (r *resolver) Period() time.Duration {
    method Stop (line 552) | func (r *resolver) Stop() {
    method Stopped (line 561) | func (r *resolver) Stopped() bool {
    method String (line 570) | func (r *resolver) String() string {
  function NewResolver (line 201) | func NewResolver(ttl time.Duration, servers ...NameServer) ReloadResolver {
  function newResolver (line 206) | func newResolver(ttl time.Duration, servers ...NameServer) *resolver {
  type resolverCacheKey (line 588) | type resolverCacheKey
  function newResolverCacheKey (line 591) | func newResolverCacheKey(q *dns.Question) resolverCacheKey {
  type resolverCacheItem (line 599) | type resolverCacheItem struct
  type resolverCache (line 605) | type resolverCache struct
    method loadCache (line 613) | func (rc *resolverCache) loadCache(key resolverCacheKey) *dns.Msg {
    method storeCache (line 643) | func (rc *resolverCache) storeCache(key resolverCacheKey, mr *dns.Msg,...
  function newResolverCache (line 609) | func newResolverCache(ttl time.Duration) *resolverCache {
  type Exchanger (line 659) | type Exchanger interface
  type exchangerOptions (line 663) | type exchangerOptions struct
  type ExchangerOption (line 669) | type ExchangerOption
  function ChainExchangerOption (line 672) | func ChainExchangerOption(chain *Chain) ExchangerOption {
  function TimeoutExchangerOption (line 679) | func TimeoutExchangerOption(timeout time.Duration) ExchangerOption {
  type dnsExchanger (line 685) | type dnsExchanger struct
    method Exchange (line 707) | func (ex *dnsExchanger) Exchange(ctx context.Context, query []byte) ([...
  function NewDNSExchanger (line 691) | func NewDNSExchanger(addr string, opts ...ExchangerOption) Exchanger {
  type dnsTCPExchanger (line 735) | type dnsTCPExchanger struct
    method Exchange (line 757) | func (ex *dnsTCPExchanger) Exchange(ctx context.Context, query []byte)...
  function NewDNSTCPExchanger (line 741) | func NewDNSTCPExchanger(addr string, opts ...ExchangerOption) Exchanger {
  type dotExchanger (line 784) | type dotExchanger struct
    method dial (line 813) | func (ex *dotExchanger) dial(ctx context.Context, network, address str...
    method Exchange (line 826) | func (ex *dotExchanger) Exchange(ctx context.Context, query []byte) ([...
  function NewDoTExchanger (line 791) | func NewDoTExchanger(addr string, tlsConfig *tls.Config, opts ...Exchang...
  type dohExchanger (line 850) | type dohExchanger struct
    method dialContext (line 884) | func (ex *dohExchanger) dialContext(ctx context.Context, network, addr...
    method Exchange (line 891) | func (ex *dohExchanger) Exchange(ctx context.Context, query []byte) ([...
  function NewDoHExchanger (line 857) | func NewDoHExchanger(urlStr *url.URL, tlsConfig *tls.Config, opts ...Exc...

FILE: resolver_test.go
  function dnsResolverRoundtrip (line 33) | func dnsResolverRoundtrip(t *testing.T, r Resolver, host string) error {
  function TestDNSResolver (line 43) | func TestDNSResolver(t *testing.T) {
  function TestResolverReload (line 215) | func TestResolverReload(t *testing.T) {
  function compareNameServer (line 260) | func compareNameServer(n1, n2 *NameServer) bool {

FILE: selector.go
  type NodeSelector (line 22) | type NodeSelector interface
  type defaultSelector (line 26) | type defaultSelector struct
    method Select (line 29) | func (s *defaultSelector) Select(nodes []Node, opts ...SelectOption) (...
  type SelectOption (line 49) | type SelectOption
  type SelectOptions (line 52) | type SelectOptions struct
  function WithFilter (line 59) | func WithFilter(f ...Filter) SelectOption {
  function WithStrategy (line 66) | func WithStrategy(s Strategy) SelectOption {
  type Strategy (line 73) | type Strategy interface
  function NewStrategy (line 79) | func NewStrategy(s string) Strategy {
  type RoundStrategy (line 94) | type RoundStrategy struct
    method Apply (line 99) | func (s *RoundStrategy) Apply(nodes []Node) Node {
    method String (line 108) | func (s *RoundStrategy) String() string {
  type RandomStrategy (line 114) | type RandomStrategy struct
    method Apply (line 122) | func (s *RandomStrategy) Apply(nodes []Node) Node {
    method String (line 141) | func (s *RandomStrategy) String() string {
  type FIFOStrategy (line 148) | type FIFOStrategy struct
    method Apply (line 151) | func (s *FIFOStrategy) Apply(nodes []Node) Node {
    method String (line 158) | func (s *FIFOStrategy) String() string {
  type Filter (line 163) | type Filter interface
  constant DefaultMaxFails (line 170) | DefaultMaxFails    = 1
  constant DefaultFailTimeout (line 171) | DefaultFailTimeout = 30 * time.Second
  type FailFilter (line 176) | type FailFilter struct
    method Filter (line 182) | func (f *FailFilter) Filter(nodes []Node) []Node {
    method String (line 207) | func (f *FailFilter) String() string {
  type FastestFilter (line 212) | type FastestFilter struct
    method Filter (line 235) | func (f *FastestFilter) Filter(nodes []Node) []Node {
    method String (line 280) | func (f *FastestFilter) String() string {
    method doTcpPing (line 285) | func (f *FastestFilter) doTcpPing(address string) int {
  function NewFastestFilter (line 222) | func NewFastestFilter(pingTimeOut int, topCount int) *FastestFilter {
  type InvalidFilter (line 301) | type InvalidFilter struct
    method Filter (line 304) | func (f *InvalidFilter) Filter(nodes []Node) []Node {
    method String (line 315) | func (f *InvalidFilter) String() string {
  type failMarker (line 319) | type failMarker struct
    method FailTime (line 325) | func (m *failMarker) FailTime() int64 {
    method FailCount (line 336) | func (m *failMarker) FailCount() uint32 {
    method Mark (line 347) | func (m *failMarker) Mark() {
    method Reset (line 359) | func (m *failMarker) Reset() {
    method Clone (line 371) | func (m *failMarker) Clone() *failMarker {

FILE: selector_test.go
  function TestRoundStrategy (line 8) | func TestRoundStrategy(t *testing.T) {
  function TestRandomStrategy (line 28) | func TestRandomStrategy(t *testing.T) {
  function TestFIFOStrategy (line 48) | func TestFIFOStrategy(t *testing.T) {
  function TestFailFilter (line 68) | func TestFailFilter(t *testing.T) {
  function TestFastestFilter (line 130) | func TestFastestFilter(t *testing.T) {
  function TestSelector (line 154) | func TestSelector(t *testing.T) {

FILE: server.go
  type Accepter (line 12) | type Accepter interface
  type Server (line 17) | type Server struct
    method Init (line 24) | func (s *Server) Init(opts ...ServerOption) {
    method Addr (line 34) | func (s *Server) Addr() net.Addr {
    method Close (line 39) | func (s *Server) Close() error {
    method Serve (line 44) | func (s *Server) Serve(h Handler, opts ...ServerOption) error {
    method Run (line 89) | func (s *Server) Run() error {
  type ServerOptions (line 94) | type ServerOptions struct
  type ServerOption (line 98) | type ServerOption
  type Listener (line 101) | type Listener interface
  function transport (line 105) | func transport(rw1, rw2 io.ReadWriter) error {
  function copyBuffer (line 122) | func copyBuffer(dst io.Writer, src io.Reader) error {

FILE: signal.go
  function kcpSigHandler (line 6) | func kcpSigHandler() {}

FILE: signal_unix.go
  function kcpSigHandler (line 15) | func kcpSigHandler() {

FILE: sni.go
  type sniConnector (line 25) | type sniConnector struct
    method Connect (line 34) | func (c *sniConnector) Connect(conn net.Conn, address string, options ...
    method ConnectContext (line 38) | func (c *sniConnector) ConnectContext(ctx context.Context, conn net.Co...
  function SNIConnector (line 30) | func SNIConnector(host string) Connector {
  type sniHandler (line 47) | type sniHandler struct
    method Init (line 59) | func (h *sniHandler) Init(options ...HandlerOption) {
    method Handle (line 69) | func (h *sniHandler) Handle(conn net.Conn) {
  function SNIHandler (line 52) | func SNIHandler(opts ...HandlerOption) Handler {
  type sniSniffConn (line 183) | type sniSniffConn struct
    method Read (line 188) | func (c sniSniffConn) Read(p []byte) (int, error) { return c.r.Read(p) }
    method Write (line 189) | func (sniSniffConn) Write(p []byte) (int, error)  { return 0, io.EOF }
  type sniClientConn (line 191) | type sniClientConn struct
    method Write (line 199) | func (c *sniClientConn) Write(p []byte) (int, error) {
    method obfuscate (line 210) | func (c *sniClientConn) obfuscate(p []byte) ([]byte, error) {
  function readClientHelloRecord (line 273) | func readClientHelloRecord(r io.Reader, host string, isClient bool) ([]b...
  function encodeServerName (line 327) | func encodeServerName(name string) string {
  function decodeServerName (line 334) | func decodeServerName(s string) (string, error) {

FILE: sni_test.go
  function sniRoundtrip (line 18) | func sniRoundtrip(client *Client, server *Server, targetURL string, data...
  function sniProxyRoundtrip (line 84) | func sniProxyRoundtrip(targetURL string, data []byte, host string) error {
  function TestSNIProxy (line 111) | func TestSNIProxy(t *testing.T) {

FILE: sockopts_linux.go
  function setSocketMark (line 5) | func setSocketMark(fd int, value int) (e error) {
  function setSocketInterface (line 9) | func setSocketInterface(fd int, value string) (e error) {

FILE: sockopts_other.go
  function setSocketMark (line 6) | func setSocketMark(fd int, value int) (e error) {
  function setSocketInterface (line 10) | func setSocketInterface(fd int, value string) (e error) {

FILE: socks.go
  constant MethodTLS (line 25) | MethodTLS uint8 = 0x80
  constant MethodTLSAuth (line 27) | MethodTLSAuth uint8 = 0x82
  constant MethodMux (line 29) | MethodMux = 0x88
  constant CmdMuxBind (line 35) | CmdMuxBind uint8 = 0xF2
  constant CmdUDPTun (line 37) | CmdUDPTun uint8 = 0xF3
  type clientSelector (line 44) | type clientSelector struct
    method Methods (line 50) | func (selector *clientSelector) Methods() []uint8 {
    method AddMethod (line 57) | func (selector *clientSelector) AddMethod(methods ...uint8) {
    method Select (line 61) | func (selector *clientSelector) Select(methods ...uint8) (method uint8) {
    method OnSelected (line 65) | func (selector *clientSelector) OnSelected(method uint8, conn net.Conn...
  type serverSelector (line 110) | type serverSelector struct
    method Methods (line 117) | func (selector *serverSelector) Methods() []uint8 {
    method AddMethod (line 121) | func (selector *serverSelector) AddMethod(methods ...uint8) {
    method Select (line 125) | func (selector *serverSelector) Select(methods ...uint8) (method uint8) {
    method OnSelected (line 150) | func (selector *serverSelector) OnSelected(method uint8, conn net.Conn...
  type socks5Connector (line 200) | type socks5Connector struct
    method Connect (line 210) | func (c *socks5Connector) Connect(conn net.Conn, address string, optio...
    method ConnectContext (line 214) | func (c *socks5Connector) ConnectContext(ctx context.Context, conn net...
  function SOCKS5Connector (line 206) | func SOCKS5Connector(user *url.Userinfo) Connector {
  type socks5BindConnector (line 282) | type socks5BindConnector struct
    method Connect (line 292) | func (c *socks5BindConnector) Connect(conn net.Conn, address string, o...
    method ConnectContext (line 296) | func (c *socks5BindConnector) ConnectContext(ctx context.Context, conn...
  function SOCKS5BindConnector (line 288) | func SOCKS5BindConnector(user *url.Userinfo) Connector {
  type socks5MuxBindConnector (line 371) | type socks5MuxBindConnector struct
    method Connect (line 378) | func (c *socks5MuxBindConnector) Connect(conn net.Conn, address string...
    method ConnectContext (line 383) | func (c *socks5MuxBindConnector) ConnectContext(ctx context.Context, c...
  function Socks5MuxBindConnector (line 374) | func Socks5MuxBindConnector() Connector {
  type socks5MuxBindTransporter (line 397) | type socks5MuxBindTransporter struct
    method Dial (line 411) | func (tr *socks5MuxBindTransporter) Dial(addr string, options ...DialO...
    method Handshake (line 445) | func (tr *socks5MuxBindTransporter) Handshake(conn net.Conn, options ....
    method initSession (line 477) | func (tr *socks5MuxBindTransporter) initSession(conn net.Conn, addr st...
    method Multiplex (line 536) | func (tr *socks5MuxBindTransporter) Multiplex() bool {
  function SOCKS5MuxBindTransporter (line 404) | func SOCKS5MuxBindTransporter(bindAddr string) Transporter {
  type socks5UDPConnector (line 540) | type socks5UDPConnector struct
    method Connect (line 550) | func (c *socks5UDPConnector) Connect(conn net.Conn, address string, op...
    method ConnectContext (line 554) | func (c *socks5UDPConnector) ConnectContext(ctx context.Context, conn ...
  function SOCKS5UDPConnector (line 546) | func SOCKS5UDPConnector(user *url.Userinfo) Connector {
  type socks5UDPTunConnector (line 632) | type socks5UDPTunConnector struct
    method Connect (line 642) | func (c *socks5UDPTunConnector) Connect(conn net.Conn, address string,...
    method ConnectContext (line 646) | func (c *socks5UDPTunConnector) ConnectContext(ctx context.Context, co...
  function SOCKS5UDPTunConnector (line 638) | func SOCKS5UDPTunConnector(user *url.Userinfo) Connector {
  type socks4Connector (line 678) | type socks4Connector struct
    method Connect (line 685) | func (c *socks4Connector) Connect(conn net.Conn, address string, optio...
    method ConnectContext (line 689) | func (c *socks4Connector) ConnectContext(ctx context.Context, conn net...
  function SOCKS4Connector (line 681) | func SOCKS4Connector() Connector {
  type socks4aConnector (line 747) | type socks4aConnector struct
    method Connect (line 754) | func (c *socks4aConnector) Connect(conn net.Conn, address string, opti...
    method ConnectContext (line 758) | func (c *socks4aConnector) ConnectContext(ctx context.Context, conn ne...
  function SOCKS4AConnector (line 750) | func SOCKS4AConnector() Connector {
  type socks5Handler (line 809) | type socks5Handler struct
    method Init (line 822) | func (h *socks5Handler) Init(options ...HandlerOption) {
    method Handle (line 849) | func (h *socks5Handler) Handle(conn net.Conn) {
    method handleConnect (line 886) | func (h *socks5Handler) handleConnect(conn net.Conn, req *gosocks5.Req...
    method handleBind (line 981) | func (h *socks5Handler) handleBind(conn net.Conn, req *gosocks5.Reques...
    method bindOn (line 1020) | func (h *socks5Handler) bindOn(conn net.Conn, addr string) {
    method handleUDPRelay (line 1116) | func (h *socks5Handler) handleUDPRelay(conn net.Conn, req *gosocks5.Re...
    method discardClientData (line 1219) | func (h *socks5Handler) discardClientData(conn net.Conn) (err error) {
    method transportUDP (line 1235) | func (h *socks5Handler) transportUDP(relay, peer net.PacketConn) (err ...
    method tunnelClientUDP (line 1315) | func (h *socks5Handler) tunnelClientUDP(uc *net.UDPConn, cc net.Conn) ...
    method handleUDPTunnel (line 1397) | func (h *socks5Handler) handleUDPTunnel(conn net.Conn, req *gosocks5.R...
    method tunnelServerUDP (line 1457) | func (h *socks5Handler) tunnelServerUDP(cc net.Conn, pc net.PacketConn...
    method handleMuxBind (line 1526) | func (h *socks5Handler) handleMuxBind(conn net.Conn, req *gosocks5.Req...
    method muxBindOn (line 1558) | func (h *socks5Handler) muxBindOn(conn net.Conn, addr string) {
  function SOCKS5Handler (line 815) | func SOCKS5Handler(opts ...HandlerOption) Handler {
  function toSocksAddr (line 1634) | func toSocksAddr(addr net.Addr) *gosocks5.Addr {
  type socks4Handler (line 1653) | type socks4Handler struct
    method Init (line 1665) | func (h *socks4Handler) Init(options ...HandlerOption) {
    method Handle (line 1675) | func (h *socks4Handler) Handle(conn net.Conn) {
    method handleConnect (line 1704) | func (h *socks4Handler) handleConnect(conn net.Conn, req *gosocks4.Req...
    method handleBind (line 1800) | func (h *socks4Handler) handleBind(conn net.Conn, req *gosocks4.Reques...
  function SOCKS4Handler (line 1658) | func SOCKS4Handler(opts ...HandlerOption) Handler {
  type socks5HandshakeOptions (line 1832) | type socks5HandshakeOptions struct
  type socks5HandshakeOption (line 1839) | type socks5HandshakeOption
  function selectorSocks5HandshakeOption (line 1841) | func selectorSocks5HandshakeOption(selector gosocks5.Selector) socks5Han...
  function userSocks5HandshakeOption (line 1847) | func userSocks5HandshakeOption(user *url.Userinfo) socks5HandshakeOption {
  function noTLSSocks5HandshakeOption (line 1853) | func noTLSSocks5HandshakeOption(noTLS bool) socks5HandshakeOption {
  function socks5Handshake (line 1859) | func socks5Handshake(conn net.Conn, opts ...socks5HandshakeOption) (net....
  function getSocks5UDPTunnel (line 1887) | func getSocks5UDPTunnel(chain *Chain, addr net.Addr) (net.Conn, error) {
  type socks5UDPTunnelConn (line 1905) | type socks5UDPTunnelConn struct
    method Read (line 1949) | func (c *socks5UDPTunnelConn) Read(b []byte) (n int, err error) {
    method ReadFrom (line 1954) | func (c *socks5UDPTunnelConn) ReadFrom(b []byte) (n int, addr net.Addr...
    method Write (line 1964) | func (c *socks5UDPTunnelConn) Write(b []byte) (n int, err error) {
    method WriteTo (line 1968) | func (c *socks5UDPTunnelConn) WriteTo(b []byte, addr net.Addr) (n int,...
  function newSocks5UDPTunnelConn (line 1910) | func newSocks5UDPTunnelConn(conn net.Conn, raddr, taddr net.Addr, opts ....
  type socks5BindConn (line 1977) | type socks5BindConn struct
    method Handshake (line 1986) | func (c *socks5BindConn) Handshake() (err error) {
    method Read (line 2007) | func (c *socks5BindConn) Read(b []byte) (n int, err error) {
    method Write (line 2014) | func (c *socks5BindConn) Write(b []byte) (n int, err error) {
    method LocalAddr (line 2021) | func (c *socks5BindConn) LocalAddr() net.Addr {
    method RemoteAddr (line 2025) | func (c *socks5BindConn) RemoteAddr() net.Addr {
  type socks5UDPConn (line 2029) | type socks5UDPConn struct
    method Read (line 2034) | func (c *socks5UDPConn) Read(b []byte) (n int, err error) {
    method ReadFrom (line 2039) | func (c *socks5UDPConn) ReadFrom(b []byte) (n int, addr net.Addr, err ...
    method Write (line 2058) | func (c *socks5UDPConn) Write(b []byte) (int, error) {
    method WriteTo (line 2062) | func (c *socks5UDPConn) WriteTo(b []byte, addr net.Addr) (int, error) {
  type muxBindClientConn (line 2076) | type muxBindClientConn struct
    method Accept (line 2081) | func (c *muxBindClientConn) Accept() (net.Conn, error) {

FILE: socks_test.go
  function socks5ProxyRoundtrip (line 34) | func socks5ProxyRoundtrip(targetURL string, data []byte, clientInfo *url...
  function TestSOCKS5Proxy (line 56) | func TestSOCKS5Proxy(t *testing.T) {
  function BenchmarkSOCKS5Proxy (line 81) | func BenchmarkSOCKS5Proxy(b *testing.B) {
  function BenchmarkSOCKS5ProxyParallel (line 113) | func BenchmarkSOCKS5ProxyParallel(b *testing.B) {
  function socks4ProxyRoundtrip (line 147) | func socks4ProxyRoundtrip(targetURL string, data []byte) error {
  function TestSOCKS4Proxy (line 168) | func TestSOCKS4Proxy(t *testing.T) {
  function BenchmarkSOCKS4Proxy (line 182) | func BenchmarkSOCKS4Proxy(b *testing.B) {
  function BenchmarkSOCKS4ProxyParallel (line 213) | func BenchmarkSOCKS4ProxyParallel(b *testing.B) {
  function socks4aProxyRoundtrip (line 246) | func socks4aProxyRoundtrip(targetURL string, data []byte) error {
  function TestSOCKS4AProxy (line 268) | func TestSOCKS4AProxy(t *testing.T) {
  function BenchmarkSOCKS4AProxy (line 282) | func BenchmarkSOCKS4AProxy(b *testing.B) {
  function BenchmarkSOCKS4AProxyParallel (line 314) | func BenchmarkSOCKS4AProxyParallel(b *testing.B) {
  function socks5BindRoundtrip (line 348) | func socks5BindRoundtrip(t *testing.T, targetURL string, data []byte) (e...
  function TestSOCKS5Bind (line 401) | func TestSOCKS5Bind(t *testing.T) {
  function socks5MuxBindRoundtrip (line 413) | func socks5MuxBindRoundtrip(t *testing.T, targetURL string, data []byte)...
  function muxBindRoundtrip (line 442) | func muxBindRoundtrip(client *Client, server *Server, bindAddr, targetUR...
  function TestSOCKS5MuxBind (line 484) | func TestSOCKS5MuxBind(t *testing.T) {
  function BenchmarkSOCKS5MuxBind (line 496) | func BenchmarkSOCKS5MuxBind(b *testing.B) {
  function socks5UDPRoundtrip (line 535) | func socks5UDPRoundtrip(t *testing.T, host string, data []byte) (err err...
  function TestSOCKS5UDP (line 556) | func TestSOCKS5UDP(t *testing.T) {
  function BenchmarkSOCKS5UDP (line 570) | func BenchmarkSOCKS5UDP(b *testing.B) {
  function BenchmarkSOCKS5UDPSingleConn (line 602) | func BenchmarkSOCKS5UDPSingleConn(b *testing.B) {
  function socks5UDPTunRoundtrip (line 664) | func socks5UDPTunRoundtrip(t *testing.T, host string, data []byte) (err ...
  function TestSOCKS5UDPTun (line 685) | func TestSOCKS5UDPTun(t *testing.T) {
  function BenchmarkSOCKS5UDPTun (line 698) | func BenchmarkSOCKS5UDPTun(b *testing.B) {
  function BenchmarkSOCKS5UDPTunSingleConn (line 730) | func BenchmarkSOCKS5UDPTunSingleConn(b *testing.B) {

FILE: ss.go
  constant maxSocksAddrLen (line 20) | maxSocksAddrLen = 259
  type shadowConnector (line 28) | type shadowConnector struct
    method Connect (line 40) | func (c *shadowConnector) Connect(conn net.Conn, address string, optio...
    method ConnectContext (line 44) | func (c *shadowConnector) ConnectContext(ctx context.Context, conn net...
  function ShadowConnector (line 34) | func ShadowConnector(info *url.Userinfo) Connector {
  type shadowHandler (line 95) | type shadowHandler struct
    method Init (line 108) | func (h *shadowHandler) Init(options ...HandlerOption) {
    method Handle (line 121) | func (h *shadowHandler) Handle(conn net.Conn) {
  function ShadowHandler (line 101) | func ShadowHandler(opts ...HandlerOption) Handler {
  type shadowUDPConnector (line 206) | type shadowUDPConnector struct
    method Connect (line 218) | func (c *shadowUDPConnector) Connect(conn net.Conn, address string, op...
    method ConnectContext (line 222) | func (c *shadowUDPConnector) ConnectContext(ctx context.Context, conn ...
  function ShadowUDPConnector (line 212) | func ShadowUDPConnector(info *url.Userinfo) Connector {
  type shadowUDPHandler (line 271) | type shadowUDPHandler struct
    method Init (line 284) | func (h *shadowUDPHandler) Init(options ...HandlerOption) {
    method Handle (line 296) | func (h *shadowUDPHandler) Handle(conn net.Conn) {
    method transportPacket (line 336) | func (h *shadowUDPHandler) transportPacket(conn, cc net.PacketConn) (e...
    method transportUDP (line 418) | func (h *shadowUDPHandler) transportUDP(conn net.Conn, cc net.PacketCo...
  function ShadowUDPHandler (line 277) | func ShadowUDPHandler(opts ...HandlerOption) Handler {
  type shadowConn (line 493) | type shadowConn struct
    method Write (line 498) | func (c *shadowConn) Write(b []byte) (n int, err error) {
  type shadowUDPPacketConn (line 510) | type shadowUDPPacketConn struct
    method ReadFrom (line 516) | func (c *shadowUDPPacketConn) ReadFrom(b []byte) (n int, addr net.Addr...
    method Read (line 540) | func (c *shadowUDPPacketConn) Read(b []byte) (n int, err error) {
    method WriteTo (line 545) | func (c *shadowUDPPacketConn) WriteTo(b []byte, addr net.Addr) (n int,...
    method Write (line 566) | func (c *shadowUDPPacketConn) Write(b []byte) (n int, err error) {
    method RemoteAddr (line 570) | func (c *shadowUDPPacketConn) RemoteAddr() net.Addr {
  type shadowCipher (line 574) | type shadowCipher struct
    method StreamConn (line 578) | func (c *shadowCipher) StreamConn(conn net.Conn) net.Conn {
    method PacketConn (line 582) | func (c *shadowCipher) PacketConn(conn net.PacketConn) net.PacketConn {
  function initShadowCipher (line 586) | func initShadowCipher(info *url.Userinfo) (cipher core.Cipher) {
  function readSocksAddr (line 612) | func readSocksAddr(r io.Reader) (*gosocks5.Addr, error) {

FILE: ss_test.go
  function init (line 13) | func init() {
  function ssProxyRoundtrip (line 157) | func ssProxyRoundtrip(targetURL string, data []byte, clientInfo *url.Use...
  function TestShadowTCP (line 179) | func TestShadowTCP(t *testing.T) {
  function BenchmarkSSProxy_AES256 (line 207) | func BenchmarkSSProxy_AES256(b *testing.B) {
  function BenchmarkSSProxy_Chacha20 (line 239) | func BenchmarkSSProxy_Chacha20(b *testing.B) {
  function BenchmarkSSProxy_Chacha20_ietf (line 271) | func BenchmarkSSProxy_Chacha20_ietf(b *testing.B) {
  function BenchmarkSSProxyParallel (line 303) | func BenchmarkSSProxyParallel(b *testing.B) {
  function shadowUDPRoundtrip (line 456) | func shadowUDPRoundtrip(t *testing.T, host string, data []byte,
  function TestShadowUDP (line 481) | func TestShadowUDP(t *testing.T) {
  function BenchmarkShadowUDP (line 510) | func BenchmarkShadowUDP(b *testing.B) {

FILE: ssh.go
  constant DirectForwardRequest (line 22) | DirectForwardRequest       = "direct-tcpip"
  constant RemoteForwardRequest (line 23) | RemoteForwardRequest       = "tcpip-forward"
  constant ForwardedTCPReturnRequest (line 24) | ForwardedTCPReturnRequest  = "forwarded-tcpip"
  constant CancelRemoteForwardRequest (line 25) | CancelRemoteForwardRequest = "cancel-tcpip-forward"
  constant GostSSHTunnelRequest (line 27) | GostSSHTunnelRequest = "gost-tunnel"
  function ParseSSHKeyFile (line 33) | func ParseSSHKeyFile(fp string) (ssh.Signer, error) {
  function ParseSSHAuthorizedKeysFile (line 42) | func ParseSSHAuthorizedKeysFile(fp string) (map[string]bool, error) {
  type sshDirectForwardConnector (line 60) | type sshDirectForwardConnector struct
    method Connect (line 67) | func (c *sshDirectForwardConnector) Connect(conn net.Conn, raddr strin...
    method ConnectContext (line 71) | func (c *sshDirectForwardConnector) ConnectContext(ctx context.Context...
  function SSHDirectForwardConnector (line 63) | func SSHDirectForwardConnector() Connector {
  type sshRemoteForwardConnector (line 103) | type sshRemoteForwardConnector struct
    method Connect (line 110) | func (c *sshRemoteForwardConnector) Connect(conn net.Conn, address str...
    method ConnectContext (line 114) | func (c *sshRemoteForwardConnector) ConnectContext(ctx context.Context...
  function SSHRemoteForwardConnector (line 106) | func SSHRemoteForwardConnector() Connector {
  type sshForwardTransporter (line 166) | type sshForwardTransporter struct
    method Dial (line 178) | func (tr *sshForwardTransporter) Dial(addr string, options ...DialOpti...
    method Handshake (line 212) | func (tr *sshForwardTransporter) Handshake(conn net.Conn, options ...H...
    method Multiplex (line 276) | func (tr *sshForwardTransporter) Multiplex() bool {
  function SSHForwardTransporter (line 172) | func SSHForwardTransporter() Transporter {
  type sshTunnelTransporter (line 280) | type sshTunnelTransporter struct
    method Dial (line 292) | func (tr *sshTunnelTransporter) Dial(addr string, options ...DialOptio...
    method Handshake (line 326) | func (tr *sshTunnelTransporter) Handshake(conn net.Conn, options ...Ha...
    method Multiplex (line 394) | func (tr *sshTunnelTransporter) Multiplex() bool {
  function SSHTunnelTransporter (line 286) | func SSHTunnelTransporter() Transporter {
  type sshSession (line 398) | type sshSession struct
    method Ping (line 408) | func (s *sshSession) Ping(interval, timeout time.Duration, retries int) {
    method sendPing (line 461) | func (s *sshSession) sendPing() <-chan error {
    method waitServer (line 472) | func (s *sshSession) waitServer() error {
    method waitClose (line 477) | func (s *sshSession) waitClose() {
    method Closed (line 486) | func (s *sshSession) Closed() bool {
  type sshForwardHandler (line 497) | type sshForwardHandler struct
    method Init (line 510) | func (h *sshForwardHandler) Init(options ...HandlerOption) {
    method Handle (line 537) | func (h *sshForwardHandler) Handle(conn net.Conn) {
    method handleForward (line 551) | func (h *sshForwardHandler) handleForward(conn ssh.Conn, chans <-chan ...
    method directPortForwardChannel (line 599) | func (h *sshForwardHandler) directPortForwardChannel(channel ssh.Chann...
    method tcpipForwardRequest (line 637) | func (h *sshForwardHandler) tcpipForwardRequest(sshConn ssh.Conn, req ...
  function SSHForwardHandler (line 503) | func SSHForwardHandler(opts ...HandlerOption) Handler {
  type tcpipForward (line 632) | type tcpipForward struct
  type SSHConfig (line 718) | type SSHConfig struct
  type sshTunnelListener (line 725) | type sshTunnelListener struct
    method listenLoop (line 774) | func (l *sshTunnelListener) listenLoop() {
    method serveConn (line 787) | func (l *sshTunnelListener) serveConn(conn net.Conn) {
    method Accept (line 829) | func (l *sshTunnelListener) Accept() (conn net.Conn, err error) {
  function SSHTunnelListener (line 733) | func SSHTunnelListener(addr string, config *SSHConfig) (Listener, error) {
  type directForward (line 842) | type directForward struct
    method String (line 849) | func (p directForward) String() string {
  function getHostPortFromAddr (line 853) | func getHostPortFromAddr(addr net.Addr) (host string, port int, err erro...
  type PasswordCallbackFunc (line 864) | type PasswordCallbackFunc
  function defaultSSHPasswordCallback (line 866) | func defaultSSHPasswordCallback(au Authenticator) PasswordCallbackFunc {
  type PublicKeyCallbackFunc (line 881) | type PublicKeyCallbackFunc
  function defaultSSHPublicKeyCallback (line 883) | func defaultSSHPublicKeyCallback(keys map[string]bool) PublicKeyCallback...
  type sshNopConn (line 901) | type sshNopConn struct
    method Read (line 905) | func (c *sshNopConn) Read(b []byte) (n int, err error) {
    method Write (line 909) | func (c *sshNopConn) Write(b []byte) (n int, err error) {
    method Close (line 913) | func (c *sshNopConn) Close() error {
    method LocalAddr (line 917) | func (c *sshNopConn) LocalAddr() net.Addr {
    method RemoteAddr (line 924) | func (c *sshNopConn) RemoteAddr() net.Addr {
    method SetDeadline (line 931) | func (c *sshNopConn) SetDeadline(t time.Time) error {
    method SetReadDeadline (line 935) | func (c *sshNopConn) SetReadDeadline(t time.Time) error {
    method SetWriteDeadline (line 939) | func (c *sshNopConn) SetWriteDeadline(t time.Time) error {
  type sshConn (line 943) | type sshConn struct
    method Read (line 948) | func (c *sshConn) Read(b []byte) (n int, err error) {
    method Write (line 952) | func (c *sshConn) Write(b []byte) (n int, err error) {
    method Close (line 956) | func (c *sshConn) Close() error {
    method LocalAddr (line 960) | func (c *sshConn) LocalAddr() net.Addr {
    method RemoteAddr (line 964) | func (c *sshConn) RemoteAddr() net.Addr {
    method SetDeadline (line 968) | func (c *sshConn) SetDeadline(t time.Time) error {
    method SetReadDeadline (line 972) | func (c *sshConn) SetReadDeadline(t time.Time) error {
    method SetWriteDeadline (line 976) | func (c *sshConn) SetWriteDeadline(t time.Time) error {

FILE: ssh_test.go
  function sshDirectForwardRoundtrip (line 13) | func sshDirectForwardRoundtrip(targetURL string, data []byte) error {
  function TestSSHDirectForward (line 35) | func TestSSHDirectForward(t *testing.T) {
  function BenchmarkSSHDirectForward (line 48) | func BenchmarkSSHDirectForward(b *testing.B) {
  function BenchmarkSSHDirectForwardParallel (line 80) | func BenchmarkSSHDirectForwardParallel(b *testing.B) {
  function sshRemoteForwardRoundtrip (line 114) | func sshRemoteForwardRoundtrip(t *testing.T, targetURL string, data []by...
  function _TestSSHRemoteForward (line 170) | func _TestSSHRemoteForward(t *testing.T) {
  function httpOverSSHTunnelRoundtrip (line 183) | func httpOverSSHTunnelRoundtrip(targetURL string, data []byte, tlsConfig...
  function TestHTTPOverSSHTunnel (line 209) | func TestHTTPOverSSHTunnel(t *testing.T) {
  function BenchmarkHTTPOverSSHTunnel (line 233) | func BenchmarkHTTPOverSSHTunnel(b *testing.B) {
  function BenchmarkHTTPOverSSHTunnelParallel (line 266) | func BenchmarkHTTPOverSSHTunnelParallel(b *testing.B) {
  function socks5OverSSHTunnelRoundtrip (line 301) | func socks5OverSSHTunnelRoundtrip(targetURL string, data []byte, tlsConf...
  function TestSOCKS5OverSSHTunnel (line 327) | func TestSOCKS5OverSSHTunnel(t *testing.T) {
  function socks4OverSSHTunnelRoundtrip (line 353) | func socks4OverSSHTunnelRoundtrip(targetURL string, data []byte, tlsConf...
  function TestSOCKS4OverSSHTunnel (line 375) | func TestSOCKS4OverSSHTunnel(t *testing.T) {
  function socks4aOverSSHTunnelRoundtrip (line 389) | func socks4aOverSSHTunnelRoundtrip(targetURL string, data []byte, tlsCon...
  function TestSOCKS4AOverSSHTunnel (line 411) | func TestSOCKS4AOverSSHTunnel(t *testing.T) {
  function ssOverSSHTunnelRoundtrip (line 425) | func ssOverSSHTunnelRoundtrip(targetURL string, data []byte, tlsConfig *...
  function TestSSOverSSHTunnel (line 451) | func TestSSOverSSHTunnel(t *testing.T) {
  function sniOverSSHTunnelRoundtrip (line 477) | func sniOverSSHTunnelRoundtrip(targetURL string, data []byte, host strin...
  function TestSNIOverSSHTunnel (line 504) | func TestSNIOverSSHTunnel(t *testing.T) {
  function sshForwardTunnelRoundtrip (line 542) | func sshForwardTunnelRoundtrip(targetURL string, data []byte) error {
  function TestSSHForwardTunnel (line 570) | func TestSSHForwardTunnel(t *testing.T) {

FILE: tcp.go
  type tcpTransporter (line 6) | type tcpTransporter struct
    method Dial (line 13) | func (tr *tcpTransporter) Dial(addr string, options ...DialOption) (ne...
    method Handshake (line 29) | func (tr *tcpTransporter) Handshake(conn net.Conn, options ...Handshak...
    method Multiplex (line 33) | func (tr *tcpTransporter) Multiplex() bool {
  function TCPTransporter (line 9) | func TCPTransporter() Transporter {
  type tcpListener (line 37) | type tcpListener struct
  function TCPListener (line 42) | func TCPListener(addr string) (Listener, error) {
  type tcpKeepAliveListener (line 54) | type tcpKeepAliveListener struct
    method Accept (line 58) | func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {

FILE: tls.go
  type tlsTransporter (line 15) | type tlsTransporter struct
    method Handshake (line 24) | func (tr *tlsTransporter) Handshake(conn net.Conn, options ...Handshak...
  function TLSTransporter (line 20) | func TLSTransporter() Transporter {
  type mtlsTransporter (line 41) | type mtlsTransporter struct
    method Dial (line 54) | func (tr *mtlsTransporter) Dial(addr string, options ...DialOption) (c...
    method Handshake (line 88) | func (tr *mtlsTransporter) Handshake(conn net.Conn, options ...Handsha...
    method initSession (line 126) | func (tr *mtlsTransporter) initSession(addr string, conn net.Conn, opt...
    method Multiplex (line 147) | func (tr *mtlsTransporter) Multiplex() bool {
  function MTLSTransporter (line 48) | func MTLSTransporter() Transporter {
  type tlsListener (line 151) | type tlsListener struct
  function TLSListener (line 156) | func TLSListener(addr string, config *tls.Config) (Listener, error) {
  type mtlsListener (line 169) | type mtlsListener struct
    method listenLoop (line 195) | func (l *mtlsListener) listenLoop() {
    method mux (line 208) | func (l *mtlsListener) mux(conn net.Conn) {
    method Accept (line 238) | func (l *mtlsListener) Accept() (conn net.Conn, err error) {
    method Addr (line 249) | func (l *mtlsListener) Addr() net.Addr {
    method Close (line 253) | func (l *mtlsListener) Close() error {
  function MTLSListener (line 176) | func MTLSListener(addr string, config *tls.Config) (Listener, error) {
  function wrapTLSClient (line 270) | func wrapTLSClient(conn net.Conn, tlsConfig *tls.Config, timeout time.Du...

FILE: tls_test.go
  function httpOverTLSRoundtrip (line 12) | func httpOverTLSRoundtrip(targetURL string, data []byte, tlsConfig *tls....
  function TestHTTPOverTLS (line 38) | func TestHTTPOverTLS(t *testing.T) {
  function BenchmarkHTTPOverTLS (line 62) | func BenchmarkHTTPOverTLS(b *testing.B) {
  function BenchmarkHTTPOverTLSParallel (line 95) | func BenchmarkHTTPOverTLSParallel(b *testing.B) {
  function socks5OverTLSRoundtrip (line 130) | func socks5OverTLSRoundtrip(targetURL string, data []byte, tlsConfig *tl...
  function TestSOCKS5OverTLS (line 156) | func TestSOCKS5OverTLS(t *testing.T) {
  function socks4OverTLSRoundtrip (line 182) | func socks4OverTLSRoundtrip(targetURL string, data []byte, tlsConfig *tl...
  function TestSOCKS4OverTLS (line 204) | func TestSOCKS4OverTLS(t *testing.T) {
  function socks4aOverTLSRoundtrip (line 218) | func socks4aOverTLSRoundtrip(targetURL string, data []byte, tlsConfig *t...
  function TestSOCKS4AOverTLS (line 240) | func TestSOCKS4AOverTLS(t *testing.T) {
  function ssOverTLSRoundtrip (line 254) | func ssOverTLSRoundtrip(targetURL string, data []byte, tlsConfig *tls.Co...
  function TestSSOverTLS (line 280) | func TestSSOverTLS(t *testing.T) {
  function sniOverTLSRoundtrip (line 306) | func sniOverTLSRoundtrip(targetURL string, data []byte, host string) err...
  function TestSNIOverTLS (line 333) | func TestSNIOverTLS(t *testing.T) {
  function tlsForwardTunnelRoundtrip (line 371) | func tlsForwardTunnelRoundtrip(targetURL string, data []byte) error {
  function TestTLSForwardTunnel (line 399) | func TestTLSForwardTunnel(t *testing.T) {
  function httpOverMTLSRoundtrip (line 412) | func httpOverMTLSRoundtrip(targetURL string, data []byte, tlsConfig *tls...
  function TestHTTPOverMTLS (line 438) | func TestHTTPOverMTLS(t *testing.T) {
  function BenchmarkHTTPOverMTLS (line 462) | func BenchmarkHTTPOverMTLS(b *testing.B) {
  function BenchmarkHTTPOverMTLSParallel (line 495) | func BenchmarkHTTPOverMTLSParallel(b *testing.B) {
  function socks5OverMTLSRoundtrip (line 530) | func socks5OverMTLSRoundtrip(targetURL string, data []byte, tlsConfig *t...
  function TestSOCKS5OverMTLS (line 556) | func TestSOCKS5OverMTLS(t *testing.T) {
  function socks4OverMTLSRoundtrip (line 582) | func socks4OverMTLSRoundtrip(targetURL string, data []byte, tlsConfig *t...
  function TestSOCKS4OverMTLS (line 604) | func TestSOCKS4OverMTLS(t *testing.T) {
  function socks4aOverMTLSRoundtrip (line 618) | func socks4aOverMTLSRoundtrip(targetURL string, data []byte, tlsConfig *...
  function TestSOCKS4AOverMTLS (line 640) | func TestSOCKS4AOverMTLS(t *testing.T) {
  function ssOverMTLSRoundtrip (line 654) | func ssOverMTLSRoundtrip(targetURL string, data []byte, tlsConfig *tls.C...
  function TestSSOverMTLS (line 680) | func TestSSOverMTLS(t *testing.T) {
  function sniOverMTLSRoundtrip (line 706) | func sniOverMTLSRoundtrip(targetURL string, data []byte, host string) er...
  function TestSNIOverMTLS (line 733) | func TestSNIOverMTLS(t *testing.T) {
  function mtlsForwardTunnelRoundtrip (line 771) | func mtlsForwardTunnelRoundtrip(targetURL string, data []byte) error {
  function TestMTLSForwardTunnel (line 799) | func TestMTLSForwardTunnel(t *testing.T) {

FILE: tuntap.go
  function ipProtocol (line 35) | func ipProtocol(p waterutil.IPProtocol) string {
  type IPRoute (line 43) | type IPRoute struct
  type TunConfig (line 49) | type TunConfig struct
  type tunRouteKey (line 58) | type tunRouteKey
  function ipToTunRouteKey (line 60) | func ipToTunRouteKey(ip net.IP) (key tunRouteKey) {
  type tunListener (line 65) | type tunListener struct
    method Accept (line 98) | func (l *tunListener) Accept() (net.Conn, error) {
    method Addr (line 108) | func (l *tunListener) Addr() net.Addr {
    method Close (line 112) | func (l *tunListener) Close() error {
  function TunListener (line 73) | func TunListener(cfg TunConfig) (Listener, error) {
  type tunHandler (line 122) | type tunHandler struct
    method Init (line 141) | func (h *tunHandler) Init(options ...HandlerOption) {
    method Handle (line 150) | func (h *tunHandler) Handle(conn net.Conn) {
    method initTunnelConn (line 231) | func (h *tunHandler) initTunnelConn(pc net.PacketConn) (net.PacketConn...
    method findRouteFor (line 243) | func (h *tunHandler) findRouteFor(dst net.IP) net.Addr {
    method transportTun (line 257) | func (h *tunHandler) transportTun(tun net.Conn, conn net.PacketConn, r...
  function TunHandler (line 129) | func TunHandler(opts ...HandlerOption) Handler {
  function etherType (line 433) | func etherType(et waterutil.Ethertype) string {
  type TapConfig (line 441) | type TapConfig struct
  type tapRouteKey (line 449) | type tapRouteKey
  function hwAddrToTapRouteKey (line 451) | func hwAddrToTapRouteKey(addr net.HardwareAddr) (key tapRouteKey) {
  type tapListener (line 456) | type tapListener struct
    method Accept (line 488) | func (l *tapListener) Accept() (net.Conn, error) {
    method Addr (line 498) | func (l *tapListener) Addr() net.Addr {
    method Close (line 502) | func (l *tapListener) Close() error {
  function TapListener (line 464) | func TapListener(cfg TapConfig) (Listener, error) {
  type tapHandler (line 512) | type tapHandler struct
    method Init (line 531) | func (h *tapHandler) Init(options ...HandlerOption) {
    method Handle (line 540) | func (h *tapHandler) Handle(conn net.Conn) {
    method initTunnelConn (line 621) | func (h *tapHandler) initTunnelConn(pc net.PacketConn) (net.PacketConn...
    method transportTap (line 633) | func (h *tapHandler) transportTap(tap net.Conn, conn net.PacketConn, r...
  function TapHandler (line 519) | func TapHandler(opts ...HandlerOption) Handler {
  type tunTapConn (line 775) | type tunTapConn struct
    method Read (line 780) | func (c *tunTapConn) Read(b []byte) (n int, err error) {
    method Write (line 784) | func (c *tunTapConn) Write(b []byte) (n int, err error) {
    method Close (line 788) | func (c *tunTapConn) Close() (err error) {
    method LocalAddr (line 792) | func (c *tunTapConn) LocalAddr() net.Addr {
    method RemoteAddr (line 796) | func (c *tunTapConn) RemoteAddr() net.Addr {
    method SetDeadline (line 800) | func (c *tunTapConn) SetDeadline(t time.Time) error {
    method SetReadDeadline (line 804) | func (c *tunTapConn) SetReadDeadline(t time.Time) error {
    method SetWriteDeadline (line 808) | func (c *tunTapConn) SetWriteDeadline(t time.Time) error {
  function IsIPv6Multicast (line 813) | func IsIPv6Multicast(addr net.HardwareAddr) bool {

FILE: tuntap_darwin.go
  function createTun (line 14) | func createTun(cfg TunConfig) (conn net.Conn, itf *net.Interface, err er...
  function createTap (line 61) | func createTap(cfg TapConfig) (conn net.Conn, itf *net.Interface, err er...
  function addTunRoutes (line 66) | func addTunRoutes(ifName string, routes ...IPRoute) error {

FILE: tuntap_linux.go
  function createTun (line 13) | func createTun(cfg TunConfig) (conn net.Conn, itf *net.Interface, err er...
  function createTap (line 62) | func createTap(cfg TapConfig) (conn net.Conn, itf *net.Interface, err er...
  function addTunRoutes (line 116) | func addTunRoutes(ifName string, routes ...IPRoute) error {
  function addTapRoutes (line 132) | func addTapRoutes(ifName string, gw string, routes ...string) error {
  function exeCmd (line 148) | func exeCmd(cmd string) error {

FILE: tuntap_unix.go
  function createTun (line 16) | func createTun(cfg TunConfig) (conn net.Conn, itf *net.Interface, err er...
  function createTap (line 58) | func createTap(cfg TapConfig) (conn net.Conn, itf *net.Interface, err er...
  function addTunRoutes (line 102) | func addTunRoutes(ifName string, routes ...IPRoute) error {
  function addTapRoutes (line 117) | func addTapRoutes(ifName string, gw string, routes ...string) error {

FILE: tuntap_windows.go
  function createTun (line 13) | func createTun(cfg TunConfig) (conn net.Conn, itf *net.Interface, err er...
  function createTap (line 57) | func createTap(cfg TapConfig) (conn net.Conn, itf *net.Interface, err er...
  function addTunRoutes (line 100) | func addTunRoutes(ifName string, gw string, routes ...IPRoute) error {
  function addTapRoutes (line 122) | func addTapRoutes(ifName string, gw string, routes ...string) error {
  function deleteRoute (line 144) | func deleteRoute(ifName string, route string) error {
  function ipMask (line 151) | func ipMask(mask net.IPMask) string {

FILE: udp.go
  type udpTransporter (line 14) | type udpTransporter struct
    method Dial (line 21) | func (tr *udpTransporter) Dial(addr string, options ...DialOption) (ne...
    method Handshake (line 36) | func (tr *udpTransporter) Handshake(conn net.Conn, options ...Handshak...
    method Multiplex (line 40) | func (tr *udpTransporter) Multiplex() bool {
  function UDPTransporter (line 17) | func UDPTransporter() Transporter {
  type UDPListenConfig (line 45) | type UDPListenConfig struct
  type udpListener (line 51) | type udpListener struct
    method listenLoop (line 90) | func (l *udpListener) listenLoop() {
    method Accept (line 136) | func (l *udpListener) Accept() (conn net.Conn, err error) {
    method Addr (line 148) | func (l *udpListener) Addr() net.Addr {
    method Close (line 152) | func (l *udpListener) Close() error {
  function UDPListener (line 60) | func UDPListener(addr string, cfg *UDPListenConfig) (Listener, error) {
  type udpConnMap (line 162) | type udpConnMap struct
    method Get (line 167) | func (m *udpConnMap) Get(key interface{}) (conn *udpServerConn, ok boo...
    method Set (line 175) | func (m *udpConnMap) Set(key interface{}, conn *udpServerConn) {
    method Delete (line 180) | func (m *udpConnMap) Delete(key interface{}) {
    method Range (line 185) | func (m *udpConnMap) Range(f func(key interface{}, value *udpServerCon...
    method Size (line 191) | func (m *udpConnMap) Size() int64 {
  type udpServerConn (line 196) | type udpServerConn struct
    method Read (line 236) | func (c *udpServerConn) Read(b []byte) (n int, err error) {
    method ReadFrom (line 241) | func (c *udpServerConn) ReadFrom(b []byte) (n int, addr net.Addr, err ...
    method Write (line 263) | func (c *udpServerConn) Write(b []byte) (n int, err error) {
    method WriteTo (line 267) | func (c *udpServerConn) WriteTo(b []byte, addr net.Addr) (n int, err e...
    method Close (line 284) | func (c *udpServerConn) Close() error {
    method ttlWait (line 300) | func (c *udpServerConn) ttlWait() {
    method LocalAddr (line 324) | func (c *udpServerConn) LocalAddr() net.Addr {
    method RemoteAddr (line 328) | func (c *udpServerConn) RemoteAddr() net.Addr {
    method SetDeadline (line 332) | func (c *udpServerConn) SetDeadline(t time.Time) error {
    method SetReadDeadline (line 336) | func (c *udpServerConn) SetReadDeadline(t time.Time) error {
    method SetWriteDeadline (line 340) | func (c *udpServerConn) SetWriteDeadline(t time.Time) error {
  type udpServerConnConfig (line 206) | type udpServerConnConfig struct
  function newUDPServerConn (line 212) | func newUDPServerConn(conn net.PacketConn, raddr net.Addr, cfg *udpServe...
  type udpClientConn (line 344) | type udpClientConn struct
    method WriteTo (line 348) | func (c *udpClientConn) WriteTo(b []byte, addr net.Addr) (int, error) {
    method ReadFrom (line 352) | func (c *udpClientConn) ReadFrom(b []byte) (n int, addr net.Addr, err ...

FILE: vsock.go
  type vsockTransporter (line 11) | type vsockTransporter struct
    method Dial (line 18) | func (tr *vsockTransporter) Dial(addr string, options ...DialOption) (...
    method Handshake (line 61) | func (tr *vsockTransporter) Handshake(conn net.Conn, options ...Handsh...
    method Multiplex (line 65) | func (tr *vsockTransporter) Multiplex() bool {
  function VSOCKTransporter (line 14) | func VSOCKTransporter() Transporter {
  function parseUint32 (line 33) | func parseUint32(s string) (uint32, error ) {
  function parseAddr (line 41) | func parseAddr(addr string) (*vsock.Addr, error) {
  function VSOCKListener (line 70) | func VSOCKListener(addr string) (Listener, error) {

FILE: ws.go
  constant defaultWSPath (line 23) | defaultWSPath = "/ws"
  type WSOptions (line 27) | type WSOptions struct
  type wsTransporter (line 36) | type wsTransporter struct
    method Handshake (line 48) | func (tr *wsTransporter) Handshake(conn net.Conn, options ...Handshake...
  function WSTransporter (line 42) | func WSTransporter(opts *WSOptions) Transporter {
  type mwsTransporter (line 69) | type mwsTransporter struct
    method Dial (line 84) | func (tr *mwsTransporter) Dial(addr string, options ...DialOption) (co...
    method Handshake (line 118) | func (tr *mwsTransporter) Handshake(conn net.Conn, options ...Handshak...
    method initSession (line 156) | func (tr *mwsTransporter) initSession(addr string, conn net.Conn, opts...
    method Multiplex (line 186) | func (tr *mwsTransporter) Multiplex() bool {
  function MWSTransporter (line 77) | func MWSTransporter(opts *WSOptions) Transporter {
  type wssTransporter (line 190) | type wssTransporter struct
    method Handshake (line 202) | func (tr *wssTransporter) Handshake(conn net.Conn, options ...Handshak...
  function WSSTransporter (line 196) | func WSSTransporter(opts *WSOptions) Transporter {
  type mwssTransporter (line 226) | type mwssTransporter struct
    method Dial (line 241) | func (tr *mwssTransporter) Dial(addr string, options ...DialOption) (c...
    method Handshake (line 275) | func (tr *mwssTransporter) Handshake(conn net.Conn, options ...Handsha...
    method initSession (line 312) | func (tr *mwssTransporter) initSession(addr string, conn net.Conn, opt...
    method Multiplex (line 346) | func (tr *mwssTransporter) Multiplex() bool {
  function MWSSTransporter (line 234) | func MWSSTransporter(opts *WSOptions) Transporter {
  type wsListener (line 350) | type wsListener struct
    method upgrade (line 412) | func (l *wsListener) upgrade(w http.ResponseWriter, r *http.Request) {
    method Accept (line 431) | func (l *wsListener) Accept() (conn net.Conn, err error) {
    method Close (line 439) | func (l *wsListener) Close() error {
    method Addr (line 443) | func (l *wsListener) Addr() net.Addr {
  function WSListener (line 359) | func WSListener(addr string, options *WSOptions) (Listener, error) {
  type mwsListener (line 447) | type mwsListener struct
    method upgrade (line 510) | func (l *mwsListener) upgrade(w http.ResponseWriter, r *http.Request) {
    method mux (line 525) | func (l *mwsListener) mux(conn net.Conn) {
    method Accept (line 554) | func (l *mwsListener) Accept() (conn net.Conn, err error) {
    method Close (line 562) | func (l *mwsListener) Close() error {
    method Addr (line 566) | func (l *mwsListener) Addr() net.Addr {
  function MWSListener (line 456) | func MWSListener(addr string, options *WSOptions) (Listener, error) {
  type wssListener (line 570) | type wssListener struct
  function WSSListener (line 575) | func WSSListener(addr string, tlsConfig *tls.Config, options *WSOptions)...
  type mwssListener (line 636) | type mwssListener struct
  function MWSSListener (line 641) | func MWSSListener(addr string, tlsConfig *tls.Config, options *WSOptions...
  function computeAcceptKey (line 704) | func computeAcceptKey(challengeKey string) string {
  function generateChallengeKey (line 711) | func generateChallengeKey() (string, error) {
  type websocketConn (line 722) | type websocketConn struct
    method Read (line 767) | func (c *websocketConn) Read(b []byte) (n int, err error) {
    method Write (line 776) | func (c *websocketConn) Write(b []byte) (n int, err error) {
    method Close (line 782) | func (c *websocketConn) Close() error {
    method LocalAddr (line 786) | func (c *websocketConn) LocalAddr() net.Addr {
    method RemoteAddr (line 790) | func (c *websocketConn) RemoteAddr() net.Addr {
    method SetDeadline (line 794) | func (c *websocketConn) SetDeadline(t time.Time) error {
    method SetReadDeadline (line 800) | func (c *websocketConn) SetReadDeadline(t time.Time) error {
    method SetWriteDeadline (line 804) | func (c *websocketConn) SetWriteDeadline(t time.Time) error {
  function websocketClientConn (line 727) | func websocketClientConn(url string, conn net.Conn, tlsConfig *tls.Confi...
  function websocketServerConn (line 760) | func websocketServerConn(conn *websocket.Conn) net.Conn {

FILE: ws_test.go
  function httpOverWSRoundtrip (line 11) | func httpOverWSRoundtrip(targetURL string, data []byte,
  function TestHTTPOverWS (line 37) | func TestHTTPOverWS(t *testing.T) {
  function BenchmarkHTTPOverWS (line 61) | func BenchmarkHTTPOverWS(b *testing.B) {
  function BenchmarkHTTPOverWSParallel (line 94) | func BenchmarkHTTPOverWSParallel(b *testing.B) {
  function socks5OverWSRoundtrip (line 129) | func socks5OverWSRoundtrip(targetURL string, data []byte,
  function TestSOCKS5OverWS (line 155) | func TestSOCKS5OverWS(t *testing.T) {
  function socks4OverWSRoundtrip (line 180) | func socks4OverWSRoundtrip(targetURL string, data []byte) error {
  function TestSOCKS4OverWS (line 202) | func TestSOCKS4OverWS(t *testing.T) {
  function socks4aOverWSRoundtrip (line 216) | func socks4aOverWSRoundtrip(targetURL string, data []byte) error {
  function TestSOCKS4AOverWS (line 238) | func TestSOCKS4AOverWS(t *testing.T) {
  function ssOverWSRoundtrip (line 253) | func ssOverWSRoundtrip(targetURL string, data []byte,
  function TestSSOverWS (line 279) | func TestSSOverWS(t *testing.T) {
  function sniOverWSRoundtrip (line 304) | func sniOverWSRoundtrip(targetURL string, data []byte, host string) error {
  function TestSNIOverWS (line 331) | func TestSNIOverWS(t *testing.T) {
  function wsForwardTunnelRoundtrip (line 369) | func wsForwardTunnelRoundtrip(targetURL string, data []byte) error {
  function TestWSForwardTunnel (line 397) | func TestWSForwardTunnel(t *testing.T) {
  function httpOverMWSRoundtrip (line 410) | func httpOverMWSRoundtrip(targetURL string, data []byte,
  function TestHTTPOverMWS (line 436) | func TestHTTPOverMWS(t *testing.T) {
  function BenchmarkHTTPOverMWS (line 460) | func BenchmarkHTTPOverMWS(b *testing.B) {
  function BenchmarkHTTPOverMWSParallel (line 493) | func BenchmarkHTTPOverMWSParallel(b *testing.B) {
  function socks5OverMWSRoundtrip (line 529) | func socks5OverMWSRoundtrip(targetURL string, data []byte,
  function TestSOCKS5OverMWS (line 555) | func TestSOCKS5OverMWS(t *testing.T) {
  function socks4OverMWSRoundtrip (line 580) | func socks4OverMWSRoundtrip(targetURL string, data []byte) error {
  function TestSOCKS4OverMWS (line 602) | func TestSOCKS4OverMWS(t *testing.T) {
  function socks4aOverMWSRoundtrip (line 616) | func socks4aOverMWSRoundtrip(targetURL string, data []byte) error {
  function TestSOCKS4AOverMWS (line 638) | func TestSOCKS4AOverMWS(t *testing.T) {
  function ssOverMWSRoundtrip (line 653) | func ssOverMWSRoundtrip(targetURL string, data []byte,
  function TestSSOverMWS (line 679) | func TestSSOverMWS(t *testing.T) {
  function sniOverMWSRoundtrip (line 704) | func sniOverMWSRoundtrip(targetURL string, data []byte, host string) err...
  function TestSNIOverMWS (line 731) | func TestSNIOverMWS(t *testing.T) {
  function mwsForwardTunnelRoundtrip (line 769) | func mwsForwardTunnelRoundtrip(targetURL string, data []byte) error {
  function TestMWSForwardTunnel (line 797) | func TestMWSForwardTunnel(t *testing.T) {

FILE: wss_test.go
  function httpOverWSSRoundtrip (line 12) | func httpOverWSSRoundtrip(targetURL string, data []byte, tlsConfig *tls....
  function TestHTTPOverWSS (line 38) | func TestHTTPOverWSS(t *testing.T) {
  function BenchmarkHTTPOverWSS (line 62) | func BenchmarkHTTPOverWSS(b *testing.B) {
  function BenchmarkHTTPOverWSSParallel (line 95) | func BenchmarkHTTPOverWSSParallel(b *testing.B) {
  function socks5OverWSSRoundtrip (line 130) | func socks5OverWSSRoundtrip(targetURL string, data []byte,
  function TestSOCKS5OverWSS (line 156) | func TestSOCKS5OverWSS(t *testing.T) {
  function socks4OverWSSRoundtrip (line 181) | func socks4OverWSSRoundtrip(targetURL string, data []byte) error {
  function TestSOCKS4OverWSS (line 203) | func TestSOCKS4OverWSS(t *testing.T) {
  function socks4aOverWSSRoundtrip (line 217) | func socks4aOverWSSRoundtrip(targetURL string, data []byte) error {
  function TestSOCKS4AOverWSS (line 239) | func TestSOCKS4AOverWSS(t *testing.T) {
  function ssOverWSSRoundtrip (line 254) | func ssOverWSSRoundtrip(targetURL string, data []byte,
  function TestSSOverWSS (line 280) | func TestSSOverWSS(t *testing.T) {
  function sniOverWSSRoundtrip (line 305) | func sniOverWSSRoundtrip(targetURL string, data []byte, host string) err...
  function TestSNIOverWSS (line 332) | func TestSNIOverWSS(t *testing.T) {
  function wssForwardTunnelRoundtrip (line 370) | func wssForwardTunnelRoundtrip(targetURL string, data []byte) error {
  function TestWSSForwardTunnel (line 398) | func TestWSSForwardTunnel(t *testing.T) {
  function httpOverMWSSRoundtrip (line 411) | func httpOverMWSSRoundtrip(targetURL string, data []byte,
  function TestHTTPOverMWSS (line 437) | func TestHTTPOverMWSS(t *testing.T) {
  function BenchmarkHTTPOverMWSS (line 461) | func BenchmarkHTTPOverMWSS(b *testing.B) {
  function BenchmarkHTTPOverMWSSParallel (line 494) | func BenchmarkHTTPOverMWSSParallel(b *testing.B) {
  function socks5OverMWSSRoundtrip (line 530) | func socks5OverMWSSRoundtrip(targetURL string, data []byte,
  function TestSOCKS5OverMWSS (line 556) | func TestSOCKS5OverMWSS(t *testing.T) {
  function socks4OverMWSSRoundtrip (line 581) | func socks4OverMWSSRoundtrip(targetURL string, data []byte) error {
  function TestSOCKS4OverMWSS (line 603) | func TestSOCKS4OverMWSS(t *testing.T) {
  function socks4aOverMWSSRoundtrip (line 617) | func socks4aOverMWSSRoundtrip(targetURL string, data []byte) error {
  function TestSOCKS4AOverMWSS (line 639) | func TestSOCKS4AOverMWSS(t *testing.T) {
  function ssOverMWSSRoundtrip (line 654) | func ssOverMWSSRoundtrip(targetURL string, data []byte,
  function TestSSOverMWSS (line 680) | func TestSSOverMWSS(t *testing.T) {
  function sniOverMWSSRoundtrip (line 705) | func sniOverMWSSRoundtrip(targetURL string, data []byte, host string) er...
  function TestSNIOverMWSS (line 732) | func TestSNIOverMWSS(t *testing.T) {
  function mwssForwardTunnelRoundtrip (line 770) | func mwssForwardTunnelRoundtrip(targetURL string, data []byte) error {
  function TestMWSSForwardTunnel (line 798) | func TestMWSSForwardTunnel(t *testing.T) {
Condensed preview — 115 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (794K chars).
[
  {
    "path": ".config/bypass.txt",
    "chars": 1218,
    "preview": "# period for live reloading\nreload      10s\n\n# matcher reversed\n reverse     true\n\n*.example.com\n\n# this will match exam"
  },
  {
    "path": ".config/dns.txt",
    "chars": 384,
    "preview": "# resolver timeout, default 30s.\ntimeout     10s\n\n# resolver cache TTL, \n# minus value means that cache is disabled,\n# d"
  },
  {
    "path": ".config/gost.json",
    "chars": 481,
    "preview": "{\n    \"Retries\": 1,\n    \"Debug\": false,\n    \"ServeNodes\": [\n        \":12345\"\n    ],\n    \"ChainNodes\": [\n        \"http://"
  },
  {
    "path": ".config/hosts.txt",
    "chars": 573,
    "preview": "# period for live reloading\nreload      10s\n\n# The following lines are desirable for IPv4 capable hosts\n127.0.0.1       "
  },
  {
    "path": ".config/kcp.json",
    "chars": 330,
    "preview": "{\n\t\"key\": \"it's a secrect\",\n\t\"crypt\": \"aes\",\n\t\"mode\": \"fast\",\n\t\"mtu\" : 1350,\n\t\"sndwnd\": 1024,\n\t\"rcvwnd\": 1024,\n\t\"datasha"
  },
  {
    "path": ".config/peer.txt",
    "chars": 231,
    "preview": "# strategy for node selecting\nstrategy        random\n\nmax_fails       1\n\nfail_timeout    30s\n\n# period for live reloadin"
  },
  {
    "path": ".config/probe_resist.txt",
    "chars": 12,
    "preview": "Hello World!"
  },
  {
    "path": ".config/secrets.txt",
    "chars": 189,
    "preview": "# period for live reloading\nreload          3s\n\n# username password\n\n$test.admin$ $123456$\n@test.admin@ @123456@\ntest.ad"
  },
  {
    "path": ".dockerignore",
    "chars": 225,
    "preview": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\nrelease\ndebian\ndocs"
  },
  {
    "path": ".github/workflows/buildx.yml",
    "chars": 2368,
    "preview": "# ref: https://docs.docker.com/ci-cd/github-actions/\n# https://blog.oddbit.com/post/2020-09-25-building-multi-architectu"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 964,
    "preview": "name: goreleaser\n\non:\n  push:\n    # run only against tags\n    tags:\n      - 'v*'\n\npermissions:\n  contents: write\n  # pac"
  },
  {
    "path": ".gitignore",
    "chars": 328,
    "preview": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\nrelease\ndebian\nbin\n"
  },
  {
    "path": ".goreleaser.yaml",
    "chars": 1444,
    "preview": "# This is an example .goreleaser.yml file with some sensible defaults.\n# Make sure to check the documentation at https:/"
  },
  {
    "path": ".travis.yml",
    "chars": 214,
    "preview": "language: go\nsudo: false\ngo:\n  - 1.x\n\ninstall: true\nscript:\n  - go test -race -v -coverprofile=coverage.txt -covermode=a"
  },
  {
    "path": "Dockerfile",
    "chars": 469,
    "preview": "FROM --platform=$BUILDPLATFORM tonistiigi/xx:1.5.0 AS xx\n\nFROM --platform=$BUILDPLATFORM golang:1.23-alpine3.20 AS build"
  },
  {
    "path": "LICENSE",
    "chars": 1065,
    "preview": "MIT License\n\nCopyright (c) 2016 ginuerzh\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\no"
  },
  {
    "path": "Makefile",
    "chars": 3056,
    "preview": "NAME=gost\nBINDIR=bin\nVERSION=$(shell cat gost.go | grep 'Version =' | sed 's/.*\\\"\\(.*\\)\\\".*/\\1/g')\nGOBUILD=CGO_ENABLED=0"
  },
  {
    "path": "README.md",
    "chars": 6997,
    "preview": "GO Simple Tunnel\n======\n\n### GO语言实现的安全隧道\n\n[![GoDoc](https://godoc.org/github.com/ginuerzh/gost?status.svg)](https://godo"
  },
  {
    "path": "README_en.md",
    "chars": 10223,
    "preview": "gost - GO Simple Tunnel\n======\n \n### A simple security tunnel written in Golang\n\n[![GoDoc](https://godoc.org/github.com/"
  },
  {
    "path": "auth.go",
    "chars": 2931,
    "preview": "package gost\n\nimport (\n\t\"bufio\"\n\t\"io\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n)\n\n// Authenticator is an interface for user authentica"
  },
  {
    "path": "auth_test.go",
    "chars": 5023,
    "preview": "package gost\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n)\n\nvar localAuthenticatorTests = []struct {\n\t"
  },
  {
    "path": "bypass.go",
    "chars": 6064,
    "preview": "package gost\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\tglob \"github.com/go"
  },
  {
    "path": "bypass_test.go",
    "chars": 10502,
    "preview": "package gost\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n)\n\nvar bypassContainTests = []struct {\n\tpatterns []strin"
  },
  {
    "path": "chain.go",
    "chars": 9119,
    "preview": "package gost\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/go-log/log\"\n)\n\nvar (\n\t// ErrE"
  },
  {
    "path": "client.go",
    "chars": 7636,
    "preview": "package gost\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"net\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"github.com/go-gost/gosocks5\"\n)\n\n// Client i"
  },
  {
    "path": "cmd/gost/.ssl/README.md",
    "chars": 1451,
    "preview": "[//]: <> (https://gist.github.com/fntlnz/cf14feb5a46b2eda428e000157447309)\n\n# Create Root CA (Done once)\n\n## Create Root"
  },
  {
    "path": "cmd/gost/.ssl/localhost.crt",
    "chars": 1359,
    "preview": "-----BEGIN CERTIFICATE-----\nMIIDvjCCAaYCCQC0XjV3wljvnjANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls\nb2NhbGhvc3QwHhcNMTgwNzA4MDQ"
  },
  {
    "path": "cmd/gost/.ssl/localhost.csr",
    "chars": 928,
    "preview": "-----BEGIN CERTIFICATE REQUEST-----\nMIICczCCAVsCAQAwLjELMAkGA1UEBhMCQ04xCzAJBgNVBAcMAlNIMRIwEAYDVQQD\nDAlsb2NhbGhvc3QwggE"
  },
  {
    "path": "cmd/gost/.ssl/localhost.key",
    "chars": 1675,
    "preview": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAw4qDNaKX8qPJHLYDFvdeUsHWczAsUkKkLqvzJv7Uqr+V1mCE\nlm/Ka4VWOf5uKG8mq9mI6/g"
  },
  {
    "path": "cmd/gost/.ssl/rootCA.crt",
    "chars": 1671,
    "preview": "-----BEGIN CERTIFICATE-----\nMIIEpDCCAowCCQDwV08QFUCcSzANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls\nb2NhbGhvc3QwHhcNMTgwNzA4MDQ"
  },
  {
    "path": "cmd/gost/.ssl/rootCA.key",
    "chars": 3243,
    "preview": "-----BEGIN RSA PRIVATE KEY-----\nMIIJKAIBAAKCAgEAxPu9cl/b0GN5edgt9XtOAAr5tqDTC0gqyzlxnsDkxab/cl44\npzAtAG+l2uMgeDD7Xbo1g0h"
  },
  {
    "path": "cmd/gost/.ssl/rootCA.srl",
    "chars": 17,
    "preview": "B45E3577C258EF9E\n"
  },
  {
    "path": "cmd/gost/cfg.go",
    "chars": 6381,
    "preview": "package main\n\nimport (\n\t\"bufio\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/url\"\n\t\"os\"\n\t\"strings\"\n"
  },
  {
    "path": "cmd/gost/main.go",
    "chars": 2516,
    "preview": "package main\n\nimport (\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"os\"\n\t\"runtime\"\n\n\t_ \"net/http/pprof\"\n\n\t\"githu"
  },
  {
    "path": "cmd/gost/peer.go",
    "chars": 3121,
    "preview": "package main\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/ginuerzh/gos"
  },
  {
    "path": "cmd/gost/route.go",
    "chars": 18177,
    "preview": "package main\n\nimport (\n\t\"crypto/sha256\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/url\"\n\t\"os\"\n\t"
  },
  {
    "path": "common_test.go",
    "chars": 4902,
    "preview": "package gost\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"sync\"\n\t\"ti"
  },
  {
    "path": "dns.go",
    "chars": 9150,
    "preview": "package gost\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/tls\"\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"strconv"
  },
  {
    "path": "examples/bench/cli.go",
    "chars": 4501,
    "preview": "package main\n\nimport (\n\t\"bufio\"\n\t\"flag\"\n\t\"log\"\n\t\"net/http\"\n\t\"net/http/httputil\"\n\t\"net/url\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com"
  },
  {
    "path": "examples/bench/srv.go",
    "chars": 9291,
    "preview": "package main\n\nimport (\n\t\"crypto/tls\"\n\t\"flag\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"github.com/ginuerzh/gost\"\n\t"
  },
  {
    "path": "examples/forward/direct/client.go",
    "chars": 532,
    "preview": "package main\n\nimport (\n\t\"log\"\n\n\t\"github.com/ginuerzh/gost\"\n)\n\nfunc main() {\n\ttcpForward()\n}\n\nfunc tcpForward() {\n\tchain "
  },
  {
    "path": "examples/forward/direct/server.go",
    "chars": 3439,
    "preview": "package main\n\nimport (\n\t\"crypto/tls\"\n\t\"log\"\n\n\t\"github.com/ginuerzh/gost\"\n)\n\nfunc main() {\n\tsshForwardServer()\n}\n\nfunc ss"
  },
  {
    "path": "examples/forward/remote/client.go",
    "chars": 584,
    "preview": "package main\n\nimport (\n\t\"log\"\n\n\t\"github.com/ginuerzh/gost\"\n)\n\nfunc main() {\n\tsshRemoteForward()\n}\n\nfunc sshRemoteForward"
  },
  {
    "path": "examples/forward/remote/server.go",
    "chars": 3451,
    "preview": "package main\n\nimport (\n\t\"crypto/tls\"\n\t\"log\"\n\n\t\"github.com/ginuerzh/gost\"\n)\n\nfunc main() {\n\tsshRemoteForwardServer()\n}\n\nf"
  },
  {
    "path": "examples/forward/udp/cli.go",
    "chars": 874,
    "preview": "package main\n\nimport (\n\t\"flag\"\n\t\"log\"\n\t\"net\"\n\t\"time\"\n)\n\nvar (\n\tconcurrency int\n\tsaddr       string\n)\n\nfunc init() {\n\tlog"
  },
  {
    "path": "examples/forward/udp/direct.go",
    "chars": 1087,
    "preview": "package main\n\nimport (\n\t\"flag\"\n\t\"log\"\n\t\"time\"\n\n\t\"github.com/ginuerzh/gost\"\n)\n\nvar (\n\tladdr, faddr string\n\tquiet        b"
  },
  {
    "path": "examples/forward/udp/remote.go",
    "chars": 1088,
    "preview": "package main\n\nimport (\n\t\"flag\"\n\t\"log\"\n\t\"time\"\n\n\t\"github.com/ginuerzh/gost\"\n)\n\nvar (\n\tladdr, faddr string\n\tquiet        b"
  },
  {
    "path": "examples/forward/udp/srv.go",
    "chars": 622,
    "preview": "package main\n\nimport (\n\t\"flag\"\n\t\"log\"\n\t\"net\"\n)\n\nvar (\n\tladdr string\n)\n\nfunc init() {\n\tlog.SetFlags(log.LstdFlags | log.L"
  },
  {
    "path": "examples/http2/http2.go",
    "chars": 4414,
    "preview": "package main\n\nimport (\n\t\"crypto/tls\"\n\t\"flag\"\n\t\"log\"\n\t\"net/url\"\n\n\t\"golang.org/x/net/http2\"\n\n\t\"github.com/ginuerzh/gost\"\n)"
  },
  {
    "path": "examples/quic/quicc.go",
    "chars": 4023,
    "preview": "package main\n\nimport (\n\t\"crypto/tls\"\n\t\"flag\"\n\t\"log\"\n\t\"time\"\n\n\t\"github.com/ginuerzh/gost\"\n)\n\nvar (\n\tladdr, faddr string\n\t"
  },
  {
    "path": "examples/quic/quics.go",
    "chars": 3726,
    "preview": "package main\n\nimport (\n\t\"crypto/tls\"\n\t\"flag\"\n\t\"log\"\n\n\t\"github.com/ginuerzh/gost\"\n)\n\nvar (\n\tladdr string\n\tquiet bool\n)\n\nf"
  },
  {
    "path": "examples/ssh/sshc.go",
    "chars": 4062,
    "preview": "package main\n\nimport (\n\t\"crypto/tls\"\n\t\"flag\"\n\t\"log\"\n\t\"time\"\n\n\t\"github.com/ginuerzh/gost\"\n)\n\nvar (\n\tladdr, faddr string\n\t"
  },
  {
    "path": "examples/ssh/sshd.go",
    "chars": 3740,
    "preview": "package main\n\nimport (\n\t\"crypto/tls\"\n\t\"flag\"\n\t\"log\"\n\n\t\"github.com/ginuerzh/gost\"\n)\n\nvar (\n\tladdr string\n\tquiet bool\n)\n\nf"
  },
  {
    "path": "examples/ssu/ssu.go",
    "chars": 1315,
    "preview": "package main\n\nimport (\n\t\"bytes\"\n\t\"log\"\n\t\"net\"\n\t\"strconv\"\n\n\t\"github.com/go-gost/gosocks5\"\n\tss \"github.com/shadowsocks/sha"
  },
  {
    "path": "forward.go",
    "chars": 17403,
    "preview": "package gost\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"fmt\"\n\n\t\"github.com/go-gost/gosocks5\"\n\t\""
  },
  {
    "path": "forward_test.go",
    "chars": 5867,
    "preview": "package gost\n\nimport (\n\t\"crypto/rand\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n)\n\nfunc tcpDirectForwardRoundtrip(targe"
  },
  {
    "path": "ftcp.go",
    "chars": 3575,
    "preview": "package gost\n\nimport (\n\t\"errors\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/go-log/log\"\n\t\"github.com/xtaci/tcpraw\"\n)\n\ntype fakeTCPTran"
  },
  {
    "path": "go.mod",
    "chars": 2586,
    "preview": "module github.com/ginuerzh/gost\n\ngo 1.22\n\nreplace github.com/templexxx/cpu v0.0.7 => github.com/templexxx/cpu v0.0.10-0."
  },
  {
    "path": "go.sum",
    "chars": 19677,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\nfilippo.io/edwards25519 v1.0.0-rc.1.0"
  },
  {
    "path": "gost.go",
    "chars": 5441,
    "preview": "package gost\n\nimport (\n\t\"crypto/rand\"\n\t\"crypto/rsa\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"crypto/x509/pkix\"\n\t\"encoding/pem\"\n\t\"e"
  },
  {
    "path": "handler.go",
    "chars": 7108,
    "preview": "package gost\n\nimport (\n\t\"bufio\"\n\t\"crypto/tls\"\n\t\"net\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"github.com/go-gost/gosocks4\"\n\t\"github.com/go-"
  },
  {
    "path": "handler_test.go",
    "chars": 4942,
    "preview": "package gost\n\nimport (\n\t\"crypto/rand\"\n\t\"crypto/tls\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n)\n\nfunc autoHTTPProxyRoun"
  },
  {
    "path": "hosts.go",
    "chars": 2941,
    "preview": "package gost\n\nimport (\n\t\"bufio\"\n\t\"io\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/go-log/log\"\n)\n\n// Host is a static mapping fr"
  },
  {
    "path": "hosts_test.go",
    "chars": 3149,
    "preview": "package gost\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n)\n\nvar hostsLookupTests = []struct {\n\thosts []Host\n\thost"
  },
  {
    "path": "http.go",
    "chars": 11895,
    "preview": "package gost\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httput"
  },
  {
    "path": "http2.go",
    "chars": 22707,
    "preview": "package gost\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/tls\"\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net"
  },
  {
    "path": "http2_test.go",
    "chars": 23270,
    "preview": "package gost\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/"
  },
  {
    "path": "http_test.go",
    "chars": 8341,
    "preview": "package gost\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing"
  },
  {
    "path": "kcp.go",
    "chars": 12479,
    "preview": "package gost\n\nimport (\n\t\"crypto/sha1\"\n\t\"encoding/csv\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"time\"\n\n\t\"golang.org/x/crypto/pbkdf"
  },
  {
    "path": "kcp_test.go",
    "chars": 8074,
    "preview": "package gost\n\nimport (\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n)\n\nfunc httpOverKCPRoundtrip(tar"
  },
  {
    "path": "log.go",
    "chars": 709,
    "preview": "package gost\n\nimport (\n\t\"fmt\"\n\t\"log\"\n)\n\nfunc init() {\n\tlog.SetFlags(log.LstdFlags | log.Lshortfile)\n}\n\n// LogLogger uses"
  },
  {
    "path": "mux.go",
    "chars": 1193,
    "preview": "package gost\n\nimport (\n\t\"net\"\n\n\tsmux \"github.com/xtaci/smux\"\n)\n\ntype muxStreamConn struct {\n\tnet.Conn\n\tstream *smux.Stre"
  },
  {
    "path": "node.go",
    "chars": 6102,
    "preview": "package gost\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n)\n\nvar (\n\t// ErrInvalidNode is "
  },
  {
    "path": "node_test.go",
    "chars": 3053,
    "preview": "package gost\n\nimport \"testing\"\nimport \"net/url\"\n\nvar nodeTests = []struct {\n\tin       string\n\tout      Node\n\thasError bo"
  },
  {
    "path": "obfs.go",
    "chars": 17625,
    "preview": "// obfs4 connection wrappers\n\npackage gost\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"i"
  },
  {
    "path": "obfs_test.go",
    "chars": 8587,
    "preview": "package gost\n\nimport (\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n)\n\nfunc httpOverObfsHTTPRoundtri"
  },
  {
    "path": "permissions.go",
    "chars": 4650,
    "preview": "package gost\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\n\tglob \"github.com/ryanuber/go-glob\"\n)\n\n// Permissi"
  },
  {
    "path": "permissions_test.go",
    "chars": 4113,
    "preview": "package gost\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n)\n\nvar portRangeTests = []struct {\n\tin  string\n\tout *PortRange\n}{\n\t{\"1\", &PortR"
  },
  {
    "path": "quic.go",
    "chars": 7360,
    "preview": "package gost\n\nimport (\n\t\"context\"\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/rand\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"io\"\n\t\"net\"\n\t\"s"
  },
  {
    "path": "quic_test.go",
    "chars": 9349,
    "preview": "package gost\n\nimport (\n\t\"crypto/rand\"\n\t\"crypto/sha256\"\n\t\"fmt\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n)\n\nfunc httpOve"
  },
  {
    "path": "redirect.go",
    "chars": 4965,
    "preview": "//go:build linux\n// +build linux\n\npackage gost\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\t\"syscall\"\n\t\"time\"\n\n"
  },
  {
    "path": "redirect_other.go",
    "chars": 1371,
    "preview": "//go:build !linux\n// +build !linux\n\npackage gost\n\nimport (\n\t\"errors\"\n\t\"net\"\n\n\t\"github.com/go-log/log\"\n)\n\ntype tcpRedirec"
  },
  {
    "path": "relay.go",
    "chars": 7897,
    "preview": "package gost\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"sync"
  },
  {
    "path": "reload.go",
    "chars": 1226,
    "preview": "package gost\n\nimport (\n\t\"io\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/go-log/log\"\n)\n\n// Reloader is the interface for objects that su"
  },
  {
    "path": "resolver.go",
    "chars": 19789,
    "preview": "package gost\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t"
  },
  {
    "path": "resolver_test.go",
    "chars": 6394,
    "preview": "package gost\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n)\n\nvar dnsTests = []struct {\n\tns   NameServer\n\tho"
  },
  {
    "path": "selector.go",
    "chars": 7556,
    "preview": "package gost\n\nimport (\n\t\"errors\"\n\t\"math/rand\"\n\t\"net\"\n\t\"sort\"\n\t\"strconv\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/go-"
  },
  {
    "path": "selector_test.go",
    "chars": 3644,
    "preview": "package gost\n\nimport (\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestRoundStrategy(t *testing.T) {\n\tnodes := []Node{\n\t\tNode{ID: 1},\n\t\tN"
  },
  {
    "path": "server.go",
    "chars": 2313,
    "preview": "package gost\n\nimport (\n\t\"io\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/go-log/log\"\n)\n\n// Accepter represents a network endpoint that "
  },
  {
    "path": "signal.go",
    "chars": 76,
    "preview": "//go:build windows\n// +build windows\n\npackage gost\n\nfunc kcpSigHandler() {}\n"
  },
  {
    "path": "signal_unix.go",
    "chars": 354,
    "preview": "//go:build !windows\n// +build !windows\n\npackage gost\n\nimport (\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\n\t\"github.com/go-log/log\"\n\t"
  },
  {
    "path": "snap/snapcraft.yaml",
    "chars": 577,
    "preview": "name: gost\nbase: core20\nversion: '2.12.0'\nsummary: A simple security tunnel written in golang\ndescription: |\n  Project: "
  },
  {
    "path": "sni.go",
    "chars": 7997,
    "preview": "// SNI proxy based on https://github.com/bradfitz/tcpproxy\n\npackage gost\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"encodi"
  },
  {
    "path": "sni_test.go",
    "chars": 2685,
    "preview": "package gost\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/http"
  },
  {
    "path": "sockopts_linux.go",
    "chars": 312,
    "preview": "package gost\n\nimport \"syscall\"\n\nfunc setSocketMark(fd int, value int) (e error) {\n\treturn syscall.SetsockoptInt(fd, sysc"
  },
  {
    "path": "sockopts_other.go",
    "chars": 187,
    "preview": "//go:build !linux\n// +build !linux\n\npackage gost\n\nfunc setSocketMark(fd int, value int) (e error) {\n\treturn nil\n}\n\nfunc "
  },
  {
    "path": "socks.go",
    "chars": 51669,
    "preview": "package gost\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n"
  },
  {
    "path": "socks_test.go",
    "chars": 16283,
    "preview": "package gost\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n)\n\nvar s"
  },
  {
    "path": "ss.go",
    "chars": 13635,
    "preview": "package gost\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"github.com/go-go"
  },
  {
    "path": "ss_test.go",
    "chars": 22000,
    "preview": "package gost\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc init() "
  },
  {
    "path": "ssh.go",
    "chars": 23741,
    "preview": "package gost\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t"
  },
  {
    "path": "ssh_test.go",
    "chars": 11428,
    "preview": "package gost\n\nimport (\n\t\"crypto/rand\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n)\n\nfunc ssh"
  },
  {
    "path": "tcp.go",
    "chars": 1369,
    "preview": "package gost\n\nimport \"net\"\n\n// tcpTransporter is a raw TCP transporter.\ntype tcpTransporter struct{}\n\n// TCPTransporter "
  },
  {
    "path": "tls.go",
    "chars": 7552,
    "preview": "package gost\n\nimport (\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/go-log/log\"\n\n\tsmux \"github.com/xtaci"
  },
  {
    "path": "tls_test.go",
    "chars": 16221,
    "preview": "package gost\n\nimport (\n\t\"crypto/rand\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n)\n\nfunc httpOverTL"
  },
  {
    "path": "tuntap.go",
    "chars": 17573,
    "preview": "package gost\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"os\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/go-log/log\"\n\t\"github"
  },
  {
    "path": "tuntap_darwin.go",
    "chars": 1522,
    "preview": "package gost\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"os/exec\"\n\t\"strings\"\n\n\t\"github.com/go-log/log\"\n\t\"github.com/songgao/wate"
  },
  {
    "path": "tuntap_linux.go",
    "chars": 3065,
    "preview": "package gost\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"os/exec\"\n\t\"strings\"\n\n\t\"github.com/go-log/log\"\n\t\"github.com/songgao/water\"\n)\n\nfunc"
  },
  {
    "path": "tuntap_unix.go",
    "chars": 2689,
    "preview": "//go:build !linux && !windows && !darwin\n// +build !linux,!windows,!darwin\n\npackage gost\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"os/ex"
  },
  {
    "path": "tuntap_windows.go",
    "chars": 3502,
    "preview": "package gost\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"os/exec\"\n\t\"strings\"\n\n\t\"github.com/go-log/log\"\n\t\"github.com/songgao/water\"\n)\n\nfunc"
  },
  {
    "path": "udp.go",
    "chars": 7041,
    "preview": "package gost\n\nimport (\n\t\"errors\"\n\t\"net\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/go-log/log\"\n)\n\n// udpTransporter is"
  },
  {
    "path": "vsock.go",
    "chars": 1566,
    "preview": "package gost\n\nimport (\n\t\"net\"\n\t\"strconv\"\n\n\t\"github.com/mdlayher/vsock\"\n)\n\n// vsockTransporter is a raw VSOCK transporter"
  },
  {
    "path": "ws.go",
    "chars": 17734,
    "preview": "package gost\n\nimport (\n\t\"crypto/rand\"\n\t\"crypto/sha1\"\n\t\"crypto/tls\"\n\t\"encoding/base64\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/htt"
  },
  {
    "path": "ws_test.go",
    "chars": 15847,
    "preview": "package gost\n\nimport (\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n)\n\nfunc httpOverWSRoundtrip(targ"
  },
  {
    "path": "wss_test.go",
    "chars": 16067,
    "preview": "package gost\n\nimport (\n\t\"crypto/rand\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n)\n\nfunc httpOverWS"
  }
]

About this extraction

This page contains the full source code of the ginuerzh/gost GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 115 files (696.7 KB), approximately 233.6k tokens, and a symbol index with 1448 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!