Compare commits
297 commits
Author | SHA1 | Date | |
---|---|---|---|
|
66d34ba031 | ||
|
a350629abc | ||
|
5d53ddeb7a | ||
|
933b646d98 | ||
|
404ea744fe | ||
|
b30676729c | ||
|
6ab38e9d01 | ||
|
19d00b970e | ||
|
3d001c21f0 | ||
|
3c2bcf9bc9 | ||
|
a4d7ee02d9 | ||
|
327cf680c7 | ||
|
cab02d012b | ||
|
8824c495f5 | ||
|
1c79a8db64 | ||
|
7af41a7723 | ||
|
aa216a7d72 | ||
|
520cdd7063 | ||
|
f8d9ed6b5e | ||
|
e816385534 | ||
|
4a02bd6270 | ||
|
5163a571dc | ||
|
7187a57ceb | ||
|
5f81102814 | ||
|
94a9dc1eed | ||
|
fe571e8e4e | ||
|
93ab736d55 | ||
|
a1a1f0462a | ||
|
7970b38a68 | ||
|
8d63ad5334 | ||
|
219755bd5c | ||
|
622f631bbd | ||
|
4422d7c1d0 | ||
|
cb246793e6 | ||
|
cd1be4debf | ||
|
856300a446 | ||
|
ec19b924c8 | ||
|
ef8486c4eb | ||
|
60e4971fdf | ||
|
59dc4b4f79 | ||
|
4b22d08d0b | ||
|
31ebcc8bf8 | ||
|
3d75970db9 | ||
|
be7f7650a4 | ||
|
dff22bc62c | ||
|
f9bf4076f2 | ||
|
e1d5c970e0 | ||
|
f3a608957a | ||
|
c7700e858f | ||
|
1632aa4389 | ||
|
86a7340189 | ||
|
780f75ae7c | ||
|
2eab964f13 | ||
|
dd70313cf5 | ||
|
d04d249538 | ||
|
174fe4d7a2 | ||
|
6e8c975859 | ||
|
74f6108315 | ||
|
e746dc3616 | ||
|
cd21d586ae | ||
|
41ccdf6d7f | ||
|
9e8e9eb535 | ||
|
24fa2404dd | ||
|
122143529e | ||
|
bbee9243e8 | ||
|
847d475cc2 | ||
|
136db8d776 | ||
|
7f8d5fa390 | ||
|
8db60694b6 | ||
|
49d1af71b4 | ||
|
6fc899c759 | ||
|
7454c250dc | ||
|
ad69639117 | ||
|
fd4c4ebb47 | ||
|
db05e85500 | ||
|
6b7bc8e876 | ||
|
395a890632 | ||
|
0d6b836173 | ||
|
1c51495b9a | ||
|
76deebb4b0 | ||
|
a3209179a0 | ||
|
f365e94395 | ||
|
aa88696c37 | ||
|
e7b0c16282 | ||
|
8be6b166fc | ||
|
0bfccb395e | ||
|
6c35c96929 | ||
|
fc68e6449c | ||
|
b899f65b5a | ||
|
1ac3aabd08 | ||
|
a575babaa7 | ||
|
f2d1e1a5b3 | ||
|
6fa90c210b | ||
|
5a61d67923 | ||
|
2de5b16e2e | ||
|
29b3f73ada | ||
|
112fb03249 | ||
|
a9848f254a | ||
|
de0b4c2730 | ||
|
d038899851 | ||
|
0c6be88983 | ||
|
f51245fda4 | ||
|
f97c162f3f | ||
|
fd8c39df04 | ||
|
b8b216c115 | ||
|
9fcaf84ac3 | ||
|
db7551731a | ||
|
c71b537898 | ||
|
7b90bc40a6 | ||
|
5c313bff4e | ||
|
5b52521521 | ||
|
a797fd5cc7 | ||
|
a923fed6fc | ||
|
1dc3fe11be | ||
|
f988b2c483 | ||
|
0a18ded9cc | ||
|
dd04aa9b14 | ||
|
6913d315da | ||
|
b1f6acb659 | ||
|
3b6f4eebcf | ||
|
32ee72b850 | ||
|
d7f3c68d89 | ||
|
9b26464d10 | ||
|
d9ebc5c9f6 | ||
|
aaff23309f | ||
|
ba73a631a6 | ||
|
610b029dd9 | ||
|
2d3ed37feb | ||
|
2734daddc6 | ||
|
fc865f754d | ||
|
2b1abdf783 | ||
|
408c939da4 | ||
|
0ad2ad5fca | ||
|
9917c5bdcb | ||
|
41e144ceca | ||
|
ff392de1f1 | ||
|
44a1a5853d | ||
|
43f40eda1b | ||
|
1d67562804 | ||
|
b4f7e69f6b | ||
|
aa046d8a2f | ||
|
d4731262db | ||
|
852c0b1761 | ||
|
a33439b013 | ||
|
ba20b02358 | ||
|
00dfd7246b | ||
|
c79b7a2cea | ||
|
e0c5fd7b2f | ||
|
c66a9189eb | ||
|
0f3d847962 | ||
|
97866a3486 | ||
|
52337521dd | ||
|
74c53223b0 | ||
|
8954af9416 | ||
|
e5831b152c | ||
|
85c558a677 | ||
|
c5a6c80561 | ||
|
e16bff920e | ||
|
7b9113cd38 | ||
|
57b58f555d | ||
|
5eb78f2802 | ||
|
abd6db0ac5 | ||
|
8ba207626e | ||
|
9e0ae35149 | ||
|
321517df80 | ||
|
ddea3a66bc | ||
|
fd4b189c6f | ||
|
fa445c7d89 | ||
|
371dd4baa0 | ||
|
9e62422db6 | ||
|
1a994d448a | ||
|
0d61b60eaa | ||
|
d11d7c4b87 | ||
|
4986c989e3 | ||
|
c2ff8fa632 | ||
|
0b0a9cdc6a | ||
|
8651c222c4 | ||
|
3050373508 | ||
|
1b02df4a4d | ||
|
69273a94cc | ||
|
524fdb836d | ||
|
bf6270387e | ||
|
91de7cb8f0 | ||
|
cb7d489988 | ||
|
728c2705b2 | ||
|
a70fcdff74 | ||
|
afa564c81d | ||
|
33b164e63f | ||
|
8fb7712b54 | ||
|
599fb597e8 | ||
|
18fa88a798 | ||
|
a0a5ef06fb | ||
|
97ac0742b6 | ||
|
9665e03f6f | ||
|
ae593ddeb2 | ||
|
db35790150 | ||
|
d84320fffb | ||
|
5c0c08b7f3 | ||
|
1657f46784 | ||
|
30b1cd117b | ||
|
8d1d2bd6a2 | ||
|
0ba2aa2297 | ||
|
2a75a80a0e | ||
|
64f8ec24e6 | ||
|
831a5ee51d | ||
|
a71309c8cc | ||
|
d25f8499f6 | ||
|
08f0f61840 | ||
|
f323941276 | ||
|
160d6efc89 | ||
|
a4573f1540 | ||
|
a43e5c435f | ||
|
9b86a95dfc | ||
|
c348cfb2e9 | ||
|
4bfa31eea1 | ||
|
dc91b48b34 | ||
|
4bb047d433 | ||
|
6c7341375b | ||
|
225992d9eb | ||
|
8b712a1a9d | ||
|
85e3f4d20a | ||
|
28eee0c37d | ||
|
15c292777f | ||
|
e1fb19862c | ||
|
b7e82c053a | ||
|
feba1f555a | ||
|
2b6ecc47ae | ||
|
1113420ed9 | ||
|
de8be340ff | ||
|
c2c8ad1985 | ||
|
47c1d9117a | ||
|
6c495b2cf8 | ||
|
16c7838109 | ||
|
78346d4c6c | ||
|
1f8263a322 | ||
|
48b27bfe00 | ||
|
ae787b421e | ||
|
2495f2290f | ||
|
d69f971519 | ||
|
551c1437e5 | ||
|
013c6124d9 | ||
|
2dd984018c | ||
|
79a278a90f | ||
|
6ad90d18aa | ||
|
aed73279f7 | ||
|
f93b24d3d1 | ||
|
b67d5d372d | ||
|
37005c8ae8 | ||
|
d0897dd522 | ||
|
dc02a58284 | ||
|
7b88a879e1 | ||
|
63e557b566 | ||
|
2b37b02276 | ||
|
1222033a82 | ||
|
b1fd10de27 | ||
|
284dcccd18 | ||
|
bf39ee41b2 | ||
|
9e1d5d61b2 | ||
|
51bf1778c5 | ||
|
15e53f1f52 | ||
|
c90545eaf6 | ||
|
c923db7d8a | ||
|
82045f9e55 | ||
|
2ffba2224b | ||
|
a2f8819782 | ||
|
a2c2ab95e2 | ||
|
60cb43cb2e | ||
|
f97c2fb4d0 | ||
|
f06498e912 | ||
|
2ed5548a6f | ||
|
ba76acaf87 | ||
|
b15faae234 | ||
|
a13cd98e29 | ||
|
ff3daaed0f | ||
|
111b7397d8 | ||
|
b0c7bc5949 | ||
|
b88c2320f3 | ||
|
959dd136d9 | ||
|
d3479c08a1 | ||
|
120d949c59 | ||
|
d34ecbaca6 | ||
|
2fda6b845c | ||
|
f6e315ba37 | ||
|
f12978b35b | ||
|
5a8b3469ba | ||
|
f512f32ec1 | ||
|
0c41f5e7d3 | ||
|
a2f409453b | ||
|
14315b85ab | ||
|
a72544515e | ||
|
05b7ff19aa | ||
|
a40c5c8232 | ||
|
13b2cbca81 | ||
|
f275f81308 | ||
|
a3036dcc66 | ||
|
1402d824c6 | ||
|
65cd195ca8 |
25 changed files with 2007 additions and 594 deletions
34
.github/workflows/docker-image.yml
vendored
Normal file
34
.github/workflows/docker-image.yml
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
name: Docker Image CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
-
|
||||
name: Build and push
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
push: true
|
||||
tags: esrrhs/pingtunnel:latest
|
30
.github/workflows/go.yml
vendored
Normal file
30
.github/workflows/go.yml
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
# This workflow will build a golang project
|
||||
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
|
||||
|
||||
name: Go
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.21
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
go mod tidy
|
||||
go build -v ./...
|
||||
|
||||
- name: Test
|
||||
run: go test -v ./...
|
7
.idea/vcs.xml
generated
7
.idea/vcs.xml
generated
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/src/github.com/esrrhs/pingtunnel" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
13
Dockerfile
Normal file
13
Dockerfile
Normal file
|
@ -0,0 +1,13 @@
|
|||
FROM golang AS build-env
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY go.* ./
|
||||
RUN go mod download
|
||||
COPY . ./
|
||||
RUN go build -v -o pingtunnel
|
||||
|
||||
FROM debian
|
||||
COPY --from=build-env /app/pingtunnel .
|
||||
COPY GeoLite2-Country.mmdb .
|
||||
WORKDIR ./
|
BIN
GeoLite2-Country.mmdb
Normal file
BIN
GeoLite2-Country.mmdb
Normal file
Binary file not shown.
123
README.md
123
README.md
|
@ -1,71 +1,78 @@
|
|||
# Pingtunnel
|
||||
pingtunnel是把udp流量伪装成icmp流量进行转发的工具,类似于kcptun。用于突破网络封锁,或是绕过WIFI网络的登陆验证。可以与kcptun很方便的结合使用。
|
||||
<br />Pingtunnel is a tool that advertises udp traffic as icmp traffic for forwarding, similar to kcptun. Used to break through the network blockade, or to bypass the WIFI network login verification. Can be combined with kcptun very convenient.
|
||||

