├── .github
└── workflows
│ ├── docker-image.yml
│ └── go.yml
├── .gitignore
├── Dockerfile
├── LICENSE
├── README.md
├── _config.yml
├── benchmark
├── local_tcp
│ ├── iperf_client_direct.sh
│ ├── iperf_client_spp.sh
│ ├── iperf_server.sh
│ ├── spp_client_compress_kcp.sh
│ ├── spp_client_compress_quic.sh
│ ├── spp_client_compress_rhttp.sh
│ ├── spp_client_compress_ricmp.sh
│ ├── spp_client_compress_rudp.sh
│ ├── spp_client_compress_tcp.sh
│ ├── spp_client_encrypt_kcp.sh
│ ├── spp_client_encrypt_quic.sh
│ ├── spp_client_encrypt_rhttp.sh
│ ├── spp_client_encrypt_ricmp.sh
│ ├── spp_client_encrypt_rudp.sh
│ ├── spp_client_encrypt_tcp.sh
│ ├── spp_client_nocompress_kcp.sh
│ ├── spp_client_nocompress_quic.sh
│ ├── spp_client_nocompress_rhttp.sh
│ ├── spp_client_nocompress_ricmp.sh
│ ├── spp_client_nocompress_rudp.sh
│ ├── spp_client_nocompress_tcp.sh
│ ├── spp_server_compress_kcp.sh
│ ├── spp_server_compress_quic.sh
│ ├── spp_server_compress_rhttp.sh
│ ├── spp_server_compress_ricmp.sh
│ ├── spp_server_compress_rudp.sh
│ ├── spp_server_compress_tcp.sh
│ ├── spp_server_encrypt_kcp.sh
│ ├── spp_server_encrypt_quic.sh
│ ├── spp_server_encrypt_rhttp.sh
│ ├── spp_server_encrypt_ricmp.sh
│ ├── spp_server_encrypt_rudp.sh
│ ├── spp_server_encrypt_tcp.sh
│ ├── spp_server_nocompress_kcp.sh
│ ├── spp_server_nocompress_quic.sh
│ ├── spp_server_nocompress_rhttp.sh
│ ├── spp_server_nocompress_ricmp.sh
│ ├── spp_server_nocompress_rudp.sh
│ └── spp_server_nocompress_tcp.sh
├── prepare.sh
└── remote_tcp
│ ├── iperf_client_direct.sh
│ ├── iperf_client_spp.sh
│ ├── iperf_server.sh
│ ├── server
│ ├── spp_client_compress_kcp.sh
│ ├── spp_client_compress_quic.sh
│ ├── spp_client_compress_rhttp.sh
│ ├── spp_client_compress_ricmp.sh
│ ├── spp_client_compress_rudp.sh
│ ├── spp_client_compress_tcp.sh
│ ├── spp_client_encrypt_kcp.sh
│ ├── spp_client_encrypt_quic.sh
│ ├── spp_client_encrypt_rhttp.sh
│ ├── spp_client_encrypt_ricmp.sh
│ ├── spp_client_encrypt_rudp.sh
│ ├── spp_client_encrypt_tcp.sh
│ ├── spp_client_nocompress_kcp.sh
│ ├── spp_client_nocompress_quic.sh
│ ├── spp_client_nocompress_rhttp.sh
│ ├── spp_client_nocompress_ricmp.sh
│ ├── spp_client_nocompress_rudp.sh
│ ├── spp_client_nocompress_tcp.sh
│ ├── spp_server_compress_kcp.sh
│ ├── spp_server_compress_quic.sh
│ ├── spp_server_compress_rhttp.sh
│ ├── spp_server_compress_ricmp.sh
│ ├── spp_server_compress_rudp.sh
│ ├── spp_server_compress_tcp.sh
│ ├── spp_server_encrypt_kcp.sh
│ ├── spp_server_encrypt_quic.sh
│ ├── spp_server_encrypt_rhttp.sh
│ ├── spp_server_encrypt_ricmp.sh
│ ├── spp_server_encrypt_rudp.sh
│ ├── spp_server_encrypt_tcp.sh
│ ├── spp_server_nocompress_kcp.sh
│ ├── spp_server_nocompress_quic.sh
│ ├── spp_server_nocompress_rhttp.sh
│ ├── spp_server_nocompress_ricmp.sh
│ ├── spp_server_nocompress_rudp.sh
│ └── spp_server_nocompress_tcp.sh
├── go.mod
├── go.sum
├── main.go
├── pack.sh
├── proxy
├── client.go
├── common.go
├── common_test.go
├── gen.bat
├── inputer.go
├── outputer.go
├── proxy.pb.go
├── proxy.proto
└── server.go
└── show.png
/.github/workflows/docker-image.yml:
--------------------------------------------------------------------------------
1 | name: Docker Image CI
2 |
3 | on:
4 | push:
5 | branches: [ "master" ]
6 | pull_request:
7 | branches: [ "master" ]
8 |
9 | jobs:
10 |
11 | build:
12 |
13 | runs-on: ubuntu-latest
14 |
15 | steps:
16 | -
17 | name: Set up QEMU
18 | uses: docker/setup-qemu-action@v1
19 | -
20 | name: Set up Docker Buildx
21 | uses: docker/setup-buildx-action@v1
22 | -
23 | name: Login to DockerHub
24 | uses: docker/login-action@v1
25 | with:
26 | username: ${{ secrets.DOCKERHUB_USERNAME }}
27 | password: ${{ secrets.DOCKERHUB_TOKEN }}
28 | -
29 | name: Build and push
30 | id: docker_build
31 | uses: docker/build-push-action@v2
32 | with:
33 | push: true
34 | tags: esrrhs/spp:latest
35 |
--------------------------------------------------------------------------------
/.github/workflows/go.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a golang project
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
3 |
4 | name: Go
5 |
6 | on:
7 | push:
8 | branches: [ "master" ]
9 | pull_request:
10 | branches: [ "master" ]
11 |
12 | jobs:
13 |
14 | build:
15 | runs-on: ubuntu-latest
16 | steps:
17 | - uses: actions/checkout@v3
18 |
19 | - name: Set up Go
20 | uses: actions/setup-go@v3
21 | with:
22 | go-version: 1.21
23 |
24 | - name: Build
25 | run: |
26 | go mod tidy
27 | go build -v ./...
28 |
29 | - name: Test
30 | run: go test -v ./...
31 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 |
8 | # Test binary, built with `go test -c`
9 | *.test
10 |
11 | # Output of the go coverage tool, specifically when used with LiteIDE
12 | *.out
13 |
14 | # Dependency directories (remove the comment below to include it)
15 | # vendor/
16 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM golang AS build-env
2 |
3 | WORKDIR /app
4 |
5 | COPY go.* ./
6 | RUN go mod download
7 | COPY . ./
8 | RUN go mod tidy
9 | RUN go build -v -o spp
10 |
11 | FROM debian
12 | COPY --from=build-env /app/spp .
13 | WORKDIR ./
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 zhao xin
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # spp
2 |
3 | [
](https://github.com/esrrhs/spp)
4 | [
](https://github.com/esrrhs/spp)
5 | [](https://goreportcard.com/report/github.com/esrrhs/spp)
6 | [
](https://github.com/esrrhs/spp/releases)
7 | [
](https://github.com/esrrhs/spp/releases)
8 | [
](https://hub.docker.com/repository/docker/esrrhs/spp)
9 | [
](https://github.com/esrrhs/spp/actions)
10 |
11 | SPP is a simple and powerful proxy
12 |
13 | ## Note: This tool is only to be used for study and research, do not use it for illegal purposes
14 |
15 | 
16 |
17 | # Features
18 | * Supported protocol: TCP, UDP, RUDP (Reliable UDP), RICMP (Reliable ICMP), RHTTP (Reliable HTTP), KCP, Quic
19 | * Support type: forward proxy, reverse agent, SOCKS5 forward agent, SOCKS5 reverse agent
20 | * Agreement and type can be freely combined
21 | * External agent agreement and internal forwarding protocols can freely combine
22 | * Support Shadowsocks plug-in, [spp-shadowsocks-plugin](https://github.com/esrrhs/spp-shadowsocks-plugin),[spp-shadowsocks-plugin-android](https://github.com/esrrhs/spp-shadowsocks-plugin-android)
23 |
24 | # Instructions
25 | ### Server
26 | * Start Server, assume that the server IP is www.server.com, listening port 8888
27 | ```
28 | # ./spp -type server -proto tcp -listen :8888
29 | ```
30 | * You can also listen simultaneously with other types of ports and protocols.
31 | ```
32 | # ./spp -type server -proto tcp -listen :8888 -proto rudp -listen :9999 -proto ricmp -listen 0.0.0.0
33 | ```
34 | * Can also use Docker
35 | ```
36 | # docker run --name my-server -d --restart=always --network host esrrhs/spp ./spp -proto tcp -listen :8888
37 | ```
38 | ### Client
39 | * Start TCP forward proxy, map the 8080 port of www.server.com to the local 8080 so that access to local 8080 is equivalent to accessing www.server.com 8080
40 | ```
41 | # ./spp -name "test" -type proxy_client -server www.server.com:8888 -fromaddr :8080 -toaddr :8080 -proxyproto tcp
42 | ```
43 | * Start the TCP reverse agent, map the local 8080 to the 8080 port of www.server.com, which visit www.server.com 8080 is equivalent to accessing the local 8080
44 | ```
45 | # ./spp -name "test" -type reverse_proxy_client -server www.server.com:8888 -fromaddr :8080 -toaddr :8080 -proxyproto tcp
46 | ```
47 | * Start TCP Positive Socks5 Agent, open the SOCKS5 protocol in the local 8080 port, access the network in Server through Server
48 | ```
49 | # ./spp -name "test" -type socks5_client -server www.server.com:8888 -fromaddr :8080 -proxyproto tcp
50 | ```
51 | * Start TCP Reverse Socks5 Agent, open the Socks5 protocol at www.server.com's 8080 port, access the network in the client through the Client
52 | ```
53 | # ./spp -name "test" -type reverse_socks5_client -server www.server.com:8888 -fromaddr :8080 -proxyproto tcp
54 | ```
55 | * Other proxy protocols, only need to modify the proxyProto parameters of the client, for example
56 |
57 | ```
58 | Proxy UDP
59 | # ./spp -name "test" -type proxy_client -server www.server.com:8888 -fromaddr :8080 -toaddr :8080 -proxyproto udp
60 |
61 | Proxy rudp
62 | # ./spp -name "test" -type proxy_client -server www.server.com:8888 -fromaddr :8081 -toaddr :8081 -proxyproto rudp
63 |
64 | Proxy ricmp
65 | # ./spp -name "test" -type proxy_client -server www.server.com:8888 -fromaddr :8082 -toaddr :8082 -proxyproto ricmp
66 |
67 | At the same time, the above three
68 | # ./spp -name "test" -type proxy_client -server www.server.com:8888 -fromaddr :8080 -toaddr :8080 -proxyproto udp -fromaddr :8081 -toaddr :8081 -proxyproto rudp -fromaddr :8082 -toaddr :8082 -proxyproto ricmp
69 |
70 | ```
71 | * Internal communication between Client and Server, can also be modified to other protocols, automatic conversion between external protocols and internal protocols. E.g
72 |
73 | ```
74 | Proxy TCP, internal RUDP protocol forwarding
75 | # ./spp -name "test" -type proxy_client -server www.server.com:8888 -fromaddr :8080 -toaddr :8080 -proxyproto tcp -proto rudp
76 |
77 | Proxy TCP, internal RICMP protocol forwarding
78 | # ./spp -name "test" -type proxy_client -server www.server.com -fromaddr :8080 -toaddr :8080 -proxyproto tcp -proto ricmp
79 |
80 | Agent UDP, internal TCP protocol forwarding
81 | # ./spp -name "test" -type proxy_client -server www.server.com:8888 -fromaddr :8080 -toaddr :8080 -proxyproto udp -proto tcp
82 |
83 | Agent UDP, internal KCP protocol forwarding
84 | # ./spp -name "test" -type proxy_client -server www.server.com:8888 -fromaddr :8080 -toaddr :8080 -proxyproto udp -proto kcp
85 |
86 | Proxy TCP, internal Quic protocol forwarding
87 | # ./spp -name "test" -type proxy_client -server www.server.com:8888 -fromaddr :8080 -toaddr :8080 -proxyproto tcp -proto quic
88 |
89 | Proxy TCP, internal RHTTP protocol forwarding
90 | # ./spp -name "test" -type proxy_client -server www.server.com:8888 -fromaddr :8080 -toaddr :8080 -proxyproto tcp -proto rhttp
91 | ```
92 | * Can also use Docker
93 |
94 | ```
95 | # docker run --name my-client -d --restart=always --network host esrrhs/spp ./spp -name "test" -type proxy_client -server www.server.com:8888 -fromaddr :8080 -toaddr :8080 -proxyproto tcp
96 | ```
97 |
98 | # Performance Testing
99 | * Test the maximum bandwidth speed in the case where the IPERF script using the Benchmark / local_tcp directory is tested in the CPU. The proxy protocol is TCP, and the results of various transit protocols are used as follows:
100 |
101 | | Agent | Speed | Speed (Ency) | Speed (Encryption Compression)
102 | |--------------|----------|----------|----------|
103 | | Direct connection | 3535 MBytes/sec | | |
104 | | tcp forwarding | 663 MBytes/sec | 225 MBytes/sec | 23.4 MBytes/sec |
105 | | rudp forwarding | 5.15 MBytes/sec | 5.81 MBytes/sec | 5.05 MBytes/sec|
106 | | ricmp forwarding | 3.34 MBytes/sec | 3.25 MBytes/sec|3.46 MBytes/sec |
107 | | rhttp forwarding | 10.7 MBytes/sec | 10.8 MBytes/sec| 8.73 MBytes/sec|
108 | | kcp forwarding | 18.2 MBytes/sec | 18.6 MBytes/sec| 14.7 MBytes/sec|
109 | | quic forwarding | 35.5 MBytes/sec | 32.8 MBytes/sec|15.1 MBytes/sec |
110 |
111 | * Using the IPERF script of the Benchmark / Remote_TCP directory, in the multi-machine test, the server is located in Tencent Cloud, the client is located locally, and the maximum bandwidth speed is tested. The proxy protocol is TCP, and the results of various transit protocols are used as follows:
112 |
113 | | Agent | Speed | Speed (Ency) | Speed (Encryption Compression)
114 | |--------------|----------|----------|----------|
115 | | Direct connection | 2.74 MBytes/sec | | |
116 | | tcp forwarding | 3.81 MBytes/sec |3.90 MBytes/sec | 4.02 MBytes/sec|
117 | | rudp forwarding | 3.33 MBytes/sec | 3.41 MBytes/sec| 3.58 MBytes/sec|
118 | | ricmp forwarding | 3.21 MBytes/sec | 2.95 MBytes/sec| 3.17 MBytes/sec|
119 | | rhttp forwarding | 3.48 MBytes/sec |3.49 MBytes/sec |3.39 MBytes/sec |
120 | | kcp forwarding | 3.58 MBytes/sec |3.58 MBytes/sec | 3.75 MBytes/sec |
121 | | quic forwarding | 3.85 MBytes/sec | 3.83 MBytes/sec | 3.92 MBytes/sec |
122 |
123 |
124 | * Note: The test data is Centos.ISO, which has been compressed, so the effect of compression forwarding is not obvious.
125 | * If you want to directly test each protocol bandwidth of the network, use multi-protocol bandwidth test tools [connperf](https://github.com/esrrhs/connperf)
126 |
127 |
128 | ## Thanks for free JetBrains Open Source license
129 |
130 |
131 |
132 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/benchmark/local_tcp/iperf_client_direct.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../iperf -c 127.0.0.1 -p 8844 -f M -F ../data.bin -t 60
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/iperf_client_spp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../iperf -c 127.0.0.1 -p 8855 -f M -F ../data.bin -t 60
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/iperf_server.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../iperf -s -p 8844 -f M
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_client_compress_kcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -name "test" -type proxy_client -server :8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto kcp
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_client_compress_quic.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -name "test" -type proxy_client -server :8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto quic
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_client_compress_rhttp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -name "test" -type proxy_client -server :8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto rhttp
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_client_compress_ricmp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -name "test" -type proxy_client -server 127.0.0.1 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto ricmp
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_client_compress_rudp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -name "test" -type proxy_client -server :8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto rudp
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_client_compress_tcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -name "test" -type proxy_client -server :8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto tcp
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_client_encrypt_kcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -name "test" -type proxy_client -server :8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto kcp -compress 0
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_client_encrypt_quic.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -name "test" -type proxy_client -server :8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto quic -compress 0
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_client_encrypt_rhttp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -name "test" -type proxy_client -server :8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto rhttp -compress 0
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_client_encrypt_ricmp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -name "test" -type proxy_client -server 127.0.0.1 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto ricmp -compress 0
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_client_encrypt_rudp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -name "test" -type proxy_client -server :8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto rudp -compress 0
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_client_encrypt_tcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -name "test" -type proxy_client -server :8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto tcp -compress 0
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_client_nocompress_kcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -name "test" -type proxy_client -server :8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto kcp -compress 0 -encrypt=""
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_client_nocompress_quic.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -name "test" -type proxy_client -server :8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto quic -compress 0 -encrypt=""
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_client_nocompress_rhttp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -name "test" -type proxy_client -server :8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto rhttp -compress 0 -encrypt=""
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_client_nocompress_ricmp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -name "test" -type proxy_client -server 127.0.0.1 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto ricmp -compress 0 -encrypt=""
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_client_nocompress_rudp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -name "test" -type proxy_client -server :8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto rudp -compress 0 -encrypt=""
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_client_nocompress_tcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -name "test" -type proxy_client -server :8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto tcp -compress 0 -encrypt=""
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_server_compress_kcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto kcp
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_server_compress_quic.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto quic
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_server_compress_rhttp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto rhttp
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_server_compress_ricmp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen 0.0.0.0 -proto ricmp
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_server_compress_rudp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto rudp
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_server_compress_tcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto tcp
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_server_encrypt_kcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto kcp -compress 0
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_server_encrypt_quic.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto quic -compress 0
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_server_encrypt_rhttp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto rhttp -compress 0
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_server_encrypt_ricmp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen 0.0.0.0 -proto ricmp -compress 0
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_server_encrypt_rudp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto rudp -compress 0
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_server_encrypt_tcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto tcp -compress 0
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_server_nocompress_kcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto kcp -compress 0 -encrypt=""
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_server_nocompress_quic.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto quic -compress 0 -encrypt=""
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_server_nocompress_rhttp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto rhttp -compress 0 -encrypt=""
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_server_nocompress_ricmp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen 0.0.0.0 -proto ricmp -compress 0 -encrypt=""
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_server_nocompress_rudp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto rudp -compress 0 -encrypt=""
4 |
--------------------------------------------------------------------------------
/benchmark/local_tcp/spp_server_nocompress_tcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto tcp -compress 0 -encrypt=""
4 |
--------------------------------------------------------------------------------
/benchmark/prepare.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 |
4 | if test -f "data.bin"; then
5 | echo "data.bin exist"
6 | else
7 | rm CentOS-8.2.2004-x86_64-minimal.iso -rf
8 | wget http://mirrors.cqu.edu.cn/CentOS/8.2.2004/isos/x86_64/CentOS-8.2.2004-x86_64-minimal.iso
9 | mv CentOS-8.2.2004-x86_64-minimal.iso data.bin
10 | fi
11 |
12 | if test -f "smalldata.bin"; then
13 | echo "smalldata.bin exist"
14 | else
15 | rm CentOS-8.2.2004-x86_64-boot.iso -rf
16 | wget http://mirrors.cqu.edu.cn/CentOS/8.2.2004/isos/x86_64/CentOS-8.2.2004-x86_64-boot.iso
17 | mv CentOS-8.2.2004-x86_64-boot.iso smalldata.bin
18 | fi
19 |
20 | rm ./iperf
21 | sudo wget -O ./iperf https://iperf.fr/download/ubuntu/iperf_2.0.9
22 | chmod a+x ./iperf
23 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/iperf_client_direct.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | SER=`cat server`
4 | ../iperf -c $SER -p 8844 -f M -F ../smalldata.bin -t 60
5 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/iperf_client_spp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../iperf -c 127.0.0.1 -p 8855 -f M -F ../smalldata.bin -t 60
4 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/iperf_server.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../iperf -s -p 8844 -f M
4 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/server:
--------------------------------------------------------------------------------
1 | www.esrrhs.gq
2 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_client_compress_kcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | SER=`cat server`
4 | ../../spp -name "test" -type proxy_client -server $SER:8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto kcp
5 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_client_compress_quic.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | SER=`cat server`
4 | ../../spp -name "test" -type proxy_client -server $SER:8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto quic
5 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_client_compress_rhttp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | SER=`cat server`
4 | ../../spp -name "test" -type proxy_client -server $SER:8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto rhttp
5 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_client_compress_ricmp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | SER=`cat server`
4 | ../../spp -name "test" -type proxy_client -server $SER -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto ricmp
5 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_client_compress_rudp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | SER=`cat server`
4 | ../../spp -name "test" -type proxy_client -server $SER:8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto rudp
5 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_client_compress_tcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | SER=`cat server`
4 | ../../spp -name "test" -type proxy_client -server $SER:8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto tcp
5 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_client_encrypt_kcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | SER=`cat server`
4 | ../../spp -name "test" -type proxy_client -server $SER:8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto kcp -compress 0
5 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_client_encrypt_quic.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | SER=`cat server`
4 | ../../spp -name "test" -type proxy_client -server $SER:8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto quic -compress 0
5 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_client_encrypt_rhttp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | SER=`cat server`
4 | ../../spp -name "test" -type proxy_client -server $SER:8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto rhttp -compress 0
5 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_client_encrypt_ricmp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | SER=`cat server`
4 | ../../spp -name "test" -type proxy_client -server $SER -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto ricmp -compress 0
5 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_client_encrypt_rudp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | SER=`cat server`
4 | ../../spp -name "test" -type proxy_client -server $SER:8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto rudp -compress 0
5 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_client_encrypt_tcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | SER=`cat server`
4 | ../../spp -name "test" -type proxy_client -server $SER:8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto tcp -compress 0
5 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_client_nocompress_kcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | SER=`cat server`
4 | ../../spp -name "test" -type proxy_client -server $SER:8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto kcp -compress 0 -encrypt=""
5 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_client_nocompress_quic.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | SER=`cat server`
4 | ../../spp -name "test" -type proxy_client -server $SER:8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto quic -compress 0 -encrypt=""
5 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_client_nocompress_rhttp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | SER=`cat server`
4 | ../../spp -name "test" -type proxy_client -server $SER:8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto rhttp -compress 0 -encrypt=""
5 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_client_nocompress_ricmp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | SER=`cat server`
4 | ../../spp -name "test" -type proxy_client -server $SER -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto ricmp -compress 0 -encrypt=""
5 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_client_nocompress_rudp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | SER=`cat server`
4 | ../../spp -name "test" -type proxy_client -server $SER:8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto rudp -compress 0 -encrypt=""
5 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_client_nocompress_tcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | SER=`cat server`
4 | ../../spp -name "test" -type proxy_client -server $SER:8888 -fromaddr :8855 -toaddr :8844 -proxyproto tcp -proto tcp -compress 0 -encrypt=""
5 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_server_compress_kcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto kcp
4 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_server_compress_quic.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto quic
4 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_server_compress_rhttp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto rhttp
4 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_server_compress_ricmp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen 0.0.0.0 -proto ricmp
4 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_server_compress_rudp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto rudp
4 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_server_compress_tcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto tcp
4 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_server_encrypt_kcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto kcp -compress 0
4 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_server_encrypt_quic.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto quic -compress 0
4 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_server_encrypt_rhttp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto rhttp -compress 0
4 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_server_encrypt_ricmp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen 0.0.0.0 -proto ricmp -compress 0
4 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_server_encrypt_rudp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto rudp -compress 0
4 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_server_encrypt_tcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto tcp -compress 0
4 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_server_nocompress_kcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto kcp -compress 0 -encrypt=""
4 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_server_nocompress_quic.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto quic -compress 0 -encrypt=""
4 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_server_nocompress_rhttp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto rhttp -compress 0 -encrypt=""
4 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_server_nocompress_ricmp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen 0.0.0.0 -proto ricmp -compress 0 -encrypt=""
4 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_server_nocompress_rudp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto rudp -compress 0 -encrypt=""
4 |
--------------------------------------------------------------------------------
/benchmark/remote_tcp/spp_server_nocompress_tcp.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | ../../spp -type server -listen :8888 -proto tcp -compress 0 -encrypt=""
4 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/esrrhs/spp
2 |
3 | go 1.24.1
4 |
5 | require (
6 | github.com/esrrhs/gohome v0.0.0-20250426022937-504d912bccf7
7 | github.com/golang/protobuf v1.5.4
8 | )
9 |
10 | require (
11 | github.com/OneOfOne/xxhash v1.2.8 // indirect
12 | github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
13 | github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4 // indirect
14 | github.com/google/uuid v1.6.0 // indirect
15 | github.com/klauspost/cpuid/v2 v2.2.10 // indirect
16 | github.com/klauspost/reedsolomon v1.12.4 // indirect
17 | github.com/onsi/ginkgo/v2 v2.23.4 // indirect
18 | github.com/pkg/errors v0.9.1 // indirect
19 | github.com/quic-go/quic-go v0.51.0 // indirect
20 | github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect
21 | github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b // indirect
22 | github.com/tjfoc/gmsm v1.4.1 // indirect
23 | github.com/xtaci/kcp-go v5.4.20+incompatible // indirect
24 | github.com/xtaci/smux v1.5.34 // indirect
25 | go.uber.org/automaxprocs v1.6.0 // indirect
26 | go.uber.org/mock v0.5.1 // indirect
27 | golang.org/x/crypto v0.37.0 // indirect
28 | golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
29 | golang.org/x/mod v0.24.0 // indirect
30 | golang.org/x/net v0.39.0 // indirect
31 | golang.org/x/sync v0.13.0 // indirect
32 | golang.org/x/sys v0.32.0 // indirect
33 | golang.org/x/tools v0.32.0 // indirect
34 | google.golang.org/protobuf v1.36.6 // indirect
35 | )
36 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
2 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
3 | github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=
4 | github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
5 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
6 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
7 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
8 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
9 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
10 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
11 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
12 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
13 | github.com/esrrhs/gohome v0.0.0-20231129030235-4e6f13493d6c h1:i5uscwGClUYsOier4aVbkD8Tna7aQgRZpbllMygKSMM=
14 | github.com/esrrhs/gohome v0.0.0-20231129030235-4e6f13493d6c/go.mod h1:gSrPvj3oNMs3rdHFQka+Di6hHlFnkZbSKCa2z80KisU=
15 | github.com/esrrhs/gohome v0.0.0-20250426022937-504d912bccf7 h1:EpgZzfBgtv89nRgnpziXylmWiatXGCijG41xK0XqZUM=
16 | github.com/esrrhs/gohome v0.0.0-20250426022937-504d912bccf7/go.mod h1:4kAeSdLmMeWMOpzi/Jx82YvDnrBHcbWcLT18FwTujFA=
17 | github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
18 | github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
19 | github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
20 | github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
21 | github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
22 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
23 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
24 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
25 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
26 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
27 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
28 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
29 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
30 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
31 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
32 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
33 | github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
34 | github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
35 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
36 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
37 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
38 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
39 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
40 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
41 | github.com/google/pprof v0.0.0-20241101162523-b92577c0c142 h1:sAGdeJj0bnMgUNVeUpp6AYlVdCt3/GdI3pGRqsNSQLs=
42 | github.com/google/pprof v0.0.0-20241101162523-b92577c0c142/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
43 | github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4 h1:gD0vax+4I+mAj+jEChEf25Ia07Jq7kYOFO5PPhAxFl4=
44 | github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
45 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
46 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
47 | github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
48 | github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
49 | github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
50 | github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
51 | github.com/klauspost/reedsolomon v1.12.4 h1:5aDr3ZGoJbgu/8+j45KtUJxzYm8k08JGtB9Wx1VQ4OA=
52 | github.com/klauspost/reedsolomon v1.12.4/go.mod h1:d3CzOMOt0JXGIFZm1StgkyF14EYr3xneR2rNWo7NcMU=
53 | github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
54 | github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
55 | github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
56 | github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
57 | github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8=
58 | github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc=
59 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
60 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
61 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
62 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
63 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
64 | github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE=
65 | github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
66 | github.com/quic-go/quic-go v0.51.0 h1:K8exxe9zXxeRKxaXxi/GpUqYiTrtdiWP8bo1KFya6Wc=
67 | github.com/quic-go/quic-go v0.51.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
68 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
69 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
70 | github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
71 | github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
72 | github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b h1:fj5tQ8acgNUr6O8LEplsxDhUIe2573iLkJc+PqnzZTI=
73 | github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
74 | github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
75 | github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
76 | github.com/xtaci/kcp-go v5.4.20+incompatible h1:TN1uey3Raw0sTz0Fg8GkfM0uH3YwzhnZWQ1bABv5xAg=
77 | github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
78 | github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 h1:EWU6Pktpas0n8lLQwDsRyZfmkPeRbdgPtW609es+/9E=
79 | github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37/go.mod h1:HpMP7DB2CyokmAh4lp0EQnnWhmycP/TvwBGzvuie+H0=
80 | github.com/xtaci/smux v1.5.31 h1:3ha7sHtH46h85Iv7MfQogxasuRt1KPRhoFB3S4rmHgU=
81 | github.com/xtaci/smux v1.5.31/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY=
82 | github.com/xtaci/smux v1.5.34 h1:OUA9JaDFHJDT8ZT3ebwLWPAgEfE6sWo2LaTy3anXqwg=
83 | github.com/xtaci/smux v1.5.34/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY=
84 | go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
85 | go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
86 | go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
87 | go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
88 | go.uber.org/mock v0.5.1 h1:ASgazW/qBmR+A32MYFDB6E2POoTgOwT509VP0CT/fjs=
89 | go.uber.org/mock v0.5.1/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
90 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
91 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
92 | golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
93 | golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
94 | golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
95 | golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
96 | golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
97 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
98 | golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
99 | golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
100 | golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
101 | golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
102 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
103 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
104 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
105 | golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
106 | golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
107 | golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
108 | golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
109 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
110 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
111 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
112 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
113 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
114 | golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
115 | golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
116 | golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
117 | golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
118 | golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
119 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
120 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
121 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
122 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
123 | golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
124 | golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
125 | golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
126 | golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
127 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
128 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
129 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
130 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
131 | golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
132 | golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
133 | golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
134 | golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
135 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
136 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
137 | golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
138 | golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
139 | golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
140 | golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
141 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
142 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
143 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
144 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
145 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
146 | golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
147 | golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
148 | golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
149 | golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
150 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
151 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
152 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
153 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
154 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
155 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
156 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
157 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
158 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
159 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
160 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
161 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
162 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
163 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
164 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
165 | google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
166 | google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
167 | google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
168 | google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
169 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
170 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
171 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
172 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
173 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 | "github.com/esrrhs/gohome/common"
7 | "github.com/esrrhs/gohome/loggo"
8 | "github.com/esrrhs/gohome/network"
9 | "github.com/esrrhs/spp/proxy"
10 | "net/http"
11 | _ "net/http/pprof"
12 | "strconv"
13 | "strings"
14 | "time"
15 | )
16 |
17 | type fromFlags []string
18 |
19 | func (f *fromFlags) String() string {
20 | return ""
21 | }
22 |
23 | func (f *fromFlags) Set(value string) error {
24 | *f = append(*f, value)
25 | return nil
26 | }
27 |
28 | type toFlags []string
29 |
30 | func (f *toFlags) String() string {
31 | return ""
32 | }
33 |
34 | func (f *toFlags) Set(value string) error {
35 | *f = append(*f, value)
36 | return nil
37 | }
38 |
39 | type proxyprotoFlags []string
40 |
41 | func (f *proxyprotoFlags) String() string {
42 | return "tcp"
43 | }
44 |
45 | func (f *proxyprotoFlags) Set(value string) error {
46 | *f = append(*f, value)
47 | return nil
48 | }
49 |
50 | type protoFlags []string
51 |
52 | func (f *protoFlags) String() string {
53 | return "tcp"
54 | }
55 |
56 | func (f *protoFlags) Set(value string) error {
57 | *f = append(*f, value)
58 | return nil
59 | }
60 |
61 | type listenAddrs []string
62 |
63 | func (f *listenAddrs) String() string {
64 | return ""
65 | }
66 |
67 | func (f *listenAddrs) Set(value string) error {
68 | *f = append(*f, value)
69 | return nil
70 | }
71 |
72 | func main() {
73 |
74 | defer common.CrashLog()
75 |
76 | t := flag.String("type", "", "type: server/proxy_client/reverse_proxy_client/socks5_client/reverse_socks5_client")
77 | var protos protoFlags
78 | flag.Var(&protos, "proto", "main proto type: "+fmt.Sprintf("%v", network.SupportReliableProtos()))
79 | var proxyproto proxyprotoFlags
80 | flag.Var(&proxyproto, "proxyproto", "proxy proto type: "+fmt.Sprintf("%v", network.SupportProtos()))
81 | var listenaddrs listenAddrs
82 | flag.Var(&listenaddrs, "listen", "server listen addr")
83 | name := flag.String("name", "client", "client name")
84 | server := flag.String("server", "", "server addr")
85 | var fromaddr fromFlags
86 | flag.Var(&fromaddr, "fromaddr", "from addr")
87 | var toaddr toFlags
88 | flag.Var(&toaddr, "toaddr", "to addr")
89 | key := flag.String("key", "123456", "verify key")
90 | encrypt := flag.String("encrypt", "default", "encrypt key, empty means off")
91 | compress := flag.Int("compress", 128, "start compress size, 0 means off")
92 | nolog := flag.Int("nolog", 0, "write log file")
93 | noprint := flag.Int("noprint", 0, "print stdout")
94 | loglevel := flag.String("loglevel", "info", "log level")
95 | profile := flag.Int("profile", 0, "open profile")
96 | ping := flag.Bool("ping", false, "show ping")
97 | username := flag.String("username", "", "socks5 username")
98 | password := flag.String("password", "", "socks5 password")
99 | maxclient := flag.Int("maxclient", 8, "max client connection")
100 | maxconn := flag.Int("maxconn", 128, "max connection")
101 |
102 | flag.Parse()
103 |
104 | for _, p := range protos {
105 | if !network.HasReliableProto(p) {
106 | fmt.Println("[proto] must be " + fmt.Sprintf("%v", network.SupportReliableProtos()) + "\n")
107 | flag.Usage()
108 | return
109 | }
110 | }
111 |
112 | for _, p := range proxyproto {
113 | if !network.HasProto(p) {
114 | fmt.Println("[proxyproto] " + fmt.Sprintf("%v", network.SupportProtos()) + "\n")
115 | flag.Usage()
116 | return
117 | }
118 | }
119 |
120 | if *t != "proxy_client" &&
121 | *t != "reverse_proxy_client" &&
122 | *t != "socks5_client" &&
123 | *t != "reverse_socks5_client" &&
124 | *t != "server" {
125 | fmt.Println("[type] must be server/proxy_client/reverse_proxy_client/socks5_client/reverse_socks5_client")
126 | fmt.Println()
127 | flag.Usage()
128 | return
129 | }
130 |
131 | if *t == "proxy_client" ||
132 | *t == "reverse_proxy_client" {
133 | for i, _ := range proxyproto {
134 | if len(fromaddr[i]) == 0 || len(*server) == 0 || len(toaddr[i]) == 0 {
135 | fmt.Println("[proxy_client] or [reverse_proxy_client] need [server] [fromaddr] [toaddr] [proxyproto]")
136 | fmt.Println()
137 | flag.Usage()
138 | return
139 | }
140 | }
141 |
142 | if !(len(fromaddr) == len(toaddr) && len(fromaddr) == len(proxyproto)) {
143 | fmt.Println("[fromaddr] [toaddr] [proxyproto] len must be equal")
144 | fmt.Println()
145 | flag.Usage()
146 | return
147 | }
148 |
149 | if len(protos) == 0 {
150 | protos = append(protos, "tcp")
151 | }
152 | }
153 |
154 | if *t == "socks5_client" ||
155 | *t == "reverse_socks5_client" {
156 | for i, _ := range proxyproto {
157 | if len(fromaddr[i]) == 0 || len(*server) == 0 {
158 | fmt.Println("[socks5_client] or [reverse_socks5_client] need [server] [fromaddr] [proxyproto]")
159 | fmt.Println()
160 | flag.Usage()
161 | return
162 | }
163 | }
164 |
165 | if !(len(fromaddr) == len(proxyproto)) {
166 | fmt.Println("[fromaddr] [proxyproto] len must be equal")
167 | fmt.Println()
168 | flag.Usage()
169 | return
170 | }
171 |
172 | if len(protos) == 0 {
173 | protos = append(protos, "tcp")
174 | }
175 | }
176 |
177 | if *t == "server" {
178 | if len(listenaddrs) != len(protos) {
179 | fmt.Println("[proto] [listen] len must be equal")
180 | fmt.Println()
181 | flag.Usage()
182 | return
183 | }
184 | }
185 |
186 | logprefix := "server"
187 | if *t != "server" {
188 | logprefix = "client"
189 | }
190 |
191 | level := loggo.LEVEL_INFO
192 | if loggo.NameToLevel(*loglevel) >= 0 {
193 | level = loggo.NameToLevel(*loglevel)
194 | }
195 | loggo.Ini(loggo.Config{
196 | Level: level,
197 | Prefix: "spp" + logprefix,
198 | MaxDay: 3,
199 | NoLogFile: *nolog > 0,
200 | NoPrint: *noprint > 0,
201 | })
202 | loggo.Info("start...")
203 |
204 | config := proxy.DefaultConfig()
205 | config.Compress = *compress
206 | config.Key = *key
207 | config.Encrypt = *encrypt
208 | config.ShowPing = *ping
209 | config.Username = *username
210 | config.Password = *password
211 | config.MaxClient = *maxclient
212 | config.MaxSonny = *maxconn
213 |
214 | if *t == "server" {
215 | _, err := proxy.NewServer(config, protos, listenaddrs)
216 | if err != nil {
217 | loggo.Error("main NewServer fail %s", err.Error())
218 | return
219 | }
220 | loggo.Info("Server start")
221 | } else {
222 | clienttypestr := strings.Replace(*t, "_client", "", -1)
223 | clienttypestr = strings.ToUpper(clienttypestr)
224 | _, err := proxy.NewClient(config, protos[0], *server, *name, clienttypestr, proxyproto, fromaddr, toaddr)
225 | if err != nil {
226 | loggo.Error("main NewClient fail %s", err.Error())
227 | return
228 | }
229 | loggo.Info("Client start")
230 | }
231 |
232 | if *profile > 0 {
233 | go http.ListenAndServe("0.0.0.0:"+strconv.Itoa(*profile), nil)
234 | }
235 |
236 | for {
237 | time.Sleep(time.Hour)
238 | }
239 | }
240 |
--------------------------------------------------------------------------------
/pack.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 | #set -x
3 | NAME="spp"
4 |
5 | export GO111MODULE=on
6 |
7 | #go tool dist list
8 | build_list=$(go tool dist list)
9 |
10 | rm pack -rf
11 | rm pack.zip -f
12 | mkdir pack
13 |
14 | go mod tidy
15 |
16 | for line in $build_list; do
17 | os=$(echo "$line" | awk -F"/" '{print $1}')
18 | arch=$(echo "$line" | awk -F"/" '{print $2}')
19 | echo "os="$os" arch="$arch" start build"
20 | if [ $os == "android" ]; then
21 | continue
22 | fi
23 | if [ $os == "ios" ]; then
24 | continue
25 | fi
26 | if [ $arch == "riscv64" ]; then
27 | continue
28 | fi
29 | if [ $arch == "mips64" ] && [ $os == "openbsd" ]; then
30 | continue
31 | fi
32 |
33 | CGO_ENABLED=0 GOOS=$os GOARCH=$arch go build -ldflags="-s -w"
34 | if [ $? -ne 0 ]; then
35 | echo "os="$os" arch="$arch" build fail"
36 | exit 1
37 | fi
38 | if [ $os = "windows" ]; then
39 | zip ${NAME}_"${os}"_"${arch}"".zip" $NAME".exe"
40 | if [ $? -ne 0 ]; then
41 | echo "os="$os" arch="$arch" zip fail"
42 | exit 1
43 | fi
44 | mv ${NAME}_"${os}"_"${arch}"".zip" pack/
45 | rm $NAME".exe" -f
46 | else
47 | zip ${NAME}_"${os}"_"${arch}"".zip" $NAME
48 | if [ $? -ne 0 ]; then
49 | echo "os="$os" arch="$arch" zip fail"
50 | exit 1
51 | fi
52 | mv ${NAME}_"${os}"_"${arch}"".zip" pack/
53 | rm $NAME -f
54 | fi
55 | echo "os="$os" arch="$arch" done build"
56 | done
57 |
58 | zip pack.zip pack/ -r
59 |
60 | echo "all done"
61 |
--------------------------------------------------------------------------------
/proxy/client.go:
--------------------------------------------------------------------------------
1 | package proxy
2 |
3 | import (
4 | "errors"
5 | "github.com/esrrhs/gohome/common"
6 | "github.com/esrrhs/gohome/loggo"
7 | "github.com/esrrhs/gohome/network"
8 | "github.com/esrrhs/gohome/thread"
9 | "strconv"
10 | "strings"
11 | "sync/atomic"
12 | "time"
13 | )
14 |
15 | type ServerConn struct {
16 | ProxyConn
17 | output *Outputer
18 | input *Inputer
19 | }
20 |
21 | type Client struct {
22 | config *Config
23 | server string
24 | name string
25 | clienttype CLIENT_TYPE
26 | proxyproto []PROXY_PROTO
27 | fromaddr []string
28 | toaddr []string
29 | serverconn []*ServerConn
30 | wg *thread.Group
31 | }
32 |
33 | func NewClient(config *Config, serverproto string, server string, name string, clienttypestr string, proxyprotostr []string, fromaddr []string, toaddr []string) (*Client, error) {
34 |
35 | if config == nil {
36 | config = DefaultConfig()
37 | }
38 |
39 | cn, err := network.NewConn(serverproto)
40 | if cn == nil {
41 | return nil, err
42 | }
43 |
44 | setCongestion(cn, config)
45 |
46 | clienttypestr = strings.ToUpper(clienttypestr)
47 | clienttype, ok := CLIENT_TYPE_value[clienttypestr]
48 | if !ok {
49 | return nil, errors.New("no CLIENT_TYPE " + clienttypestr)
50 | }
51 |
52 | var proxyproto []PROXY_PROTO
53 | for i, _ := range proxyprotostr {
54 | p, ok := PROXY_PROTO_value[strings.ToUpper(proxyprotostr[i])]
55 | if !ok {
56 | return nil, errors.New("no PROXY_PROTO " + proxyprotostr[i])
57 | }
58 | proxyproto = append(proxyproto, PROXY_PROTO(p))
59 | }
60 |
61 | wg := thread.NewGroup("Clent"+" "+clienttypestr, nil, nil)
62 |
63 | c := &Client{
64 | config: config,
65 | server: server,
66 | name: name,
67 | clienttype: CLIENT_TYPE(clienttype),
68 | proxyproto: proxyproto,
69 | fromaddr: fromaddr,
70 | toaddr: toaddr,
71 | serverconn: make([]*ServerConn, len(proxyprotostr)),
72 | wg: wg,
73 | }
74 |
75 | wg.Go("Client state"+" "+clienttypestr, func() error {
76 | return showState(wg)
77 | })
78 |
79 | wg.Go("Client check deadlock"+" "+clienttypestr, func() error {
80 | return checkDeadLock(wg)
81 | })
82 |
83 | for i, _ := range proxyprotostr {
84 | index := i
85 | toaddrstr := ""
86 | if len(toaddr) > 0 {
87 | toaddrstr = toaddr[i]
88 | }
89 | wg.Go("Client connect"+" "+fromaddr[i]+" "+toaddrstr, func() error {
90 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
91 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
92 | return c.connect(index, cn)
93 | })
94 | }
95 |
96 | return c, nil
97 | }
98 |
99 | func (c *Client) Close() {
100 | c.wg.Stop()
101 | c.wg.Wait()
102 | }
103 |
104 | func (c *Client) connect(index int, conn network.Conn) error {
105 | loggo.Info("connect start %d %s", index, c.server)
106 |
107 | for !c.wg.IsExit() {
108 | if c.serverconn[index] == nil {
109 | targetconn, err := conn.Dial(c.server)
110 | if err != nil {
111 | loggo.Error("connect Dial fail: %s %s", c.server, err.Error())
112 | time.Sleep(time.Second)
113 | continue
114 | }
115 | c.serverconn[index] = &ServerConn{ProxyConn: ProxyConn{conn: targetconn}}
116 | c.wg.Go("Client useServer"+" "+targetconn.Info(), func() error {
117 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
118 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
119 | return c.useServer(index, c.serverconn[index])
120 | })
121 | } else {
122 | time.Sleep(time.Second)
123 | }
124 | }
125 | loggo.Info("connect end %s", c.server)
126 | return nil
127 | }
128 |
129 | func (c *Client) useServer(index int, serverconn *ServerConn) error {
130 |
131 | loggo.Info("useServer %s", serverconn.conn.Info())
132 |
133 | sendch := common.NewChannel(c.config.MainBuffer)
134 | recvch := common.NewChannel(c.config.MainBuffer)
135 |
136 | serverconn.sendch = sendch
137 | serverconn.recvch = recvch
138 |
139 | wg := thread.NewGroup("Client useServer"+" "+serverconn.conn.Info(), c.wg, func() {
140 | loggo.Info("group start exit %s", serverconn.conn.Info())
141 | serverconn.conn.Close()
142 | sendch.Close()
143 | recvch.Close()
144 | if serverconn.output != nil {
145 | serverconn.output.Close()
146 | }
147 | if serverconn.input != nil {
148 | serverconn.input.Close()
149 | }
150 | loggo.Info("group end exit %s", serverconn.conn.Info())
151 | })
152 |
153 | c.login(index, sendch)
154 |
155 | var pingflag int32
156 | var pongflag int32
157 | var pongtime int64
158 |
159 | wg.Go("Client recvFrom"+" "+serverconn.conn.Info(), func() error {
160 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
161 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
162 | return recvFrom(wg, recvch, serverconn.conn, c.config.MaxMsgSize, c.config.Encrypt)
163 | })
164 |
165 | wg.Go("Client sendTo"+" "+serverconn.conn.Info(), func() error {
166 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
167 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
168 | return sendTo(wg, sendch, serverconn.conn, c.config.Compress, c.config.MaxMsgSize, c.config.Encrypt, &pingflag, &pongflag, &pongtime)
169 | })
170 |
171 | wg.Go("Client checkPingActive"+" "+serverconn.conn.Info(), func() error {
172 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
173 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
174 | return checkPingActive(wg, sendch, recvch, &serverconn.ProxyConn, c.config.EstablishedTimeout, c.config.PingInter, c.config.PingTimeoutInter, c.config.ShowPing, &pingflag)
175 | })
176 |
177 | wg.Go("Client checkNeedClose"+" "+serverconn.conn.Info(), func() error {
178 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
179 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
180 | return checkNeedClose(wg, &serverconn.ProxyConn)
181 | })
182 |
183 | wg.Go("Client process"+" "+serverconn.conn.Info(), func() error {
184 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
185 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
186 | return c.process(wg, index, sendch, recvch, serverconn, &pongflag, &pongtime)
187 | })
188 |
189 | wg.Wait()
190 | c.serverconn[index] = nil
191 | loggo.Info("useServer close %s %s", c.server, serverconn.conn.Info())
192 |
193 | return nil
194 | }
195 |
196 | func (c *Client) login(index int, sendch *common.Channel) {
197 | f := &ProxyFrame{}
198 | f.Type = FRAME_TYPE_LOGIN
199 | f.LoginFrame = &LoginFrame{}
200 | f.LoginFrame.Proxyproto = c.proxyproto[index]
201 | f.LoginFrame.Clienttype = c.clienttype
202 | f.LoginFrame.Fromaddr = c.fromaddr[index]
203 | if len(c.toaddr) > 0 {
204 | f.LoginFrame.Toaddr = c.toaddr[index]
205 | }
206 | f.LoginFrame.Name = c.name + "_" + strconv.Itoa(index)
207 | f.LoginFrame.Key = c.config.Key
208 |
209 | sendch.Write(f)
210 |
211 | loggo.Info("start login %d %s %s", index, c.server, f.LoginFrame.String())
212 | }
213 |
214 | func (c *Client) process(wg *thread.Group, index int, sendch *common.Channel, recvch *common.Channel, serverconn *ServerConn, pongflag *int32, pongtime *int64) error {
215 |
216 | loggo.Info("process start %s", serverconn.conn.Info())
217 |
218 | for !wg.IsExit() {
219 |
220 | ff := <-recvch.Ch()
221 | if ff == nil {
222 | break
223 | }
224 | f := ff.(*ProxyFrame)
225 | switch f.Type {
226 | case FRAME_TYPE_LOGINRSP:
227 | c.processLoginRsp(wg, index, f, sendch, serverconn)
228 |
229 | case FRAME_TYPE_PING:
230 | processPing(f, sendch, &serverconn.ProxyConn, pongflag, pongtime)
231 |
232 | case FRAME_TYPE_PONG:
233 | processPong(f, sendch, &serverconn.ProxyConn, c.config.ShowPing)
234 |
235 | case FRAME_TYPE_DATA:
236 | c.processData(f, serverconn)
237 |
238 | case FRAME_TYPE_OPEN:
239 | c.processOpen(f, serverconn)
240 |
241 | case FRAME_TYPE_OPENRSP:
242 | c.processOpenRsp(f, serverconn)
243 |
244 | case FRAME_TYPE_CLOSE:
245 | c.processClose(f, serverconn)
246 | }
247 | }
248 | loggo.Info("process end %s", serverconn.conn.Info())
249 | return nil
250 | }
251 |
252 | func (c *Client) processLoginRsp(wg *thread.Group, index int, f *ProxyFrame, sendch *common.Channel, serverconn *ServerConn) {
253 | if !f.LoginRspFrame.Ret {
254 | serverconn.needclose = true
255 | loggo.Error("processLoginRsp fail %s %s", c.server, f.LoginRspFrame.Msg)
256 | return
257 | }
258 |
259 | loggo.Info("processLoginRsp ok %s", c.server)
260 |
261 | err := c.iniService(wg, index, serverconn)
262 | if err != nil {
263 | loggo.Error("processLoginRsp iniService fail %s %s", c.server, err)
264 | return
265 | }
266 |
267 | serverconn.established = true
268 | }
269 |
270 | func (c *Client) iniService(wg *thread.Group, index int, serverConn *ServerConn) error {
271 | switch c.clienttype {
272 | case CLIENT_TYPE_PROXY:
273 | input, err := NewInputer(wg, c.proxyproto[index].String(), c.fromaddr[index], c.clienttype, c.config, &serverConn.ProxyConn, c.toaddr[index])
274 | if err != nil {
275 | return err
276 | }
277 | serverConn.input = input
278 | case CLIENT_TYPE_REVERSE_PROXY:
279 | output, err := NewOutputer(wg, c.proxyproto[index].String(), c.clienttype, c.config, &serverConn.ProxyConn)
280 | if err != nil {
281 | return err
282 | }
283 | serverConn.output = output
284 | case CLIENT_TYPE_SOCKS5:
285 | input, err := NewSocks5Inputer(wg, c.proxyproto[index].String(), c.fromaddr[index], c.clienttype, c.config, &serverConn.ProxyConn)
286 | if err != nil {
287 | return err
288 | }
289 | serverConn.input = input
290 | case CLIENT_TYPE_REVERSE_SOCKS5:
291 | output, err := NewOutputer(wg, c.proxyproto[index].String(), c.clienttype, c.config, &serverConn.ProxyConn)
292 | if err != nil {
293 | return err
294 | }
295 | serverConn.output = output
296 | case CLIENT_TYPE_SS_PROXY:
297 | input, err := NewInputer(wg, c.proxyproto[index].String(), c.fromaddr[index], c.clienttype, c.config, &serverConn.ProxyConn, c.toaddr[index])
298 | if err != nil {
299 | return err
300 | }
301 | serverConn.input = input
302 | default:
303 | return errors.New("error CLIENT_TYPE " + strconv.Itoa(int(c.clienttype)))
304 | }
305 | return nil
306 | }
307 |
308 | func (c *Client) processData(f *ProxyFrame, serverconn *ServerConn) {
309 | if serverconn.input != nil {
310 | serverconn.input.processDataFrame(f)
311 | } else if serverconn.output != nil {
312 | serverconn.output.processDataFrame(f)
313 | }
314 | }
315 |
316 | func (c *Client) processOpen(f *ProxyFrame, serverconn *ServerConn) {
317 | if serverconn.output != nil {
318 | serverconn.output.processOpenFrame(f)
319 | }
320 | }
321 |
322 | func (c *Client) processOpenRsp(f *ProxyFrame, serverconn *ServerConn) {
323 | if serverconn.input != nil {
324 | serverconn.input.processOpenRspFrame(f)
325 | }
326 | }
327 |
328 | func (c *Client) processClose(f *ProxyFrame, serverconn *ServerConn) {
329 | if serverconn.input != nil {
330 | serverconn.input.processCloseFrame(f)
331 | } else if serverconn.output != nil {
332 | serverconn.output.processCloseFrame(f)
333 | }
334 | }
335 |
--------------------------------------------------------------------------------
/proxy/common.go:
--------------------------------------------------------------------------------
1 | package proxy
2 |
3 | import (
4 | "encoding/binary"
5 | "errors"
6 | "github.com/esrrhs/gohome/common"
7 | "github.com/esrrhs/gohome/loggo"
8 | "github.com/esrrhs/gohome/network"
9 | "github.com/esrrhs/gohome/thread"
10 | "github.com/golang/protobuf/proto"
11 | "io"
12 | "strconv"
13 | "sync/atomic"
14 | "time"
15 | )
16 |
17 | type Config struct {
18 | MaxMsgSize int // 消息最大长度
19 | MainBuffer int // 主通道buffer最大长度
20 | ConnBuffer int // 每个conn buffer最大长度
21 | EstablishedTimeout int // 主通道登录超时
22 | PingInter int // 主通道ping间隔
23 | PingTimeoutInter int // 主通道ping超时间隔
24 | ConnTimeout int // 每个conn的不活跃超时时间
25 | ConnectTimeout int // 每个conn的连接超时
26 | Key string // 连接密码
27 | Encrypt string // 加密密钥
28 | Compress int // 压缩设置
29 | ShowPing bool // 是否显示ping
30 | Username string // 登录用户名
31 | Password string // 登录密码
32 | MaxClient int // 最大客户端数目
33 | MaxSonny int // 最大连接数目
34 | MainWriteChannelTimeoutMs int // 主通道转发消息超时
35 | Congestion string // 拥塞算法
36 | }
37 |
38 | func DefaultConfig() *Config {
39 | return &Config{
40 | MaxMsgSize: 1024 * 1024,
41 | MainBuffer: 64,
42 | ConnBuffer: 16,
43 | EstablishedTimeout: 10,
44 | PingInter: 1,
45 | PingTimeoutInter: 30,
46 | ConnTimeout: 60,
47 | ConnectTimeout: 10,
48 | Key: "123456",
49 | Encrypt: "default",
50 | Compress: 128,
51 | ShowPing: false,
52 | Username: "",
53 | Password: "",
54 | MaxClient: 8,
55 | MaxSonny: 128,
56 | MainWriteChannelTimeoutMs: 1000,
57 | Congestion: "bb",
58 | }
59 | }
60 |
61 | type ProxyConn struct {
62 | conn network.Conn
63 | established bool
64 | sendch *common.Channel // *ProxyFrame
65 | recvch *common.Channel // *ProxyFrame
66 | actived int
67 | pinged int
68 | id string
69 | needclose bool
70 | }
71 |
72 | func checkProxyFame(f *ProxyFrame) error {
73 | switch f.Type {
74 | case FRAME_TYPE_LOGIN:
75 | if f.LoginFrame == nil {
76 | return errors.New("LoginFrame nil")
77 | }
78 | case FRAME_TYPE_LOGINRSP:
79 | if f.LoginRspFrame == nil {
80 | return errors.New("LoginRspFrame nil")
81 | }
82 | case FRAME_TYPE_DATA:
83 | if f.DataFrame == nil {
84 | return errors.New("DataFrame nil")
85 | }
86 | case FRAME_TYPE_PING:
87 | if f.PingFrame == nil {
88 | return errors.New("PingFrame nil")
89 | }
90 | case FRAME_TYPE_PONG:
91 | if f.PongFrame == nil {
92 | return errors.New("PongFrame nil")
93 | }
94 | case FRAME_TYPE_OPEN:
95 | if f.OpenFrame == nil {
96 | return errors.New("OpenFrame nil")
97 | }
98 | case FRAME_TYPE_OPENRSP:
99 | if f.OpenRspFrame == nil {
100 | return errors.New("OpenRspFrame nil")
101 | }
102 | case FRAME_TYPE_CLOSE:
103 | if f.CloseFrame == nil {
104 | return errors.New("CloseFrame nil")
105 | }
106 | default:
107 | return errors.New("Type error")
108 | }
109 |
110 | return nil
111 | }
112 |
113 | func MarshalSrpFrame(f *ProxyFrame, compress int, encrpyt string) ([]byte, error) {
114 |
115 | err := checkProxyFame(f)
116 | if err != nil {
117 | return nil, err
118 | }
119 |
120 | if f.Type == FRAME_TYPE_DATA && compress > 0 && len(f.DataFrame.Data) > compress && !f.DataFrame.Compress {
121 | newb := common.CompressData(f.DataFrame.Data)
122 | if len(newb) < len(f.DataFrame.Data) {
123 | if loggo.IsDebug() {
124 | loggo.Debug("MarshalSrpFrame Compress from %d %d", len(f.DataFrame.Data), len(newb))
125 | }
126 | atomic.AddInt64(&gState.SendCompSaveSize, int64(len(f.DataFrame.Data)-len(newb)))
127 | f.DataFrame.Data = newb
128 | f.DataFrame.Compress = true
129 | }
130 | }
131 |
132 | if f.Type == FRAME_TYPE_DATA && encrpyt != "" {
133 | newb, err := common.Rc4(encrpyt, f.DataFrame.Data)
134 | if err != nil {
135 | return nil, err
136 | }
137 | if loggo.IsDebug() {
138 | loggo.Debug("MarshalSrpFrame Rc4 from %s %s", common.GetCrc32(f.DataFrame.Data), common.GetCrc32(newb))
139 | }
140 | f.DataFrame.Data = newb
141 | }
142 |
143 | mb, err := proto.Marshal(f)
144 | if err != nil {
145 | return nil, err
146 | }
147 | return mb, err
148 | }
149 |
150 | func UnmarshalSrpFrame(b []byte, encrpyt string) (*ProxyFrame, error) {
151 |
152 | f := &ProxyFrame{}
153 | err := proto.Unmarshal(b, f)
154 | if err != nil {
155 | return nil, err
156 | }
157 |
158 | err = checkProxyFame(f)
159 | if err != nil {
160 | return nil, err
161 | }
162 |
163 | if f.Type == FRAME_TYPE_DATA && encrpyt != "" {
164 | newb, err := common.Rc4(encrpyt, f.DataFrame.Data)
165 | if err != nil {
166 | return nil, err
167 | }
168 | if loggo.IsDebug() {
169 | loggo.Debug("UnmarshalSrpFrame Rc4 from %s %s", common.GetCrc32(f.DataFrame.Data), common.GetCrc32(newb))
170 | }
171 | f.DataFrame.Data = newb
172 | }
173 |
174 | if f.Type == FRAME_TYPE_DATA && f.DataFrame.Compress {
175 | newb, err := common.DeCompressData(f.DataFrame.Data)
176 | if err != nil {
177 | return nil, err
178 | }
179 | if loggo.IsDebug() {
180 | loggo.Debug("UnmarshalSrpFrame Compress from %d %d", len(f.DataFrame.Data), len(newb))
181 | }
182 | atomic.AddInt64(&gState.RecvCompSaveSize, int64(len(newb)-len(f.DataFrame.Data)))
183 | f.DataFrame.Data = newb
184 | f.DataFrame.Compress = false
185 | }
186 |
187 | return f, nil
188 | }
189 |
190 | const (
191 | MAX_PROTO_PACK_SIZE = 100
192 | )
193 |
194 | func recvFrom(wg *thread.Group, recvch *common.Channel, conn network.Conn, maxmsgsize int, encrypt string) error {
195 |
196 | atomic.AddInt32(&gStateThreadNum.RecvThread, 1)
197 | defer atomic.AddInt32(&gStateThreadNum.RecvThread, -1)
198 |
199 | loggo.Info("recvFrom start %s", conn.Info())
200 | bs := make([]byte, 4)
201 | ds := make([]byte, maxmsgsize+MAX_PROTO_PACK_SIZE)
202 |
203 | for !wg.IsExit() {
204 | atomic.AddInt32(&gState.RecvFrames, 1)
205 |
206 | if loggo.IsDebug() {
207 | loggo.Debug("recvFrom start ReadFull len %s", conn.Info())
208 | }
209 | _, err := io.ReadFull(conn, bs)
210 | if err != nil {
211 | loggo.Info("recvFrom ReadFull fail: %s %s", conn.Info(), err.Error())
212 | return err
213 | }
214 |
215 | msglen := binary.LittleEndian.Uint32(bs)
216 | if msglen > uint32(maxmsgsize)+MAX_PROTO_PACK_SIZE || msglen <= 0 {
217 | loggo.Error("recvFrom len fail: %s %d", conn.Info(), msglen)
218 | return errors.New("msg len fail " + strconv.Itoa(int(msglen)))
219 | }
220 |
221 | gDeadLock.recvTime = time.Now()
222 | gDeadLock.recving = true
223 |
224 | if loggo.IsDebug() {
225 | loggo.Debug("recvFrom start ReadFull body %s %d", conn.Info(), msglen)
226 | }
227 | _, err = io.ReadFull(conn, ds[0:msglen])
228 | if err != nil {
229 | loggo.Info("recvFrom ReadFull fail: %s %s", conn.Info(), err.Error())
230 | return err
231 | }
232 |
233 | f, err := UnmarshalSrpFrame(ds[0:msglen], encrypt)
234 | if err != nil {
235 | loggo.Error("recvFrom UnmarshalSrpFrame fail: %s %s", conn.Info(), err.Error())
236 | return err
237 | }
238 |
239 | if loggo.IsDebug() {
240 | loggo.Debug("recvFrom start Write %s", conn.Info())
241 | }
242 | recvch.Write(f)
243 |
244 | if f.Type != FRAME_TYPE_PING && f.Type != FRAME_TYPE_PONG && loggo.IsDebug() {
245 | loggo.Debug("recvFrom %s %s", conn.Info(), f.Type.String())
246 | if f.Type == FRAME_TYPE_DATA {
247 | if common.GetCrc32(f.DataFrame.Data) != f.DataFrame.Crc {
248 | loggo.Error("recvFrom crc error %s %s %s %p", conn.Info(), common.GetCrc32(f.DataFrame.Data), f.DataFrame.Crc, f)
249 | return errors.New("conn crc error")
250 | }
251 | }
252 | }
253 |
254 | atomic.AddInt32(&gState.MainRecvNum, 1)
255 | atomic.AddInt64(&gState.MainRecvSize, int64(msglen)+4)
256 |
257 | gDeadLock.recving = false
258 | }
259 |
260 | loggo.Info("recvFrom end %s", conn.Info())
261 | return nil
262 | }
263 |
264 | func sendTo(wg *thread.Group, sendch *common.Channel, conn network.Conn, compress int, maxmsgsize int, encrypt string, pingflag *int32, pongflag *int32, pongtime *int64) error {
265 |
266 | atomic.AddInt32(&gStateThreadNum.SendThread, 1)
267 | defer atomic.AddInt32(&gStateThreadNum.SendThread, -1)
268 |
269 | loggo.Info("sendTo start %s", conn.Info())
270 | bs := make([]byte, 4)
271 |
272 | for !wg.IsExit() {
273 | atomic.AddInt32(&gState.SendFrames, 1)
274 |
275 | var f *ProxyFrame
276 | if *pingflag > 0 {
277 | *pingflag = 0
278 | f = &ProxyFrame{}
279 | f.Type = FRAME_TYPE_PING
280 | f.PingFrame = &PingFrame{}
281 | f.PingFrame.Time = time.Now().UnixNano()
282 | } else if *pongflag > 0 {
283 | *pongflag = 0
284 | f = &ProxyFrame{}
285 | f.Type = FRAME_TYPE_PONG
286 | f.PongFrame = &PongFrame{}
287 | f.PongFrame.Time = *pongtime
288 | } else {
289 | exit := false
290 | select {
291 | case ff := <-sendch.Ch():
292 | if ff == nil {
293 | exit = true
294 | break
295 | }
296 | f = ff.(*ProxyFrame)
297 | case <-time.After(time.Second):
298 | break
299 | }
300 | if f == nil {
301 | if exit {
302 | break
303 | }
304 | continue
305 | }
306 | }
307 | mb, err := MarshalSrpFrame(f, compress, encrypt)
308 | if err != nil {
309 | loggo.Error("sendTo MarshalSrpFrame fail: %s %s", conn.Info(), err.Error())
310 | return err
311 | }
312 |
313 | msglen := uint32(len(mb))
314 | if msglen > uint32(maxmsgsize)+MAX_PROTO_PACK_SIZE || msglen <= 0 {
315 | loggo.Error("sendTo len fail: %s %d", conn.Info(), msglen)
316 | return errors.New("msg len fail " + strconv.Itoa(int(msglen)))
317 | }
318 |
319 | gDeadLock.sendTime = time.Now()
320 | gDeadLock.sending = true
321 |
322 | if loggo.IsDebug() {
323 | loggo.Debug("sendTo start Write len %s", conn.Info())
324 | }
325 | binary.LittleEndian.PutUint32(bs, msglen)
326 | _, err = conn.Write(bs)
327 | if err != nil {
328 | loggo.Info("sendTo Write fail: %s %s", conn.Info(), err.Error())
329 | return err
330 | }
331 |
332 | if loggo.IsDebug() {
333 | loggo.Debug("sendTo start Write body %s %d", conn.Info(), msglen)
334 | }
335 | n, err := conn.Write(mb)
336 | if err != nil {
337 | loggo.Info("sendTo Write fail: %s %s", conn.Info(), err.Error())
338 | return err
339 | }
340 |
341 | if n != len(mb) {
342 | loggo.Error("sendTo Write len fail: %s %d %d", conn.Info(), n, len(mb))
343 | return errors.New("len error")
344 | }
345 |
346 | if f.Type != FRAME_TYPE_PING && f.Type != FRAME_TYPE_PONG && loggo.IsDebug() {
347 | loggo.Debug("sendTo %s %s", conn.Info(), f.Type.String())
348 | if f.Type == FRAME_TYPE_DATA {
349 | if common.GetCrc32(f.DataFrame.Data) != f.DataFrame.Crc {
350 | loggo.Error("sendTo crc error %s %s %s %p", conn.Info(), common.GetCrc32(f.DataFrame.Data), f.DataFrame.Crc, f)
351 | return errors.New("conn crc error")
352 | }
353 | }
354 | }
355 |
356 | atomic.AddInt32(&gState.MainSendNum, 1)
357 | atomic.AddInt64(&gState.MainSendSize, int64(msglen)+4)
358 |
359 | gDeadLock.sending = false
360 | }
361 | loggo.Info("sendTo end %s", conn.Info())
362 | return nil
363 | }
364 |
365 | const (
366 | MAX_INDEX = 1024
367 | )
368 |
369 | func recvFromSonny(wg *thread.Group, recvch *common.Channel, conn network.Conn, maxmsgsize int) error {
370 |
371 | atomic.AddInt32(&gStateThreadNum.RecvSonnyThread, 1)
372 | defer atomic.AddInt32(&gStateThreadNum.RecvSonnyThread, -1)
373 |
374 | loggo.Info("recvFromSonny start %s", conn.Info())
375 | ds := make([]byte, maxmsgsize)
376 |
377 | index := int32(0)
378 | for !wg.IsExit() {
379 | atomic.AddInt32(&gState.RecvSonnyFrames, 1)
380 |
381 | msglen, err := conn.Read(ds)
382 | if err != nil {
383 | loggo.Info("recvFromSonny Read fail: %s %s", conn.Info(), err.Error())
384 | if err == io.EOF {
385 | return nil
386 | }
387 | return err
388 | }
389 |
390 | if msglen <= 0 {
391 | loggo.Error("recvFromSonny len error: %s %d", conn.Info(), msglen)
392 | return errors.New("len error " + strconv.Itoa(msglen))
393 | }
394 |
395 | f := &ProxyFrame{}
396 | f.Type = FRAME_TYPE_DATA
397 | f.DataFrame = &DataFrame{}
398 | f.DataFrame.Data = make([]byte, msglen)
399 | copy(f.DataFrame.Data, ds[0:msglen])
400 | f.DataFrame.Compress = false
401 | if loggo.IsDebug() {
402 | f.DataFrame.Crc = common.GetCrc32(f.DataFrame.Data)
403 | }
404 | index++
405 | f.DataFrame.Index = index % MAX_INDEX
406 |
407 | recvch.Write(f)
408 |
409 | if loggo.IsDebug() {
410 | loggo.Debug("recvFromSonny %s %d %s %d %p", conn.Info(), msglen, f.DataFrame.Crc, f.DataFrame.Index, f)
411 | }
412 |
413 | atomic.AddInt32(&gState.RecvNum, 1)
414 | atomic.AddInt64(&gState.RecvSize, int64(len(f.DataFrame.Data)))
415 | }
416 | loggo.Info("recvFromSonny end %s", conn.Info())
417 | return nil
418 | }
419 |
420 | func sendToSonny(wg *thread.Group, sendch *common.Channel, conn network.Conn, maxmsgsize int) error {
421 |
422 | atomic.AddInt32(&gStateThreadNum.SendSonnyThread, 1)
423 | defer atomic.AddInt32(&gStateThreadNum.SendSonnyThread, -1)
424 |
425 | loggo.Info("sendToSonny start %s", conn.Info())
426 | index := int32(0)
427 | for !wg.IsExit() {
428 | atomic.AddInt32(&gState.SendSonnyFrames, 1)
429 |
430 | ff := <-sendch.Ch()
431 | if ff == nil {
432 | break
433 | }
434 | f := ff.(*ProxyFrame)
435 | if f.Type == FRAME_TYPE_CLOSE {
436 | loggo.Info("sendToSonny close by remote: %s", conn.Info())
437 | return errors.New("close by remote")
438 | }
439 | if f.DataFrame.Compress {
440 | loggo.Error("sendToSonny Compress error: %s", conn.Info())
441 | return errors.New("msg compress error")
442 | }
443 |
444 | if len(f.DataFrame.Data) <= 0 {
445 | loggo.Error("sendToSonny len error: %s %d", conn.Info(), len(f.DataFrame.Data))
446 | return errors.New("len error " + strconv.Itoa(len(f.DataFrame.Data)))
447 | }
448 |
449 | if len(f.DataFrame.Data) > maxmsgsize {
450 | loggo.Error("sendToSonny len error: %s %d", conn.Info(), len(f.DataFrame.Data))
451 | return errors.New("len error " + strconv.Itoa(len(f.DataFrame.Data)))
452 | }
453 |
454 | if loggo.IsDebug() {
455 | if f.DataFrame.Crc != common.GetCrc32(f.DataFrame.Data) {
456 | loggo.Error("sendToSonny crc error: %s %d %s %s", conn.Info(), len(f.DataFrame.Data), f.DataFrame.Crc, common.GetCrc32(f.DataFrame.Data))
457 | return errors.New("crc error")
458 | }
459 | }
460 |
461 | index++
462 | index = index % MAX_INDEX
463 | if f.DataFrame.Index != index {
464 | loggo.Error("sendToSonny index error: %s %d %d %d", conn.Info(), len(f.DataFrame.Data), f.DataFrame.Index, index)
465 | return errors.New("index error")
466 | }
467 |
468 | n, err := conn.Write(f.DataFrame.Data)
469 | if err != nil {
470 | loggo.Info("sendToSonny Write fail: %s %s", conn.Info(), err.Error())
471 | return err
472 | }
473 |
474 | if n != len(f.DataFrame.Data) {
475 | loggo.Error("sendToSonny Write len fail: %s %d %d", conn.Info(), n, len(f.DataFrame.Data))
476 | return errors.New("len error")
477 | }
478 |
479 | if loggo.IsDebug() {
480 | loggo.Debug("sendToSonny %s %d %s %d", conn.Info(), len(f.DataFrame.Data), f.DataFrame.Crc, f.DataFrame.Index)
481 | }
482 |
483 | atomic.AddInt32(&gState.SendNum, 1)
484 | atomic.AddInt64(&gState.SendSize, int64(len(f.DataFrame.Data)))
485 | }
486 | loggo.Info("sendToSonny end %s", conn.Info())
487 | return nil
488 | }
489 |
490 | func checkPingActive(wg *thread.Group, sendch *common.Channel, recvch *common.Channel, proxyconn *ProxyConn,
491 | estimeout int, pinginter int, pingintertimeout int, showping bool, pingflag *int32) error {
492 |
493 | atomic.AddInt32(&gStateThreadNum.CheckThread, 1)
494 | defer atomic.AddInt32(&gStateThreadNum.CheckThread, -1)
495 |
496 | loggo.Info("checkPingActive start %s", proxyconn.conn.Info())
497 |
498 | begin := time.Now()
499 | for !wg.IsExit() {
500 | atomic.AddInt32(&gState.CheckFrames, 1)
501 |
502 | if !proxyconn.established {
503 | if time.Now().Sub(begin) > time.Second*time.Duration(estimeout) {
504 | loggo.Info("checkPingActive established timeout %s", proxyconn.conn.Info())
505 | return errors.New("established timeout")
506 | }
507 | } else {
508 | break
509 | }
510 | time.Sleep(time.Millisecond * 100)
511 | }
512 |
513 | begin = time.Now()
514 | for !wg.IsExit() {
515 | atomic.AddInt32(&gState.CheckFrames, 1)
516 |
517 | if time.Now().Sub(begin) > time.Duration(pinginter)*time.Second {
518 | begin = time.Now()
519 |
520 | if proxyconn.pinged > pingintertimeout {
521 | loggo.Info("checkPingActive ping pong timeout %s", proxyconn.conn.Info())
522 | return errors.New("ping pong timeout")
523 | }
524 |
525 | atomic.AddInt32(pingflag, 1)
526 |
527 | proxyconn.pinged++
528 | if showping {
529 | loggo.Info("ping %s", proxyconn.conn.Info())
530 | }
531 | }
532 | time.Sleep(time.Millisecond * 100)
533 | }
534 |
535 | loggo.Info("checkPingActive end %s", proxyconn.conn.Info())
536 | return nil
537 | }
538 |
539 | func checkNeedClose(wg *thread.Group, proxyconn *ProxyConn) error {
540 |
541 | atomic.AddInt32(&gStateThreadNum.CheckThread, 1)
542 | defer atomic.AddInt32(&gStateThreadNum.CheckThread, -1)
543 |
544 | loggo.Info("checkNeedClose start %s", proxyconn.conn.Info())
545 |
546 | for !wg.IsExit() {
547 | atomic.AddInt32(&gState.CheckFrames, 1)
548 |
549 | if proxyconn.needclose {
550 | loggo.Error("checkNeedClose needclose %s", proxyconn.conn.Info())
551 | return errors.New("needclose")
552 | }
553 | time.Sleep(time.Millisecond * 100)
554 | }
555 |
556 | loggo.Info("checkNeedClose end %s", proxyconn.conn.Info())
557 |
558 | return nil
559 | }
560 |
561 | func processPing(f *ProxyFrame, sendch *common.Channel, proxyconn *ProxyConn, pongflag *int32, pongtime *int64) {
562 | atomic.AddInt32(pongflag, 1)
563 | *pongtime = f.PingFrame.Time
564 | }
565 |
566 | func processPong(f *ProxyFrame, sendch *common.Channel, proxyconn *ProxyConn, showping bool) {
567 | elapse := time.Duration(time.Now().UnixNano() - f.PongFrame.Time)
568 | proxyconn.pinged = 0
569 | if showping {
570 | loggo.Info("pong %s %s", proxyconn.conn.Info(), elapse.String())
571 | }
572 | }
573 |
574 | func checkSonnyActive(wg *thread.Group, proxyconn *ProxyConn, estimeout int, timeout int) error {
575 |
576 | atomic.AddInt32(&gStateThreadNum.CheckThread, 1)
577 | defer atomic.AddInt32(&gStateThreadNum.CheckThread, -1)
578 |
579 | loggo.Info("checkSonnyActive start %s", proxyconn.conn.Info())
580 |
581 | begin := time.Now()
582 | for !wg.IsExit() {
583 | atomic.AddInt32(&gState.CheckFrames, 1)
584 |
585 | if !proxyconn.established {
586 | if time.Now().Sub(begin) > time.Second*time.Duration(estimeout) {
587 | loggo.Error("checkSonnyActive established timeout %s", proxyconn.conn.Info())
588 | return errors.New("established timeout")
589 | }
590 | } else {
591 | break
592 | }
593 | time.Sleep(time.Millisecond * 100)
594 | }
595 |
596 | begin = time.Now()
597 | for !wg.IsExit() {
598 | atomic.AddInt32(&gState.CheckFrames, 1)
599 |
600 | if time.Now().Sub(begin) > time.Second*time.Duration(timeout) {
601 | if proxyconn.actived == 0 {
602 | loggo.Error("checkSonnyActive timeout %s", proxyconn.conn.Info())
603 | return errors.New("conn timeout")
604 | }
605 | proxyconn.actived = 0
606 | begin = time.Now()
607 | }
608 | time.Sleep(time.Millisecond * 100)
609 | }
610 | loggo.Info("checkSonnyActive end %s", proxyconn.conn.Info())
611 | return nil
612 | }
613 |
614 | func copySonnyRecv(wg *thread.Group, recvch *common.Channel, proxyConn *ProxyConn, father *ProxyConn) error {
615 |
616 | atomic.AddInt32(&gStateThreadNum.CopyThread, 1)
617 | defer atomic.AddInt32(&gStateThreadNum.CopyThread, -1)
618 |
619 | loggo.Info("copySonnyRecv start %s", proxyConn.conn.Info())
620 |
621 | for !wg.IsExit() {
622 | atomic.AddInt32(&gState.CopyFrames, 1)
623 |
624 | ff := <-recvch.Ch()
625 | if ff == nil {
626 | break
627 | }
628 | f := ff.(*ProxyFrame)
629 | if f.Type != FRAME_TYPE_DATA {
630 | loggo.Error("copySonnyRecv type error %s %d", proxyConn.conn.Info(), f.Type)
631 | return errors.New("conn type error")
632 | }
633 | if f.DataFrame.Compress {
634 | loggo.Error("copySonnyRecv compress error %s %d", proxyConn.conn.Info(), f.Type)
635 | return errors.New("conn compress error")
636 | }
637 | if loggo.IsDebug() {
638 | if common.GetCrc32(f.DataFrame.Data) != f.DataFrame.Crc {
639 | loggo.Error("copySonnyRecv crc error %s %s %s", proxyConn.conn.Info(), common.GetCrc32(f.DataFrame.Data), f.DataFrame.Crc)
640 | return errors.New("conn crc error")
641 | }
642 | }
643 | f.DataFrame.Id = proxyConn.id
644 | proxyConn.actived++
645 |
646 | father.sendch.Write(f)
647 |
648 | loggo.Debug("copySonnyRecv %s %d %s %p", proxyConn.id, len(f.DataFrame.Data), f.DataFrame.Crc, f)
649 | }
650 | loggo.Info("copySonnyRecv end %s", proxyConn.conn.Info())
651 | return nil
652 | }
653 |
654 | func closeRemoteConn(proxyConn *ProxyConn, father *ProxyConn) {
655 | f := &ProxyFrame{}
656 | f.Type = FRAME_TYPE_CLOSE
657 | f.CloseFrame = &CloseFrame{}
658 | f.CloseFrame.Id = proxyConn.id
659 |
660 | father.sendch.Write(f)
661 | loggo.Info("closeConn %s", proxyConn.id)
662 | }
663 |
664 | type StateThreadNum struct {
665 | ThreadNum int32
666 | RecvThread int32
667 | SendThread int32
668 | RecvSonnyThread int32
669 | SendSonnyThread int32
670 | CopyThread int32
671 | CheckThread int32
672 | }
673 |
674 | type State struct {
675 | RecvFrames int32
676 | SendFrames int32
677 | RecvSonnyFrames int32
678 | SendSonnyFrames int32
679 | CopyFrames int32
680 | CheckFrames int32
681 |
682 | RecvFps int32
683 | SendFps int32
684 | RecvSonnyFps int32
685 | SendSonnyFps int32
686 | CopyFps int32
687 | CheckFps int32
688 |
689 | MainRecvNum int32
690 | MainSendNum int32
691 | MainRecvSize int64
692 | MainSendSize int64
693 | RecvNum int32
694 | SendNum int32
695 | RecvSize int64
696 | SendSize int64
697 |
698 | RecvCompSaveSize int64
699 | SendCompSaveSize int64
700 | }
701 |
702 | type DeadLock struct {
703 | sending bool
704 | sendTime time.Time
705 | recving bool
706 | recvTime time.Time
707 | }
708 |
709 | var gStateThreadNum StateThreadNum
710 | var gState State
711 | var gDeadLock DeadLock
712 |
713 | func showState(wg *thread.Group) error {
714 | loggo.Info("showState start ")
715 | begin := time.Now()
716 | for !wg.IsExit() {
717 | dur := time.Now().Sub(begin)
718 | if dur > time.Minute {
719 | begin = time.Now()
720 |
721 | dur := int32(dur / time.Second)
722 |
723 | if gStateThreadNum.RecvThread > 0 {
724 | gState.RecvFps = gState.RecvFrames / gStateThreadNum.RecvThread / dur
725 | } else {
726 | gState.RecvFps = 0
727 | }
728 | if gStateThreadNum.SendThread > 0 {
729 | gState.SendFps = gState.SendFrames / gStateThreadNum.SendThread / dur
730 | } else {
731 | gState.SendFps = 0
732 | }
733 | if gStateThreadNum.RecvSonnyThread > 0 {
734 | gState.RecvSonnyFps = gState.RecvSonnyFrames / gStateThreadNum.RecvSonnyThread / dur
735 | } else {
736 | gState.RecvSonnyFps = 0
737 | }
738 | if gStateThreadNum.SendSonnyThread > 0 {
739 | gState.SendSonnyFps = gState.SendSonnyFrames / gStateThreadNum.SendSonnyThread / dur
740 | } else {
741 | gState.SendSonnyFps = 0
742 | }
743 | if gStateThreadNum.CopyThread > 0 {
744 | gState.CopyFps = gState.CopyFrames / gStateThreadNum.CopyThread / dur
745 | } else {
746 | gState.CopyFps = 0
747 | }
748 | if gStateThreadNum.CheckThread > 0 {
749 | gState.CheckFps = gState.CheckFrames / gStateThreadNum.CheckThread / dur
750 | } else {
751 | gState.CheckFps = 0
752 | }
753 |
754 | loggo.Info("showState\n%s\n%s", common.StructToTable(&gStateThreadNum), common.StructToTable(&gState))
755 |
756 | gState = State{}
757 | }
758 | time.Sleep(time.Second)
759 | }
760 | loggo.Info("showState end")
761 | return nil
762 | }
763 |
764 | func checkDeadLock(wg *thread.Group) error {
765 | loggo.Info("checkDeadLock start ")
766 | begin := time.Now()
767 | for !wg.IsExit() {
768 | dur := time.Now().Sub(begin)
769 | if dur > time.Second {
770 | begin = time.Now()
771 |
772 | if gDeadLock.sending && time.Now().Sub(gDeadLock.sendTime) > 5*time.Second {
773 | loggo.Error("send dead lock %v", time.Now().Sub(gDeadLock.sendTime))
774 | }
775 | if gDeadLock.recving && time.Now().Sub(gDeadLock.recvTime) > 5*time.Second {
776 | loggo.Error("recv dead lock")
777 | loggo.Error("send dead lock %v", time.Now().Sub(gDeadLock.recvTime))
778 | }
779 | }
780 | time.Sleep(time.Millisecond * 300)
781 | }
782 | loggo.Info("checkDeadLock end")
783 | return nil
784 | }
785 |
786 | func setCongestion(c network.Conn, config *Config) {
787 | if c.Name() == "rudp" {
788 | cf := c.(*network.RudpConn).GetConfig()
789 | cf.Congestion = config.Congestion
790 | c.(*network.RudpConn).SetConfig(cf)
791 | } else if c.Name() == "ricmp" {
792 | cf := c.(*network.RicmpConn).GetConfig()
793 | cf.Congestion = config.Congestion
794 | c.(*network.RicmpConn).SetConfig(cf)
795 | }
796 | }
797 |
--------------------------------------------------------------------------------
/proxy/common_test.go:
--------------------------------------------------------------------------------
1 | package proxy
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 | )
7 |
8 | func Test0001(t *testing.T) {
9 | src := "aaabsfasasdfasfas3rdsfasfdhsafdshsafafafafaffasfsafa1111111111111111111111111111111111111111111111111111111111"
10 | f := &ProxyFrame{}
11 | f.Type = FRAME_TYPE_DATA
12 | f.DataFrame = &DataFrame{}
13 | f.DataFrame.Data = []byte(src)
14 | fmt.Println(len(f.DataFrame.Data))
15 | b, err := MarshalSrpFrame(f, 10, "123123")
16 | if err != nil {
17 | t.Error(err)
18 | }
19 | fmt.Println(len(f.DataFrame.Data))
20 | ff, err := UnmarshalSrpFrame(b, "123123")
21 | if err != nil {
22 | t.Error(err)
23 | }
24 | if string(ff.DataFrame.Data) != src {
25 | t.Error(err)
26 | }
27 | fmt.Println(string(ff.DataFrame.Data))
28 | }
29 |
--------------------------------------------------------------------------------
/proxy/gen.bat:
--------------------------------------------------------------------------------
1 | protoc --go_out=. *.proto
--------------------------------------------------------------------------------
/proxy/inputer.go:
--------------------------------------------------------------------------------
1 | package proxy
2 |
3 | import (
4 | "errors"
5 | "github.com/esrrhs/gohome/common"
6 | "github.com/esrrhs/gohome/loggo"
7 | "github.com/esrrhs/gohome/network"
8 | "github.com/esrrhs/gohome/thread"
9 | "sync"
10 | "sync/atomic"
11 | )
12 |
13 | type Inputer struct {
14 | clienttype CLIENT_TYPE
15 | config *Config
16 | proto string
17 | addr string
18 | father *ProxyConn
19 | fwg *thread.Group
20 |
21 | listenconn network.Conn
22 | sonny sync.Map
23 | }
24 |
25 | func NewInputer(wg *thread.Group, proto string, addr string, clienttype CLIENT_TYPE, config *Config, father *ProxyConn, targetAddr string) (*Inputer, error) {
26 | conn, err := network.NewConn(proto)
27 | if conn == nil {
28 | return nil, err
29 | }
30 |
31 | listenconn, err := conn.Listen(addr)
32 | if err != nil {
33 | return nil, err
34 | }
35 |
36 | input := &Inputer{
37 | clienttype: clienttype,
38 | config: config,
39 | proto: proto,
40 | addr: addr,
41 | father: father,
42 | fwg: wg,
43 | listenconn: listenconn,
44 | }
45 |
46 | wg.Go("Inputer listen"+" "+targetAddr, func() error {
47 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
48 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
49 | return input.listen(targetAddr)
50 | })
51 |
52 | loggo.Info("NewInputer ok %s", addr)
53 |
54 | return input, nil
55 | }
56 |
57 | func NewSocks5Inputer(wg *thread.Group, proto string, addr string, clienttype CLIENT_TYPE, config *Config, father *ProxyConn) (*Inputer, error) {
58 | conn, err := network.NewConn(proto)
59 | if conn == nil {
60 | return nil, err
61 | }
62 |
63 | listenconn, err := conn.Listen(addr)
64 | if err != nil {
65 | return nil, err
66 | }
67 |
68 | input := &Inputer{
69 | clienttype: clienttype,
70 | config: config,
71 | proto: proto,
72 | addr: addr,
73 | father: father,
74 | fwg: wg,
75 | listenconn: listenconn,
76 | }
77 |
78 | wg.Go("Inputer listenSocks5"+" "+addr, func() error {
79 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
80 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
81 | return input.listenSocks5()
82 | })
83 |
84 | loggo.Info("NewInputer ok %s", addr)
85 |
86 | return input, nil
87 | }
88 |
89 | func (i *Inputer) Close() {
90 | i.listenconn.Close()
91 | }
92 |
93 | func (i *Inputer) processDataFrame(f *ProxyFrame) {
94 | id := f.DataFrame.Id
95 | v, ok := i.sonny.Load(id)
96 | if !ok {
97 | loggo.Debug("Inputer processDataFrame no sonnny %s %d", id, len(f.DataFrame.Data))
98 | return
99 | }
100 | sonny := v.(*ProxyConn)
101 | if !sonny.sendch.WriteTimeout(f, i.config.MainWriteChannelTimeoutMs) {
102 | sonny.needclose = true
103 | loggo.Error("Inputer processDataFrame timeout sonnny %s %d", f.DataFrame.Id, len(f.DataFrame.Data))
104 | }
105 | sonny.actived++
106 | loggo.Debug("Inputer processDataFrame %s %d", f.DataFrame.Id, len(f.DataFrame.Data))
107 | }
108 |
109 | func (i *Inputer) processCloseFrame(f *ProxyFrame) {
110 | id := f.CloseFrame.Id
111 | v, ok := i.sonny.Load(id)
112 | if !ok {
113 | loggo.Info("Inputer processCloseFrame no sonnny %s", f.CloseFrame.Id)
114 | return
115 | }
116 |
117 | sonny := v.(*ProxyConn)
118 | sonny.sendch.Write(f)
119 | }
120 |
121 | func (i *Inputer) processOpenRspFrame(f *ProxyFrame) {
122 | id := f.OpenRspFrame.Id
123 | v, ok := i.sonny.Load(id)
124 | if !ok {
125 | loggo.Info("Inputer processOpenRspFrame no sonnny %s", id)
126 | return
127 | }
128 | sonny := v.(*ProxyConn)
129 | if f.OpenRspFrame.Ret {
130 | sonny.established = true
131 | loggo.Info("Inputer processOpenRspFrame ok %s %s", id, sonny.conn.Info())
132 | } else {
133 | sonny.needclose = true
134 | loggo.Info("Inputer processOpenRspFrame fail %s %s", id, sonny.conn.Info())
135 | }
136 | }
137 |
138 | func (i *Inputer) listen(targetAddr string) error {
139 |
140 | loggo.Info("Inputer start listen %s %s", i.addr, targetAddr)
141 |
142 | for !i.fwg.IsExit() {
143 | conn, err := i.listenconn.Accept()
144 | if err != nil {
145 | loggo.Info("Inputer listen Accept fail %s", err)
146 | continue
147 | }
148 |
149 | size := i.sonnySize()
150 | if size >= i.config.MaxSonny {
151 | loggo.Info("Inputer listen max sonny %s %d", conn.Info(), size)
152 | conn.Close()
153 | continue
154 | }
155 |
156 | proxyconn := &ProxyConn{conn: conn}
157 | i.fwg.Go("Inputer processProxyConn"+" "+targetAddr, func() error {
158 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
159 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
160 | return i.processProxyConn(proxyconn, targetAddr)
161 | })
162 | }
163 | loggo.Info("Inputer end listen %s", i.addr)
164 | return nil
165 | }
166 |
167 | func (i *Inputer) listenSocks5() error {
168 |
169 | loggo.Info("Inputer start listenSocks5 %s", i.addr)
170 |
171 | for !i.fwg.IsExit() {
172 | conn, err := i.listenconn.Accept()
173 | if err != nil {
174 | loggo.Info("Inputer listen Accept fail %s", err)
175 | continue
176 | }
177 |
178 | size := i.sonnySize()
179 | if size >= i.config.MaxSonny {
180 | loggo.Info("Inputer listen max sonny %s %d", conn.Info(), size)
181 | conn.Close()
182 | continue
183 | }
184 |
185 | proxyconn := &ProxyConn{conn: conn}
186 | i.fwg.Go("Inputer processSocks5Conn"+" "+conn.Info(), func() error {
187 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
188 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
189 | return i.processSocks5Conn(proxyconn)
190 | })
191 | }
192 | loggo.Info("Inputer end listenSocks5 %s", i.addr)
193 | return nil
194 | }
195 |
196 | func (i *Inputer) processSocks5Conn(proxyConn *ProxyConn) error {
197 |
198 | loggo.Info("processSocks5Conn start %s", proxyConn.conn.Info())
199 |
200 | wg := thread.NewGroup("Inputer processSocks5Conn"+" "+proxyConn.conn.Info(), i.fwg, func() {
201 | loggo.Info("group start exit %s", proxyConn.conn.Info())
202 | proxyConn.conn.Close()
203 | loggo.Info("group end exit %s", proxyConn.conn.Info())
204 | })
205 |
206 | targetAddr := ""
207 | wg.Go("Inputer socks5"+" "+proxyConn.conn.Info(), func() error {
208 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
209 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
210 |
211 | if proxyConn.conn.Name() != "tcp" {
212 | loggo.Error("processSocks5Conn no tcp %s %s", proxyConn.conn.Info(), proxyConn.conn.Name())
213 | return errors.New("socks5 not tcp")
214 | }
215 |
216 | var err error = nil
217 | if err = network.Sock5HandshakeBy(proxyConn.conn, i.config.Username, i.config.Password); err != nil {
218 | loggo.Error("processSocks5Conn Sock5HandshakeBy %s %s", proxyConn.conn.Info(), err)
219 | return err
220 | }
221 | _, addr, err := network.Sock5GetRequest(proxyConn.conn)
222 | if err != nil {
223 | loggo.Error("processSocks5Conn Sock5GetRequest %s %s", proxyConn.conn.Info(), err)
224 | return err
225 | }
226 | // Sending connection established message immediately to client.
227 | // This some round trip time for creating socks connection with the client.
228 | // But if connection failed, the client will get connection reset error.
229 | _, err = proxyConn.conn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x43})
230 | if err != nil {
231 | loggo.Error("processSocks5Conn Write %s %s", proxyConn.conn.Info(), err)
232 | return err
233 | }
234 |
235 | targetAddr = addr
236 | return nil
237 | })
238 |
239 | err := wg.Wait()
240 | if err != nil {
241 | return nil
242 | }
243 |
244 | loggo.Info("processSocks5Conn ok %s %s", proxyConn.conn.Info(), targetAddr)
245 |
246 | i.fwg.Go("Inputer processProxyConn"+" "+proxyConn.conn.Info(), func() error {
247 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
248 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
249 | return i.processProxyConn(proxyConn, targetAddr)
250 | })
251 |
252 | return nil
253 | }
254 |
255 | func (i *Inputer) processProxyConn(proxyConn *ProxyConn, targetAddr string) error {
256 |
257 | proxyConn.id = common.UniqueId()
258 |
259 | loggo.Info("Inputer processProxyConn start %s %s %s", proxyConn.id, proxyConn.conn.Info(), targetAddr)
260 |
261 | _, loaded := i.sonny.LoadOrStore(proxyConn.id, proxyConn)
262 | if loaded {
263 | loggo.Error("Inputer processProxyConn LoadOrStore fail %s", proxyConn.id)
264 | proxyConn.conn.Close()
265 | return nil
266 | }
267 |
268 | sendch := common.NewChannel(i.config.ConnBuffer)
269 | recvch := common.NewChannel(i.config.ConnBuffer)
270 |
271 | proxyConn.sendch = sendch
272 | proxyConn.recvch = recvch
273 |
274 | wg := thread.NewGroup("Inputer processProxyConn"+" "+proxyConn.conn.Info(), i.fwg, func() {
275 | loggo.Info("group start exit %s", proxyConn.conn.Info())
276 | proxyConn.conn.Close()
277 | sendch.Close()
278 | recvch.Close()
279 | loggo.Info("group end exit %s", proxyConn.conn.Info())
280 | })
281 |
282 | i.openConn(proxyConn, targetAddr)
283 |
284 | wg.Go("Inputer recvFromSonny"+" "+proxyConn.conn.Info(), func() error {
285 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
286 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
287 | return recvFromSonny(wg, recvch, proxyConn.conn, i.config.MaxMsgSize)
288 | })
289 |
290 | wg.Go("Inputer sendToSonny"+" "+proxyConn.conn.Info(), func() error {
291 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
292 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
293 | return sendToSonny(wg, sendch, proxyConn.conn, i.config.MaxMsgSize)
294 | })
295 |
296 | wg.Go("Inputer checkSonnyActive"+" "+proxyConn.conn.Info(), func() error {
297 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
298 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
299 | return checkSonnyActive(wg, proxyConn, i.config.EstablishedTimeout, i.config.ConnTimeout)
300 | })
301 |
302 | wg.Go("Inputer checkNeedClose"+" "+proxyConn.conn.Info(), func() error {
303 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
304 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
305 | return checkNeedClose(wg, proxyConn)
306 | })
307 |
308 | wg.Go("Inputer copySonnyRecv"+" "+proxyConn.conn.Info(), func() error {
309 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
310 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
311 | return copySonnyRecv(wg, recvch, proxyConn, i.father)
312 | })
313 |
314 | wg.Wait()
315 | i.sonny.Delete(proxyConn.id)
316 |
317 | closeRemoteConn(proxyConn, i.father)
318 |
319 | loggo.Info("Inputer processProxyConn end %s %s %s", proxyConn.id, proxyConn.conn.Info(), targetAddr)
320 |
321 | return nil
322 | }
323 |
324 | func (i *Inputer) openConn(proxyConn *ProxyConn, targetAddr string) {
325 | f := &ProxyFrame{}
326 | f.Type = FRAME_TYPE_OPEN
327 | f.OpenFrame = &OpenConnFrame{}
328 | f.OpenFrame.Id = proxyConn.id
329 | f.OpenFrame.Toaddr = targetAddr
330 |
331 | i.father.sendch.Write(f)
332 | loggo.Info("Inputer openConn %s %s", proxyConn.id, targetAddr)
333 | }
334 |
335 | func (i *Inputer) sonnySize() int {
336 | size := 0
337 | i.sonny.Range(func(key, value interface{}) bool {
338 | size++
339 | return true
340 | })
341 | return size
342 | }
343 |
--------------------------------------------------------------------------------
/proxy/outputer.go:
--------------------------------------------------------------------------------
1 | package proxy
2 |
3 | import (
4 | "github.com/esrrhs/gohome/common"
5 | "github.com/esrrhs/gohome/loggo"
6 | "github.com/esrrhs/gohome/network"
7 | "github.com/esrrhs/gohome/thread"
8 | "os"
9 | "sync"
10 | "sync/atomic"
11 | )
12 |
13 | type Outputer struct {
14 | clienttype CLIENT_TYPE
15 | config *Config
16 | proto string
17 | father *ProxyConn
18 | fwg *thread.Group
19 |
20 | conn network.Conn
21 | sonny sync.Map
22 |
23 | ss bool
24 | }
25 |
26 | func NewOutputer(wg *thread.Group, proto string, clienttype CLIENT_TYPE, config *Config, father *ProxyConn) (*Outputer, error) {
27 | conn, err := network.NewConn(proto)
28 | if conn == nil {
29 | return nil, err
30 | }
31 |
32 | output := &Outputer{
33 | clienttype: clienttype,
34 | config: config,
35 | conn: conn,
36 | proto: proto,
37 | father: father,
38 | fwg: wg,
39 | }
40 |
41 | loggo.Info("NewOutputer ok %s", proto)
42 |
43 | return output, nil
44 | }
45 |
46 | func NewSSOutputer(wg *thread.Group, proto string, clienttype CLIENT_TYPE, config *Config, father *ProxyConn) (*Outputer, error) {
47 | conn, err := network.NewConn(proto)
48 | if conn == nil {
49 | return nil, err
50 | }
51 |
52 | output := &Outputer{
53 | clienttype: clienttype,
54 | config: config,
55 | conn: conn,
56 | proto: proto,
57 | father: father,
58 | fwg: wg,
59 | ss: true,
60 | }
61 |
62 | loggo.Info("NewSSOutputer ok %s", proto)
63 |
64 | return output, nil
65 | }
66 |
67 | func (o *Outputer) Close() {
68 | o.conn.Close()
69 | }
70 |
71 | func (o *Outputer) processDataFrame(f *ProxyFrame) {
72 | id := f.DataFrame.Id
73 | v, ok := o.sonny.Load(id)
74 | if !ok {
75 | loggo.Debug("Outputer processDataFrame no sonnny %s %d", f.DataFrame.Id, len(f.DataFrame.Data))
76 | return
77 | }
78 | sonny := v.(*ProxyConn)
79 | if !sonny.sendch.WriteTimeout(f, o.config.MainWriteChannelTimeoutMs) {
80 | sonny.needclose = true
81 | loggo.Error("Outputer processDataFrame timeout sonnny %s %d", f.DataFrame.Id, len(f.DataFrame.Data))
82 | }
83 | sonny.actived++
84 | loggo.Debug("Outputer processDataFrame %s %d", f.DataFrame.Id, len(f.DataFrame.Data))
85 | }
86 |
87 | func (o *Outputer) processCloseFrame(f *ProxyFrame) {
88 | id := f.CloseFrame.Id
89 | v, ok := o.sonny.Load(id)
90 | if !ok {
91 | loggo.Info("Outputer processCloseFrame no sonnny %s", f.CloseFrame.Id)
92 | return
93 | }
94 |
95 | sonny := v.(*ProxyConn)
96 | sonny.sendch.Write(f)
97 | }
98 |
99 | func (o *Outputer) open(proxyconn *ProxyConn, targetAddr string) bool {
100 |
101 | id := proxyconn.id
102 |
103 | loggo.Info("Outputer open start %s %s", id, targetAddr)
104 |
105 | rf := &ProxyFrame{}
106 | rf.Type = FRAME_TYPE_OPENRSP
107 | rf.OpenRspFrame = &OpenConnRspFrame{}
108 | rf.OpenRspFrame.Id = id
109 |
110 | c, err := network.NewConn(o.conn.Name())
111 | if err != nil {
112 | rf.OpenRspFrame.Ret = false
113 | rf.OpenRspFrame.Msg = "NewConn fail " + targetAddr
114 | o.father.sendch.Write(rf)
115 | loggo.Error("Outputer open NewConn fail %s %s", targetAddr, err.Error())
116 | return false
117 | }
118 |
119 | wg := thread.NewGroup("Outputer open"+" "+targetAddr, o.fwg, func() {
120 | loggo.Info("group start exit %s", c.Info())
121 | c.Close()
122 | loggo.Info("group end exit %s", c.Info())
123 | })
124 |
125 | var conn network.Conn
126 | wg.Go("Outputer Dial"+" "+targetAddr, func() error {
127 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
128 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
129 | cc, err := c.Dial(targetAddr)
130 | if err != nil {
131 | return err
132 | }
133 | conn = cc
134 | return nil
135 | })
136 |
137 | err = wg.Wait()
138 | if err != nil {
139 | rf.OpenRspFrame.Ret = false
140 | rf.OpenRspFrame.Msg = "Dial fail " + targetAddr
141 | o.father.sendch.Write(rf)
142 | loggo.Error("Outputer open Dial fail %s %s", targetAddr, err.Error())
143 | return false
144 | }
145 |
146 | loggo.Info("Outputer open Dial ok %s %s", id, targetAddr)
147 |
148 | proxyconn.conn = conn
149 |
150 | rf.OpenRspFrame.Ret = true
151 | rf.OpenRspFrame.Msg = "ok"
152 | o.father.sendch.Write(rf)
153 |
154 | return true
155 | }
156 |
157 | func (o *Outputer) processOpenFrame(f *ProxyFrame) {
158 |
159 | id := f.OpenFrame.Id
160 | targetAddr := f.OpenFrame.Toaddr
161 |
162 | rf := &ProxyFrame{}
163 | rf.Type = FRAME_TYPE_OPENRSP
164 | rf.OpenRspFrame = &OpenConnRspFrame{}
165 | rf.OpenRspFrame.Id = id
166 | rf.OpenRspFrame.Ret = false
167 |
168 | if o.ss {
169 | ss_local_host := os.Getenv("SS_LOCAL_HOST")
170 | ss_local_port := os.Getenv("SS_LOCAL_PORT")
171 | if len(ss_local_host) <= 0 || len(ss_local_port) <= 0 {
172 | rf.OpenRspFrame.Msg = "ss no env"
173 | o.father.sendch.Write(rf)
174 | loggo.Info("Outputer ss no env %s %s", ss_local_host, ss_local_port)
175 | return
176 | }
177 | targetAddr = ss_local_host + ":" + ss_local_port
178 | }
179 |
180 | size := o.sonnySize()
181 | if size >= o.config.MaxSonny {
182 | rf.OpenRspFrame.Msg = "max sonny"
183 | o.father.sendch.Write(rf)
184 | loggo.Info("Outputer listen max sonny %s %d", id, size)
185 | return
186 | }
187 |
188 | proxyconn := &ProxyConn{id: id, conn: nil, established: true}
189 | _, loaded := o.sonny.LoadOrStore(proxyconn.id, proxyconn)
190 | if loaded {
191 | rf.OpenRspFrame.Msg = "Conn id fail"
192 | o.father.sendch.Write(rf)
193 | loggo.Error("Outputer processOpenFrame LoadOrStore fail %s %s", targetAddr, id)
194 | return
195 | }
196 |
197 | sendch := common.NewChannel(o.config.ConnBuffer)
198 | recvch := common.NewChannel(o.config.ConnBuffer)
199 |
200 | proxyconn.sendch = sendch
201 | proxyconn.recvch = recvch
202 |
203 | o.fwg.Go("Outputer processProxyConn"+" "+targetAddr, func() error {
204 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
205 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
206 | return o.processProxyConn(proxyconn, targetAddr)
207 | })
208 | }
209 |
210 | func (o *Outputer) processProxyConn(proxyConn *ProxyConn, targetAddr string) error {
211 |
212 | loggo.Info("Outputer processProxyConn start %s %s", proxyConn.id, targetAddr)
213 |
214 | sendch := proxyConn.sendch
215 | recvch := proxyConn.recvch
216 |
217 | if !o.open(proxyConn, targetAddr) {
218 | sendch.Close()
219 | recvch.Close()
220 | return nil
221 | }
222 |
223 | loggo.Info("Outputer processProxyConn open ok %s %s", proxyConn.id, proxyConn.conn.Info())
224 |
225 | wg := thread.NewGroup("Outputer processProxyConn"+" "+proxyConn.conn.Info(), o.fwg, func() {
226 | loggo.Info("group start exit %s", proxyConn.conn.Info())
227 | proxyConn.conn.Close()
228 | sendch.Close()
229 | recvch.Close()
230 | loggo.Info("group end exit %s", proxyConn.conn.Info())
231 | })
232 |
233 | wg.Go("Outputer recvFromSonny"+" "+proxyConn.conn.Info(), func() error {
234 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
235 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
236 | return recvFromSonny(wg, recvch, proxyConn.conn, o.config.MaxMsgSize)
237 | })
238 |
239 | wg.Go("Outputer sendToSonny"+" "+proxyConn.conn.Info(), func() error {
240 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
241 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
242 | return sendToSonny(wg, sendch, proxyConn.conn, o.config.MaxMsgSize)
243 | })
244 |
245 | wg.Go("Outputer checkSonnyActive"+" "+proxyConn.conn.Info(), func() error {
246 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
247 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
248 | return checkSonnyActive(wg, proxyConn, o.config.EstablishedTimeout, o.config.ConnTimeout)
249 | })
250 |
251 | wg.Go("Outputer checkNeedClose"+" "+proxyConn.conn.Info(), func() error {
252 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
253 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
254 | return checkNeedClose(wg, proxyConn)
255 | })
256 |
257 | wg.Go("Outputer copySonnyRecv"+" "+proxyConn.conn.Info(), func() error {
258 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
259 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
260 | return copySonnyRecv(wg, recvch, proxyConn, o.father)
261 | })
262 |
263 | wg.Wait()
264 | o.sonny.Delete(proxyConn.id)
265 |
266 | closeRemoteConn(proxyConn, o.father)
267 |
268 | loggo.Info("Outputer processProxyConn end %s %s", proxyConn.id, proxyConn.conn.Info())
269 |
270 | return nil
271 | }
272 |
273 | func (o *Outputer) sonnySize() int {
274 | size := 0
275 | o.sonny.Range(func(key, value interface{}) bool {
276 | size++
277 | return true
278 | })
279 | return size
280 | }
281 |
--------------------------------------------------------------------------------
/proxy/proxy.pb.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-go. DO NOT EDIT.
2 | // source: proxy.proto
3 |
4 | package proxy
5 |
6 | import (
7 | fmt "fmt"
8 | proto "github.com/golang/protobuf/proto"
9 | math "math"
10 | )
11 |
12 | // Reference imports to suppress errors if they are not otherwise used.
13 | var _ = proto.Marshal
14 | var _ = fmt.Errorf
15 | var _ = math.Inf
16 |
17 | // This is a compile-time assertion to ensure that this generated file
18 | // is compatible with the proto package it is being compiled against.
19 | // A compilation error at this line likely means your copy of the
20 | // proto package needs to be updated.
21 | const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
22 |
23 | type PROXY_PROTO int32
24 |
25 | const (
26 | PROXY_PROTO_TCP PROXY_PROTO = 0
27 | PROXY_PROTO_UDP PROXY_PROTO = 1
28 | PROXY_PROTO_RUDP PROXY_PROTO = 2
29 | PROXY_PROTO_RICMP PROXY_PROTO = 3
30 | PROXY_PROTO_KCP PROXY_PROTO = 4
31 | )
32 |
33 | var PROXY_PROTO_name = map[int32]string{
34 | 0: "TCP",
35 | 1: "UDP",
36 | 2: "RUDP",
37 | 3: "RICMP",
38 | 4: "KCP",
39 | }
40 |
41 | var PROXY_PROTO_value = map[string]int32{
42 | "TCP": 0,
43 | "UDP": 1,
44 | "RUDP": 2,
45 | "RICMP": 3,
46 | "KCP": 4,
47 | }
48 |
49 | func (x PROXY_PROTO) String() string {
50 | return proto.EnumName(PROXY_PROTO_name, int32(x))
51 | }
52 |
53 | func (PROXY_PROTO) EnumDescriptor() ([]byte, []int) {
54 | return fileDescriptor_700b50b08ed8dbaf, []int{0}
55 | }
56 |
57 | type CLIENT_TYPE int32
58 |
59 | const (
60 | // client fromaddr -> server toaddr
61 | CLIENT_TYPE_PROXY CLIENT_TYPE = 0
62 | // server fromaddr -> client toaddr
63 | CLIENT_TYPE_REVERSE_PROXY CLIENT_TYPE = 1
64 | // client fromaddr -> server
65 | CLIENT_TYPE_SOCKS5 CLIENT_TYPE = 2
66 | // server fromaddr -> client
67 | CLIENT_TYPE_REVERSE_SOCKS5 CLIENT_TYPE = 3
68 | // client fromaddr -> server shadowsocks address [SS_LOCAL_HOST:SS_LOCAL_PORT]
69 | CLIENT_TYPE_SS_PROXY CLIENT_TYPE = 4
70 | )
71 |
72 | var CLIENT_TYPE_name = map[int32]string{
73 | 0: "PROXY",
74 | 1: "REVERSE_PROXY",
75 | 2: "SOCKS5",
76 | 3: "REVERSE_SOCKS5",
77 | 4: "SS_PROXY",
78 | }
79 |
80 | var CLIENT_TYPE_value = map[string]int32{
81 | "PROXY": 0,
82 | "REVERSE_PROXY": 1,
83 | "SOCKS5": 2,
84 | "REVERSE_SOCKS5": 3,
85 | "SS_PROXY": 4,
86 | }
87 |
88 | func (x CLIENT_TYPE) String() string {
89 | return proto.EnumName(CLIENT_TYPE_name, int32(x))
90 | }
91 |
92 | func (CLIENT_TYPE) EnumDescriptor() ([]byte, []int) {
93 | return fileDescriptor_700b50b08ed8dbaf, []int{1}
94 | }
95 |
96 | type FRAME_TYPE int32
97 |
98 | const (
99 | FRAME_TYPE_LOGIN FRAME_TYPE = 0
100 | FRAME_TYPE_LOGINRSP FRAME_TYPE = 1
101 | FRAME_TYPE_DATA FRAME_TYPE = 2
102 | FRAME_TYPE_PING FRAME_TYPE = 3
103 | FRAME_TYPE_PONG FRAME_TYPE = 4
104 | FRAME_TYPE_OPEN FRAME_TYPE = 5
105 | FRAME_TYPE_OPENRSP FRAME_TYPE = 6
106 | FRAME_TYPE_CLOSE FRAME_TYPE = 7
107 | )
108 |
109 | var FRAME_TYPE_name = map[int32]string{
110 | 0: "LOGIN",
111 | 1: "LOGINRSP",
112 | 2: "DATA",
113 | 3: "PING",
114 | 4: "PONG",
115 | 5: "OPEN",
116 | 6: "OPENRSP",
117 | 7: "CLOSE",
118 | }
119 |
120 | var FRAME_TYPE_value = map[string]int32{
121 | "LOGIN": 0,
122 | "LOGINRSP": 1,
123 | "DATA": 2,
124 | "PING": 3,
125 | "PONG": 4,
126 | "OPEN": 5,
127 | "OPENRSP": 6,
128 | "CLOSE": 7,
129 | }
130 |
131 | func (x FRAME_TYPE) String() string {
132 | return proto.EnumName(FRAME_TYPE_name, int32(x))
133 | }
134 |
135 | func (FRAME_TYPE) EnumDescriptor() ([]byte, []int) {
136 | return fileDescriptor_700b50b08ed8dbaf, []int{2}
137 | }
138 |
139 | type LoginFrame struct {
140 | Proxyproto PROXY_PROTO `protobuf:"varint,1,opt,name=proxyproto,proto3,enum=PROXY_PROTO" json:"proxyproto,omitempty"`
141 | Clienttype CLIENT_TYPE `protobuf:"varint,2,opt,name=clienttype,proto3,enum=CLIENT_TYPE" json:"clienttype,omitempty"`
142 | Fromaddr string `protobuf:"bytes,3,opt,name=fromaddr,proto3" json:"fromaddr,omitempty"`
143 | Toaddr string `protobuf:"bytes,4,opt,name=toaddr,proto3" json:"toaddr,omitempty"`
144 | Name string `protobuf:"bytes,5,opt,name=name,proto3" json:"name,omitempty"`
145 | Key string `protobuf:"bytes,6,opt,name=key,proto3" json:"key,omitempty"`
146 | XXX_NoUnkeyedLiteral struct{} `json:"-"`
147 | XXX_unrecognized []byte `json:"-"`
148 | XXX_sizecache int32 `json:"-"`
149 | }
150 |
151 | func (m *LoginFrame) Reset() { *m = LoginFrame{} }
152 | func (m *LoginFrame) String() string { return proto.CompactTextString(m) }
153 | func (*LoginFrame) ProtoMessage() {}
154 | func (*LoginFrame) Descriptor() ([]byte, []int) {
155 | return fileDescriptor_700b50b08ed8dbaf, []int{0}
156 | }
157 |
158 | func (m *LoginFrame) XXX_Unmarshal(b []byte) error {
159 | return xxx_messageInfo_LoginFrame.Unmarshal(m, b)
160 | }
161 | func (m *LoginFrame) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
162 | return xxx_messageInfo_LoginFrame.Marshal(b, m, deterministic)
163 | }
164 | func (m *LoginFrame) XXX_Merge(src proto.Message) {
165 | xxx_messageInfo_LoginFrame.Merge(m, src)
166 | }
167 | func (m *LoginFrame) XXX_Size() int {
168 | return xxx_messageInfo_LoginFrame.Size(m)
169 | }
170 | func (m *LoginFrame) XXX_DiscardUnknown() {
171 | xxx_messageInfo_LoginFrame.DiscardUnknown(m)
172 | }
173 |
174 | var xxx_messageInfo_LoginFrame proto.InternalMessageInfo
175 |
176 | func (m *LoginFrame) GetProxyproto() PROXY_PROTO {
177 | if m != nil {
178 | return m.Proxyproto
179 | }
180 | return PROXY_PROTO_TCP
181 | }
182 |
183 | func (m *LoginFrame) GetClienttype() CLIENT_TYPE {
184 | if m != nil {
185 | return m.Clienttype
186 | }
187 | return CLIENT_TYPE_PROXY
188 | }
189 |
190 | func (m *LoginFrame) GetFromaddr() string {
191 | if m != nil {
192 | return m.Fromaddr
193 | }
194 | return ""
195 | }
196 |
197 | func (m *LoginFrame) GetToaddr() string {
198 | if m != nil {
199 | return m.Toaddr
200 | }
201 | return ""
202 | }
203 |
204 | func (m *LoginFrame) GetName() string {
205 | if m != nil {
206 | return m.Name
207 | }
208 | return ""
209 | }
210 |
211 | func (m *LoginFrame) GetKey() string {
212 | if m != nil {
213 | return m.Key
214 | }
215 | return ""
216 | }
217 |
218 | type LoginRspFrame struct {
219 | Ret bool `protobuf:"varint,1,opt,name=ret,proto3" json:"ret,omitempty"`
220 | Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"`
221 | XXX_NoUnkeyedLiteral struct{} `json:"-"`
222 | XXX_unrecognized []byte `json:"-"`
223 | XXX_sizecache int32 `json:"-"`
224 | }
225 |
226 | func (m *LoginRspFrame) Reset() { *m = LoginRspFrame{} }
227 | func (m *LoginRspFrame) String() string { return proto.CompactTextString(m) }
228 | func (*LoginRspFrame) ProtoMessage() {}
229 | func (*LoginRspFrame) Descriptor() ([]byte, []int) {
230 | return fileDescriptor_700b50b08ed8dbaf, []int{1}
231 | }
232 |
233 | func (m *LoginRspFrame) XXX_Unmarshal(b []byte) error {
234 | return xxx_messageInfo_LoginRspFrame.Unmarshal(m, b)
235 | }
236 | func (m *LoginRspFrame) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
237 | return xxx_messageInfo_LoginRspFrame.Marshal(b, m, deterministic)
238 | }
239 | func (m *LoginRspFrame) XXX_Merge(src proto.Message) {
240 | xxx_messageInfo_LoginRspFrame.Merge(m, src)
241 | }
242 | func (m *LoginRspFrame) XXX_Size() int {
243 | return xxx_messageInfo_LoginRspFrame.Size(m)
244 | }
245 | func (m *LoginRspFrame) XXX_DiscardUnknown() {
246 | xxx_messageInfo_LoginRspFrame.DiscardUnknown(m)
247 | }
248 |
249 | var xxx_messageInfo_LoginRspFrame proto.InternalMessageInfo
250 |
251 | func (m *LoginRspFrame) GetRet() bool {
252 | if m != nil {
253 | return m.Ret
254 | }
255 | return false
256 | }
257 |
258 | func (m *LoginRspFrame) GetMsg() string {
259 | if m != nil {
260 | return m.Msg
261 | }
262 | return ""
263 | }
264 |
265 | type PingFrame struct {
266 | Time int64 `protobuf:"varint,1,opt,name=time,proto3" json:"time,omitempty"`
267 | XXX_NoUnkeyedLiteral struct{} `json:"-"`
268 | XXX_unrecognized []byte `json:"-"`
269 | XXX_sizecache int32 `json:"-"`
270 | }
271 |
272 | func (m *PingFrame) Reset() { *m = PingFrame{} }
273 | func (m *PingFrame) String() string { return proto.CompactTextString(m) }
274 | func (*PingFrame) ProtoMessage() {}
275 | func (*PingFrame) Descriptor() ([]byte, []int) {
276 | return fileDescriptor_700b50b08ed8dbaf, []int{2}
277 | }
278 |
279 | func (m *PingFrame) XXX_Unmarshal(b []byte) error {
280 | return xxx_messageInfo_PingFrame.Unmarshal(m, b)
281 | }
282 | func (m *PingFrame) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
283 | return xxx_messageInfo_PingFrame.Marshal(b, m, deterministic)
284 | }
285 | func (m *PingFrame) XXX_Merge(src proto.Message) {
286 | xxx_messageInfo_PingFrame.Merge(m, src)
287 | }
288 | func (m *PingFrame) XXX_Size() int {
289 | return xxx_messageInfo_PingFrame.Size(m)
290 | }
291 | func (m *PingFrame) XXX_DiscardUnknown() {
292 | xxx_messageInfo_PingFrame.DiscardUnknown(m)
293 | }
294 |
295 | var xxx_messageInfo_PingFrame proto.InternalMessageInfo
296 |
297 | func (m *PingFrame) GetTime() int64 {
298 | if m != nil {
299 | return m.Time
300 | }
301 | return 0
302 | }
303 |
304 | type PongFrame struct {
305 | Time int64 `protobuf:"varint,1,opt,name=time,proto3" json:"time,omitempty"`
306 | XXX_NoUnkeyedLiteral struct{} `json:"-"`
307 | XXX_unrecognized []byte `json:"-"`
308 | XXX_sizecache int32 `json:"-"`
309 | }
310 |
311 | func (m *PongFrame) Reset() { *m = PongFrame{} }
312 | func (m *PongFrame) String() string { return proto.CompactTextString(m) }
313 | func (*PongFrame) ProtoMessage() {}
314 | func (*PongFrame) Descriptor() ([]byte, []int) {
315 | return fileDescriptor_700b50b08ed8dbaf, []int{3}
316 | }
317 |
318 | func (m *PongFrame) XXX_Unmarshal(b []byte) error {
319 | return xxx_messageInfo_PongFrame.Unmarshal(m, b)
320 | }
321 | func (m *PongFrame) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
322 | return xxx_messageInfo_PongFrame.Marshal(b, m, deterministic)
323 | }
324 | func (m *PongFrame) XXX_Merge(src proto.Message) {
325 | xxx_messageInfo_PongFrame.Merge(m, src)
326 | }
327 | func (m *PongFrame) XXX_Size() int {
328 | return xxx_messageInfo_PongFrame.Size(m)
329 | }
330 | func (m *PongFrame) XXX_DiscardUnknown() {
331 | xxx_messageInfo_PongFrame.DiscardUnknown(m)
332 | }
333 |
334 | var xxx_messageInfo_PongFrame proto.InternalMessageInfo
335 |
336 | func (m *PongFrame) GetTime() int64 {
337 | if m != nil {
338 | return m.Time
339 | }
340 | return 0
341 | }
342 |
343 | type OpenConnFrame struct {
344 | Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
345 | Toaddr string `protobuf:"bytes,2,opt,name=toaddr,proto3" json:"toaddr,omitempty"`
346 | XXX_NoUnkeyedLiteral struct{} `json:"-"`
347 | XXX_unrecognized []byte `json:"-"`
348 | XXX_sizecache int32 `json:"-"`
349 | }
350 |
351 | func (m *OpenConnFrame) Reset() { *m = OpenConnFrame{} }
352 | func (m *OpenConnFrame) String() string { return proto.CompactTextString(m) }
353 | func (*OpenConnFrame) ProtoMessage() {}
354 | func (*OpenConnFrame) Descriptor() ([]byte, []int) {
355 | return fileDescriptor_700b50b08ed8dbaf, []int{4}
356 | }
357 |
358 | func (m *OpenConnFrame) XXX_Unmarshal(b []byte) error {
359 | return xxx_messageInfo_OpenConnFrame.Unmarshal(m, b)
360 | }
361 | func (m *OpenConnFrame) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
362 | return xxx_messageInfo_OpenConnFrame.Marshal(b, m, deterministic)
363 | }
364 | func (m *OpenConnFrame) XXX_Merge(src proto.Message) {
365 | xxx_messageInfo_OpenConnFrame.Merge(m, src)
366 | }
367 | func (m *OpenConnFrame) XXX_Size() int {
368 | return xxx_messageInfo_OpenConnFrame.Size(m)
369 | }
370 | func (m *OpenConnFrame) XXX_DiscardUnknown() {
371 | xxx_messageInfo_OpenConnFrame.DiscardUnknown(m)
372 | }
373 |
374 | var xxx_messageInfo_OpenConnFrame proto.InternalMessageInfo
375 |
376 | func (m *OpenConnFrame) GetId() string {
377 | if m != nil {
378 | return m.Id
379 | }
380 | return ""
381 | }
382 |
383 | func (m *OpenConnFrame) GetToaddr() string {
384 | if m != nil {
385 | return m.Toaddr
386 | }
387 | return ""
388 | }
389 |
390 | type OpenConnRspFrame struct {
391 | Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
392 | Ret bool `protobuf:"varint,2,opt,name=ret,proto3" json:"ret,omitempty"`
393 | Msg string `protobuf:"bytes,3,opt,name=msg,proto3" json:"msg,omitempty"`
394 | XXX_NoUnkeyedLiteral struct{} `json:"-"`
395 | XXX_unrecognized []byte `json:"-"`
396 | XXX_sizecache int32 `json:"-"`
397 | }
398 |
399 | func (m *OpenConnRspFrame) Reset() { *m = OpenConnRspFrame{} }
400 | func (m *OpenConnRspFrame) String() string { return proto.CompactTextString(m) }
401 | func (*OpenConnRspFrame) ProtoMessage() {}
402 | func (*OpenConnRspFrame) Descriptor() ([]byte, []int) {
403 | return fileDescriptor_700b50b08ed8dbaf, []int{5}
404 | }
405 |
406 | func (m *OpenConnRspFrame) XXX_Unmarshal(b []byte) error {
407 | return xxx_messageInfo_OpenConnRspFrame.Unmarshal(m, b)
408 | }
409 | func (m *OpenConnRspFrame) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
410 | return xxx_messageInfo_OpenConnRspFrame.Marshal(b, m, deterministic)
411 | }
412 | func (m *OpenConnRspFrame) XXX_Merge(src proto.Message) {
413 | xxx_messageInfo_OpenConnRspFrame.Merge(m, src)
414 | }
415 | func (m *OpenConnRspFrame) XXX_Size() int {
416 | return xxx_messageInfo_OpenConnRspFrame.Size(m)
417 | }
418 | func (m *OpenConnRspFrame) XXX_DiscardUnknown() {
419 | xxx_messageInfo_OpenConnRspFrame.DiscardUnknown(m)
420 | }
421 |
422 | var xxx_messageInfo_OpenConnRspFrame proto.InternalMessageInfo
423 |
424 | func (m *OpenConnRspFrame) GetId() string {
425 | if m != nil {
426 | return m.Id
427 | }
428 | return ""
429 | }
430 |
431 | func (m *OpenConnRspFrame) GetRet() bool {
432 | if m != nil {
433 | return m.Ret
434 | }
435 | return false
436 | }
437 |
438 | func (m *OpenConnRspFrame) GetMsg() string {
439 | if m != nil {
440 | return m.Msg
441 | }
442 | return ""
443 | }
444 |
445 | type CloseFrame struct {
446 | Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
447 | XXX_NoUnkeyedLiteral struct{} `json:"-"`
448 | XXX_unrecognized []byte `json:"-"`
449 | XXX_sizecache int32 `json:"-"`
450 | }
451 |
452 | func (m *CloseFrame) Reset() { *m = CloseFrame{} }
453 | func (m *CloseFrame) String() string { return proto.CompactTextString(m) }
454 | func (*CloseFrame) ProtoMessage() {}
455 | func (*CloseFrame) Descriptor() ([]byte, []int) {
456 | return fileDescriptor_700b50b08ed8dbaf, []int{6}
457 | }
458 |
459 | func (m *CloseFrame) XXX_Unmarshal(b []byte) error {
460 | return xxx_messageInfo_CloseFrame.Unmarshal(m, b)
461 | }
462 | func (m *CloseFrame) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
463 | return xxx_messageInfo_CloseFrame.Marshal(b, m, deterministic)
464 | }
465 | func (m *CloseFrame) XXX_Merge(src proto.Message) {
466 | xxx_messageInfo_CloseFrame.Merge(m, src)
467 | }
468 | func (m *CloseFrame) XXX_Size() int {
469 | return xxx_messageInfo_CloseFrame.Size(m)
470 | }
471 | func (m *CloseFrame) XXX_DiscardUnknown() {
472 | xxx_messageInfo_CloseFrame.DiscardUnknown(m)
473 | }
474 |
475 | var xxx_messageInfo_CloseFrame proto.InternalMessageInfo
476 |
477 | func (m *CloseFrame) GetId() string {
478 | if m != nil {
479 | return m.Id
480 | }
481 | return ""
482 | }
483 |
484 | type DataFrame struct {
485 | Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
486 | Compress bool `protobuf:"varint,2,opt,name=compress,proto3" json:"compress,omitempty"`
487 | Crc string `protobuf:"bytes,3,opt,name=crc,proto3" json:"crc,omitempty"`
488 | Data []byte `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"`
489 | Index int32 `protobuf:"varint,5,opt,name=index,proto3" json:"index,omitempty"`
490 | XXX_NoUnkeyedLiteral struct{} `json:"-"`
491 | XXX_unrecognized []byte `json:"-"`
492 | XXX_sizecache int32 `json:"-"`
493 | }
494 |
495 | func (m *DataFrame) Reset() { *m = DataFrame{} }
496 | func (m *DataFrame) String() string { return proto.CompactTextString(m) }
497 | func (*DataFrame) ProtoMessage() {}
498 | func (*DataFrame) Descriptor() ([]byte, []int) {
499 | return fileDescriptor_700b50b08ed8dbaf, []int{7}
500 | }
501 |
502 | func (m *DataFrame) XXX_Unmarshal(b []byte) error {
503 | return xxx_messageInfo_DataFrame.Unmarshal(m, b)
504 | }
505 | func (m *DataFrame) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
506 | return xxx_messageInfo_DataFrame.Marshal(b, m, deterministic)
507 | }
508 | func (m *DataFrame) XXX_Merge(src proto.Message) {
509 | xxx_messageInfo_DataFrame.Merge(m, src)
510 | }
511 | func (m *DataFrame) XXX_Size() int {
512 | return xxx_messageInfo_DataFrame.Size(m)
513 | }
514 | func (m *DataFrame) XXX_DiscardUnknown() {
515 | xxx_messageInfo_DataFrame.DiscardUnknown(m)
516 | }
517 |
518 | var xxx_messageInfo_DataFrame proto.InternalMessageInfo
519 |
520 | func (m *DataFrame) GetId() string {
521 | if m != nil {
522 | return m.Id
523 | }
524 | return ""
525 | }
526 |
527 | func (m *DataFrame) GetCompress() bool {
528 | if m != nil {
529 | return m.Compress
530 | }
531 | return false
532 | }
533 |
534 | func (m *DataFrame) GetCrc() string {
535 | if m != nil {
536 | return m.Crc
537 | }
538 | return ""
539 | }
540 |
541 | func (m *DataFrame) GetData() []byte {
542 | if m != nil {
543 | return m.Data
544 | }
545 | return nil
546 | }
547 |
548 | func (m *DataFrame) GetIndex() int32 {
549 | if m != nil {
550 | return m.Index
551 | }
552 | return 0
553 | }
554 |
555 | type ProxyFrame struct {
556 | Type FRAME_TYPE `protobuf:"varint,1,opt,name=type,proto3,enum=FRAME_TYPE" json:"type,omitempty"`
557 | LoginFrame *LoginFrame `protobuf:"bytes,2,opt,name=loginFrame,proto3" json:"loginFrame,omitempty"`
558 | LoginRspFrame *LoginRspFrame `protobuf:"bytes,3,opt,name=loginRspFrame,proto3" json:"loginRspFrame,omitempty"`
559 | DataFrame *DataFrame `protobuf:"bytes,4,opt,name=dataFrame,proto3" json:"dataFrame,omitempty"`
560 | PingFrame *PingFrame `protobuf:"bytes,5,opt,name=pingFrame,proto3" json:"pingFrame,omitempty"`
561 | PongFrame *PongFrame `protobuf:"bytes,6,opt,name=pongFrame,proto3" json:"pongFrame,omitempty"`
562 | OpenFrame *OpenConnFrame `protobuf:"bytes,7,opt,name=openFrame,proto3" json:"openFrame,omitempty"`
563 | OpenRspFrame *OpenConnRspFrame `protobuf:"bytes,8,opt,name=openRspFrame,proto3" json:"openRspFrame,omitempty"`
564 | CloseFrame *CloseFrame `protobuf:"bytes,9,opt,name=closeFrame,proto3" json:"closeFrame,omitempty"`
565 | XXX_NoUnkeyedLiteral struct{} `json:"-"`
566 | XXX_unrecognized []byte `json:"-"`
567 | XXX_sizecache int32 `json:"-"`
568 | }
569 |
570 | func (m *ProxyFrame) Reset() { *m = ProxyFrame{} }
571 | func (m *ProxyFrame) String() string { return proto.CompactTextString(m) }
572 | func (*ProxyFrame) ProtoMessage() {}
573 | func (*ProxyFrame) Descriptor() ([]byte, []int) {
574 | return fileDescriptor_700b50b08ed8dbaf, []int{8}
575 | }
576 |
577 | func (m *ProxyFrame) XXX_Unmarshal(b []byte) error {
578 | return xxx_messageInfo_ProxyFrame.Unmarshal(m, b)
579 | }
580 | func (m *ProxyFrame) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
581 | return xxx_messageInfo_ProxyFrame.Marshal(b, m, deterministic)
582 | }
583 | func (m *ProxyFrame) XXX_Merge(src proto.Message) {
584 | xxx_messageInfo_ProxyFrame.Merge(m, src)
585 | }
586 | func (m *ProxyFrame) XXX_Size() int {
587 | return xxx_messageInfo_ProxyFrame.Size(m)
588 | }
589 | func (m *ProxyFrame) XXX_DiscardUnknown() {
590 | xxx_messageInfo_ProxyFrame.DiscardUnknown(m)
591 | }
592 |
593 | var xxx_messageInfo_ProxyFrame proto.InternalMessageInfo
594 |
595 | func (m *ProxyFrame) GetType() FRAME_TYPE {
596 | if m != nil {
597 | return m.Type
598 | }
599 | return FRAME_TYPE_LOGIN
600 | }
601 |
602 | func (m *ProxyFrame) GetLoginFrame() *LoginFrame {
603 | if m != nil {
604 | return m.LoginFrame
605 | }
606 | return nil
607 | }
608 |
609 | func (m *ProxyFrame) GetLoginRspFrame() *LoginRspFrame {
610 | if m != nil {
611 | return m.LoginRspFrame
612 | }
613 | return nil
614 | }
615 |
616 | func (m *ProxyFrame) GetDataFrame() *DataFrame {
617 | if m != nil {
618 | return m.DataFrame
619 | }
620 | return nil
621 | }
622 |
623 | func (m *ProxyFrame) GetPingFrame() *PingFrame {
624 | if m != nil {
625 | return m.PingFrame
626 | }
627 | return nil
628 | }
629 |
630 | func (m *ProxyFrame) GetPongFrame() *PongFrame {
631 | if m != nil {
632 | return m.PongFrame
633 | }
634 | return nil
635 | }
636 |
637 | func (m *ProxyFrame) GetOpenFrame() *OpenConnFrame {
638 | if m != nil {
639 | return m.OpenFrame
640 | }
641 | return nil
642 | }
643 |
644 | func (m *ProxyFrame) GetOpenRspFrame() *OpenConnRspFrame {
645 | if m != nil {
646 | return m.OpenRspFrame
647 | }
648 | return nil
649 | }
650 |
651 | func (m *ProxyFrame) GetCloseFrame() *CloseFrame {
652 | if m != nil {
653 | return m.CloseFrame
654 | }
655 | return nil
656 | }
657 |
658 | func init() {
659 | proto.RegisterEnum("PROXY_PROTO", PROXY_PROTO_name, PROXY_PROTO_value)
660 | proto.RegisterEnum("CLIENT_TYPE", CLIENT_TYPE_name, CLIENT_TYPE_value)
661 | proto.RegisterEnum("FRAME_TYPE", FRAME_TYPE_name, FRAME_TYPE_value)
662 | proto.RegisterType((*LoginFrame)(nil), "LoginFrame")
663 | proto.RegisterType((*LoginRspFrame)(nil), "LoginRspFrame")
664 | proto.RegisterType((*PingFrame)(nil), "PingFrame")
665 | proto.RegisterType((*PongFrame)(nil), "PongFrame")
666 | proto.RegisterType((*OpenConnFrame)(nil), "OpenConnFrame")
667 | proto.RegisterType((*OpenConnRspFrame)(nil), "OpenConnRspFrame")
668 | proto.RegisterType((*CloseFrame)(nil), "CloseFrame")
669 | proto.RegisterType((*DataFrame)(nil), "DataFrame")
670 | proto.RegisterType((*ProxyFrame)(nil), "ProxyFrame")
671 | }
672 |
673 | func init() { proto.RegisterFile("proxy.proto", fileDescriptor_700b50b08ed8dbaf) }
674 |
675 | var fileDescriptor_700b50b08ed8dbaf = []byte{
676 | // 634 bytes of a gzipped FileDescriptorProto
677 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x54, 0x4d, 0x6f, 0x9b, 0x40,
678 | 0x10, 0x8d, 0x01, 0x7f, 0x30, 0xd8, 0xd6, 0x66, 0x55, 0x55, 0x56, 0x54, 0x29, 0x91, 0x4f, 0x51,
679 | 0x1a, 0x71, 0x70, 0x1a, 0xf5, 0xd4, 0x43, 0x4a, 0x48, 0x64, 0xc5, 0x31, 0x68, 0x70, 0xab, 0xa6,
680 | 0x97, 0x88, 0xc2, 0x36, 0x42, 0xb5, 0x01, 0x61, 0x0e, 0xf1, 0xbf, 0xe9, 0x6f, 0xe9, 0x2f, 0xab,
681 | 0x76, 0xf8, 0x74, 0x1a, 0xf5, 0xf6, 0x76, 0xdf, 0x9b, 0xdd, 0x79, 0xb3, 0x0f, 0xc0, 0x48, 0xb3,
682 | 0xe4, 0x79, 0x67, 0xa6, 0x59, 0x92, 0x27, 0xd3, 0x3f, 0x1d, 0x80, 0x45, 0xf2, 0x14, 0xc5, 0x37,
683 | 0x99, 0xbf, 0x11, 0xfc, 0x1c, 0x80, 0x58, 0x22, 0x27, 0x9d, 0x93, 0xce, 0xe9, 0x78, 0x36, 0x34,
684 | 0x5d, 0x74, 0xbe, 0x3d, 0x3c, 0xba, 0xe8, 0xac, 0x1c, 0x6c, 0xf1, 0x52, 0x1d, 0xac, 0x23, 0x11,
685 | 0xe7, 0xf9, 0x2e, 0x15, 0x13, 0xa5, 0x54, 0x5b, 0x8b, 0xb9, 0xbd, 0x5c, 0x3d, 0xae, 0x1e, 0x5c,
686 | 0x1b, 0x5b, 0x3c, 0x3f, 0x82, 0xc1, 0xcf, 0x2c, 0xd9, 0xf8, 0x61, 0x98, 0x4d, 0xd4, 0x93, 0xce,
687 | 0xa9, 0x8e, 0xf5, 0x9a, 0xbf, 0x85, 0x5e, 0x9e, 0x10, 0xa3, 0x11, 0x53, 0xae, 0x38, 0x07, 0x2d,
688 | 0xf6, 0x37, 0x62, 0xd2, 0xa5, 0x5d, 0xc2, 0x9c, 0x81, 0xfa, 0x4b, 0xec, 0x26, 0x3d, 0xda, 0x92,
689 | 0x70, 0x7a, 0x01, 0x23, 0xf2, 0x80, 0xdb, 0xb4, 0xb0, 0xc1, 0x40, 0xcd, 0x44, 0x4e, 0xfd, 0x0f,
690 | 0x50, 0x42, 0xb9, 0xb3, 0xd9, 0x3e, 0x51, 0x8f, 0x3a, 0x4a, 0x38, 0x3d, 0x06, 0xdd, 0x8d, 0xe2,
691 | 0xa7, 0xa2, 0x80, 0x83, 0x96, 0x47, 0x1b, 0x41, 0x15, 0x2a, 0x12, 0x26, 0x41, 0xf2, 0x3f, 0xc1,
692 | 0x47, 0x18, 0x39, 0xa9, 0x88, 0xad, 0x24, 0x2e, 0xa7, 0x37, 0x06, 0x25, 0x0a, 0x49, 0xa2, 0xa3,
693 | 0x12, 0x85, 0x2d, 0x57, 0x4a, 0xdb, 0xd5, 0xf4, 0x06, 0x58, 0x55, 0x58, 0xb7, 0xfc, 0xb2, 0xb6,
694 | 0xb4, 0xa0, 0xfc, 0x63, 0x41, 0x6d, 0x2c, 0xbc, 0x03, 0xb0, 0xd6, 0xc9, 0x56, 0xbc, 0x7a, 0xc2,
695 | 0x74, 0x0b, 0xfa, 0xb5, 0x9f, 0xfb, 0xaf, 0x1f, 0x7f, 0x04, 0x83, 0x20, 0xd9, 0xa4, 0x99, 0xd8,
696 | 0x6e, 0xcb, 0x3b, 0xea, 0xb5, 0xbc, 0x28, 0xc8, 0x82, 0xea, 0xa2, 0x20, 0x0b, 0xa4, 0xfb, 0xd0,
697 | 0xcf, 0x7d, 0x7a, 0x9c, 0x21, 0x12, 0xe6, 0x6f, 0xa0, 0x1b, 0xc5, 0xa1, 0x78, 0xa6, 0xb7, 0xe9,
698 | 0x62, 0xb1, 0x98, 0xfe, 0x56, 0x01, 0x5c, 0x99, 0x90, 0xe2, 0xda, 0x63, 0xd0, 0x28, 0x1b, 0x45,
699 | 0x92, 0x0c, 0xf3, 0x06, 0xaf, 0xee, 0xed, 0x22, 0x1a, 0x44, 0xf0, 0xf7, 0x00, 0xeb, 0x3a, 0x7e,
700 | 0xd4, 0x89, 0x31, 0x33, 0xcc, 0x26, 0x91, 0xd8, 0xa2, 0xf9, 0x07, 0x18, 0xad, 0xdb, 0xef, 0x4c,
701 | 0x2d, 0x1a, 0xb3, 0xb1, 0xb9, 0xf7, 0xfa, 0xb8, 0x2f, 0xe2, 0xa7, 0xa0, 0x87, 0xd5, 0x1c, 0xc8,
702 | 0x81, 0x31, 0x03, 0xb3, 0x9e, 0x0c, 0x36, 0xa4, 0x54, 0xa6, 0x55, 0x24, 0xc8, 0x96, 0x54, 0xd6,
703 | 0x21, 0xc1, 0x86, 0x24, 0x65, 0x95, 0x0d, 0x4a, 0x22, 0x29, 0x93, 0x46, 0x59, 0x07, 0xe7, 0x1c,
704 | 0xf4, 0x24, 0x15, 0xa5, 0xbf, 0x7e, 0xd9, 0xef, 0x5e, 0x6c, 0xb0, 0x11, 0xf0, 0x4b, 0x18, 0xca,
705 | 0x45, 0x6d, 0x70, 0x40, 0x05, 0x87, 0xe6, 0xcb, 0xb8, 0xe0, 0x9e, 0x4c, 0x4e, 0x31, 0xa8, 0x83,
706 | 0x30, 0xd1, 0xcb, 0x29, 0x36, 0xd9, 0xc0, 0x16, 0x7d, 0xf6, 0x09, 0x8c, 0xd6, 0x07, 0xcd, 0xfb,
707 | 0xa0, 0xae, 0x2c, 0x97, 0x1d, 0x48, 0xf0, 0xe5, 0xda, 0x65, 0x1d, 0x3e, 0x00, 0x0d, 0x25, 0x52,
708 | 0xb8, 0x0e, 0x5d, 0x9c, 0x5b, 0xf7, 0x2e, 0x53, 0x25, 0x7b, 0x67, 0xb9, 0x4c, 0x3b, 0x7b, 0x00,
709 | 0xa3, 0xf5, 0x85, 0x4b, 0x09, 0x9d, 0xc6, 0x0e, 0xf8, 0x21, 0x8c, 0xd0, 0xfe, 0x6a, 0xa3, 0x67,
710 | 0x3f, 0x16, 0x5b, 0x1d, 0x0e, 0xd0, 0xf3, 0x1c, 0xeb, 0xce, 0xbb, 0x64, 0x0a, 0xe7, 0x30, 0xae,
711 | 0xe8, 0x72, 0x4f, 0xe5, 0x43, 0x18, 0x78, 0x5e, 0xa9, 0xd6, 0xce, 0x04, 0x40, 0x13, 0x10, 0x79,
712 | 0xf2, 0xc2, 0xb9, 0x9d, 0x2f, 0xd9, 0x81, 0x94, 0x11, 0x44, 0xaf, 0xec, 0xef, 0xfa, 0x6a, 0x75,
713 | 0xc5, 0x14, 0x89, 0xdc, 0xf9, 0xf2, 0x96, 0xa9, 0x84, 0x9c, 0xe5, 0x2d, 0xd3, 0x24, 0x72, 0x5c,
714 | 0x7b, 0xc9, 0xba, 0xdc, 0x80, 0xbe, 0x44, 0xb2, 0xa8, 0x27, 0x4f, 0xb3, 0x16, 0x8e, 0x67, 0xb3,
715 | 0xfe, 0xe7, 0xfe, 0xf7, 0x2e, 0xfd, 0xc4, 0x7e, 0xf4, 0xe8, 0x37, 0x76, 0xf1, 0x37, 0x00, 0x00,
716 | 0xff, 0xff, 0xd7, 0x9c, 0x13, 0xae, 0x12, 0x05, 0x00, 0x00,
717 | }
718 |
--------------------------------------------------------------------------------
/proxy/proxy.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | option go_package = "proxy";
3 |
4 | enum PROXY_PROTO {
5 | TCP = 0;
6 | UDP = 1;
7 | RUDP = 2;
8 | RICMP = 3;
9 | KCP = 4;
10 | }
11 |
12 | enum CLIENT_TYPE {
13 | // client fromaddr -> server toaddr
14 | PROXY = 0;
15 | // server fromaddr -> client toaddr
16 | REVERSE_PROXY = 1;
17 | // client fromaddr -> server
18 | SOCKS5 = 2;
19 | // server fromaddr -> client
20 | REVERSE_SOCKS5 = 3;
21 | // client fromaddr -> server shadowsocks address [SS_LOCAL_HOST:SS_LOCAL_PORT]
22 | SS_PROXY = 4;
23 | }
24 |
25 | message LoginFrame {
26 | PROXY_PROTO proxyproto = 1;
27 | CLIENT_TYPE clienttype = 2;
28 | string fromaddr = 3;
29 | string toaddr = 4;
30 | string name = 5;
31 | string key = 6;
32 | }
33 |
34 | message LoginRspFrame {
35 | bool ret = 1;
36 | string msg = 2;
37 | }
38 |
39 | message PingFrame {
40 | int64 time = 1;
41 | }
42 |
43 | message PongFrame {
44 | int64 time = 1;
45 | }
46 |
47 | message OpenConnFrame {
48 | string id = 1;
49 | string toaddr = 2;
50 | }
51 |
52 | message OpenConnRspFrame {
53 | string id = 1;
54 | bool ret = 2;
55 | string msg = 3;
56 | }
57 |
58 | message CloseFrame {
59 | string id = 1;
60 | }
61 |
62 | message DataFrame {
63 | string id = 1;
64 | bool compress = 2;
65 | string crc = 3;
66 | bytes data = 4;
67 | int32 index = 5;
68 | }
69 |
70 | enum FRAME_TYPE {
71 | LOGIN = 0;
72 | LOGINRSP = 1;
73 | DATA = 2;
74 | PING = 3;
75 | PONG = 4;
76 | OPEN = 5;
77 | OPENRSP = 6;
78 | CLOSE = 7;
79 | }
80 |
81 | message ProxyFrame {
82 | FRAME_TYPE type = 1;
83 | LoginFrame loginFrame = 2;
84 | LoginRspFrame loginRspFrame = 3;
85 | DataFrame dataFrame = 4;
86 | PingFrame pingFrame = 5;
87 | PongFrame pongFrame = 6;
88 | OpenConnFrame openFrame = 7;
89 | OpenConnRspFrame openRspFrame = 8;
90 | CloseFrame closeFrame = 9;
91 | }
92 |
--------------------------------------------------------------------------------
/proxy/server.go:
--------------------------------------------------------------------------------
1 | package proxy
2 |
3 | import (
4 | "errors"
5 | "github.com/esrrhs/gohome/common"
6 | "github.com/esrrhs/gohome/loggo"
7 | "github.com/esrrhs/gohome/network"
8 | "github.com/esrrhs/gohome/thread"
9 | "strconv"
10 | "sync"
11 | "sync/atomic"
12 | )
13 |
14 | type ClientConn struct {
15 | ProxyConn
16 |
17 | proxyproto PROXY_PROTO
18 | clienttype CLIENT_TYPE
19 | fromaddr string
20 | toaddr string
21 | name string
22 |
23 | input *Inputer
24 | output *Outputer
25 | }
26 |
27 | type Server struct {
28 | config *Config
29 | listenaddrs []string
30 | listenConns []network.Conn
31 | wg *thread.Group
32 | clients sync.Map
33 | }
34 |
35 | func NewServer(config *Config, proto []string, listenaddrs []string) (*Server, error) {
36 |
37 | if config == nil {
38 | config = DefaultConfig()
39 | }
40 |
41 | var listenConns []network.Conn
42 |
43 | for i, _ := range proto {
44 | conn, err := network.NewConn(proto[i])
45 | if conn == nil {
46 | return nil, err
47 | }
48 |
49 | setCongestion(conn, config)
50 |
51 | listenConn, err := conn.Listen(listenaddrs[i])
52 | if err != nil {
53 | return nil, err
54 | }
55 |
56 | listenConns = append(listenConns, listenConn)
57 | }
58 |
59 | wg := thread.NewGroup("Server", nil, func() {
60 | for i, _ := range listenConns {
61 | loggo.Info("group start exit %s", listenConns[i].Info())
62 | listenConns[i].Close()
63 | loggo.Info("group start exit %s", listenConns[i].Info())
64 | }
65 | })
66 |
67 | s := &Server{
68 | config: config,
69 | listenaddrs: listenaddrs,
70 | listenConns: listenConns,
71 | wg: wg,
72 | }
73 |
74 | for i, _ := range proto {
75 | index := i
76 | wg.Go("Server listen"+" "+listenaddrs[i], func() error {
77 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
78 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
79 | return s.listen(index)
80 | })
81 | }
82 |
83 | wg.Go("Client state", func() error {
84 | return showState(wg)
85 | })
86 |
87 | return s, nil
88 | }
89 |
90 | func (s *Server) Close() {
91 | s.wg.Stop()
92 | s.wg.Wait()
93 | }
94 |
95 | func (s *Server) listen(index int) error {
96 | loggo.Info("listen start %d %s", index, s.listenaddrs[index])
97 | for !s.wg.IsExit() {
98 | conn, err := s.listenConns[index].Accept()
99 | if err != nil {
100 | loggo.Info("Server listen Accept fail %s", err)
101 | continue
102 | }
103 |
104 | size := s.clientSize()
105 | if size >= s.config.MaxClient {
106 | loggo.Info("Server listen max client %s %d", conn.Info(), size)
107 | conn.Close()
108 | continue
109 | }
110 |
111 | clientconn := &ClientConn{ProxyConn: ProxyConn{conn: conn}}
112 | s.wg.Go("Server serveClient"+" "+conn.Info(), func() error {
113 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
114 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
115 | return s.serveClient(clientconn)
116 | })
117 | }
118 | loggo.Info("listen end %d %s", index, s.listenaddrs[index])
119 | return nil
120 | }
121 |
122 | func (s *Server) clientSize() int {
123 | size := 0
124 | s.clients.Range(func(key, value interface{}) bool {
125 | size++
126 | return true
127 | })
128 | return size
129 | }
130 |
131 | func (s *Server) serveClient(clientconn *ClientConn) error {
132 |
133 | loggo.Info("serveClient accept new client %s", clientconn.conn.Info())
134 |
135 | sendch := common.NewChannel(s.config.MainBuffer)
136 | recvch := common.NewChannel(s.config.MainBuffer)
137 |
138 | clientconn.sendch = sendch
139 | clientconn.recvch = recvch
140 |
141 | wg := thread.NewGroup("Server serveClient"+" "+clientconn.conn.Info(), s.wg, func() {
142 | loggo.Info("group start exit %s", clientconn.conn.Info())
143 | clientconn.conn.Close()
144 | sendch.Close()
145 | recvch.Close()
146 | if clientconn.input != nil {
147 | clientconn.input.Close()
148 | }
149 | if clientconn.output != nil {
150 | clientconn.output.Close()
151 | }
152 | loggo.Info("group end exit %s", clientconn.conn.Info())
153 | })
154 |
155 | var pingflag int32
156 | var pongflag int32
157 | var pongtime int64
158 |
159 | wg.Go("Server recvFrom"+" "+clientconn.conn.Info(), func() error {
160 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
161 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
162 | return recvFrom(wg, recvch, clientconn.conn, s.config.MaxMsgSize, s.config.Encrypt)
163 | })
164 |
165 | wg.Go("Server sendTo"+" "+clientconn.conn.Info(), func() error {
166 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
167 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
168 | return sendTo(wg, sendch, clientconn.conn, s.config.Compress, s.config.MaxMsgSize, s.config.Encrypt, &pingflag, &pongflag, &pongtime)
169 | })
170 |
171 | wg.Go("Server checkPingActive"+" "+clientconn.conn.Info(), func() error {
172 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
173 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
174 | return checkPingActive(wg, sendch, recvch, &clientconn.ProxyConn, s.config.EstablishedTimeout, s.config.PingInter, s.config.PingTimeoutInter, s.config.ShowPing, &pingflag)
175 | })
176 |
177 | wg.Go("Server checkNeedClose"+" "+clientconn.conn.Info(), func() error {
178 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
179 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
180 | return checkNeedClose(wg, &clientconn.ProxyConn)
181 | })
182 |
183 | wg.Go("Server process"+" "+clientconn.conn.Info(), func() error {
184 | atomic.AddInt32(&gStateThreadNum.ThreadNum, 1)
185 | defer atomic.AddInt32(&gStateThreadNum.ThreadNum, -1)
186 | return s.process(wg, sendch, recvch, clientconn, &pongflag, &pongtime)
187 | })
188 |
189 | wg.Wait()
190 | if clientconn.established {
191 | s.clients.Delete(clientconn.name)
192 | }
193 |
194 | loggo.Info("serveClient close client %s", clientconn.conn.Info())
195 |
196 | return nil
197 | }
198 |
199 | func (s *Server) process(wg *thread.Group, sendch *common.Channel, recvch *common.Channel, clientconn *ClientConn, pongflag *int32, pongtime *int64) error {
200 |
201 | loggo.Info("process start %s", clientconn.conn.Info())
202 |
203 | for !wg.IsExit() {
204 | ff := <-recvch.Ch()
205 | if ff == nil {
206 | break
207 | }
208 | f := ff.(*ProxyFrame)
209 | switch f.Type {
210 | case FRAME_TYPE_LOGIN:
211 | s.processLogin(wg, f, sendch, clientconn)
212 |
213 | case FRAME_TYPE_PING:
214 | processPing(f, sendch, &clientconn.ProxyConn, pongflag, pongtime)
215 |
216 | case FRAME_TYPE_PONG:
217 | processPong(f, sendch, &clientconn.ProxyConn, s.config.ShowPing)
218 |
219 | case FRAME_TYPE_DATA:
220 | s.processData(f, clientconn)
221 |
222 | case FRAME_TYPE_OPEN:
223 | s.processOpen(f, clientconn)
224 |
225 | case FRAME_TYPE_OPENRSP:
226 | s.processOpenRsp(f, clientconn)
227 |
228 | case FRAME_TYPE_CLOSE:
229 | s.processClose(f, clientconn)
230 | }
231 | }
232 | loggo.Info("process end %s", clientconn.conn.Info())
233 | return nil
234 | }
235 |
236 | func (s *Server) processLogin(wg *thread.Group, f *ProxyFrame, sendch *common.Channel, clientconn *ClientConn) {
237 | loggo.Info("processLogin from %s %s", clientconn.conn.Info(), f.LoginFrame.String())
238 |
239 | clientconn.proxyproto = f.LoginFrame.Proxyproto
240 | clientconn.clienttype = f.LoginFrame.Clienttype
241 | clientconn.fromaddr = f.LoginFrame.Fromaddr
242 | clientconn.toaddr = f.LoginFrame.Toaddr
243 | clientconn.name = f.LoginFrame.Name
244 |
245 | rf := &ProxyFrame{}
246 | rf.Type = FRAME_TYPE_LOGINRSP
247 | rf.LoginRspFrame = &LoginRspFrame{}
248 |
249 | if f.LoginFrame.Key != s.config.Key {
250 | rf.LoginRspFrame.Ret = false
251 | rf.LoginRspFrame.Msg = "key error"
252 | sendch.Write(rf)
253 | loggo.Error("processLogin fail key error %s %s", clientconn.conn.Info(), f.LoginFrame.String())
254 | return
255 | }
256 |
257 | if clientconn.established {
258 | rf.LoginRspFrame.Ret = false
259 | rf.LoginRspFrame.Msg = "has established before"
260 | sendch.Write(rf)
261 | loggo.Error("processLogin fail has established before %s %s", clientconn.conn.Info(), f.LoginFrame.String())
262 | return
263 | }
264 |
265 | _, loaded := s.clients.LoadOrStore(f.LoginFrame.Name, clientconn)
266 | if loaded {
267 | rf.LoginRspFrame.Ret = false
268 | rf.LoginRspFrame.Msg = f.LoginFrame.Name + " has login before"
269 | sendch.Write(rf)
270 | loggo.Error("processLogin fail %s has login before %s %s", f.LoginFrame.Name, clientconn.conn.Info(), f.LoginFrame.String())
271 | return
272 | }
273 |
274 | err := s.iniService(wg, f, clientconn)
275 | if err != nil {
276 | s.clients.Delete(clientconn.name)
277 | rf.LoginRspFrame.Ret = false
278 | rf.LoginRspFrame.Msg = "iniService fail"
279 | sendch.Write(rf)
280 | loggo.Error("processLogin iniService fail %s %s %s", clientconn.conn.Info(), f.LoginFrame.String(), err)
281 | return
282 | }
283 |
284 | clientconn.established = true
285 |
286 | rf.LoginRspFrame.Ret = true
287 | rf.LoginRspFrame.Msg = "ok"
288 | sendch.Write(rf)
289 |
290 | loggo.Info("processLogin ok %s %s", clientconn.conn.Info(), f.LoginFrame.String())
291 | }
292 |
293 | func (s *Server) iniService(wg *thread.Group, f *ProxyFrame, clientConn *ClientConn) error {
294 | switch f.LoginFrame.Clienttype {
295 | case CLIENT_TYPE_PROXY:
296 | output, err := NewOutputer(wg, f.LoginFrame.Proxyproto.String(), f.LoginFrame.Clienttype, s.config, &clientConn.ProxyConn)
297 | if err != nil {
298 | return err
299 | }
300 | clientConn.output = output
301 | case CLIENT_TYPE_REVERSE_PROXY:
302 | input, err := NewInputer(wg, f.LoginFrame.Proxyproto.String(), f.LoginFrame.Fromaddr, f.LoginFrame.Clienttype, s.config, &clientConn.ProxyConn, clientConn.toaddr)
303 | if err != nil {
304 | return err
305 | }
306 | clientConn.input = input
307 | case CLIENT_TYPE_SOCKS5:
308 | output, err := NewOutputer(wg, f.LoginFrame.Proxyproto.String(), f.LoginFrame.Clienttype, s.config, &clientConn.ProxyConn)
309 | if err != nil {
310 | return err
311 | }
312 | clientConn.output = output
313 | case CLIENT_TYPE_REVERSE_SOCKS5:
314 | input, err := NewSocks5Inputer(wg, f.LoginFrame.Proxyproto.String(), f.LoginFrame.Fromaddr, f.LoginFrame.Clienttype, s.config, &clientConn.ProxyConn)
315 | if err != nil {
316 | return err
317 | }
318 | clientConn.input = input
319 | case CLIENT_TYPE_SS_PROXY:
320 | output, err := NewSSOutputer(wg, f.LoginFrame.Proxyproto.String(), f.LoginFrame.Clienttype, s.config, &clientConn.ProxyConn)
321 | if err != nil {
322 | return err
323 | }
324 | clientConn.output = output
325 | default:
326 | return errors.New("error CLIENT_TYPE " + strconv.Itoa(int(f.LoginFrame.Clienttype)))
327 | }
328 | return nil
329 | }
330 |
331 | func (s *Server) processData(f *ProxyFrame, clientconn *ClientConn) {
332 | if clientconn.input != nil {
333 | clientconn.input.processDataFrame(f)
334 | } else if clientconn.output != nil {
335 | clientconn.output.processDataFrame(f)
336 | }
337 | }
338 |
339 | func (s *Server) processOpenRsp(f *ProxyFrame, clientconn *ClientConn) {
340 | if clientconn.input != nil {
341 | clientconn.input.processOpenRspFrame(f)
342 | }
343 | }
344 |
345 | func (c *Server) processOpen(f *ProxyFrame, clientconn *ClientConn) {
346 | if clientconn.output != nil {
347 | clientconn.output.processOpenFrame(f)
348 | }
349 | }
350 |
351 | func (c *Server) processClose(f *ProxyFrame, clientconn *ClientConn) {
352 | if clientconn.input != nil {
353 | clientconn.input.processCloseFrame(f)
354 | } else if clientconn.output != nil {
355 | clientconn.output.processCloseFrame(f)
356 | }
357 | }
358 |
--------------------------------------------------------------------------------
/show.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/esrrhs/spp/732cc1dc438702820864021c47df3ad810e0c167/show.png
--------------------------------------------------------------------------------