├── .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 | [![Go Report Card](https://goreportcard.com/badge/github.com/esrrhs/spp)](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 | ![image](show.png) 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 --------------------------------------------------------------------------------