|
||||
# Sample
|
||||
如把本机的:4455的UDP流量转发到www.yourserver.com:4455:For example, the UDP traffic of the machine: 4545 is forwarded to www.yourserver.com:4455:
|
||||
* 在www.yourserver.com的服务器上用root权限运行。Run with root privileges on the server at www.yourserver.com
|
||||
|
||||
[<img src="https://img.shields.io/github/license/esrrhs/pingtunnel">](https://github.com/esrrhs/pingtunnel)
|
||||
[<img src="https://img.shields.io/github/languages/top/esrrhs/pingtunnel">](https://github.com/esrrhs/pingtunnel)
|
||||
[](https://goreportcard.com/report/github.com/esrrhs/pingtunnel)
|
||||
[<img src="https://img.shields.io/github/v/release/esrrhs/pingtunnel">](https://github.com/esrrhs/pingtunnel/releases)
|
||||
[<img src="https://img.shields.io/github/downloads/esrrhs/pingtunnel/total">](https://github.com/esrrhs/pingtunnel/releases)
|
||||
[<img src="https://img.shields.io/docker/pulls/esrrhs/pingtunnel">](https://hub.docker.com/repository/docker/esrrhs/pingtunnel)
|
||||
[<img src="https://img.shields.io/github/actions/workflow/status/esrrhs/pingtunnel/go.yml?branch=master">](https://github.com/esrrhs/pingtunnel/actions)
|
||||
|
||||
Pingtunnel is a tool that send TCP/UDP traffic over ICMP.
|
||||
|
||||
## Note: This tool is only to be used for study and research, do not use it for illegal purposes
|
||||
|
||||

|
||||
|
||||
## Usage
|
||||
|
||||
### Install server
|
||||
|
||||
- First prepare a server with a public IP, such as EC2 on AWS, assuming the domain name or public IP is www.yourserver.com
|
||||
- Download the corresponding installation package from [releases](https://github.com/esrrhs/pingtunnel/releases), such as pingtunnel_linux64.zip, then decompress and execute with **root** privileges
|
||||
- “-key” parameter is **int** type, only supports numbers between 0-2147483647
|
||||
|
||||
```
|
||||
sudo wget (link of latest release)
|
||||
sudo unzip pingtunnel_linux64.zip
|
||||
sudo ./pingtunnel -type server
|
||||
```
|
||||
* 在你本地电脑上用管理员权限运行。Run with administrator privileges on your local computer
|
||||
|
||||
- (Optional) Disable system default ping
|
||||
|
||||
```
|
||||
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all
|
||||
```
|
||||
|
||||
### Install the client
|
||||
|
||||
- Download the corresponding installation package from [releases](https://github.com/esrrhs/pingtunnel/releases), such as pingtunnel_windows64.zip, and decompress it
|
||||
- Then run with **administrator** privileges. The commands corresponding to different forwarding functions are as follows.
|
||||
- If you see a log of ping pong, the connection is normal
|
||||
- “-key” parameter is **int** type, only supports numbers between 0-2147483647
|
||||
|
||||
|
||||
#### Forward sock5
|
||||
|
||||
```
|
||||
pingtunnel.exe -type client -l :4455 -s www.yourserver.com -sock5 1
|
||||
```
|
||||
|
||||
#### Forward tcp
|
||||
|
||||
```
|
||||
pingtunnel.exe -type client -l :4455 -s www.yourserver.com -t www.yourserver.com:4455 -tcp 1
|
||||
```
|
||||
|
||||
#### Forward udp
|
||||
|
||||
```
|
||||
pingtunnel.exe -type client -l :4455 -s www.yourserver.com -t www.yourserver.com:4455
|
||||
```
|
||||
* 如果看到客户端不停的ping、pong日志输出,说明工作正常。If you see the client ping, pong log output, it means normal work
|
||||
|
||||
### Use Docker
|
||||
It can also be started directly with docker, which is more convenient. Same parameters as above
|
||||
- server:
|
||||
```
|
||||
ping www.xx.com 2018-12-23 13:05:50.5724495 +0800 CST m=+3.023909301 8 0 1997 2
|
||||
pong from xx.xx.xx.xx 210.8078ms
|
||||
docker run --name pingtunnel-server -d --privileged --network host --restart=always esrrhs/pingtunnel ./pingtunnel -type server -key 123456
|
||||
```
|
||||
- client:
|
||||
```
|
||||
docker run --name pingtunnel-client -d --restart=always -p 1080:1080 esrrhs/pingtunnel ./pingtunnel -type client -l :1080 -s www.yourserver.com -sock5 1 -key 123456
|
||||
```
|
||||
|
||||
# 注意
|
||||
对于某些网络,比如长城宽带、宽带通,需要特殊处理才能正常工作。方法是
|
||||
* 关闭服务器的系统ping,例如
|
||||
```
|
||||
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all
|
||||
```
|
||||
* 客户端添加catch参数,用来主动抓取服务器回包,100就是每秒主动抓100个包
|
||||
```
|
||||
pingtunnel.exe -type client -l :4455 -s www.yourserver.com -t www.yourserver.com:4455 -catch 100
|
||||
```
|
||||
* 这个是在某开放wifi上,利用shadowsocks、kcptun、pingtunnel绕过验证直接上网,可以看到wifi是受限的,但是仍然可以通过远程访问网络,ip地址显示是远程服务器的地址,因为他没有禁ping
|
||||

|
||||
## Thanks for free JetBrains Open Source license
|
||||
|
||||
# Usage
|
||||
<img src="https://resources.jetbrains.com/storage/products/company/brand/logos/GoLand.png" height="200"/></a>
|
||||
|
||||
|
||||
通过伪造ping,把udp流量通过远程服务器转发到目的服务器上。用于突破某些运营商封锁UDP流量。
|
||||
By forging ping, the udp traffic is forwarded to the destination server through the remote server. Used to break certain operators to block UDP traffic.
|
||||
|
||||
Usage:
|
||||
|
||||
pingtunnel -type server
|
||||
|
||||
pingtunnel -type client -l LOCAL_IP:4455 -s SERVER_IP -t SERVER_IP:4455
|
||||
|
||||
-type 服务器或者客户端
|
||||
client or server
|
||||
|
||||
-l 本地的地址,发到这个端口的流量将转发到服务器
|
||||
Local address, traffic sent to this port will be forwarded to the server
|
||||
|
||||
-s 服务器的地址,流量将通过隧道转发到这个服务器
|
||||
The address of the server, the traffic will be forwarded to this server through the tunnel
|
||||
|
||||
-t 远端服务器转发的目的地址,流量将转发到这个地址
|
||||
Destination address forwarded by the remote server, traffic will be forwarded to this address
|
||||
|
||||
-timeout 本地记录连接超时的时间,单位是秒
|
||||
The time when the local record connection timed out, in seconds
|
||||
|
||||
-sproto 客户端发送ping协议的协议,默认是13
|
||||
The protocol that the client sends the ping. The default is 13.
|
||||
|
||||
-rproto 客户端接收ping协议的协议,默认是14
|
||||
The protocol that the client receives the ping. The default is 14.
|
||||
|
||||
-catch 主动抓模式,每秒从服务器主动抓多少个reply包,默认0
|
||||
Active capture mode, how many reply packets are actively captured from the server per second, default 0
|
||||
|
||||
-key 设置的密码,默认0
|
||||
Set password, default 0
|
1
_config.yml
Normal file
1
_config.yml
Normal file
|
@ -0,0 +1 @@
|
|||
theme: jekyll-theme-cayman
|
820
client.go
820
client.go
|
@ -1,19 +1,43 @@
|
|||
package pingtunnel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/esrrhs/gohome/common"
|
||||
"github.com/esrrhs/gohome/frame"
|
||||
"github.com/esrrhs/gohome/loggo"
|
||||
"github.com/esrrhs/gohome/network"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"golang.org/x/net/icmp"
|
||||
"io"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
func NewClient(addr string, server string, target string, timeout int, sproto int, rproto int, catch int, key int) (*Client, error) {
|
||||
const (
|
||||
SEND_PROTO int = 8
|
||||
RECV_PROTO int = 0
|
||||
)
|
||||
|
||||
ipaddr, err := net.ResolveUDPAddr("udp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func NewClient(addr string, server string, target string, timeout int, key int,
|
||||
tcpmode int, tcpmode_buffersize int, tcpmode_maxwin int, tcpmode_resend_timems int, tcpmode_compress int,
|
||||
tcpmode_stat int, open_sock5 int, maxconn int, sock5_filter *func(addr string) bool) (*Client, error) {
|
||||
|
||||
var ipaddr *net.UDPAddr
|
||||
var tcpaddr *net.TCPAddr
|
||||
var err error
|
||||
|
||||
if tcpmode > 0 {
|
||||
tcpaddr, err = net.ResolveTCPAddr("tcp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
ipaddr, err = net.ResolveUDPAddr("udp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
ipaddrServer, err := net.ResolveIPAddr("ip", server)
|
||||
|
@ -21,60 +45,93 @@ func NewClient(addr string, server string, target string, timeout int, sproto in
|
|||
return nil, err
|
||||
}
|
||||
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
return &Client{
|
||||
id: r.Intn(math.MaxInt16),
|
||||
ipaddr: ipaddr,
|
||||
addr: addr,
|
||||
ipaddrServer: ipaddrServer,
|
||||
addrServer: server,
|
||||
targetAddr: target,
|
||||
timeout: timeout,
|
||||
sproto: sproto,
|
||||
rproto: rproto,
|
||||
catch: catch,
|
||||
key: key,
|
||||
exit: false,
|
||||
rtt: 0,
|
||||
id: rand.Intn(math.MaxInt16),
|
||||
ipaddr: ipaddr,
|
||||
tcpaddr: tcpaddr,
|
||||
addr: addr,
|
||||
ipaddrServer: ipaddrServer,
|
||||
addrServer: server,
|
||||
targetAddr: target,
|
||||
timeout: timeout,
|
||||
key: key,
|
||||
tcpmode: tcpmode,
|
||||
tcpmode_buffersize: tcpmode_buffersize,
|
||||
tcpmode_maxwin: tcpmode_maxwin,
|
||||
tcpmode_resend_timems: tcpmode_resend_timems,
|
||||
tcpmode_compress: tcpmode_compress,
|
||||
tcpmode_stat: tcpmode_stat,
|
||||
open_sock5: open_sock5,
|
||||
maxconn: maxconn,
|
||||
pongTime: time.Now(),
|
||||
sock5_filter: sock5_filter,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
exit bool
|
||||
rtt time.Duration
|
||||
workResultLock sync.WaitGroup
|
||||
maxconn int
|
||||
|
||||
id int
|
||||
sequence int
|
||||
|
||||
timeout int
|
||||
sproto int
|
||||
rproto int
|
||||
catch int
|
||||
key int
|
||||
timeout int
|
||||
sproto int
|
||||
rproto int
|
||||
key int
|
||||
tcpmode int
|
||||
tcpmode_buffersize int
|
||||
tcpmode_maxwin int
|
||||
tcpmode_resend_timems int
|
||||
tcpmode_compress int
|
||||
tcpmode_stat int
|
||||
|
||||
ipaddr *net.UDPAddr
|
||||
addr string
|
||||
open_sock5 int
|
||||
sock5_filter *func(addr string) bool
|
||||
|
||||
ipaddr *net.UDPAddr
|
||||
tcpaddr *net.TCPAddr
|
||||
addr string
|
||||
|
||||
ipaddrServer *net.IPAddr
|
||||
addrServer string
|
||||
|
||||
targetAddr string
|
||||
|
||||
conn *icmp.PacketConn
|
||||
listenConn *net.UDPConn
|
||||
conn *icmp.PacketConn
|
||||
listenConn *net.UDPConn
|
||||
tcplistenConn *net.TCPListener
|
||||
|
||||
localAddrToConnMap map[string]*ClientConn
|
||||
localIdToConnMap map[string]*ClientConn
|
||||
localAddrToConnMap sync.Map
|
||||
localIdToConnMap sync.Map
|
||||
|
||||
sendPacket uint64
|
||||
recvPacket uint64
|
||||
sendPacketSize uint64
|
||||
recvPacketSize uint64
|
||||
sendPacket uint64
|
||||
recvPacket uint64
|
||||
sendPacketSize uint64
|
||||
recvPacketSize uint64
|
||||
localAddrToConnMapSize int
|
||||
localIdToConnMapSize int
|
||||
|
||||
sendCatchPacket uint64
|
||||
recvCatchPacket uint64
|
||||
recvcontrol chan int
|
||||
|
||||
pongTime time.Time
|
||||
}
|
||||
|
||||
type ClientConn struct {
|
||||
ipaddr *net.UDPAddr
|
||||
id string
|
||||
activeTime time.Time
|
||||
close bool
|
||||
exit bool
|
||||
ipaddr *net.UDPAddr
|
||||
tcpaddr *net.TCPAddr
|
||||
id string
|
||||
activeRecvTime time.Time
|
||||
activeSendTime time.Time
|
||||
close bool
|
||||
|
||||
fm *frame.FrameMgr
|
||||
}
|
||||
|
||||
func (p *Client) Addr() string {
|
||||
|
@ -97,108 +154,420 @@ func (p *Client) ServerAddr() string {
|
|||
return p.addrServer
|
||||
}
|
||||
|
||||
func (p *Client) Run() {
|
||||
func (p *Client) RTT() time.Duration {
|
||||
return p.rtt
|
||||
}
|
||||
|
||||
func (p *Client) RecvPacketSize() uint64 {
|
||||
return p.recvPacketSize
|
||||
}
|
||||
|
||||
func (p *Client) SendPacketSize() uint64 {
|
||||
return p.sendPacketSize
|
||||
}
|
||||
|
||||
func (p *Client) RecvPacket() uint64 {
|
||||
return p.recvPacket
|
||||
}
|
||||
|
||||
func (p *Client) SendPacket() uint64 {
|
||||
return p.sendPacket
|
||||
}
|
||||
|
||||
func (p *Client) LocalIdToConnMapSize() int {
|
||||
return p.localIdToConnMapSize
|
||||
}
|
||||
|
||||
func (p *Client) LocalAddrToConnMapSize() int {
|
||||
return p.localAddrToConnMapSize
|
||||
}
|
||||
|
||||
func (p *Client) Run() error {
|
||||
|
||||
conn, err := icmp.ListenPacket("ip4:icmp", "")
|
||||
if err != nil {
|
||||
fmt.Printf("Error listening for ICMP packets: %s\n", err.Error())
|
||||
return
|
||||
loggo.Error("Error listening for ICMP packets: %s", err.Error())
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
p.conn = conn
|
||||
|
||||
listener, err := net.ListenUDP("udp", p.ipaddr)
|
||||
if err != nil {
|
||||
fmt.Printf("Error listening for udp packets: %s\n", err.Error())
|
||||
return
|
||||
if p.tcpmode > 0 {
|
||||
tcplistenConn, err := net.ListenTCP("tcp", p.tcpaddr)
|
||||
if err != nil {
|
||||
loggo.Error("Error listening for tcp packets: %s", err.Error())
|
||||
return err
|
||||
}
|
||||
p.tcplistenConn = tcplistenConn
|
||||
} else {
|
||||
listener, err := net.ListenUDP("udp", p.ipaddr)
|
||||
if err != nil {
|
||||
loggo.Error("Error listening for udp packets: %s", err.Error())
|
||||
return err
|
||||
}
|
||||
p.listenConn = listener
|
||||
}
|
||||
defer listener.Close()
|
||||
p.listenConn = listener
|
||||
|
||||
p.localAddrToConnMap = make(map[string]*ClientConn)
|
||||
p.localIdToConnMap = make(map[string]*ClientConn)
|
||||
|
||||
go p.Accept()
|
||||
if p.tcpmode > 0 {
|
||||
go p.AcceptTcp()
|
||||
} else {
|
||||
go p.Accept()
|
||||
}
|
||||
|
||||
recv := make(chan *Packet, 10000)
|
||||
go recvICMP(*p.conn, recv)
|
||||
p.recvcontrol = make(chan int, 1)
|
||||
go recvICMP(&p.workResultLock, &p.exit, *p.conn, recv)
|
||||
|
||||
interval := time.NewTicker(time.Second)
|
||||
defer interval.Stop()
|
||||
go func() {
|
||||
defer common.CrashLog()
|
||||
|
||||
inter := 1000
|
||||
if p.catch > 0 {
|
||||
inter = 1000 / p.catch
|
||||
if inter <= 0 {
|
||||
inter = 1
|
||||
}
|
||||
}
|
||||
intervalCatch := time.NewTicker(time.Millisecond * time.Duration(inter))
|
||||
defer intervalCatch.Stop()
|
||||
p.workResultLock.Add(1)
|
||||
defer p.workResultLock.Done()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-interval.C:
|
||||
for !p.exit {
|
||||
p.checkTimeoutConn()
|
||||
p.ping()
|
||||
p.showNet()
|
||||
case <-intervalCatch.C:
|
||||
p.sendCatch()
|
||||
case r := <-recv:
|
||||
p.processPacket(r)
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer common.CrashLog()
|
||||
|
||||
p.workResultLock.Add(1)
|
||||
defer p.workResultLock.Done()
|
||||
|
||||
for !p.exit {
|
||||
p.updateServerAddr()
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer common.CrashLog()
|
||||
|
||||
p.workResultLock.Add(1)
|
||||
defer p.workResultLock.Done()
|
||||
|
||||
for !p.exit {
|
||||
select {
|
||||
case <-p.recvcontrol:
|
||||
return
|
||||
case r := <-recv:
|
||||
p.processPacket(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Client) Stop() {
|
||||
p.exit = true
|
||||
p.recvcontrol <- 1
|
||||
p.workResultLock.Wait()
|
||||
p.conn.Close()
|
||||
if p.tcplistenConn != nil {
|
||||
p.tcplistenConn.Close()
|
||||
}
|
||||
if p.listenConn != nil {
|
||||
p.listenConn.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Client) AcceptTcp() error {
|
||||
|
||||
defer common.CrashLog()
|
||||
|
||||
p.workResultLock.Add(1)
|
||||
defer p.workResultLock.Done()
|
||||
|
||||
loggo.Info("client waiting local accept tcp")
|
||||
|
||||
for !p.exit {
|
||||
p.tcplistenConn.SetDeadline(time.Now().Add(time.Millisecond * 1000))
|
||||
|
||||
conn, err := p.tcplistenConn.AcceptTCP()
|
||||
if err != nil {
|
||||
nerr, ok := err.(net.Error)
|
||||
if !ok || !nerr.Timeout() {
|
||||
loggo.Info("Error accept tcp %s", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if conn != nil {
|
||||
if p.open_sock5 > 0 {
|
||||
go p.AcceptSock5Conn(conn)
|
||||
} else {
|
||||
go p.AcceptTcpConn(conn, p.targetAddr)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Client) AcceptTcpConn(conn *net.TCPConn, targetAddr string) {
|
||||
|
||||
defer common.CrashLog()
|
||||
|
||||
p.workResultLock.Add(1)
|
||||
defer p.workResultLock.Done()
|
||||
|
||||
tcpsrcaddr := conn.RemoteAddr().(*net.TCPAddr)
|
||||
|
||||
if p.maxconn > 0 && p.localIdToConnMapSize >= p.maxconn {
|
||||
loggo.Info("too many connections %d, client accept new local tcp fail %s", p.localIdToConnMapSize, tcpsrcaddr.String())
|
||||
return
|
||||
}
|
||||
|
||||
uuid := common.UniqueId()
|
||||
|
||||
fm := frame.NewFrameMgr(FRAME_MAX_SIZE, FRAME_MAX_ID, p.tcpmode_buffersize, p.tcpmode_maxwin, p.tcpmode_resend_timems, p.tcpmode_compress, p.tcpmode_stat)
|
||||
|
||||
now := time.Now()
|
||||
clientConn := &ClientConn{exit: false, tcpaddr: tcpsrcaddr, id: uuid, activeRecvTime: now, activeSendTime: now, close: false,
|
||||
fm: fm}
|
||||
p.addClientConn(uuid, tcpsrcaddr.String(), clientConn)
|
||||
loggo.Info("client accept new local tcp %s %s", uuid, tcpsrcaddr.String())
|
||||
|
||||
loggo.Info("start connect remote tcp %s %s", uuid, tcpsrcaddr.String())
|
||||
clientConn.fm.Connect()
|
||||
startConnectTime := common.GetNowUpdateInSecond()
|
||||
for !p.exit && !clientConn.exit {
|
||||
if clientConn.fm.IsConnected() {
|
||||
break
|
||||
}
|
||||
clientConn.fm.Update()
|
||||
sendlist := clientConn.fm.GetSendList()
|
||||
for e := sendlist.Front(); e != nil; e = e.Next() {
|
||||
f := e.Value.(*frame.Frame)
|
||||
mb, _ := clientConn.fm.MarshalFrame(f)
|
||||
p.sequence++
|
||||
sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, targetAddr, clientConn.id, (uint32)(MyMsg_DATA), mb,
|
||||
SEND_PROTO, RECV_PROTO, p.key,
|
||||
p.tcpmode, p.tcpmode_buffersize, p.tcpmode_maxwin, p.tcpmode_resend_timems, p.tcpmode_compress, p.tcpmode_stat,
|
||||
p.timeout)
|
||||
p.sendPacket++
|
||||
p.sendPacketSize += (uint64)(len(mb))
|
||||
}
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
now := common.GetNowUpdateInSecond()
|
||||
diffclose := now.Sub(startConnectTime)
|
||||
if diffclose > time.Second*5 {
|
||||
loggo.Info("can not connect remote tcp %s %s", uuid, tcpsrcaddr.String())
|
||||
p.close(clientConn)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !clientConn.exit {
|
||||
loggo.Info("connected remote tcp %s %s", uuid, tcpsrcaddr.String())
|
||||
}
|
||||
|
||||
bytes := make([]byte, 10240)
|
||||
|
||||
tcpActiveRecvTime := common.GetNowUpdateInSecond()
|
||||
tcpActiveSendTime := common.GetNowUpdateInSecond()
|
||||
|
||||
for !p.exit && !clientConn.exit {
|
||||
now := common.GetNowUpdateInSecond()
|
||||
sleep := true
|
||||
|
||||
left := common.MinOfInt(clientConn.fm.GetSendBufferLeft(), len(bytes))
|
||||
if left > 0 {
|
||||
conn.SetReadDeadline(time.Now().Add(time.Millisecond * 1))
|
||||
n, err := conn.Read(bytes[0:left])
|
||||
if err != nil {
|
||||
nerr, ok := err.(net.Error)
|
||||
if !ok || !nerr.Timeout() {
|
||||
loggo.Info("Error read tcp %s %s %s", uuid, tcpsrcaddr.String(), err)
|
||||
clientConn.fm.Close()
|
||||
break
|
||||
}
|
||||
}
|
||||
if n > 0 {
|
||||
sleep = false
|
||||
clientConn.fm.WriteSendBuffer(bytes[:n])
|
||||
tcpActiveRecvTime = now
|
||||
}
|
||||
}
|
||||
|
||||
clientConn.fm.Update()
|
||||
|
||||
sendlist := clientConn.fm.GetSendList()
|
||||
if sendlist.Len() > 0 {
|
||||
sleep = false
|
||||
clientConn.activeSendTime = now
|
||||
for e := sendlist.Front(); e != nil; e = e.Next() {
|
||||
f := e.Value.(*frame.Frame)
|
||||
mb, err := clientConn.fm.MarshalFrame(f)
|
||||
if err != nil {
|
||||
loggo.Error("Error tcp Marshal %s %s %s", uuid, tcpsrcaddr.String(), err)
|
||||
continue
|
||||
}
|
||||
p.sequence++
|
||||
sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, targetAddr, clientConn.id, (uint32)(MyMsg_DATA), mb,
|
||||
SEND_PROTO, RECV_PROTO, p.key,
|
||||
p.tcpmode, 0, 0, 0, 0, 0,
|
||||
0)
|
||||
p.sendPacket++
|
||||
p.sendPacketSize += (uint64)(len(mb))
|
||||
}
|
||||
}
|
||||
|
||||
if clientConn.fm.GetRecvBufferSize() > 0 {
|
||||
sleep = false
|
||||
rr := clientConn.fm.GetRecvReadLineBuffer()
|
||||
conn.SetWriteDeadline(time.Now().Add(time.Millisecond * 1))
|
||||
n, err := conn.Write(rr)
|
||||
if err != nil {
|
||||
nerr, ok := err.(net.Error)
|
||||
if !ok || !nerr.Timeout() {
|
||||
loggo.Info("Error write tcp %s %s %s", uuid, tcpsrcaddr.String(), err)
|
||||
clientConn.fm.Close()
|
||||
break
|
||||
}
|
||||
}
|
||||
if n > 0 {
|
||||
clientConn.fm.SkipRecvBuffer(n)
|
||||
tcpActiveSendTime = now
|
||||
}
|
||||
}
|
||||
|
||||
if sleep {
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
}
|
||||
|
||||
diffrecv := now.Sub(clientConn.activeRecvTime)
|
||||
diffsend := now.Sub(clientConn.activeSendTime)
|
||||
tcpdiffrecv := now.Sub(tcpActiveRecvTime)
|
||||
tcpdiffsend := now.Sub(tcpActiveSendTime)
|
||||
if diffrecv > time.Second*(time.Duration(p.timeout)) || diffsend > time.Second*(time.Duration(p.timeout)) ||
|
||||
(tcpdiffrecv > time.Second*(time.Duration(p.timeout)) && tcpdiffsend > time.Second*(time.Duration(p.timeout))) {
|
||||
loggo.Info("close inactive conn %s %s", clientConn.id, clientConn.tcpaddr.String())
|
||||
clientConn.fm.Close()
|
||||
break
|
||||
}
|
||||
|
||||
if clientConn.fm.IsRemoteClosed() {
|
||||
loggo.Info("closed by remote conn %s %s", clientConn.id, clientConn.tcpaddr.String())
|
||||
clientConn.fm.Close()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
clientConn.fm.Close()
|
||||
|
||||
startCloseTime := common.GetNowUpdateInSecond()
|
||||
for !p.exit && !clientConn.exit {
|
||||
now := common.GetNowUpdateInSecond()
|
||||
|
||||
clientConn.fm.Update()
|
||||
|
||||
sendlist := clientConn.fm.GetSendList()
|
||||
for e := sendlist.Front(); e != nil; e = e.Next() {
|
||||
f := e.Value.(*frame.Frame)
|
||||
mb, _ := clientConn.fm.MarshalFrame(f)
|
||||
p.sequence++
|
||||
sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, targetAddr, clientConn.id, (uint32)(MyMsg_DATA), mb,
|
||||
SEND_PROTO, RECV_PROTO, p.key,
|
||||
p.tcpmode, 0, 0, 0, 0, 0,
|
||||
0)
|
||||
p.sendPacket++
|
||||
p.sendPacketSize += (uint64)(len(mb))
|
||||
}
|
||||
|
||||
nodatarecv := true
|
||||
if clientConn.fm.GetRecvBufferSize() > 0 {
|
||||
rr := clientConn.fm.GetRecvReadLineBuffer()
|
||||
conn.SetWriteDeadline(time.Now().Add(time.Millisecond * 100))
|
||||
n, _ := conn.Write(rr)
|
||||
if n > 0 {
|
||||
clientConn.fm.SkipRecvBuffer(n)
|
||||
nodatarecv = false
|
||||
}
|
||||
}
|
||||
|
||||
diffclose := now.Sub(startCloseTime)
|
||||
if diffclose > time.Second*60 {
|
||||
loggo.Info("close conn had timeout %s %s", clientConn.id, clientConn.tcpaddr.String())
|
||||
break
|
||||
}
|
||||
|
||||
remoteclosed := clientConn.fm.IsRemoteClosed()
|
||||
if remoteclosed && nodatarecv {
|
||||
loggo.Info("remote conn had closed %s %s", clientConn.id, clientConn.tcpaddr.String())
|
||||
break
|
||||
}
|
||||
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
|
||||
loggo.Info("close tcp conn %s %s", clientConn.id, clientConn.tcpaddr.String())
|
||||
conn.Close()
|
||||
p.close(clientConn)
|
||||
}
|
||||
|
||||
func (p *Client) Accept() error {
|
||||
|
||||
fmt.Println("client waiting local accept")
|
||||
defer common.CrashLog()
|
||||
|
||||
p.workResultLock.Add(1)
|
||||
defer p.workResultLock.Done()
|
||||
|
||||
loggo.Info("client waiting local accept udp")
|
||||
|
||||
bytes := make([]byte, 10240)
|
||||
|
||||
for {
|
||||
for !p.exit {
|
||||
p.listenConn.SetReadDeadline(time.Now().Add(time.Millisecond * 100))
|
||||
n, srcaddr, err := p.listenConn.ReadFromUDP(bytes)
|
||||
if err != nil {
|
||||
if neterr, ok := err.(*net.OpError); ok {
|
||||
if neterr.Timeout() {
|
||||
// Read timeout
|
||||
continue
|
||||
} else {
|
||||
fmt.Printf("Error read udp %s\n", err)
|
||||
continue
|
||||
}
|
||||
nerr, ok := err.(net.Error)
|
||||
if !ok || !nerr.Timeout() {
|
||||
loggo.Info("Error read udp %s", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
clientConn := p.localAddrToConnMap[srcaddr.String()]
|
||||
if clientConn == nil {
|
||||
uuid := UniqueId()
|
||||
clientConn = &ClientConn{ipaddr: srcaddr, id: uuid, activeTime: now, close: false}
|
||||
p.localAddrToConnMap[srcaddr.String()] = clientConn
|
||||
p.localIdToConnMap[uuid] = clientConn
|
||||
fmt.Printf("client accept new local %s %s\n", uuid, srcaddr.String())
|
||||
if n <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
clientConn.activeTime = now
|
||||
sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, p.targetAddr, clientConn.id, (uint32)(DATA), bytes[:n],
|
||||
p.sproto, p.rproto, p.catch, p.key)
|
||||
now := common.GetNowUpdateInSecond()
|
||||
clientConn := p.getClientConnByAddr(srcaddr.String())
|
||||
if clientConn == nil {
|
||||
if p.maxconn > 0 && p.localIdToConnMapSize >= p.maxconn {
|
||||
loggo.Info("too many connections %d, client accept new local udp fail %s", p.localIdToConnMapSize, srcaddr.String())
|
||||
continue
|
||||
}
|
||||
uuid := common.UniqueId()
|
||||
clientConn = &ClientConn{exit: false, ipaddr: srcaddr, id: uuid, activeRecvTime: now, activeSendTime: now, close: false}
|
||||
p.addClientConn(uuid, srcaddr.String(), clientConn)
|
||||
loggo.Info("client accept new local udp %s %s", uuid, srcaddr.String())
|
||||
}
|
||||
|
||||
clientConn.activeSendTime = now
|
||||
sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, p.targetAddr, clientConn.id, (uint32)(MyMsg_DATA), bytes[:n],
|
||||
SEND_PROTO, RECV_PROTO, p.key,
|
||||
p.tcpmode, 0, 0, 0, 0, 0,
|
||||
p.timeout)
|
||||
|
||||
p.sequence++
|
||||
|
||||
p.sendPacket++
|
||||
p.sendPacketSize += (uint64)(n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Client) processPacket(packet *Packet) {
|
||||
|
||||
if packet.rproto >= 0 {
|
||||
if packet.my.Rproto >= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if packet.key != p.key {
|
||||
if packet.my.Key != (int32)(p.key) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -206,95 +575,256 @@ func (p *Client) processPacket(packet *Packet) {
|
|||
return
|
||||
}
|
||||
|
||||
if packet.msgType == PING {
|
||||
if packet.my.Type == (int32)(MyMsg_PING) {
|
||||
t := time.Time{}
|
||||
t.UnmarshalBinary(packet.data)
|
||||
d := time.Now().Sub(t)
|
||||
fmt.Printf("pong from %s %s\n", packet.src.String(), d.String())
|
||||
t.UnmarshalBinary(packet.my.Data)
|
||||
now := time.Now()
|
||||
d := now.Sub(t)
|
||||
loggo.Info("pong from %s %s", packet.src.String(), d.String())
|
||||
p.rtt = d
|
||||
p.pongTime = now
|
||||
return
|
||||
}
|
||||
|
||||
//fmt.Printf("processPacket %s %s %d\n", packet.id, packet.src.String(), len(packet.data))
|
||||
if packet.my.Type == (int32)(MyMsg_KICK) {
|
||||
clientConn := p.getClientConnById(packet.my.Id)
|
||||
if clientConn != nil {
|
||||
p.close(clientConn)
|
||||
loggo.Info("remote kick local %s", packet.my.Id)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
clientConn := p.localIdToConnMap[packet.id]
|
||||
loggo.Debug("processPacket %s %s %d", packet.my.Id, packet.src.String(), len(packet.my.Data))
|
||||
|
||||
clientConn := p.getClientConnById(packet.my.Id)
|
||||
if clientConn == nil {
|
||||
//fmt.Printf("processPacket no conn %s \n", packet.id)
|
||||
loggo.Debug("processPacket no conn %s ", packet.my.Id)
|
||||
p.remoteError(packet.my.Id)
|
||||
return
|
||||
}
|
||||
|
||||
addr := clientConn.ipaddr
|
||||
now := common.GetNowUpdateInSecond()
|
||||
clientConn.activeRecvTime = now
|
||||
|
||||
now := time.Now()
|
||||
clientConn.activeTime = now
|
||||
if p.tcpmode > 0 {
|
||||
f := &frame.Frame{}
|
||||
err := proto.Unmarshal(packet.my.Data, f)
|
||||
if err != nil {
|
||||
loggo.Error("Unmarshal tcp Error %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
if packet.msgType == CATCH {
|
||||
p.recvCatchPacket++
|
||||
}
|
||||
|
||||
_, err := p.listenConn.WriteToUDP(packet.data, addr)
|
||||
if err != nil {
|
||||
fmt.Printf("WriteToUDP Error read udp %s\n", err)
|
||||
clientConn.close = true
|
||||
return
|
||||
clientConn.fm.OnRecvFrame(f)
|
||||
} else {
|
||||
if packet.my.Data == nil {
|
||||
return
|
||||
}
|
||||
addr := clientConn.ipaddr
|
||||
_, err := p.listenConn.WriteToUDP(packet.my.Data, addr)
|
||||
if err != nil {
|
||||
loggo.Info("WriteToUDP Error read udp %s", err)
|
||||
clientConn.close = true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
p.recvPacket++
|
||||
p.recvPacketSize += (uint64)(len(packet.data))
|
||||
p.recvPacketSize += (uint64)(len(packet.my.Data))
|
||||
}
|
||||
|
||||
func (p *Client) Close(clientConn *ClientConn) {
|
||||
if p.localIdToConnMap[clientConn.id] != nil {
|
||||
delete(p.localIdToConnMap, clientConn.id)
|
||||
delete(p.localAddrToConnMap, clientConn.ipaddr.String())
|
||||
}
|
||||
func (p *Client) close(clientConn *ClientConn) {
|
||||
clientConn.exit = true
|
||||
p.deleteClientConn(clientConn.id, clientConn.ipaddr.String())
|
||||
p.deleteClientConn(clientConn.id, clientConn.tcpaddr.String())
|
||||
}
|
||||
|
||||
func (p *Client) checkTimeoutConn() {
|
||||
now := time.Now()
|
||||
for _, conn := range p.localIdToConnMap {
|
||||
diff := now.Sub(conn.activeTime)
|
||||
if diff > time.Second*(time.Duration(p.timeout)) {
|
||||
|
||||
if p.tcpmode > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
tmp := make(map[string]*ClientConn)
|
||||
p.localIdToConnMap.Range(func(key, value interface{}) bool {
|
||||
id := key.(string)
|
||||
clientConn := value.(*ClientConn)
|
||||
tmp[id] = clientConn
|
||||
return true
|
||||
})
|
||||
|
||||
now := common.GetNowUpdateInSecond()
|
||||
for _, conn := range tmp {
|
||||
diffrecv := now.Sub(conn.activeRecvTime)
|
||||
diffsend := now.Sub(conn.activeSendTime)
|
||||
if diffrecv > time.Second*(time.Duration(p.timeout)) || diffsend > time.Second*(time.Duration(p.timeout)) {
|
||||
conn.close = true
|
||||
}
|
||||
}
|
||||
|
||||
for id, conn := range p.localIdToConnMap {
|
||||
for id, conn := range tmp {
|
||||
if conn.close {
|
||||
fmt.Printf("close inactive conn %s %s\n", id, conn.ipaddr.String())
|
||||
p.Close(conn)
|
||||
loggo.Info("close inactive conn %s %s", id, conn.ipaddr.String())
|
||||
p.close(conn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Client) ping() {
|
||||
if p.sendPacket == 0 {
|
||||
now := time.Now()
|
||||
b, _ := now.MarshalBinary()
|
||||
sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, p.targetAddr, "", (uint32)(PING), b,
|
||||
p.sproto, p.rproto, p.catch, p.key)
|
||||
fmt.Printf("ping %s %s %d %d %d %d\n", p.addrServer, now.String(), p.sproto, p.rproto, p.id, p.sequence)
|
||||
p.sequence++
|
||||
now := time.Now()
|
||||
b, _ := now.MarshalBinary()
|
||||
sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, "", "", (uint32)(MyMsg_PING), b,
|
||||
SEND_PROTO, RECV_PROTO, p.key,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0)
|
||||
loggo.Info("ping %s %s %d %d %d %d", p.addrServer, now.String(), p.sproto, p.rproto, p.id, p.sequence)
|
||||
p.sequence++
|
||||
if now.Sub(p.pongTime) > time.Second*3 {
|
||||
p.rtt = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Client) showNet() {
|
||||
fmt.Printf("send %dPacket/s %dKB/s recv %dPacket/s %dKB/s sendCatch %d/s recvCatch %d/s\n",
|
||||
p.sendPacket, p.sendPacketSize/1024, p.recvPacket, p.recvPacketSize/1024, p.sendCatchPacket, p.recvCatchPacket)
|
||||
p.localAddrToConnMapSize = 0
|
||||
p.localIdToConnMap.Range(func(key, value interface{}) bool {
|
||||
p.localAddrToConnMapSize++
|
||||
return true
|
||||
})
|
||||
p.localIdToConnMapSize = 0
|
||||
p.localIdToConnMap.Range(func(key, value interface{}) bool {
|
||||
p.localIdToConnMapSize++
|
||||
return true
|
||||
})
|
||||
loggo.Info("send %dPacket/s %dKB/s recv %dPacket/s %dKB/s %d/%dConnections",
|
||||
p.sendPacket, p.sendPacketSize/1024, p.recvPacket, p.recvPacketSize/1024, p.localAddrToConnMapSize, p.localIdToConnMapSize)
|
||||
p.sendPacket = 0
|
||||
p.recvPacket = 0
|
||||
p.sendPacketSize = 0
|
||||
p.recvPacketSize = 0
|
||||
p.sendCatchPacket = 0
|
||||
p.recvCatchPacket = 0
|
||||
}
|
||||
|
||||
func (p *Client) sendCatch() {
|
||||
if p.catch > 0 {
|
||||
for _, conn := range p.localIdToConnMap {
|
||||
sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, p.targetAddr, conn.id, (uint32)(CATCH), make([]byte, 0),
|
||||
p.sproto, p.rproto, p.catch, p.key)
|
||||
p.sequence++
|
||||
p.sendCatchPacket++
|
||||
func (p *Client) AcceptSock5Conn(conn *net.TCPConn) {
|
||||
|
||||
defer common.CrashLog()
|
||||
|
||||
p.workResultLock.Add(1)
|
||||
defer p.workResultLock.Done()
|
||||
|
||||
var err error = nil
|
||||
if err = network.Sock5HandshakeBy(conn, "", ""); err != nil {
|
||||
loggo.Error("socks handshake: %s", err)
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
_, addr, err := network.Sock5GetRequest(conn)
|
||||
if err != nil {
|
||||
loggo.Error("error getting request: %s", err)
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
// Sending connection established message immediately to client.
|
||||
// This some round trip time for creating socks connection with the client.
|
||||
// But if connection failed, the client will get connection reset error.
|
||||
_, err = conn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x43})
|
||||
if err != nil {
|
||||
loggo.Error("send connection confirmation: %s", err)
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
|
||||
loggo.Info("accept new sock5 conn: %s", addr)
|
||||
|
||||
if p.sock5_filter == nil {
|
||||
p.AcceptTcpConn(conn, addr)
|
||||
} else {
|
||||
if (*p.sock5_filter)(addr) {
|
||||
p.AcceptTcpConn(conn, addr)
|
||||
return
|
||||
}
|
||||
p.AcceptDirectTcpConn(conn, addr)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Client) addClientConn(uuid string, addr string, clientConn *ClientConn) {
|
||||
|
||||
p.localAddrToConnMap.Store(addr, clientConn)
|
||||
p.localIdToConnMap.Store(uuid, clientConn)
|
||||
}
|
||||
|
||||
func (p *Client) getClientConnByAddr(addr string) *ClientConn {
|
||||
ret, ok := p.localAddrToConnMap.Load(addr)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return ret.(*ClientConn)
|
||||
}
|
||||
|
||||
func (p *Client) getClientConnById(uuid string) *ClientConn {
|
||||
ret, ok := p.localIdToConnMap.Load(uuid)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return ret.(*ClientConn)
|
||||
}
|
||||
|
||||
func (p *Client) deleteClientConn(uuid string, addr string) {
|
||||
p.localIdToConnMap.Delete(uuid)
|
||||
p.localAddrToConnMap.Delete(addr)
|
||||
}
|
||||
|
||||
func (p *Client) remoteError(uuid string) {
|
||||
sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, "", uuid, (uint32)(MyMsg_KICK), []byte{},
|
||||
SEND_PROTO, RECV_PROTO, p.key,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0)
|
||||
}
|
||||
|
||||
func (p *Client) AcceptDirectTcpConn(conn *net.TCPConn, targetAddr string) {
|
||||
|
||||
defer common.CrashLog()
|
||||
|
||||
p.workResultLock.Add(1)
|
||||
defer p.workResultLock.Done()
|
||||
|
||||
tcpsrcaddr := conn.RemoteAddr().(*net.TCPAddr)
|
||||
|
||||
loggo.Info("client accept new direct local tcp %s %s", tcpsrcaddr.String(), targetAddr)
|
||||
|
||||
tcpaddrTarget, err := net.ResolveTCPAddr("tcp", targetAddr)
|
||||
if err != nil {
|
||||
loggo.Info("direct local tcp ResolveTCPAddr fail: %s %s", targetAddr, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
targetconn, err := net.DialTCP("tcp", nil, tcpaddrTarget)
|
||||
if err != nil {
|
||||
loggo.Info("direct local tcp DialTCP fail: %s %s", targetAddr, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
go p.transfer(conn, targetconn, conn.RemoteAddr().String(), targetconn.RemoteAddr().String())
|
||||
go p.transfer(targetconn, conn, targetconn.RemoteAddr().String(), conn.RemoteAddr().String())
|
||||
|
||||
loggo.Info("client accept new direct local tcp ok %s %s", tcpsrcaddr.String(), targetAddr)
|
||||
}
|
||||
|
||||
func (p *Client) transfer(destination io.WriteCloser, source io.ReadCloser, dst string, src string) {
|
||||
|
||||
defer common.CrashLog()
|
||||
|
||||
defer destination.Close()
|
||||
defer source.Close()
|
||||
loggo.Info("client begin transfer from %s -> %s", src, dst)
|
||||
io.Copy(destination, source)
|
||||
loggo.Info("client end transfer from %s -> %s", src, dst)
|
||||
}
|
||||
|
||||
func (p *Client) updateServerAddr() {
|
||||
ipaddrServer, err := net.ResolveIPAddr("ip", p.addrServer)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if p.ipaddrServer.String() != ipaddrServer.String() {
|
||||
p.ipaddrServer = ipaddrServer
|
||||
}
|
||||
}
|
||||
|
|
238
cmd/main.go
238
cmd/main.go
|
@ -3,22 +3,66 @@ package main
|
|||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/esrrhs/gohome/common"
|
||||
"github.com/esrrhs/gohome/geoip"
|
||||
"github.com/esrrhs/gohome/loggo"
|
||||
"github.com/esrrhs/pingtunnel"
|
||||
"net"
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
var usage = `
|
||||
通过伪造ping,把udp流量通过远程服务器转发到目的服务器上。用于突破某些运营商封锁UDP流量。
|
||||
By forging ping, the udp traffic is forwarded to the destination server through the remote server. Used to break certain operators to block UDP traffic.
|
||||
通过伪造ping,把tcp/udp/sock5流量通过远程服务器转发到目的服务器上。用于突破某些运营商封锁TCP/UDP流量。
|
||||
By forging ping, the tcp/udp/sock5 traffic is forwarded to the destination server through the remote server. Used to break certain operators to block TCP/UDP traffic.
|
||||
|
||||
Usage:
|
||||
|
||||
// server
|
||||
pingtunnel -type server
|
||||
|
||||
// client, Forward udp
|
||||
pingtunnel -type client -l LOCAL_IP:4455 -s SERVER_IP -t SERVER_IP:4455
|
||||
|
||||
// client, Forward tcp
|
||||
pingtunnel -type client -l LOCAL_IP:4455 -s SERVER_IP -t SERVER_IP:4455 -tcp 1
|
||||
|
||||
// client, Forward sock5, implicitly open tcp, so no target server is needed
|
||||
pingtunnel -type client -l LOCAL_IP:4455 -s SERVER_IP -sock5 1
|
||||
|
||||
-type 服务器或者客户端
|
||||
client or server
|
||||
|
||||
服务器参数server param:
|
||||
|
||||
-key 设置的纯数字密码,默认0, 参数为int类型,范围从0-2147483647,不可夹杂字母特殊符号
|
||||
Set password, default 0
|
||||
|
||||
-nolog 不写日志文件,只打印标准输出,默认0
|
||||
Do not write log files, only print standard output, default 0 is off
|
||||
|
||||
-noprint 不打印屏幕输出,默认0
|
||||
Do not print standard output, default 0 is off
|
||||
|
||||
-loglevel 日志文件等级,默认info
|
||||
log level, default is info
|
||||
|
||||
-maxconn 最大连接数,默认0,不受限制
|
||||
the max num of connections, default 0 is no limit
|
||||
|
||||
-maxprt server最大处理线程数,默认100
|
||||
max process thread in server, default 100
|
||||
|
||||
-maxprb server最大处理线程buffer数,默认1000
|
||||
max process thread's buffer in server, default 1000
|
||||
|
||||
-conntt server发起连接到目标地址的超时时间,默认1000ms
|
||||
The timeout period for the server to initiate a connection to the destination address. The default is 1000ms.
|
||||
|
||||
客户端参数client param:
|
||||
|
||||
-l 本地的地址,发到这个端口的流量将转发到服务器
|
||||
Local address, traffic sent to this port will be forwarded to the server
|
||||
|
||||
|
@ -31,67 +75,195 @@ Usage:
|
|||
-timeout 本地记录连接超时的时间,单位是秒,默认60s
|
||||
The time when the local record connection timed out, in seconds, 60 seconds by default
|
||||
|
||||
-sproto 客户端发送ping协议的协议,默认是8
|
||||
The protocol that the client sends the ping. The default is 8.
|
||||
|
||||
-rproto 客户端接收ping协议的协议,默认是0
|
||||
The protocol that the client receives the ping. The default is 0.
|
||||
|
||||
-catch 主动抓模式,每秒从服务器主动抓多少个reply包,默认0
|
||||
Active capture mode, how many reply packets are actively captured from the server per second, default 0
|
||||
|
||||
-key 设置的密码,默认0
|
||||
Set password, default 0
|
||||
|
||||
-tcp 设置是否转发tcp,默认0
|
||||
Set the switch to forward tcp, the default is 0
|
||||
|
||||
-tcp_bs tcp的发送接收缓冲区大小,默认1MB
|
||||
Tcp send and receive buffer size, default 1MB
|
||||
|
||||
-tcp_mw tcp的最大窗口,默认20000
|
||||
The maximum window of tcp, the default is 20000
|
||||
|
||||
-tcp_rst tcp的超时发送时间,默认400ms
|
||||
Tcp timeout resend time, default 400ms
|
||||
|
||||
-tcp_gz 当数据包超过这个大小,tcp将压缩数据,0表示不压缩,默认0
|
||||
Tcp will compress data when the packet exceeds this size, 0 means no compression, default 0
|
||||
|
||||
-tcp_stat 打印tcp的监控,默认0
|
||||
Print tcp connection statistic, default 0 is off
|
||||
|
||||
-nolog 不写日志文件,只打印标准输出,默认0
|
||||
Do not write log files, only print standard output, default 0 is off
|
||||
|
||||
-noprint 不打印屏幕输出,默认0
|
||||
Do not print standard output, default 0 is off
|
||||
|
||||
-loglevel 日志文件等级,默认info
|
||||
log level, default is info
|
||||
|
||||
-sock5 开启sock5转发,默认0
|
||||
Turn on sock5 forwarding, default 0 is off
|
||||
|
||||
-profile 在指定端口开启性能检测,默认0不开启
|
||||
Enable performance detection on the specified port. The default 0 is not enabled.
|
||||
|
||||
-s5filter sock5模式设置转发过滤,默认全转发,设置CN代表CN地区的直连不转发
|
||||
Set the forwarding filter in the sock5 mode. The default is full forwarding. For example, setting the CN indicates that the Chinese address is not forwarded.
|
||||
|
||||
-s5ftfile sock5模式转发过滤的数据文件,默认读取当前目录的GeoLite2-Country.mmdb
|
||||
The data file in sock5 filter mode, the default reading of the current directory GeoLite2-Country.mmdb
|
||||
`
|
||||
|
||||
func main() {
|
||||
|
||||
defer common.CrashLog()
|
||||
|
||||
t := flag.String("type", "", "client or server")
|
||||
listen := flag.String("l", "", "listen addr")
|
||||
target := flag.String("t", "", "target addr")
|
||||
server := flag.String("s", "", "server addr")
|
||||
timeout := flag.Int("timeout", 60, "conn timeout")
|
||||
sproto := flag.Int("sproto", 8, "send ping proto")
|
||||
rproto := flag.Int("rproto", 0, "recv ping proto")
|
||||
catch := flag.Int("catch", 0, "catch mode")
|
||||
key := flag.Int("key", 0, "key")
|
||||
tcpmode := flag.Int("tcp", 0, "tcp mode")
|
||||
tcpmode_buffersize := flag.Int("tcp_bs", 1*1024*1024, "tcp mode buffer size")
|
||||
tcpmode_maxwin := flag.Int("tcp_mw", 20000, "tcp mode max win")
|
||||
tcpmode_resend_timems := flag.Int("tcp_rst", 400, "tcp mode resend time ms")
|
||||
tcpmode_compress := flag.Int("tcp_gz", 0, "tcp data compress")
|
||||
nolog := flag.Int("nolog", 0, "write log file")
|
||||
noprint := flag.Int("noprint", 0, "print stdout")
|
||||
tcpmode_stat := flag.Int("tcp_stat", 0, "print tcp stat")
|
||||
loglevel := flag.String("loglevel", "info", "log level")
|
||||
open_sock5 := flag.Int("sock5", 0, "sock5 mode")
|
||||
maxconn := flag.Int("maxconn", 0, "max num of connections")
|
||||
max_process_thread := flag.Int("maxprt", 100, "max process thread in server")
|
||||
max_process_buffer := flag.Int("maxprb", 1000, "max process thread's buffer in server")
|
||||
profile := flag.Int("profile", 0, "open profile")
|
||||
conntt := flag.Int("conntt", 1000, "the connect call's timeout")
|
||||
s5filter := flag.String("s5filter", "", "sock5 filter")
|
||||
s5ftfile := flag.String("s5ftfile", "GeoLite2-Country.mmdb", "sock5 filter file")
|
||||
flag.Usage = func() {
|
||||
fmt.Printf(usage)
|
||||
}
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if (*t != "client" && *t != "server") || (*t == "client" && (len(*listen) == 0 || len(*target) == 0 || len(*server) == 0)) {
|
||||
if *t != "client" && *t != "server" {
|
||||
flag.Usage()
|
||||
return
|
||||
}
|
||||
if *t == "client" {
|
||||
if len(*listen) == 0 || len(*server) == 0 {
|
||||
flag.Usage()
|
||||
return
|
||||
}
|
||||
if *open_sock5 == 0 && len(*target) == 0 {
|
||||
flag.Usage()
|
||||
return
|
||||
}
|
||||
if *open_sock5 != 0 {
|
||||
*tcpmode = 1
|
||||
}
|
||||
}
|
||||
if *tcpmode_maxwin*10 > pingtunnel.FRAME_MAX_ID {
|
||||
fmt.Println("set tcp win to big, max = " + strconv.Itoa(pingtunnel.FRAME_MAX_ID/10))
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("start...")
|
||||
fmt.Printf("key %d\n", *key)
|
||||
level := loggo.LEVEL_INFO
|
||||
if loggo.NameToLevel(*loglevel) >= 0 {
|
||||
level = loggo.NameToLevel(*loglevel)
|
||||
}
|
||||
loggo.Ini(loggo.Config{
|
||||
Level: level,
|
||||
Prefix: "pingtunnel",
|
||||
MaxDay: 3,
|
||||
NoLogFile: *nolog > 0,
|
||||
NoPrint: *noprint > 0,
|
||||
})
|
||||
loggo.Info("start...")
|
||||
loggo.Info("key %d", *key)
|
||||
|
||||
if *t == "server" {
|
||||
s, err := pingtunnel.NewServer(*timeout, *key)
|
||||
s, err := pingtunnel.NewServer(*key, *maxconn, *max_process_thread, *max_process_buffer, *conntt)
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err.Error())
|
||||
loggo.Error("ERROR: %s", err.Error())
|
||||
return
|
||||
}
|
||||
fmt.Printf("Server start\n")
|
||||
s.Run()
|
||||
}
|
||||
if *t == "client" {
|
||||
|
||||
fmt.Printf("type %s\n", *t)
|
||||
fmt.Printf("listen %s\n", *listen)
|
||||
fmt.Printf("server %s\n", *server)
|
||||
fmt.Printf("target %s\n", *target)
|
||||
|
||||
c, err := pingtunnel.NewClient(*listen, *server, *target, *timeout, *sproto, *rproto, *catch, *key)
|
||||
loggo.Info("Server start")
|
||||
err = s.Run()
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: %s\n", err.Error())
|
||||
loggo.Error("Run ERROR: %s", err.Error())
|
||||
return
|
||||
}
|
||||
fmt.Printf("Client Listen %s (%s) Server %s (%s) TargetPort %s:\n", c.Addr(), c.IPAddr(),
|
||||
} else if *t == "client" {
|
||||
|
||||
loggo.Info("type %s", *t)
|
||||
loggo.Info("listen %s", *listen)
|
||||
loggo.Info("server %s", *server)
|
||||
loggo.Info("target %s", *target)
|
||||
|
||||
if *tcpmode == 0 {
|
||||
*tcpmode_buffersize = 0
|
||||
*tcpmode_maxwin = 0
|
||||
*tcpmode_resend_timems = 0
|
||||
*tcpmode_compress = 0
|
||||
*tcpmode_stat = 0
|
||||
}
|
||||
|
||||
if len(*s5filter) > 0 {
|
||||
err := geoip.Load(*s5ftfile)
|
||||
if err != nil {
|
||||
loggo.Error("Load Sock5 ip file ERROR: %s", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
filter := func(addr string) bool {
|
||||
if len(*s5filter) <= 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
taddr, err := net.ResolveTCPAddr("tcp", addr)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
ret, err := geoip.GetCountryIsoCode(taddr.IP.String())
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if len(ret) <= 0 {
|
||||
return false
|
||||
}
|
||||
return ret != *s5filter
|
||||
}
|
||||
|
||||
c, err := pingtunnel.NewClient(*listen, *server, *target, *timeout, *key,
|
||||
*tcpmode, *tcpmode_buffersize, *tcpmode_maxwin, *tcpmode_resend_timems, *tcpmode_compress,
|
||||
*tcpmode_stat, *open_sock5, *maxconn, &filter)
|
||||
if err != nil {
|
||||
loggo.Error("ERROR: %s", err.Error())
|
||||
return
|
||||
}
|
||||
loggo.Info("Client Listen %s (%s) Server %s (%s) TargetPort %s:", c.Addr(), c.IPAddr(),
|
||||
c.ServerAddr(), c.ServerIPAddr(), c.TargetAddr())
|
||||
c.Run()
|
||||
err = c.Run()
|
||||
if err != nil {
|
||||
loggo.Error("Run ERROR: %s", err.Error())
|
||||
return
|
||||
}
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
if *profile > 0 {
|
||||
go http.ListenAndServe("0.0.0.0:"+strconv.Itoa(*profile), nil)
|
||||
}
|
||||
|
||||
for {
|
||||
time.Sleep(time.Hour)
|
||||
}
|
||||
}
|
||||
|
|
2
docker-compose/.env
Normal file
2
docker-compose/.env
Normal file
|
@ -0,0 +1,2 @@
|
|||
KEY=123456
|
||||
SERVER=www.yourserver.com
|
16
docker-compose/Readme.md
Normal file
16
docker-compose/Readme.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
Deploy with docker-compose
|
||||
===========================
|
||||
**First** edit `.env` file in this directory to your appropriate value.
|
||||
|
||||
**Then** run stack with these commands:
|
||||
|
||||
- in the server
|
||||
```
|
||||
docker-compose -f server.yml up -d
|
||||
```
|
||||
- in client machine
|
||||
```
|
||||
docker-compose -f client.yml up -d
|
||||
```
|
||||
|
||||
**Now** use socks5 proxy at port `1080` of your client machine
|
9
docker-compose/client.yml
Normal file
9
docker-compose/client.yml
Normal file
|
@ -0,0 +1,9 @@
|
|||
version: "3.7"
|
||||
|
||||
services:
|
||||
pingtunnelServer:
|
||||
image: esrrhs/pingtunnel:latest
|
||||
restart: always
|
||||
ports:
|
||||
- 1080:1080
|
||||
command: "./pingtunnel -type client -l 0.0.0.0:1080 -s ${SERVER} -sock5 1 -key ${KEY}"
|
8
docker-compose/server.yml
Normal file
8
docker-compose/server.yml
Normal file
|
@ -0,0 +1,8 @@
|
|||
version: "3.7"
|
||||
|
||||
services:
|
||||
pingtunnelServer:
|
||||
image: esrrhs/pingtunnel:latest
|
||||
restart: always
|
||||
network_mode: host
|
||||
command: "./pingtunnel -type server -key ${KEY}"
|
1
gen.bat
Normal file
1
gen.bat
Normal file
|
@ -0,0 +1 @@
|
|||
protoc --go_out=. *.proto
|
18
go.mod
Normal file
18
go.mod
Normal file
|
@ -0,0 +1,18 @@
|
|||
module github.com/esrrhs/pingtunnel
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/esrrhs/gohome v0.0.0-20231102120537-c519efbde976
|
||||
github.com/golang/protobuf v1.5.3
|
||||
golang.org/x/net v0.17.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/OneOfOne/xxhash v1.2.8 // indirect
|
||||
github.com/google/uuid v1.4.0 // indirect
|
||||
github.com/oschwald/geoip2-golang v1.9.0 // indirect
|
||||
github.com/oschwald/maxminddb-golang v1.12.0 // indirect
|
||||
golang.org/x/sys v0.13.0 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
)
|
29
go.sum
Normal file
29
go.sum
Normal file
|
@ -0,0 +1,29 @@
|
|||
github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=
|
||||
github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/esrrhs/gohome v0.0.0-20231102120537-c519efbde976 h1:av0d/lRou1Z5cxdSQFwtVcqJjokFI5pJyyr63iAuYis=
|
||||
github.com/esrrhs/gohome v0.0.0-20231102120537-c519efbde976/go.mod h1:S5fYcOFy4nUPnkYg7D9hIp+SwBR9kCBiOYmWVW42Yhs=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
|
||||
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/oschwald/geoip2-golang v1.9.0 h1:uvD3O6fXAXs+usU+UGExshpdP13GAqp4GBrzN7IgKZc=
|
||||
github.com/oschwald/geoip2-golang v1.9.0/go.mod h1:BHK6TvDyATVQhKNbQBdrj9eAvuwOMi2zSFXizL3K81Y=
|
||||
github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs=
|
||||
github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
228
msg.pb.go
Normal file
228
msg.pb.go
Normal file
|
@ -0,0 +1,228 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: msg.proto
|
||||
|
||||
package pingtunnel
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type MyMsg_TYPE int32
|
||||
|
||||
const (
|
||||
MyMsg_DATA MyMsg_TYPE = 0
|
||||
MyMsg_PING MyMsg_TYPE = 1
|
||||
MyMsg_KICK MyMsg_TYPE = 2
|
||||
MyMsg_MAGIC MyMsg_TYPE = 57005
|
||||
)
|
||||
|
||||
var MyMsg_TYPE_name = map[int32]string{
|
||||
0: "DATA",
|
||||
1: "PING",
|
||||
2: "KICK",
|
||||
57005: "MAGIC",
|
||||
}
|
||||
|
||||
var MyMsg_TYPE_value = map[string]int32{
|
||||
"DATA": 0,
|
||||
"PING": 1,
|
||||
"KICK": 2,
|
||||
"MAGIC": 57005,
|
||||
}
|
||||
|
||||
func (x MyMsg_TYPE) String() string {
|
||||
return proto.EnumName(MyMsg_TYPE_name, int32(x))
|
||||
}
|
||||
|
||||
func (MyMsg_TYPE) EnumDescriptor() ([]byte, []int) {
|
||||
return fileDescriptor_c06e4cca6c2cc899, []int{0, 0}
|
||||
}
|
||||
|
||||
type MyMsg struct {
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Type int32 `protobuf:"varint,2,opt,name=type,proto3" json:"type,omitempty"`
|
||||
Target string `protobuf:"bytes,3,opt,name=target,proto3" json:"target,omitempty"`
|
||||
Data []byte `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"`
|
||||
Rproto int32 `protobuf:"zigzag32,5,opt,name=rproto,proto3" json:"rproto,omitempty"`
|
||||
Magic int32 `protobuf:"zigzag32,6,opt,name=magic,proto3" json:"magic,omitempty"`
|
||||
Key int32 `protobuf:"zigzag32,7,opt,name=key,proto3" json:"key,omitempty"`
|
||||
Timeout int32 `protobuf:"varint,8,opt,name=timeout,proto3" json:"timeout,omitempty"`
|
||||
Tcpmode int32 `protobuf:"varint,9,opt,name=tcpmode,proto3" json:"tcpmode,omitempty"`
|
||||
TcpmodeBuffersize int32 `protobuf:"varint,10,opt,name=tcpmode_buffersize,json=tcpmodeBuffersize,proto3" json:"tcpmode_buffersize,omitempty"`
|
||||
TcpmodeMaxwin int32 `protobuf:"varint,11,opt,name=tcpmode_maxwin,json=tcpmodeMaxwin,proto3" json:"tcpmode_maxwin,omitempty"`
|
||||
TcpmodeResendTimems int32 `protobuf:"varint,12,opt,name=tcpmode_resend_timems,json=tcpmodeResendTimems,proto3" json:"tcpmode_resend_timems,omitempty"`
|
||||
TcpmodeCompress int32 `protobuf:"varint,13,opt,name=tcpmode_compress,json=tcpmodeCompress,proto3" json:"tcpmode_compress,omitempty"`
|
||||
TcpmodeStat int32 `protobuf:"varint,14,opt,name=tcpmode_stat,json=tcpmodeStat,proto3" json:"tcpmode_stat,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *MyMsg) Reset() { *m = MyMsg{} }
|
||||
func (m *MyMsg) String() string { return proto.CompactTextString(m) }
|
||||
func (*MyMsg) ProtoMessage() {}
|
||||
func (*MyMsg) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_c06e4cca6c2cc899, []int{0}
|
||||
}
|
||||
|
||||
func (m *MyMsg) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_MyMsg.Unmarshal(m, b)
|
||||
}
|
||||
func (m *MyMsg) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_MyMsg.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *MyMsg) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_MyMsg.Merge(m, src)
|
||||
}
|
||||
func (m *MyMsg) XXX_Size() int {
|
||||
return xxx_messageInfo_MyMsg.Size(m)
|
||||
}
|
||||
func (m *MyMsg) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_MyMsg.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_MyMsg proto.InternalMessageInfo
|
||||
|
||||
func (m *MyMsg) GetId() string {
|
||||
if m != nil {
|
||||
return m.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *MyMsg) GetType() int32 {
|
||||
if m != nil {
|
||||
return m.Type
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *MyMsg) GetTarget() string {
|
||||
if m != nil {
|
||||
return m.Target
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *MyMsg) GetData() []byte {
|
||||
if m != nil {
|
||||
return m.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MyMsg) GetRproto() int32 {
|
||||
if m != nil {
|
||||
return m.Rproto
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *MyMsg) GetMagic() int32 {
|
||||
if m != nil {
|
||||
return m.Magic
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *MyMsg) GetKey() int32 {
|
||||
if m != nil {
|
||||
return m.Key
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *MyMsg) GetTimeout() int32 {
|
||||
if m != nil {
|
||||
return m.Timeout
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *MyMsg) GetTcpmode() int32 {
|
||||
if m != nil {
|
||||
return m.Tcpmode
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *MyMsg) GetTcpmodeBuffersize() int32 {
|
||||
if m != nil {
|
||||
return m.TcpmodeBuffersize
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *MyMsg) GetTcpmodeMaxwin() int32 {
|
||||
if m != nil {
|
||||
return m.TcpmodeMaxwin
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *MyMsg) GetTcpmodeResendTimems() int32 {
|
||||
if m != nil {
|
||||
return m.TcpmodeResendTimems
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *MyMsg) GetTcpmodeCompress() int32 {
|
||||
if m != nil {
|
||||
return m.TcpmodeCompress
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *MyMsg) GetTcpmodeStat() int32 {
|
||||
if m != nil {
|
||||
return m.TcpmodeStat
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterEnum("MyMsg_TYPE", MyMsg_TYPE_name, MyMsg_TYPE_value)
|
||||
proto.RegisterType((*MyMsg)(nil), "MyMsg")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("msg.proto", fileDescriptor_c06e4cca6c2cc899) }
|
||||
|
||||
var fileDescriptor_c06e4cca6c2cc899 = []byte{
|
||||
// 342 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x3c, 0x90, 0xdb, 0x6a, 0xe2, 0x50,
|
||||
0x14, 0x86, 0x27, 0x27, 0x0f, 0xcb, 0xe8, 0xc4, 0x35, 0x07, 0xd6, 0x65, 0x46, 0x18, 0xc8, 0x5c,
|
||||
0xcc, 0xc0, 0xb4, 0x4f, 0xa0, 0xb6, 0x88, 0x48, 0x8a, 0xa4, 0xde, 0xb4, 0x37, 0x12, 0xcd, 0x36,
|
||||
0x84, 0x36, 0x07, 0xb2, 0xb7, 0xb4, 0xf6, 0x9d, 0xfa, 0x08, 0x7d, 0x8d, 0x3e, 0x4f, 0xc9, 0x72,
|
||||
0xa7, 0x77, 0xff, 0xff, 0x7f, 0x5f, 0xc8, 0x62, 0x43, 0x3f, 0x97, 0xe9, 0xbf, 0xaa, 0x2e, 0x55,
|
||||
0x39, 0x79, 0xb7, 0xc0, 0x09, 0x4f, 0xa1, 0x4c, 0x71, 0x04, 0x66, 0x96, 0x90, 0xe1, 0x1b, 0x41,
|
||||
0x3f, 0x32, 0xb3, 0x04, 0x11, 0x6c, 0x75, 0xaa, 0x04, 0x99, 0xbe, 0x11, 0x38, 0x11, 0x67, 0xfc,
|
||||
0x09, 0x1d, 0x15, 0xd7, 0xa9, 0x50, 0x64, 0xb1, 0xa7, 0x5b, 0xe3, 0x26, 0xb1, 0x8a, 0xc9, 0xf6,
|
||||
0x8d, 0xc0, 0x8d, 0x38, 0x37, 0x6e, 0xcd, 0xff, 0x20, 0xc7, 0x37, 0x82, 0x71, 0xa4, 0x1b, 0x7e,
|
||||
0x07, 0x27, 0x8f, 0xd3, 0x6c, 0x4f, 0x1d, 0x9e, 0xcf, 0x05, 0x3d, 0xb0, 0x1e, 0xc4, 0x89, 0xba,
|
||||
0xbc, 0x35, 0x11, 0x09, 0xba, 0x2a, 0xcb, 0x45, 0x79, 0x54, 0xd4, 0xe3, 0x13, 0xda, 0xca, 0x64,
|
||||
0x5f, 0xe5, 0x65, 0x22, 0xa8, 0xaf, 0xc9, 0xb9, 0xe2, 0x5f, 0x40, 0x1d, 0xb7, 0xbb, 0xe3, 0xe1,
|
||||
0x20, 0x6a, 0x99, 0xbd, 0x08, 0x02, 0x96, 0xc6, 0x9a, 0xcc, 0x3e, 0x01, 0xfe, 0x86, 0x51, 0xab,
|
||||
0xe7, 0xf1, 0xf3, 0x53, 0x56, 0xd0, 0x80, 0xd5, 0xa1, 0x5e, 0x43, 0x1e, 0xf1, 0x02, 0x7e, 0xb4,
|
||||
0x5a, 0x2d, 0xa4, 0x28, 0x92, 0x6d, 0x73, 0x49, 0x2e, 0xc9, 0x65, 0xfb, 0x9b, 0x86, 0x11, 0xb3,
|
||||
0x0d, 0x23, 0xfc, 0x03, 0x5e, 0xfb, 0xcd, 0xbe, 0xcc, 0xab, 0x5a, 0x48, 0x49, 0x43, 0xd6, 0xbf,
|
||||
0xea, 0x7d, 0xae, 0x67, 0xfc, 0x05, 0x6e, 0xab, 0x4a, 0x15, 0x2b, 0x1a, 0xb1, 0x36, 0xd0, 0xdb,
|
||||
0xad, 0x8a, 0xd5, 0xe4, 0x3f, 0xd8, 0x9b, 0xbb, 0xf5, 0x35, 0xf6, 0xc0, 0xbe, 0x9a, 0x6e, 0xa6,
|
||||
0xde, 0x97, 0x26, 0xad, 0x97, 0x37, 0x0b, 0xcf, 0x68, 0xd2, 0x6a, 0x39, 0x5f, 0x79, 0x26, 0x0e,
|
||||
0xc0, 0x09, 0xa7, 0x8b, 0xe5, 0xdc, 0x7b, 0x7d, 0xb3, 0x66, 0xee, 0x3d, 0x54, 0x59, 0x91, 0xaa,
|
||||
0x63, 0x51, 0x88, 0xc7, 0x5d, 0x87, 0xdf, 0xfe, 0xf2, 0x23, 0x00, 0x00, 0xff, 0xff, 0x59, 0xbc,
|
||||
0x55, 0x76, 0xfa, 0x01, 0x00, 0x00,
|
||||
}
|
26
msg.proto
Normal file
26
msg.proto
Normal file
|
@ -0,0 +1,26 @@
|
|||
syntax = "proto3";
|
||||
option go_package = "pingtunnel";
|
||||
|
||||
message MyMsg {
|
||||
enum TYPE {
|
||||
DATA = 0;
|
||||
PING = 1;
|
||||
KICK = 2;
|
||||
MAGIC = 0xdead;
|
||||
}
|
||||
|
||||
string id = 1;
|
||||
int32 type = 2;
|
||||
string target = 3;
|
||||
bytes data = 4;
|
||||
sint32 rproto = 5;
|
||||
sint32 magic = 6;
|
||||
sint32 key = 7;
|
||||
int32 timeout = 8;
|
||||
int32 tcpmode = 9;
|
||||
int32 tcpmode_buffersize = 10;
|
||||
int32 tcpmode_maxwin = 11;
|
||||
int32 tcpmode_resend_timems = 12;
|
||||
int32 tcpmode_compress = 13;
|
||||
int32 tcpmode_stat = 14;
|
||||
}
|
BIN
network.jpg
Normal file
BIN
network.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
network.png
BIN
network.png
Binary file not shown.
Before Width: | Height: | Size: 17 KiB |
56
pack.sh
Executable file
56
pack.sh
Executable file
|
@ -0,0 +1,56 @@
|
|||
#! /bin/bash
|
||||
#set -x
|
||||
NAME="pingtunnel"
|
||||
|
||||
export GO111MODULE=on
|
||||
|
||||
#go tool dist list
|
||||
build_list=$(go tool dist list)
|
||||
|
||||
rm pack -rf
|
||||
rm pack.zip -f
|
||||
mkdir pack
|
||||
|
||||
go mod tidy
|
||||
|
||||
for line in $build_list; do
|
||||
os=$(echo "$line" | awk -F"/" '{print $1}')
|
||||
arch=$(echo "$line" | awk -F"/" '{print $2}')
|
||||
echo "os="$os" arch="$arch" start build"
|
||||
if [ $os == "android" ]; then
|
||||
continue
|
||||
fi
|
||||
if [ $os == "ios" ]; then
|
||||
continue
|
||||
fi
|
||||
if [ $arch == "wasm" ]; then
|
||||
continue
|
||||
fi
|
||||
CGO_ENABLED=0 GOOS=$os GOARCH=$arch go build -ldflags="-s -w"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "os="$os" arch="$arch" build fail"
|
||||
exit 1
|
||||
fi
|
||||
if [ $os = "windows" ]; then
|
||||
zip ${NAME}_"${os}"_"${arch}"".zip" $NAME".exe"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "os="$os" arch="$arch" zip fail"
|
||||
exit 1
|
||||
fi
|
||||
mv ${NAME}_"${os}"_"${arch}"".zip" pack/
|
||||
rm $NAME".exe" -f
|
||||
else
|
||||
zip ${NAME}_"${os}"_"${arch}"".zip" $NAME
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "os="$os" arch="$arch" zip fail"
|
||||
exit 1
|
||||
fi
|
||||
mv ${NAME}_"${os}"_"${arch}"".zip" pack/
|
||||
rm $NAME -f
|
||||
fi
|
||||
echo "os="$os" arch="$arch" done build"
|
||||
done
|
||||
|
||||
zip pack.zip pack/ -r
|
||||
|
||||
echo "all done"
|
261
pingtunnel.go
261
pingtunnel.go
|
@ -1,155 +1,44 @@
|
|||
package pingtunnel
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/esrrhs/gohome/common"
|
||||
"github.com/esrrhs/gohome/loggo"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"golang.org/x/net/icmp"
|
||||
"golang.org/x/net/ipv4"
|
||||
"io"
|
||||
"net"
|
||||
"syscall"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
DATA uint32 = 0x01010101
|
||||
PING uint32 = 0x02020202
|
||||
CATCH uint32 = 0x03030303
|
||||
END uint32 = 0xAAAABBBB
|
||||
)
|
||||
|
||||
type MyMsg struct {
|
||||
TYPE uint32
|
||||
ID string
|
||||
TARGET string
|
||||
Data []byte
|
||||
RPROTO uint16
|
||||
CATCH uint16
|
||||
KEY uint32
|
||||
ENDTYPE uint32
|
||||
}
|
||||
|
||||
// Len implements the Len method of MessageBody interface.
|
||||
func (p *MyMsg) Len(proto int) int {
|
||||
if p == nil {
|
||||
return 0
|
||||
}
|
||||
return 4 + p.LenString(p.ID) + p.LenString(p.TARGET) + p.LenData(p.Data) + 2 + 2 + 4 + 4
|
||||
}
|
||||
|
||||
func (p *MyMsg) LenString(s string) int {
|
||||
return 2 + len(s)
|
||||
}
|
||||
|
||||
func (p *MyMsg) LenData(data []byte) int {
|
||||
return 2 + len(data)
|
||||
}
|
||||
|
||||
// Marshal implements the Marshal method of MessageBody interface.
|
||||
func (p *MyMsg) Marshal(proto int) ([]byte, error) {
|
||||
|
||||
b := make([]byte, p.Len(proto))
|
||||
|
||||
binary.BigEndian.PutUint32(b[:4], uint32(p.TYPE))
|
||||
|
||||
id := p.MarshalString(p.ID)
|
||||
copy(b[4:], id)
|
||||
|
||||
target := p.MarshalString(p.TARGET)
|
||||
copy(b[4+p.LenString(p.ID):], target)
|
||||
|
||||
data := p.MarshalData(p.Data)
|
||||
copy(b[4+p.LenString(p.ID)+p.LenString(p.TARGET):], data)
|
||||
|
||||
binary.BigEndian.PutUint16(b[4+p.LenString(p.ID)+p.LenString(p.TARGET)+p.LenData(p.Data):], uint16(p.RPROTO))
|
||||
|
||||
binary.BigEndian.PutUint16(b[4+p.LenString(p.ID)+p.LenString(p.TARGET)+p.LenData(p.Data)+2:], uint16(p.CATCH))
|
||||
|
||||
binary.BigEndian.PutUint32(b[4+p.LenString(p.ID)+p.LenString(p.TARGET)+p.LenData(p.Data)+4:], uint32(p.KEY))
|
||||
|
||||
binary.BigEndian.PutUint32(b[4+p.LenString(p.ID)+p.LenString(p.TARGET)+p.LenData(p.Data)+8:], uint32(p.ENDTYPE))
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (p *MyMsg) MarshalString(s string) []byte {
|
||||
b := make([]byte, p.LenString(s))
|
||||
binary.BigEndian.PutUint16(b[:2], uint16(len(s)))
|
||||
copy(b[2:], []byte(s))
|
||||
return b
|
||||
}
|
||||
|
||||
func (p *MyMsg) MarshalData(data []byte) []byte {
|
||||
b := make([]byte, p.LenData(data))
|
||||
binary.BigEndian.PutUint16(b[:2], uint16(len(data)))
|
||||
copy(b[2:], []byte(data))
|
||||
return b
|
||||
}
|
||||
|
||||
// Marshal implements the Marshal method of MessageBody interface.
|
||||
func (p *MyMsg) Unmarshal(b []byte) error {
|
||||
defer func() {
|
||||
recover()
|
||||
}()
|
||||
|
||||
p.TYPE = binary.BigEndian.Uint32(b[:4])
|
||||
|
||||
p.ID = p.UnmarshalString(b[4:])
|
||||
|
||||
p.TARGET = p.UnmarshalString(b[4+p.LenString(p.ID):])
|
||||
|
||||
p.Data = p.UnmarshalData(b[4+p.LenString(p.ID)+p.LenString(p.TARGET):])
|
||||
|
||||
p.RPROTO = binary.BigEndian.Uint16(b[4+p.LenString(p.ID)+p.LenString(p.TARGET)+p.LenData(p.Data):])
|
||||
|
||||
p.CATCH = binary.BigEndian.Uint16(b[4+p.LenString(p.ID)+p.LenString(p.TARGET)+p.LenData(p.Data)+2:])
|
||||
|
||||
p.KEY = binary.BigEndian.Uint32(b[4+p.LenString(p.ID)+p.LenString(p.TARGET)+p.LenData(p.Data)+4:])
|
||||
|
||||
p.ENDTYPE = binary.BigEndian.Uint32(b[4+p.LenString(p.ID)+p.LenString(p.TARGET)+p.LenData(p.Data)+8:])
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *MyMsg) UnmarshalString(b []byte) string {
|
||||
len := binary.BigEndian.Uint16(b[:2])
|
||||
if len > 32 || len < 0 {
|
||||
panic(nil)
|
||||
}
|
||||
data := make([]byte, len)
|
||||
copy(data, b[2:])
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func (p *MyMsg) UnmarshalData(b []byte) []byte {
|
||||
len := binary.BigEndian.Uint16(b[:2])
|
||||
if len > 2048 || len < 0 {
|
||||
panic(nil)
|
||||
}
|
||||
data := make([]byte, len)
|
||||
copy(data, b[2:])
|
||||
return data
|
||||
}
|
||||
|
||||
func sendICMP(id int, sequence int, conn icmp.PacketConn, server *net.IPAddr, target string,
|
||||
connId string, msgType uint32, data []byte, sproto int, rproto int, catch int, key int) {
|
||||
connId string, msgType uint32, data []byte, sproto int, rproto int, key int,
|
||||
tcpmode int, tcpmode_buffer_size int, tcpmode_maxwin int, tcpmode_resend_time int, tcpmode_compress int, tcpmode_stat int,
|
||||
timeout int) {
|
||||
|
||||
m := &MyMsg{
|
||||
ID: connId,
|
||||
TYPE: msgType,
|
||||
TARGET: target,
|
||||
Data: data,
|
||||
RPROTO: (uint16)(rproto),
|
||||
CATCH: (uint16)(catch),
|
||||
KEY: (uint32)(key),
|
||||
ENDTYPE: END,
|
||||
Id: connId,
|
||||
Type: (int32)(msgType),
|
||||
Target: target,
|
||||
Data: data,
|
||||
Rproto: (int32)(rproto),
|
||||
Key: (int32)(key),
|
||||
Tcpmode: (int32)(tcpmode),
|
||||
TcpmodeBuffersize: (int32)(tcpmode_buffer_size),
|
||||
TcpmodeMaxwin: (int32)(tcpmode_maxwin),
|
||||
TcpmodeResendTimems: (int32)(tcpmode_resend_time),
|
||||
TcpmodeCompress: (int32)(tcpmode_compress),
|
||||
TcpmodeStat: (int32)(tcpmode_stat),
|
||||
Timeout: (int32)(timeout),
|
||||
Magic: (int32)(MyMsg_MAGIC),
|
||||
}
|
||||
|
||||
mb, err := m.Marshal(0)
|
||||
mb, err := proto.Marshal(m)
|
||||
if err != nil {
|
||||
loggo.Error("sendICMP Marshal MyMsg error %s %s", server.String(), err)
|
||||
return
|
||||
}
|
||||
|
||||
body := &icmp.Echo{
|
||||
ID: id,
|
||||
|
@ -165,100 +54,66 @@ func sendICMP(id int, sequence int, conn icmp.PacketConn, server *net.IPAddr, ta
|
|||
|
||||
bytes, err := msg.Marshal(nil)
|
||||
if err != nil {
|
||||
fmt.Printf("sendICMP Marshal error %s %s\n", server.String(), err)
|
||||
loggo.Error("sendICMP Marshal error %s %s", server.String(), err)
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
if _, err := conn.WriteTo(bytes, server); err != nil {
|
||||
if neterr, ok := err.(*net.OpError); ok {
|
||||
if neterr.Err == syscall.ENOBUFS {
|
||||
continue
|
||||
}
|
||||
}
|
||||
fmt.Printf("sendICMP WriteTo error %s %s\n", server.String(), err)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return
|
||||
conn.WriteTo(bytes, server)
|
||||
}
|
||||
|
||||
func recvICMP(conn icmp.PacketConn, recv chan<- *Packet) {
|
||||
func recvICMP(workResultLock *sync.WaitGroup, exit *bool, conn icmp.PacketConn, recv chan<- *Packet) {
|
||||
|
||||
defer common.CrashLog()
|
||||
|
||||
(*workResultLock).Add(1)
|
||||
defer (*workResultLock).Done()
|
||||
|
||||
bytes := make([]byte, 10240)
|
||||
for {
|
||||
for !*exit {
|
||||
conn.SetReadDeadline(time.Now().Add(time.Millisecond * 100))
|
||||
n, srcaddr, err := conn.ReadFrom(bytes)
|
||||
|
||||
if err != nil {
|
||||
if neterr, ok := err.(*net.OpError); ok {
|
||||
if neterr.Timeout() {
|
||||
// Read timeout
|
||||
continue
|
||||
} else {
|
||||
fmt.Printf("Error read icmp message %s\n", err)
|
||||
continue
|
||||
}
|
||||
nerr, ok := err.(net.Error)
|
||||
if !ok || !nerr.Timeout() {
|
||||
loggo.Info("Error read icmp message %s", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if n <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
echoId := int(binary.BigEndian.Uint16(bytes[4:6]))
|
||||
echoSeq := int(binary.BigEndian.Uint16(bytes[6:8]))
|
||||
|
||||
my := &MyMsg{
|
||||
}
|
||||
my.Unmarshal(bytes[8:n])
|
||||
|
||||
if (my.TYPE != (uint32)(DATA) && my.TYPE != (uint32)(PING) && my.TYPE != (uint32)(CATCH)) ||
|
||||
my.ENDTYPE != (uint32)(END) {
|
||||
//fmt.Printf("processPacket diff type %s %d %d \n", my.ID, my.TYPE, my.ENDTYPE)
|
||||
my := &MyMsg{}
|
||||
err = proto.Unmarshal(bytes[8:n], my)
|
||||
if err != nil {
|
||||
loggo.Debug("Unmarshal MyMsg error: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if my.Data == nil {
|
||||
fmt.Printf("processPacket data nil %s\n", my.ID)
|
||||
return
|
||||
if my.Magic != (int32)(MyMsg_MAGIC) {
|
||||
loggo.Debug("processPacket data invalid %s", my.Id)
|
||||
continue
|
||||
}
|
||||
|
||||
recv <- &Packet{msgType: my.TYPE, data: my.Data, id: my.ID, target: my.TARGET,
|
||||
src: srcaddr.(*net.IPAddr), rproto: (int)((int16)(my.RPROTO)),
|
||||
echoId: echoId, echoSeq: echoSeq, catch: (int)((int16)(my.CATCH)),
|
||||
key: (int)(my.KEY)}
|
||||
recv <- &Packet{my: my,
|
||||
src: srcaddr.(*net.IPAddr),
|
||||
echoId: echoId, echoSeq: echoSeq}
|
||||
}
|
||||
}
|
||||
|
||||
type Packet struct {
|
||||
msgType uint32
|
||||
data []byte
|
||||
id string
|
||||
target string
|
||||
my *MyMsg
|
||||
src *net.IPAddr
|
||||
rproto int
|
||||
echoId int
|
||||
echoSeq int
|
||||
catch int
|
||||
key int
|
||||
}
|
||||
|
||||
func UniqueId() string {
|
||||
b := make([]byte, 48)
|
||||
|
||||
if _, err := io.ReadFull(rand.Reader, b); err != nil {
|
||||
return ""
|
||||
}
|
||||
return GetMd5String(base64.URLEncoding.EncodeToString(b))
|
||||
}
|
||||
|
||||
func GetMd5String(s string) string {
|
||||
h := md5.New()
|
||||
h.Write([]byte(s))
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
type CatchMsg struct {
|
||||
conn *ServerConn
|
||||
id string
|
||||
src *net.IPAddr
|
||||
data []byte
|
||||
}
|
||||
const (
|
||||
FRAME_MAX_SIZE int = 888
|
||||
FRAME_MAX_ID int = 1000000
|
||||
)
|
||||
|
|
|
@ -2,27 +2,26 @@ package pingtunnel
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/esrrhs/pingtunnel"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test0001(test *testing.T) {
|
||||
func Test0001(t *testing.T) {
|
||||
|
||||
my := &pingtunnel.MyMsg{
|
||||
}
|
||||
my.ID = "12345"
|
||||
my.TARGET = "111:11"
|
||||
my.TYPE = 12
|
||||
my.Data = make([]byte, 3)
|
||||
dst,_ := my.Marshal(0)
|
||||
my := &MyMsg{}
|
||||
my.Id = "12345"
|
||||
my.Target = "111:11"
|
||||
my.Type = 12
|
||||
my.Data = make([]byte, 0)
|
||||
dst, _ := proto.Marshal(my)
|
||||
fmt.Println("dst = ", dst)
|
||||
|
||||
my1 := &MyMsg{}
|
||||
proto.Unmarshal(dst, my1)
|
||||
fmt.Println("my1 = ", my1)
|
||||
fmt.Println("my1.Data = ", my1.Data)
|
||||
|
||||
my1 := &pingtunnel.MyMsg{
|
||||
}
|
||||
my1.Unmarshal(dst)
|
||||
proto.Unmarshal(dst[0:4], my1)
|
||||
fmt.Println("my1 = ", my1)
|
||||
|
||||
my1.Unmarshal(dst[0:4])
|
||||
fmt.Println("my1 = ", my1)
|
||||
}
|
||||
|
|
654
server.go
654
server.go
|
@ -1,228 +1,614 @@
|
|||
package pingtunnel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/esrrhs/gohome/common"
|
||||
"github.com/esrrhs/gohome/frame"
|
||||
"github.com/esrrhs/gohome/loggo"
|
||||
"github.com/esrrhs/gohome/threadpool"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"golang.org/x/net/icmp"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
func NewServer(timeout int, key int) (*Server, error) {
|
||||
return &Server{
|
||||
timeout: timeout,
|
||||
key: key,
|
||||
}, nil
|
||||
func NewServer(key int, maxconn int, maxprocessthread int, maxprocessbuffer int, connecttmeout int) (*Server, error) {
|
||||
s := &Server{
|
||||
exit: false,
|
||||
key: key,
|
||||
maxconn: maxconn,
|
||||
maxprocessthread: maxprocessthread,
|
||||
maxprocessbuffer: maxprocessbuffer,
|
||||
connecttmeout: connecttmeout,
|
||||
}
|
||||
|
||||
if maxprocessthread > 0 {
|
||||
s.processtp = threadpool.NewThreadPool(maxprocessthread, maxprocessbuffer, func(v interface{}) {
|
||||
packet := v.(*Packet)
|
||||
s.processDataPacket(packet)
|
||||
})
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
timeout int
|
||||
key int
|
||||
exit bool
|
||||
key int
|
||||
workResultLock sync.WaitGroup
|
||||
maxconn int
|
||||
maxprocessthread int
|
||||
maxprocessbuffer int
|
||||
connecttmeout int
|
||||
|
||||
conn *icmp.PacketConn
|
||||
|
||||
localConnMap map[string]*ServerConn
|
||||
localConnMap sync.Map
|
||||
connErrorMap sync.Map
|
||||
|
||||
sendPacket uint64
|
||||
recvPacket uint64
|
||||
sendPacketSize uint64
|
||||
recvPacketSize uint64
|
||||
sendPacket uint64
|
||||
recvPacket uint64
|
||||
sendPacketSize uint64
|
||||
recvPacketSize uint64
|
||||
localConnMapSize int
|
||||
|
||||
sendCatchPacket uint64
|
||||
recvCatchPacket uint64
|
||||
|
||||
echoId int
|
||||
echoSeq int
|
||||
processtp *threadpool.ThreadPool
|
||||
recvcontrol chan int
|
||||
}
|
||||
|
||||
type ServerConn struct {
|
||||
ipaddrTarget *net.UDPAddr
|
||||
conn *net.UDPConn
|
||||
id string
|
||||
activeTime time.Time
|
||||
close bool
|
||||
rproto int
|
||||
catch int
|
||||
catchQueue chan *CatchMsg
|
||||
exit bool
|
||||
timeout int
|
||||
ipaddrTarget *net.UDPAddr
|
||||
conn *net.UDPConn
|
||||
tcpaddrTarget *net.TCPAddr
|
||||
tcpconn *net.TCPConn
|
||||
id string
|
||||
activeRecvTime time.Time
|
||||
activeSendTime time.Time
|
||||
close bool
|
||||
rproto int
|
||||
fm *frame.FrameMgr
|
||||
tcpmode int
|
||||
echoId int
|
||||
echoSeq int
|
||||
}
|
||||
|
||||
func (p *Server) Run() {
|
||||
func (p *Server) Run() error {
|
||||
|
||||
conn, err := icmp.ListenPacket("ip4:icmp", "")
|
||||
if err != nil {
|
||||
fmt.Printf("Error listening for ICMP packets: %s\n", err.Error())
|
||||
return
|
||||
loggo.Error("Error listening for ICMP packets: %s", err.Error())
|
||||
return err
|
||||
}
|
||||
p.conn = conn
|
||||
|
||||
p.localConnMap = make(map[string]*ServerConn)
|
||||
|
||||
recv := make(chan *Packet, 10000)
|
||||
go recvICMP(*p.conn, recv)
|
||||
p.recvcontrol = make(chan int, 1)
|
||||
go recvICMP(&p.workResultLock, &p.exit, *p.conn, recv)
|
||||
|
||||
interval := time.NewTicker(time.Second)
|
||||
defer interval.Stop()
|
||||
go func() {
|
||||
defer common.CrashLog()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-interval.C:
|
||||
p.workResultLock.Add(1)
|
||||
defer p.workResultLock.Done()
|
||||
|
||||
for !p.exit {
|
||||
p.checkTimeoutConn()
|
||||
p.showNet()
|
||||
case r := <-recv:
|
||||
p.processPacket(r)
|
||||
p.updateConnError()
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer common.CrashLog()
|
||||
|
||||
p.workResultLock.Add(1)
|
||||
defer p.workResultLock.Done()
|
||||
|
||||
for !p.exit {
|
||||
select {
|
||||
case <-p.recvcontrol:
|
||||
return
|
||||
case r := <-recv:
|
||||
p.processPacket(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Server) Stop() {
|
||||
p.exit = true
|
||||
p.recvcontrol <- 1
|
||||
p.workResultLock.Wait()
|
||||
p.processtp.Stop()
|
||||
p.conn.Close()
|
||||
}
|
||||
|
||||
func (p *Server) processPacket(packet *Packet) {
|
||||
|
||||
if packet.key != p.key {
|
||||
if packet.my.Key != (int32)(p.key) {
|
||||
return
|
||||
}
|
||||
|
||||
p.echoId = packet.echoId
|
||||
p.echoSeq = packet.echoSeq
|
||||
|
||||
if packet.msgType == PING {
|
||||
if packet.my.Type == (int32)(MyMsg_PING) {
|
||||
t := time.Time{}
|
||||
t.UnmarshalBinary(packet.data)
|
||||
fmt.Printf("ping from %s %s %d %d %d\n", packet.src.String(), t.String(), packet.rproto, packet.echoId, packet.echoSeq)
|
||||
sendICMP(packet.echoId, packet.echoSeq, *p.conn, packet.src, "", "", (uint32)(PING), packet.data,
|
||||
packet.rproto, -1, 0, p.key)
|
||||
t.UnmarshalBinary(packet.my.Data)
|
||||
loggo.Info("ping from %s %s %d %d %d", packet.src.String(), t.String(), packet.my.Rproto, packet.echoId, packet.echoSeq)
|
||||
sendICMP(packet.echoId, packet.echoSeq, *p.conn, packet.src, "", "", (uint32)(MyMsg_PING), packet.my.Data,
|
||||
(int)(packet.my.Rproto), -1, p.key,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0)
|
||||
return
|
||||
}
|
||||
|
||||
//fmt.Printf("processPacket %s %s %d\n", packet.id, packet.src.String(), len(packet.data))
|
||||
|
||||
now := time.Now()
|
||||
|
||||
id := packet.id
|
||||
udpConn := p.localConnMap[id]
|
||||
if udpConn == nil {
|
||||
|
||||
addr := packet.target
|
||||
ipaddrTarget, err := net.ResolveUDPAddr("udp", addr)
|
||||
if err != nil {
|
||||
fmt.Printf("Error ResolveUDPAddr for udp addr: %s %s\n", addr, err.Error())
|
||||
return
|
||||
if packet.my.Type == (int32)(MyMsg_KICK) {
|
||||
localConn := p.getServerConnById(packet.my.Id)
|
||||
if localConn != nil {
|
||||
p.close(localConn)
|
||||
loggo.Info("remote kick local %s", packet.my.Id)
|
||||
}
|
||||
|
||||
targetConn, err := net.DialUDP("udp", nil, ipaddrTarget)
|
||||
if err != nil {
|
||||
fmt.Printf("Error listening for udp packets: %s\n", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
catchQueue := make(chan *CatchMsg, 1000)
|
||||
|
||||
udpConn = &ServerConn{conn: targetConn, ipaddrTarget: ipaddrTarget, id: id, activeTime: now, close: false,
|
||||
rproto: packet.rproto, catchQueue: catchQueue}
|
||||
|
||||
p.localConnMap[id] = udpConn
|
||||
|
||||
go p.Recv(udpConn, id, packet.src)
|
||||
}
|
||||
|
||||
udpConn.activeTime = now
|
||||
udpConn.catch = packet.catch
|
||||
|
||||
if packet.msgType == CATCH {
|
||||
select {
|
||||
case re := <-udpConn.catchQueue:
|
||||
sendICMP(packet.echoId, packet.echoSeq, *p.conn, re.src, "", re.id, (uint32)(CATCH), re.data,
|
||||
re.conn.rproto, -1, 0, p.key)
|
||||
p.sendCatchPacket++
|
||||
case <-time.After(time.Duration(1) * time.Millisecond):
|
||||
}
|
||||
p.recvCatchPacket++
|
||||
return
|
||||
}
|
||||
|
||||
if packet.msgType == DATA {
|
||||
if p.maxprocessthread > 0 {
|
||||
p.processtp.AddJob((int)(common.HashString(packet.my.Id)), packet)
|
||||
} else {
|
||||
p.processDataPacket(packet)
|
||||
}
|
||||
}
|
||||
|
||||
_, err := udpConn.conn.Write(packet.data)
|
||||
func (p *Server) processDataPacketNewConn(id string, packet *Packet) *ServerConn {
|
||||
|
||||
now := common.GetNowUpdateInSecond()
|
||||
|
||||
loggo.Info("start add new connect %s %s", id, packet.my.Target)
|
||||
|
||||
if p.maxconn > 0 && p.localConnMapSize >= p.maxconn {
|
||||
loggo.Info("too many connections %d, server connected target fail %s", p.localConnMapSize, packet.my.Target)
|
||||
p.remoteError(packet.echoId, packet.echoSeq, id, (int)(packet.my.Rproto), packet.src)
|
||||
return nil
|
||||
}
|
||||
|
||||
addr := packet.my.Target
|
||||
if p.isConnError(addr) {
|
||||
loggo.Info("addr connect Error before: %s %s", id, addr)
|
||||
p.remoteError(packet.echoId, packet.echoSeq, id, (int)(packet.my.Rproto), packet.src)
|
||||
return nil
|
||||
}
|
||||
|
||||
if packet.my.Tcpmode > 0 {
|
||||
|
||||
c, err := net.DialTimeout("tcp", addr, time.Millisecond*time.Duration(p.connecttmeout))
|
||||
if err != nil {
|
||||
fmt.Printf("WriteToUDP Error %s\n", err)
|
||||
udpConn.close = true
|
||||
loggo.Error("Error listening for tcp packets: %s %s", id, err.Error())
|
||||
p.remoteError(packet.echoId, packet.echoSeq, id, (int)(packet.my.Rproto), packet.src)
|
||||
p.addConnError(addr)
|
||||
return nil
|
||||
}
|
||||
targetConn := c.(*net.TCPConn)
|
||||
ipaddrTarget := targetConn.RemoteAddr().(*net.TCPAddr)
|
||||
|
||||
fm := frame.NewFrameMgr(FRAME_MAX_SIZE, FRAME_MAX_ID, (int)(packet.my.TcpmodeBuffersize), (int)(packet.my.TcpmodeMaxwin), (int)(packet.my.TcpmodeResendTimems), (int)(packet.my.TcpmodeCompress),
|
||||
(int)(packet.my.TcpmodeStat))
|
||||
|
||||
localConn := &ServerConn{exit: false, timeout: (int)(packet.my.Timeout), tcpconn: targetConn, tcpaddrTarget: ipaddrTarget, id: id, activeRecvTime: now, activeSendTime: now, close: false,
|
||||
rproto: (int)(packet.my.Rproto), fm: fm, tcpmode: (int)(packet.my.Tcpmode)}
|
||||
|
||||
p.addServerConn(id, localConn)
|
||||
|
||||
go p.RecvTCP(localConn, id, packet.src)
|
||||
return localConn
|
||||
|
||||
} else {
|
||||
|
||||
c, err := net.DialTimeout("udp", addr, time.Millisecond*time.Duration(p.connecttmeout))
|
||||
if err != nil {
|
||||
loggo.Error("Error listening for udp packets: %s %s", id, err.Error())
|
||||
p.remoteError(packet.echoId, packet.echoSeq, id, (int)(packet.my.Rproto), packet.src)
|
||||
p.addConnError(addr)
|
||||
return nil
|
||||
}
|
||||
targetConn := c.(*net.UDPConn)
|
||||
ipaddrTarget := targetConn.RemoteAddr().(*net.UDPAddr)
|
||||
|
||||
localConn := &ServerConn{exit: false, timeout: (int)(packet.my.Timeout), conn: targetConn, ipaddrTarget: ipaddrTarget, id: id, activeRecvTime: now, activeSendTime: now, close: false,
|
||||
rproto: (int)(packet.my.Rproto), tcpmode: (int)(packet.my.Tcpmode)}
|
||||
|
||||
p.addServerConn(id, localConn)
|
||||
|
||||
go p.Recv(localConn, id, packet.src)
|
||||
|
||||
return localConn
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Server) processDataPacket(packet *Packet) {
|
||||
|
||||
loggo.Debug("processPacket %s %s %d", packet.my.Id, packet.src.String(), len(packet.my.Data))
|
||||
|
||||
now := common.GetNowUpdateInSecond()
|
||||
|
||||
id := packet.my.Id
|
||||
localConn := p.getServerConnById(id)
|
||||
if localConn == nil {
|
||||
localConn = p.processDataPacketNewConn(id, packet)
|
||||
if localConn == nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
localConn.activeRecvTime = now
|
||||
localConn.echoId = packet.echoId
|
||||
localConn.echoSeq = packet.echoSeq
|
||||
|
||||
if packet.my.Type == (int32)(MyMsg_DATA) {
|
||||
|
||||
if packet.my.Tcpmode > 0 {
|
||||
f := &frame.Frame{}
|
||||
err := proto.Unmarshal(packet.my.Data, f)
|
||||
if err != nil {
|
||||
loggo.Error("Unmarshal tcp Error %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
localConn.fm.OnRecvFrame(f)
|
||||
|
||||
} else {
|
||||
if packet.my.Data == nil {
|
||||
return
|
||||
}
|
||||
_, err := localConn.conn.Write(packet.my.Data)
|
||||
if err != nil {
|
||||
loggo.Info("WriteToUDP Error %s", err)
|
||||
localConn.close = true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
p.recvPacket++
|
||||
p.recvPacketSize += (uint64)(len(packet.data))
|
||||
p.recvPacketSize += (uint64)(len(packet.my.Data))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Server) RecvTCP(conn *ServerConn, id string, src *net.IPAddr) {
|
||||
|
||||
defer common.CrashLog()
|
||||
|
||||
p.workResultLock.Add(1)
|
||||
defer p.workResultLock.Done()
|
||||
|
||||
loggo.Info("server waiting target response %s -> %s %s", conn.tcpaddrTarget.String(), conn.id, conn.tcpconn.LocalAddr().String())
|
||||
|
||||
loggo.Info("start wait remote connect tcp %s %s", conn.id, conn.tcpaddrTarget.String())
|
||||
startConnectTime := common.GetNowUpdateInSecond()
|
||||
for !p.exit && !conn.exit {
|
||||
if conn.fm.IsConnected() {
|
||||
break
|
||||
}
|
||||
conn.fm.Update()
|
||||
sendlist := conn.fm.GetSendList()
|
||||
for e := sendlist.Front(); e != nil; e = e.Next() {
|
||||
f := e.Value.(*frame.Frame)
|
||||
mb, _ := conn.fm.MarshalFrame(f)
|
||||
sendICMP(conn.echoId, conn.echoSeq, *p.conn, src, "", id, (uint32)(MyMsg_DATA), mb,
|
||||
conn.rproto, -1, p.key,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0)
|
||||
p.sendPacket++
|
||||
p.sendPacketSize += (uint64)(len(mb))
|
||||
}
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
now := common.GetNowUpdateInSecond()
|
||||
diffclose := now.Sub(startConnectTime)
|
||||
if diffclose > time.Second*5 {
|
||||
loggo.Info("can not connect remote tcp %s %s", conn.id, conn.tcpaddrTarget.String())
|
||||
p.close(conn)
|
||||
p.remoteError(conn.echoId, conn.echoSeq, id, conn.rproto, src)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !conn.exit {
|
||||
loggo.Info("remote connected tcp %s %s", conn.id, conn.tcpaddrTarget.String())
|
||||
}
|
||||
|
||||
bytes := make([]byte, 10240)
|
||||
|
||||
tcpActiveRecvTime := common.GetNowUpdateInSecond()
|
||||
tcpActiveSendTime := common.GetNowUpdateInSecond()
|
||||
|
||||
for !p.exit && !conn.exit {
|
||||
now := common.GetNowUpdateInSecond()
|
||||
sleep := true
|
||||
|
||||
left := common.MinOfInt(conn.fm.GetSendBufferLeft(), len(bytes))
|
||||
if left > 0 {
|
||||
conn.tcpconn.SetReadDeadline(time.Now().Add(time.Millisecond * 1))
|
||||
n, err := conn.tcpconn.Read(bytes[0:left])
|
||||
if err != nil {
|
||||
nerr, ok := err.(net.Error)
|
||||
if !ok || !nerr.Timeout() {
|
||||
loggo.Info("Error read tcp %s %s %s", conn.id, conn.tcpaddrTarget.String(), err)
|
||||
conn.fm.Close()
|
||||
break
|
||||
}
|
||||
}
|
||||
if n > 0 {
|
||||
sleep = false
|
||||
conn.fm.WriteSendBuffer(bytes[:n])
|
||||
tcpActiveRecvTime = now
|
||||
}
|
||||
}
|
||||
|
||||
conn.fm.Update()
|
||||
|
||||
sendlist := conn.fm.GetSendList()
|
||||
if sendlist.Len() > 0 {
|
||||
sleep = false
|
||||
conn.activeSendTime = now
|
||||
for e := sendlist.Front(); e != nil; e = e.Next() {
|
||||
f := e.Value.(*frame.Frame)
|
||||
mb, err := conn.fm.MarshalFrame(f)
|
||||
if err != nil {
|
||||
loggo.Error("Error tcp Marshal %s %s %s", conn.id, conn.tcpaddrTarget.String(), err)
|
||||
continue
|
||||
}
|
||||
sendICMP(conn.echoId, conn.echoSeq, *p.conn, src, "", id, (uint32)(MyMsg_DATA), mb,
|
||||
conn.rproto, -1, p.key,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0)
|
||||
p.sendPacket++
|
||||
p.sendPacketSize += (uint64)(len(mb))
|
||||
}
|
||||
}
|
||||
|
||||
if conn.fm.GetRecvBufferSize() > 0 {
|
||||
sleep = false
|
||||
rr := conn.fm.GetRecvReadLineBuffer()
|
||||
conn.tcpconn.SetWriteDeadline(time.Now().Add(time.Millisecond * 1))
|
||||
n, err := conn.tcpconn.Write(rr)
|
||||
if err != nil {
|
||||
nerr, ok := err.(net.Error)
|
||||
if !ok || !nerr.Timeout() {
|
||||
loggo.Info("Error write tcp %s %s %s", conn.id, conn.tcpaddrTarget.String(), err)
|
||||
conn.fm.Close()
|
||||
break
|
||||
}
|
||||
}
|
||||
if n > 0 {
|
||||
conn.fm.SkipRecvBuffer(n)
|
||||
tcpActiveSendTime = now
|
||||
}
|
||||
}
|
||||
|
||||
if sleep {
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
}
|
||||
|
||||
diffrecv := now.Sub(conn.activeRecvTime)
|
||||
diffsend := now.Sub(conn.activeSendTime)
|
||||
tcpdiffrecv := now.Sub(tcpActiveRecvTime)
|
||||
tcpdiffsend := now.Sub(tcpActiveSendTime)
|
||||
if diffrecv > time.Second*(time.Duration(conn.timeout)) || diffsend > time.Second*(time.Duration(conn.timeout)) ||
|
||||
(tcpdiffrecv > time.Second*(time.Duration(conn.timeout)) && tcpdiffsend > time.Second*(time.Duration(conn.timeout))) {
|
||||
loggo.Info("close inactive conn %s %s", conn.id, conn.tcpaddrTarget.String())
|
||||
conn.fm.Close()
|
||||
break
|
||||
}
|
||||
|
||||
if conn.fm.IsRemoteClosed() {
|
||||
loggo.Info("closed by remote conn %s %s", conn.id, conn.tcpaddrTarget.String())
|
||||
conn.fm.Close()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
conn.fm.Close()
|
||||
|
||||
startCloseTime := common.GetNowUpdateInSecond()
|
||||
for !p.exit && !conn.exit {
|
||||
now := common.GetNowUpdateInSecond()
|
||||
|
||||
conn.fm.Update()
|
||||
|
||||
sendlist := conn.fm.GetSendList()
|
||||
for e := sendlist.Front(); e != nil; e = e.Next() {
|
||||
f := e.Value.(*frame.Frame)
|
||||
mb, _ := conn.fm.MarshalFrame(f)
|
||||
sendICMP(conn.echoId, conn.echoSeq, *p.conn, src, "", id, (uint32)(MyMsg_DATA), mb,
|
||||
conn.rproto, -1, p.key,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0)
|
||||
p.sendPacket++
|
||||
p.sendPacketSize += (uint64)(len(mb))
|
||||
}
|
||||
|
||||
nodatarecv := true
|
||||
if conn.fm.GetRecvBufferSize() > 0 {
|
||||
rr := conn.fm.GetRecvReadLineBuffer()
|
||||
conn.tcpconn.SetWriteDeadline(time.Now().Add(time.Millisecond * 100))
|
||||
n, _ := conn.tcpconn.Write(rr)
|
||||
if n > 0 {
|
||||
conn.fm.SkipRecvBuffer(n)
|
||||
nodatarecv = false
|
||||
}
|
||||
}
|
||||
|
||||
diffclose := now.Sub(startCloseTime)
|
||||
if diffclose > time.Second*60 {
|
||||
loggo.Info("close conn had timeout %s %s", conn.id, conn.tcpaddrTarget.String())
|
||||
break
|
||||
}
|
||||
|
||||
remoteclosed := conn.fm.IsRemoteClosed()
|
||||
if remoteclosed && nodatarecv {
|
||||
loggo.Info("remote conn had closed %s %s", conn.id, conn.tcpaddrTarget.String())
|
||||
break
|
||||
}
|
||||
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
loggo.Info("close tcp conn %s %s", conn.id, conn.tcpaddrTarget.String())
|
||||
p.close(conn)
|
||||
}
|
||||
|
||||
func (p *Server) Recv(conn *ServerConn, id string, src *net.IPAddr) {
|
||||
|
||||
fmt.Printf("server waiting target response %s -> %s %s\n", conn.ipaddrTarget.String(), conn.id, conn.conn.LocalAddr().String())
|
||||
defer common.CrashLog()
|
||||
|
||||
for {
|
||||
bytes := make([]byte, 2000)
|
||||
p.workResultLock.Add(1)
|
||||
defer p.workResultLock.Done()
|
||||
|
||||
loggo.Info("server waiting target response %s -> %s %s", conn.ipaddrTarget.String(), conn.id, conn.conn.LocalAddr().String())
|
||||
|
||||
bytes := make([]byte, 2000)
|
||||
|
||||
for !p.exit {
|
||||
|
||||
conn.conn.SetReadDeadline(time.Now().Add(time.Millisecond * 100))
|
||||
n, _, err := conn.conn.ReadFromUDP(bytes)
|
||||
if err != nil {
|
||||
if neterr, ok := err.(*net.OpError); ok {
|
||||
if neterr.Timeout() {
|
||||
// Read timeout
|
||||
continue
|
||||
} else {
|
||||
fmt.Printf("ReadFromUDP Error read udp %s\n", err)
|
||||
conn.close = true
|
||||
return
|
||||
}
|
||||
nerr, ok := err.(net.Error)
|
||||
if !ok || !nerr.Timeout() {
|
||||
loggo.Info("ReadFromUDP Error read udp %s", err)
|
||||
conn.close = true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
conn.activeTime = now
|
||||
now := common.GetNowUpdateInSecond()
|
||||
conn.activeSendTime = now
|
||||
|
||||
if conn.catch > 0 {
|
||||
select {
|
||||
case conn.catchQueue <- &CatchMsg{conn: conn, id: id, src: src, data: bytes[:n]}:
|
||||
case <-time.After(time.Duration(10) * time.Millisecond):
|
||||
}
|
||||
} else {
|
||||
sendICMP(p.echoId, p.echoSeq, *p.conn, src, "", id, (uint32)(DATA), bytes[:n],
|
||||
conn.rproto, -1, 0, p.key)
|
||||
}
|
||||
sendICMP(conn.echoId, conn.echoSeq, *p.conn, src, "", id, (uint32)(MyMsg_DATA), bytes[:n],
|
||||
conn.rproto, -1, p.key,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0)
|
||||
|
||||
p.sendPacket++
|
||||
p.sendPacketSize += (uint64)(n)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Server) Close(conn *ServerConn) {
|
||||
if p.localConnMap[conn.id] != nil {
|
||||
conn.conn.Close()
|
||||
delete(p.localConnMap, conn.id)
|
||||
func (p *Server) close(conn *ServerConn) {
|
||||
if p.getServerConnById(conn.id) != nil {
|
||||
conn.exit = true
|
||||
if conn.conn != nil {
|
||||
conn.conn.Close()
|
||||
}
|
||||
if conn.tcpconn != nil {
|
||||
conn.tcpconn.Close()
|
||||
}
|
||||
p.deleteServerConn(conn.id)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Server) checkTimeoutConn() {
|
||||
|
||||
now := time.Now()
|
||||
for _, conn := range p.localConnMap {
|
||||
diff := now.Sub(conn.activeTime)
|
||||
if diff > time.Second*(time.Duration(p.timeout)) {
|
||||
tmp := make(map[string]*ServerConn)
|
||||
p.localConnMap.Range(func(key, value interface{}) bool {
|
||||
id := key.(string)
|
||||
serverConn := value.(*ServerConn)
|
||||
tmp[id] = serverConn
|
||||
return true
|
||||
})
|
||||
|
||||
now := common.GetNowUpdateInSecond()
|
||||
for _, conn := range tmp {
|
||||
if conn.tcpmode > 0 {
|
||||
continue
|
||||
}
|
||||
diffrecv := now.Sub(conn.activeRecvTime)
|
||||
diffsend := now.Sub(conn.activeSendTime)
|
||||
if diffrecv > time.Second*(time.Duration(conn.timeout)) || diffsend > time.Second*(time.Duration(conn.timeout)) {
|
||||
conn.close = true
|
||||
}
|
||||
}
|
||||
|
||||
for id, conn := range p.localConnMap {
|
||||
for id, conn := range tmp {
|
||||
if conn.tcpmode > 0 {
|
||||
continue
|
||||
}
|
||||
if conn.close {
|
||||
fmt.Printf("close inactive conn %s %s\n", id, conn.ipaddrTarget.String())
|
||||
p.Close(conn)
|
||||
loggo.Info("close inactive conn %s %s", id, conn.ipaddrTarget.String())
|
||||
p.close(conn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Server) showNet() {
|
||||
fmt.Printf("send %dPacket/s %dKB/s recv %dPacket/s %dKB/s sendCatch %d/s recvCatch %d/s\n",
|
||||
p.sendPacket, p.sendPacketSize/1024, p.recvPacket, p.recvPacketSize/1024, p.sendCatchPacket, p.recvCatchPacket)
|
||||
p.localConnMapSize = 0
|
||||
p.localConnMap.Range(func(key, value interface{}) bool {
|
||||
p.localConnMapSize++
|
||||
return true
|
||||
})
|
||||
loggo.Info("send %dPacket/s %dKB/s recv %dPacket/s %dKB/s %dConnections",
|
||||
p.sendPacket, p.sendPacketSize/1024, p.recvPacket, p.recvPacketSize/1024, p.localConnMapSize)
|
||||
p.sendPacket = 0
|
||||
p.recvPacket = 0
|
||||
p.sendPacketSize = 0
|
||||
p.recvPacketSize = 0
|
||||
p.sendCatchPacket = 0
|
||||
p.recvCatchPacket = 0
|
||||
}
|
||||
|
||||
func (p *Server) addServerConn(uuid string, serverConn *ServerConn) {
|
||||
p.localConnMap.Store(uuid, serverConn)
|
||||
}
|
||||
|
||||
func (p *Server) getServerConnById(uuid string) *ServerConn {
|
||||
ret, ok := p.localConnMap.Load(uuid)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return ret.(*ServerConn)
|
||||
}
|
||||
|
||||
func (p *Server) deleteServerConn(uuid string) {
|
||||
p.localConnMap.Delete(uuid)
|
||||
}
|
||||
|
||||
func (p *Server) remoteError(echoId int, echoSeq int, uuid string, rprpto int, src *net.IPAddr) {
|
||||
sendICMP(echoId, echoSeq, *p.conn, src, "", uuid, (uint32)(MyMsg_KICK), []byte{},
|
||||
rprpto, -1, p.key,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0)
|
||||
}
|
||||
|
||||
func (p *Server) addConnError(addr string) {
|
||||
_, ok := p.connErrorMap.Load(addr)
|
||||
if !ok {
|
||||
now := common.GetNowUpdateInSecond()
|
||||
p.connErrorMap.Store(addr, now)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Server) isConnError(addr string) bool {
|
||||
_, ok := p.connErrorMap.Load(addr)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (p *Server) updateConnError() {
|
||||
|
||||
tmp := make(map[string]time.Time)
|
||||
p.connErrorMap.Range(func(key, value interface{}) bool {
|
||||
id := key.(string)
|
||||
t := value.(time.Time)
|
||||
tmp[id] = t
|
||||
return true
|
||||
})
|
||||
|
||||
now := common.GetNowUpdateInSecond()
|
||||
for id, t := range tmp {
|
||||
diff := now.Sub(t)
|
||||
if diff > time.Second*5 {
|
||||
p.connErrorMap.Delete(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
BIN
show.png
BIN
show.png
Binary file not shown.
Before Width: | Height: | Size: 497 KiB |
Loading…
Add table
Reference in a new issue