Compare commits
No commits in common. "master" and "2.6" have entirely different histories.
16 changed files with 138 additions and 1982 deletions
34
.github/workflows/docker-image.yml
vendored
34
.github/workflows/docker-image.yml
vendored
|
@ -1,34 +0,0 @@
|
||||||
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
|
|
27
.github/workflows/go.yml
vendored
27
.github/workflows/go.yml
vendored
|
@ -1,30 +1,29 @@
|
||||||
# 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
|
name: Go
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ "master" ]
|
branches: [ master ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ "master" ]
|
branches: [ master ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.21
|
go-version: 1.17
|
||||||
|
|
||||||
- name: Build
|
- name: Get dependencies
|
||||||
run: |
|
run: |
|
||||||
go mod tidy
|
GO111MODULE=off go get -v -t -d ./...
|
||||||
go build -v ./...
|
if [ -f Gopkg.toml ]; then
|
||||||
|
curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
|
||||||
- name: Test
|
dep ensure
|
||||||
run: go test -v ./...
|
fi
|
||||||
|
- name: Build
|
||||||
|
run: GO111MODULE=off go build -v ./...
|
||||||
|
|
11
Dockerfile
11
Dockerfile
|
@ -1,13 +1,10 @@
|
||||||
FROM golang AS build-env
|
FROM golang AS build-env
|
||||||
|
|
||||||
WORKDIR /app
|
RUN GO111MODULE=off go get -u github.com/esrrhs/pingtunnel
|
||||||
|
RUN GO111MODULE=off go get -u github.com/esrrhs/pingtunnel/...
|
||||||
COPY go.* ./
|
RUN GO111MODULE=off go install github.com/esrrhs/pingtunnel
|
||||||
RUN go mod download
|
|
||||||
COPY . ./
|
|
||||||
RUN go build -v -o pingtunnel
|
|
||||||
|
|
||||||
FROM debian
|
FROM debian
|
||||||
COPY --from=build-env /app/pingtunnel .
|
COPY --from=build-env /go/bin/pingtunnel .
|
||||||
COPY GeoLite2-Country.mmdb .
|
COPY GeoLite2-Country.mmdb .
|
||||||
WORKDIR ./
|
WORKDIR ./
|
||||||
|
|
49
README.md
49
README.md
|
@ -6,62 +6,61 @@
|
||||||
[<img src="https://img.shields.io/github/v/release/esrrhs/pingtunnel">](https://github.com/esrrhs/pingtunnel/releases)
|
[<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/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/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)
|
[<img src="https://img.shields.io/github/workflow/status/esrrhs/pingtunnel/Go">](https://github.com/esrrhs/pingtunnel/actions)
|
||||||
|
|
||||||
Pingtunnel is a tool that send TCP/UDP traffic over ICMP.
|
pingtunnel 是把 tcp/udp/sock5 流量伪装成 icmp 流量进行转发的工具
|
||||||
|
|
||||||
## Note: This tool is only to be used for study and research, do not use it for illegal purposes
|
[Readme EN](./README_EN.md)
|
||||||
|
|
||||||
|
## 注意:本工具只是用作学习研究,请勿用于非法用途!!!
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 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
|
- 首先准备好一个具有公网 ip 的服务器,假定域名或者公网 ip 是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
|
- 从[releases](https://github.com/esrrhs/pingtunnel/releases)下载对应的安装包,如 pingtunnel_linux64.zip,然后解压,以**root**权限执行
|
||||||
- “-key” parameter is **int** type, only supports numbers between 0-2147483647
|
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo wget (link of latest release)
|
sudo wget (最新release的下载链接)
|
||||||
sudo unzip pingtunnel_linux64.zip
|
sudo unzip pingtunnel_linux64.zip
|
||||||
sudo ./pingtunnel -type server
|
sudo ./pingtunnel -type server
|
||||||
```
|
```
|
||||||
|
|
||||||
- (Optional) Disable system default ping
|
- (可选)关闭系统默认的 ping
|
||||||
|
|
||||||
```
|
```
|
||||||
echo 1 >/proc/sys/net/ipv4/icmp_echo_ignore_all
|
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
|
- 从[releases](https://github.com/esrrhs/pingtunnel/releases)下载对应的安装包,如 pingtunnel_windows64.zip,解压
|
||||||
- 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
|
- 如果看到有 ping pong 的 log,说明连接正常
|
||||||
- “-key” parameter is **int** type, only supports numbers between 0-2147483647
|
|
||||||
|
|
||||||
|
#### 转发 sock5
|
||||||
#### Forward sock5
|
|
||||||
|
|
||||||
```
|
```
|
||||||
pingtunnel.exe -type client -l :4455 -s www.yourserver.com -sock5 1
|
pingtunnel.exe -type client -l :4455 -s www.yourserver.com -sock5 1
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Forward tcp
|
#### 转发 tcp
|
||||||
|
|
||||||
```
|
```
|
||||||
pingtunnel.exe -type client -l :4455 -s www.yourserver.com -t www.yourserver.com:4455 -tcp 1
|
pingtunnel.exe -type client -l :4455 -s www.yourserver.com -t www.yourserver.com:4455 -tcp 1
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Forward udp
|
#### 转发 udp
|
||||||
|
|
||||||
```
|
```
|
||||||
pingtunnel.exe -type client -l :4455 -s www.yourserver.com -t www.yourserver.com:4455
|
pingtunnel.exe -type client -l :4455 -s www.yourserver.com -t www.yourserver.com:4455
|
||||||
```
|
```
|
||||||
|
|
||||||
### Use Docker
|
### Docker
|
||||||
It can also be started directly with docker, which is more convenient. Same parameters as above
|
也可直接用docker启动,更方便。参数同上
|
||||||
- server:
|
- server:
|
||||||
```
|
```
|
||||||
docker run --name pingtunnel-server -d --privileged --network host --restart=always esrrhs/pingtunnel ./pingtunnel -type server -key 123456
|
docker run --name pingtunnel-server -d --privileged --network host --restart=always esrrhs/pingtunnel ./pingtunnel -type server -key 123456
|
||||||
|
@ -71,8 +70,10 @@ docker run --name pingtunnel-server -d --privileged --network host --restart=alw
|
||||||
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
|
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
|
||||||
```
|
```
|
||||||
|
|
||||||
## Thanks for free JetBrains Open Source license
|
## 效果
|
||||||
|
|
||||||
<img src="https://resources.jetbrains.com/storage/products/company/brand/logos/GoLand.png" height="200"/></a>
|
|
||||||
|
|
||||||
|
下载 centos 镜像 [centos mirror](http://centos.s.uw.edu/centos/8.4.2105/isos/x86_64/CentOS-8.4.2105-x86_64-dvd1.iso),对比如下
|
||||||
|
|
||||||
|
| | wget | ss | kcp | pingtunnel |
|
||||||
|
| ------ | -------- | -------- | ------- | ---------- |
|
||||||
|
| 阿里云 | 26.6KB/s | 31.8KB/s | 606KB/s | 5.64MB/s |
|
||||||
|
|
77
README_EN.md
Normal file
77
README_EN.md
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
# Pingtunnel
|
||||||
|
|
||||||
|
[<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/workflow/status/esrrhs/pingtunnel/Go">](https://github.com/esrrhs/pingtunnel/actions)
|
||||||
|
|
||||||
|
Pingtunnel is a tool that advertises tcp/udp/sock5 traffic as icmp traffic for forwarding.
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo wget (link of latest release)
|
||||||
|
sudo unzip pingtunnel_linux64.zip
|
||||||
|
sudo ./pingtunnel -type server
|
||||||
|
```
|
||||||
|
|
||||||
|
- (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
|
||||||
|
|
||||||
|
#### 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
|
||||||
|
```
|
||||||
|
|
||||||
|
### Use Docker
|
||||||
|
It can also be started directly with docker, which is more convenient. Same parameters as above
|
||||||
|
- server:
|
||||||
|
```
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test
|
||||||
|
|
||||||
|
download the centos image [centos mirror](http://centos.s.uw.edu/centos/8.4.2105/isos/x86_64/CentOS-8.4.2105-x86_64-dvd1.iso)
|
||||||
|
|
||||||
|
| | wget | ss | kcp | pingtunnel |
|
||||||
|
| ------------ | -------- | -------- | ------- | ---------- |
|
||||||
|
| AlibabaCloud | 26.6KB/s | 31.8KB/s | 606KB/s | 5.64MB/s |
|
830
client.go
830
client.go
|
@ -1,830 +0,0 @@
|
||||||
package pingtunnel
|
|
||||||
|
|
||||||
import (
|
|
||||||
"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"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
SEND_PROTO int = 8
|
|
||||||
RECV_PROTO int = 0
|
|
||||||
)
|
|
||||||
|
|
||||||
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)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
rand.Seed(time.Now().UnixNano())
|
|
||||||
return &Client{
|
|
||||||
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
|
|
||||||
key int
|
|
||||||
tcpmode int
|
|
||||||
tcpmode_buffersize int
|
|
||||||
tcpmode_maxwin int
|
|
||||||
tcpmode_resend_timems int
|
|
||||||
tcpmode_compress int
|
|
||||||
tcpmode_stat int
|
|
||||||
|
|
||||||
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
|
|
||||||
tcplistenConn *net.TCPListener
|
|
||||||
|
|
||||||
localAddrToConnMap sync.Map
|
|
||||||
localIdToConnMap sync.Map
|
|
||||||
|
|
||||||
sendPacket uint64
|
|
||||||
recvPacket uint64
|
|
||||||
sendPacketSize uint64
|
|
||||||
recvPacketSize uint64
|
|
||||||
localAddrToConnMapSize int
|
|
||||||
localIdToConnMapSize int
|
|
||||||
|
|
||||||
recvcontrol chan int
|
|
||||||
|
|
||||||
pongTime time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
type ClientConn struct {
|
|
||||||
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 {
|
|
||||||
return p.addr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Client) IPAddr() *net.UDPAddr {
|
|
||||||
return p.ipaddr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Client) TargetAddr() string {
|
|
||||||
return p.targetAddr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Client) ServerIPAddr() *net.IPAddr {
|
|
||||||
return p.ipaddrServer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Client) ServerAddr() string {
|
|
||||||
return p.addrServer
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
loggo.Error("Error listening for ICMP packets: %s", err.Error())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
p.conn = conn
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.tcpmode > 0 {
|
|
||||||
go p.AcceptTcp()
|
|
||||||
} else {
|
|
||||||
go p.Accept()
|
|
||||||
}
|
|
||||||
|
|
||||||
recv := make(chan *Packet, 10000)
|
|
||||||
p.recvcontrol = make(chan int, 1)
|
|
||||||
go recvICMP(&p.workResultLock, &p.exit, *p.conn, recv)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer common.CrashLog()
|
|
||||||
|
|
||||||
p.workResultLock.Add(1)
|
|
||||||
defer p.workResultLock.Done()
|
|
||||||
|
|
||||||
for !p.exit {
|
|
||||||
p.checkTimeoutConn()
|
|
||||||
p.ping()
|
|
||||||
p.showNet()
|
|
||||||
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 {
|
|
||||||
|
|
||||||
defer common.CrashLog()
|
|
||||||
|
|
||||||
p.workResultLock.Add(1)
|
|
||||||
defer p.workResultLock.Done()
|
|
||||||
|
|
||||||
loggo.Info("client waiting local accept udp")
|
|
||||||
|
|
||||||
bytes := make([]byte, 10240)
|
|
||||||
|
|
||||||
for !p.exit {
|
|
||||||
p.listenConn.SetReadDeadline(time.Now().Add(time.Millisecond * 100))
|
|
||||||
n, srcaddr, err := p.listenConn.ReadFromUDP(bytes)
|
|
||||||
if err != nil {
|
|
||||||
nerr, ok := err.(net.Error)
|
|
||||||
if !ok || !nerr.Timeout() {
|
|
||||||
loggo.Info("Error read udp %s", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if n <= 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
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.my.Rproto >= 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if packet.my.Key != (int32)(p.key) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if packet.echoId != p.id {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if packet.my.Type == (int32)(MyMsg_PING) {
|
|
||||||
t := time.Time{}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
loggo.Debug("processPacket no conn %s ", packet.my.Id)
|
|
||||||
p.remoteError(packet.my.Id)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
now := common.GetNowUpdateInSecond()
|
|
||||||
clientConn.activeRecvTime = 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
|
|
||||||
}
|
|
||||||
|
|
||||||
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.my.Data))
|
|
||||||
}
|
|
||||||
|
|
||||||
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() {
|
|
||||||
|
|
||||||
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 tmp {
|
|
||||||
if conn.close {
|
|
||||||
loggo.Info("close inactive conn %s %s", id, conn.ipaddr.String())
|
|
||||||
p.close(conn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Client) ping() {
|
|
||||||
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() {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
1
gen.bat
1
gen.bat
|
@ -1 +0,0 @@
|
||||||
protoc --go_out=. *.proto
|
|
18
go.mod
18
go.mod
|
@ -1,18 +0,0 @@
|
||||||
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
29
go.sum
|
@ -1,29 +0,0 @@
|
||||||
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=
|
|
|
@ -3,10 +3,10 @@ package main
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/esrrhs/gohome/common"
|
"github.com/esrrhs/go-engine/src/common"
|
||||||
"github.com/esrrhs/gohome/geoip"
|
"github.com/esrrhs/go-engine/src/geoip"
|
||||||
"github.com/esrrhs/gohome/loggo"
|
"github.com/esrrhs/go-engine/src/loggo"
|
||||||
"github.com/esrrhs/pingtunnel"
|
"github.com/esrrhs/go-engine/src/pingtunnel"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
_ "net/http/pprof"
|
_ "net/http/pprof"
|
||||||
|
@ -37,7 +37,7 @@ Usage:
|
||||||
|
|
||||||
服务器参数server param:
|
服务器参数server param:
|
||||||
|
|
||||||
-key 设置的纯数字密码,默认0, 参数为int类型,范围从0-2147483647,不可夹杂字母特殊符号
|
-key 设置的密码,默认0
|
||||||
Set password, default 0
|
Set password, default 0
|
||||||
|
|
||||||
-nolog 不写日志文件,只打印标准输出,默认0
|
-nolog 不写日志文件,只打印标准输出,默认0
|
228
msg.pb.go
228
msg.pb.go
|
@ -1,228 +0,0 @@
|
||||||
// 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
26
msg.proto
|
@ -1,26 +0,0 @@
|
||||||
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;
|
|
||||||
}
|
|
12
pack.sh
12
pack.sh
|
@ -2,7 +2,7 @@
|
||||||
#set -x
|
#set -x
|
||||||
NAME="pingtunnel"
|
NAME="pingtunnel"
|
||||||
|
|
||||||
export GO111MODULE=on
|
export GO111MODULE=off
|
||||||
|
|
||||||
#go tool dist list
|
#go tool dist list
|
||||||
build_list=$(go tool dist list)
|
build_list=$(go tool dist list)
|
||||||
|
@ -11,7 +11,15 @@ rm pack -rf
|
||||||
rm pack.zip -f
|
rm pack.zip -f
|
||||||
mkdir pack
|
mkdir pack
|
||||||
|
|
||||||
go mod tidy
|
go get -u -v github.com/esrrhs/pingtunnel/...
|
||||||
|
last=`pwd`
|
||||||
|
cd $GOPATH/src/golang.org/x
|
||||||
|
for dir in `ls`; do
|
||||||
|
cd $dir
|
||||||
|
git pull
|
||||||
|
cd ..
|
||||||
|
done
|
||||||
|
cd $last
|
||||||
|
|
||||||
for line in $build_list; do
|
for line in $build_list; do
|
||||||
os=$(echo "$line" | awk -F"/" '{print $1}')
|
os=$(echo "$line" | awk -F"/" '{print $1}')
|
||||||
|
|
119
pingtunnel.go
119
pingtunnel.go
|
@ -1,119 +0,0 @@
|
||||||
package pingtunnel
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"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"
|
|
||||||
"net"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func sendICMP(id int, sequence int, conn icmp.PacketConn, server *net.IPAddr, target string,
|
|
||||||
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: (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 := proto.Marshal(m)
|
|
||||||
if err != nil {
|
|
||||||
loggo.Error("sendICMP Marshal MyMsg error %s %s", server.String(), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
body := &icmp.Echo{
|
|
||||||
ID: id,
|
|
||||||
Seq: sequence,
|
|
||||||
Data: mb,
|
|
||||||
}
|
|
||||||
|
|
||||||
msg := &icmp.Message{
|
|
||||||
Type: (ipv4.ICMPType)(sproto),
|
|
||||||
Code: 0,
|
|
||||||
Body: body,
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes, err := msg.Marshal(nil)
|
|
||||||
if err != nil {
|
|
||||||
loggo.Error("sendICMP Marshal error %s %s", server.String(), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
conn.WriteTo(bytes, server)
|
|
||||||
}
|
|
||||||
|
|
||||||
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 !*exit {
|
|
||||||
conn.SetReadDeadline(time.Now().Add(time.Millisecond * 100))
|
|
||||||
n, srcaddr, err := conn.ReadFrom(bytes)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
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{}
|
|
||||||
err = proto.Unmarshal(bytes[8:n], my)
|
|
||||||
if err != nil {
|
|
||||||
loggo.Debug("Unmarshal MyMsg error: %s", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if my.Magic != (int32)(MyMsg_MAGIC) {
|
|
||||||
loggo.Debug("processPacket data invalid %s", my.Id)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
recv <- &Packet{my: my,
|
|
||||||
src: srcaddr.(*net.IPAddr),
|
|
||||||
echoId: echoId, echoSeq: echoSeq}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Packet struct {
|
|
||||||
my *MyMsg
|
|
||||||
src *net.IPAddr
|
|
||||||
echoId int
|
|
||||||
echoSeq int
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
FRAME_MAX_SIZE int = 888
|
|
||||||
FRAME_MAX_ID int = 1000000
|
|
||||||
)
|
|
|
@ -1,27 +0,0 @@
|
||||||
package pingtunnel
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/golang/protobuf/proto"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test0001(t *testing.T) {
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
proto.Unmarshal(dst[0:4], my1)
|
|
||||||
fmt.Println("my1 = ", my1)
|
|
||||||
|
|
||||||
}
|
|
614
server.go
614
server.go
|
@ -1,614 +0,0 @@
|
||||||
package pingtunnel
|
|
||||||
|
|
||||||
import (
|
|
||||||
"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(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 {
|
|
||||||
exit bool
|
|
||||||
key int
|
|
||||||
workResultLock sync.WaitGroup
|
|
||||||
maxconn int
|
|
||||||
maxprocessthread int
|
|
||||||
maxprocessbuffer int
|
|
||||||
connecttmeout int
|
|
||||||
|
|
||||||
conn *icmp.PacketConn
|
|
||||||
|
|
||||||
localConnMap sync.Map
|
|
||||||
connErrorMap sync.Map
|
|
||||||
|
|
||||||
sendPacket uint64
|
|
||||||
recvPacket uint64
|
|
||||||
sendPacketSize uint64
|
|
||||||
recvPacketSize uint64
|
|
||||||
localConnMapSize int
|
|
||||||
|
|
||||||
processtp *threadpool.ThreadPool
|
|
||||||
recvcontrol chan int
|
|
||||||
}
|
|
||||||
|
|
||||||
type ServerConn struct {
|
|
||||||
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() error {
|
|
||||||
|
|
||||||
conn, err := icmp.ListenPacket("ip4:icmp", "")
|
|
||||||
if err != nil {
|
|
||||||
loggo.Error("Error listening for ICMP packets: %s", err.Error())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
p.conn = conn
|
|
||||||
|
|
||||||
recv := make(chan *Packet, 10000)
|
|
||||||
p.recvcontrol = make(chan int, 1)
|
|
||||||
go recvICMP(&p.workResultLock, &p.exit, *p.conn, recv)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer common.CrashLog()
|
|
||||||
|
|
||||||
p.workResultLock.Add(1)
|
|
||||||
defer p.workResultLock.Done()
|
|
||||||
|
|
||||||
for !p.exit {
|
|
||||||
p.checkTimeoutConn()
|
|
||||||
p.showNet()
|
|
||||||
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.my.Key != (int32)(p.key) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if packet.my.Type == (int32)(MyMsg_PING) {
|
|
||||||
t := time.Time{}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.maxprocessthread > 0 {
|
|
||||||
p.processtp.AddJob((int)(common.HashString(packet.my.Id)), packet)
|
|
||||||
} else {
|
|
||||||
p.processDataPacket(packet)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
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.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) {
|
|
||||||
|
|
||||||
defer common.CrashLog()
|
|
||||||
|
|
||||||
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 {
|
|
||||||
nerr, ok := err.(net.Error)
|
|
||||||
if !ok || !nerr.Timeout() {
|
|
||||||
loggo.Info("ReadFromUDP Error read udp %s", err)
|
|
||||||
conn.close = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
now := common.GetNowUpdateInSecond()
|
|
||||||
conn.activeSendTime = now
|
|
||||||
|
|
||||||
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.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() {
|
|
||||||
|
|
||||||
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 tmp {
|
|
||||||
if conn.tcpmode > 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if conn.close {
|
|
||||||
loggo.Info("close inactive conn %s %s", id, conn.ipaddrTarget.String())
|
|
||||||
p.close(conn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Server) showNet() {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Reference in a new issue