Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26e0fdf605 | ||
|
|
3653ec19cd | ||
|
|
c733a2a4a1 | ||
|
|
b54fa2c6be | ||
|
|
133fe046f8 | ||
|
|
95b46f51d0 |
47
README-ZH.md
@@ -1,7 +1,8 @@
|
||||
# [English](/README.md)|中文
|
||||
网站: [openp2p.cn](https://openp2p.cn)
|
||||
## OpenP2P是什么
|
||||
它是一个开源、免费、轻量级的P2P共享网络。任何设备接入OpenP2P,随时随地访问它们。相比BT网络用来共享文件,OpenP2P网络用来共享带宽。
|
||||
它是一个开源、免费、轻量级的P2P共享网络。你的设备将组成一个私有P2P网络,里面的设备可以直接访问其它成员,或者通过其它成员转发数据间接访问。如果私有网络无法完成通信,将会到公有P2P网络寻找共享节点协助通信。
|
||||
相比BT网络用来共享文件,OpenP2P网络用来共享带宽。
|
||||
我们的目标是:充分利用带宽,利用共享节点转发数据,建设一个远程连接的通用基础设施。
|
||||
|
||||
## 为什么选择OpenP2P
|
||||
@@ -28,38 +29,38 @@ P2P直连可以让你的设备跑满带宽。不论你的设备在任何网络
|
||||
基于OpenP2P只需数行代码,就能让原来只能局域网通信的程序,变成任何内网都能通信
|
||||
|
||||
## 快速入门
|
||||
仅需简单4步就能用起来。
|
||||
下面是一个远程办公例子:在家里连入办公室Windows电脑。
|
||||
### 1.注册
|
||||
前往<https://console.openp2p.cn> 注册新用户,暂无需任何认证
|
||||
|
||||
> :warning: 本文所有命令, Windows环境使用"openp2p.exe", Linux环境使用"./openp2p"
|
||||

|
||||
### 2.安装
|
||||
分别在本地和远程电脑下载后双击运行,一键安装
|
||||
|
||||

|
||||
|
||||
以一个最常见的例子说明OpenP2P如何使用:远程办公,在家里连入办公室Windows电脑。
|
||||
相信很多人在疫情下远程办公是刚需。
|
||||
1. 先确认办公室电脑已开启远程桌面功能(如何开启参考官方说明https://docs.microsoft.com/zh-cn/windows-server/remote/remote-desktop-services/clients/remote-desktop-allow-access)
|
||||
2. 在办公室下载最新的`OpenP2P`[下载页](https://openp2p.cn/),解压出来,在命令行执行
|
||||
```
|
||||
openp2p.exe install -node OFFICEPC1 -user USERNAME1 -password PASSWORD1
|
||||
```
|
||||
|
||||
> :warning: **切记将标记大写的参数改成自己的,3个参数的长度必须>=8个字符**
|
||||
### 3.新建P2P应用
|
||||
|
||||

|
||||
3. 在家里下载最新的OpenP2P,解压出来,在命令行执行
|
||||
```
|
||||
openp2p.exe -d -node HOMEPC123 -user USERNAME1 -password PASSWORD1 -appname WindowsRemote -peernode OFFICEPC1 -dstip 127.0.0.1 -dstport 3389 -srcport 23389 -protocol tcp
|
||||
```
|
||||
> :warning: **切记将标记大写的参数改成自己的**
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### 4.使用P2P应用
|
||||
在“MyHomePC”设备上能看到刚才创建的P2P应用,连接下图显示的“本地监听端口”即可。
|
||||
|
||||

|
||||
|
||||
在家里Windows电脑,按Win+R输入mstsc打开远程桌面,输入127.0.0.1:23389 /admin
|
||||
|
||||

|
||||

|
||||
`LISTEN ON PORT 23389 START` 看到这行日志表示P2PApp建立成功,监听23389端口。只需连接本机的127.0.0.1:23389就相当于连接公司Windows电脑的3389端口。
|
||||
|
||||
4. 在家里Windows电脑,按Win+R输入mstsc打开远程桌面,输入127.0.0.1:23389 /admin
|
||||

|
||||
|
||||

|
||||
|
||||
## 详细使用说明
|
||||
[这里](/USAGE-ZH.md)详细介绍如何使用和运行参数
|
||||
[这里](/USAGE-ZH.md)介绍如何手动运行
|
||||
|
||||
## 典型应用场景
|
||||
特别适合大流量的内网访问
|
||||
|
||||
59
README.md
@@ -1,7 +1,8 @@
|
||||
# English|[中文](/README-ZH.md)
|
||||
Website: [openp2p.cn](https://openp2p.cn)
|
||||
## What is OpenP2P
|
||||
It is an open source, free, and lightweight P2P sharing network. As long as any device joins in, you can access them anywhere. Compared with the BT network used to share files, the OpenP2P network is used to share bandwidth.
|
||||
It is an open source, free, and lightweight P2P sharing network. Your devices will form a private P2P network, in which devices can directly access other members, or indirectly access through other members forwarding data.
|
||||
If the private network cannot complete the communication, it will go to the public P2P network to find a shared node to assist in the communication. Compared with the BT network used to share files, the OpenP2P network is used to share bandwidth.
|
||||
Our goal is to make full use of bandwidth, use shared nodes to relay data, and build a common infrastructure for remote connections.
|
||||
## Why OpenP2P
|
||||
### 1. Free
|
||||
@@ -30,52 +31,40 @@ P2P direct connection lets your devices make good use of bandwidth. Your device
|
||||
Your applicaiton can call OpenP2P with a few code to make any internal networks communicate with each other.
|
||||
|
||||
## Get Started
|
||||
A common scenario to introduce OpenP2P: remote work. At home connects to office's Linux PC .
|
||||
Under the outbreak of covid-19 pandemic, surely remote work becomes a fundamental demand.
|
||||
Just 4 simple steps to use.
|
||||
Here's an example of remote work: connecting to an office Windows computer at home.
|
||||
|
||||
### 1.Register
|
||||
Go to <https://console.openp2p.cn> register a new user
|
||||
|
||||
> :warning: all commands in this doc, Windows env uses "openp2p.exe", Linux env uses "./openp2p"
|
||||
|
||||

|
||||
### 2.Install
|
||||
Download on local and remote computers and double-click to run, one-click installation
|
||||
|
||||
1. Make sure your office device(Linux) has opened the access of ssh.
|
||||
```
|
||||
netstat -nl | grep 22
|
||||
```
|
||||
Output sample
|
||||

|
||||

|
||||
|
||||
2. Download the latest version of `OpenP2P` [Download Page](https://openp2p.cn/),unzip the downloaded package, and execute below command line.
|
||||
```
|
||||
tar xzvf ${PackageName}
|
||||
./openp2p install -node OFFICEPC1 -user USERNAME1 -password PASSWORD1
|
||||
```
|
||||
### 3.New P2PApp
|
||||
|
||||
> :warning: **Must change the parameters marked in UPPERCASE to your own. These 3 parameters must >= 8 charaters**
|
||||

|
||||
|
||||
Output sample
|
||||

|
||||

|
||||
|
||||
3. Download OpenP2P on your home device,unzip and execute below command line.
|
||||
```
|
||||
openp2p.exe -d -node HOMEPC123 -user USERNAME1 -password PASSWORD1 -appname OfficeSSH -peernode OFFICEPC1 -dstip 127.0.0.1 -dstport 22 -srcport 22022 -protocol tcp
|
||||
```
|
||||
|
||||
> :warning: **Must change the parameters marked in UPPERCASE to your own**
|
||||

|
||||
|
||||
Output sample
|
||||

|
||||
The log of `LISTEN ON PORT 22022 START` indicates P2PApp runs successfully on your home device, listing port is 22022. Once connects to local ip:port,127.0.0.1:22022, it means the home device has conneccted to the office device's port, 22.
|
||||

|
||||
### 4.Use P2PApp
|
||||
You can see the P2P application you just created on the "MyHomePC" device, just connect to the "local listening port" shown in the figure below.
|
||||
|
||||

|
||||
|
||||
4. Test the connection between office device and home device.In your home deivce, run SSH to login the office device.
|
||||
```
|
||||
ssh -p22022 root@127.0.0.1:22022
|
||||
```
|
||||

|
||||
On MyHomePC, press Win+R and enter MSTSC to open the remote desktop, input `127.0.0.1:23389 /admin`
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
|
||||
## Usage
|
||||
[Here](/USAGE.md) is a detailed description of how to use and running parameters
|
||||
[Here](/USAGE.md) describes how to run manually
|
||||
|
||||
## Scenarios
|
||||
Especially suitable for large traffic intranet access.
|
||||
|
||||
36
USAGE-ZH.md
@@ -1,36 +1,39 @@
|
||||
# 详细运行参数说明
|
||||
# 手动运行说明
|
||||
大部分情况通过<https://console.openp2p.cn> 操作即可。有些情况需要手动运行
|
||||
> :warning: 本文所有命令, Windows环境使用"openp2p.exe", Linux环境使用"./openp2p"
|
||||
|
||||
|
||||
## 安装和监听
|
||||
```
|
||||
./openp2p install -node OFFICEPC1 -user USERNAME1 -password PASSWORD1
|
||||
./openp2p install -node OFFICEPC1 -token TOKEN
|
||||
或
|
||||
./openp2p -d -node OFFICEPC1 -user USERNAME1 -password PASSWORD1
|
||||
./openp2p -d -node OFFICEPC1 -token TOKEN
|
||||
# 注意Windows系统把“./openp2p” 换成“openp2p.exe”
|
||||
```
|
||||
>* install: 安装模式【推荐】,会安装成系统服务,这样它就能随系统自动启动
|
||||
>* -d: daemon模式。发现worker进程意外退出就会自动启动新的worker进程
|
||||
>* -node: 独一无二的节点名字,唯一标识
|
||||
>* -user: 独一无二的用户名字,该节点属于这个user
|
||||
>* -password: 密码
|
||||
>* -sharebandwidth: 作为共享节点时提供带宽,默认10mbps. 如果是光纤大带宽,设置越大效果越好. -1表示不共享,该节点只在私有的P2P网络使用。不加入共享的P2P网络,这样也意味着无法使用别人的共享节点
|
||||
>* -token: 在<console.openp2p.cn>“我的”里面找到
|
||||
>* -sharebandwidth: 作为共享节点时提供带宽,默认10mbps. 如果是光纤大带宽,设置越大效果越好. 0表示不共享,该节点只在私有的P2P网络使用。不加入共享的P2P网络,这样也意味着无法使用别人的共享节点
|
||||
>* -loglevel: 需要查看更多调试日志,设置0;默认是1
|
||||
|
||||
### 在docker容器里运行openp2p
|
||||
我们暂时还没提供官方docker镜像,你可以在随便一个容器里运行
|
||||
```
|
||||
nohup ./openp2p -d -node OFFICEPC1 -token TOKEN &
|
||||
#这里由于一般的镜像都精简过,install系统服务会失败,所以使用直接daemon模式后台运行
|
||||
```
|
||||
## 连接
|
||||
```
|
||||
./openp2p -d -node HOMEPC123 -user USERNAME1 -password PASSWORD1 -appname OfficeWindowsRemote -peernode OFFICEPC1 -dstip 127.0.0.1 -dstport 3389 -srcport 23389 -protocol tcp
|
||||
./openp2p -d -node HOMEPC123 -token TOKEN -appname OfficeWindowsRemote -peernode OFFICEPC1 -dstip 127.0.0.1 -dstport 3389 -srcport 23389
|
||||
使用配置文件,建立多个P2PApp
|
||||
./openp2p -d -f
|
||||
./openp2p -f
|
||||
./openp2p -d
|
||||
```
|
||||
>* -appname: 这个P2P应用名字
|
||||
>* -peernode: 目标节点名字
|
||||
>* -dstip: 目标服务地址,默认本机127.0.0.1
|
||||
>* -dstport: 目标服务端口,常见的如windows远程桌面3389,Linux ssh 22
|
||||
>* -protocol: 目标服务协议 tcp、udp
|
||||
>* -peeruser: 目标用户,如果是同一个用户下的节点,则无需设置
|
||||
>* -peerpassword: 目标密码,如果是同一个用户下的节点,则无需设置
|
||||
|
||||
## 配置文件
|
||||
一般保存在当前目录,安装模式下会保存到 `C:\Program Files\OpenP2P\config.json` 或 `/usr/local/openp2p/config.json`
|
||||
@@ -41,11 +44,10 @@
|
||||
{
|
||||
"network": {
|
||||
"Node": "hhd1207-222",
|
||||
"User": "USERNAME1",
|
||||
"Password": "PASSWORD1",
|
||||
"ShareBandwidth": -1,
|
||||
"Token": "TOKEN",
|
||||
"ShareBandwidth": 0,
|
||||
"ServerHost": "api.openp2p.cn",
|
||||
"ServerPort": 27182,
|
||||
"ServerPort": 27183,
|
||||
"UDPPort1": 27182,
|
||||
"UDPPort2": 27183
|
||||
},
|
||||
@@ -57,8 +59,6 @@
|
||||
"PeerNode": "OFFICEPC1",
|
||||
"DstPort": 3389,
|
||||
"DstHost": "localhost",
|
||||
"PeerUser": "",
|
||||
"PeerPassword": ""
|
||||
},
|
||||
{
|
||||
"AppName": "OfficeServerSSH",
|
||||
@@ -67,8 +67,6 @@
|
||||
"PeerNode": "OFFICEPC1",
|
||||
"DstPort": 22,
|
||||
"DstHost": "192.168.1.5",
|
||||
"PeerUser": "",
|
||||
"PeerPassword": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
38
USAGE.md
@@ -1,37 +1,42 @@
|
||||
# Parameters details
|
||||
|
||||
|
||||
# Parameters details
|
||||
In most cases, you can operate it through <https://console.openp2p.cn>. In some cases it is necessary to run manually
|
||||
> :warning: all commands in this doc, Windows env uses "openp2p.exe", Linux env uses "./openp2p"
|
||||
|
||||
|
||||
## Install and Listen
|
||||
```
|
||||
./openp2p install -node OFFICEPC1 -user USERNAME1 -password PASSWORD1
|
||||
./openp2p install -node OFFICEPC1 -token TOKEN
|
||||
Or
|
||||
./openp2p -d -node OFFICEPC1 -user USERNAME1 -password PASSWORD1
|
||||
./openp2p -d -node OFFICEPC1 -token TOKEN
|
||||
|
||||
```
|
||||
>* install: [recommand] will install as system service. So it will autorun when system booting.
|
||||
>* -d: daemon mode run once. When the worker process is found to exit unexpectedly, a new worker process will be automatically started
|
||||
>* -node: Unique node name, unique identification
|
||||
>* -user: Unique user name, the node belongs to this user
|
||||
>* -password: Password
|
||||
>* -sharebandwidth: Provides bandwidth when used as a shared node, the default is 10mbps. If it is a large bandwidth of optical fiber, the larger the setting, the better the effect. -1 means not shared, the node is only used in a private P2P network. Do not join the shared P2P network, which also means that you CAN NOT use other people’s shared nodes
|
||||
>* -token: See <console.openp2p.cn> "Profile"
|
||||
>* -sharebandwidth: Provides bandwidth when used as a shared node, the default is 10mbps. If it is a large bandwidth of optical fiber, the larger the setting, the better the effect. 0 means not shared, the node is only used in a private P2P network. Do not join the shared P2P network, which also means that you CAN NOT use other people’s shared nodes
|
||||
>* -loglevel: Need to view more debug logs, set 0; the default is 1
|
||||
|
||||
### Run in Docker container
|
||||
We don't provide official docker image yet, you can run it in any container
|
||||
```
|
||||
nohup ./openp2p -d -node OFFICEPC1 -token TOKEN &
|
||||
# Since many docker images have been simplified, the install system service will fail, so the daemon mode is used to run in the background
|
||||
```
|
||||
|
||||
## Connect
|
||||
```
|
||||
./openp2p -d -node HOMEPC123 -user USERNAME1 -password PASSWORD1 -appname OfficeWindowsRemote -peernode OFFICEPC1 -dstip 127.0.0.1 -dstport 3389 -srcport 23389 -protocol tcp
|
||||
./openp2p -d -node HOMEPC123 -token TOKEN -appname OfficeWindowsRemote -peernode OFFICEPC1 -dstip 127.0.0.1 -dstport 3389 -srcport 23389
|
||||
Create multiple P2PApp by config file
|
||||
./openp2p -d -f
|
||||
./openp2p -f
|
||||
./openp2p -d
|
||||
```
|
||||
>* -appname: This P2PApp name
|
||||
>* -peernode: Target node name
|
||||
>* -dstip: Target service address, default local 127.0.0.1
|
||||
>* -dstport: Target service port, such as windows remote desktop 3389, Linux ssh 22
|
||||
>* -protocol: Target service protocol tcp, udp
|
||||
>* -peeruser: The target user, if it is a node under the same user, no need to set
|
||||
>* -peerpassword: The target password, if it is a node under the same user, no need to set
|
||||
|
||||
## Config file
|
||||
Generally saved in the current directory, in installation mode it will be saved to `C:\Program Files\OpenP2P\config.json` or `/usr/local/openp2p/config.json`
|
||||
@@ -42,11 +47,10 @@ Configuration example
|
||||
{
|
||||
"network": {
|
||||
"Node": "hhd1207-222",
|
||||
"User": "USERNAME1",
|
||||
"Password": "PASSWORD1",
|
||||
"ShareBandwidth": -1,
|
||||
"Token": "TOKEN",
|
||||
"ShareBandwidth": 0,
|
||||
"ServerHost": "api.openp2p.cn",
|
||||
"ServerPort": 27182,
|
||||
"ServerPort": 27183,
|
||||
"UDPPort1": 27182,
|
||||
"UDPPort2": 27183
|
||||
},
|
||||
@@ -58,8 +62,6 @@ Configuration example
|
||||
"PeerNode": "OFFICEPC1",
|
||||
"DstPort": 3389,
|
||||
"DstHost": "localhost",
|
||||
"PeerUser": "",
|
||||
"PeerPassword": ""
|
||||
},
|
||||
{
|
||||
"AppName": "OfficeServerSSH",
|
||||
@@ -68,8 +70,6 @@ Configuration example
|
||||
"PeerNode": "OFFICEPC1",
|
||||
"DstPort": 22,
|
||||
"DstHost": "192.168.1.5",
|
||||
"PeerUser": "",
|
||||
"PeerPassword": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -7,39 +7,39 @@ import (
|
||||
|
||||
// BandwidthLimiter ...
|
||||
type BandwidthLimiter struct {
|
||||
freeFlowTime time.Time
|
||||
bandwidth int // mbps
|
||||
freeFlow int // bytes
|
||||
maxFreeFlow int // bytes
|
||||
freeFlowMtx sync.Mutex
|
||||
ts time.Time
|
||||
bw int // mbps
|
||||
freeBytes int // bytes
|
||||
maxFreeBytes int // bytes
|
||||
mtx sync.Mutex
|
||||
}
|
||||
|
||||
// mbps
|
||||
func newBandwidthLimiter(bw int) *BandwidthLimiter {
|
||||
return &BandwidthLimiter{
|
||||
bandwidth: bw,
|
||||
freeFlowTime: time.Now(),
|
||||
maxFreeFlow: bw * 1024 * 1024 / 8,
|
||||
freeFlow: bw * 1024 * 1024 / 8,
|
||||
bw: bw,
|
||||
ts: time.Now(),
|
||||
maxFreeBytes: bw * 1024 * 1024 / 8,
|
||||
freeBytes: bw * 1024 * 1024 / 8,
|
||||
}
|
||||
}
|
||||
|
||||
// Add ...
|
||||
func (bl *BandwidthLimiter) Add(bytes int) {
|
||||
if bl.bandwidth <= 0 {
|
||||
if bl.bw <= 0 {
|
||||
return
|
||||
}
|
||||
bl.freeFlowMtx.Lock()
|
||||
defer bl.freeFlowMtx.Unlock()
|
||||
bl.mtx.Lock()
|
||||
defer bl.mtx.Unlock()
|
||||
// calc free flow 1000*1000/1024/1024=0.954; 1024*1024/1000/1000=1.048
|
||||
bl.freeFlow += int(time.Now().Sub(bl.freeFlowTime) * time.Duration(bl.bandwidth) / 8 / 954)
|
||||
if bl.freeFlow > bl.maxFreeFlow {
|
||||
bl.freeFlow = bl.maxFreeFlow
|
||||
bl.freeBytes += int(time.Since(bl.ts) * time.Duration(bl.bw) / 8 / 954)
|
||||
if bl.freeBytes > bl.maxFreeBytes {
|
||||
bl.freeBytes = bl.maxFreeBytes
|
||||
}
|
||||
bl.freeFlow -= bytes
|
||||
bl.freeFlowTime = time.Now()
|
||||
if bl.freeFlow < 0 {
|
||||
bl.freeBytes -= bytes
|
||||
bl.ts = time.Now()
|
||||
if bl.freeBytes < 0 {
|
||||
// sleep for the overflow
|
||||
time.Sleep(time.Millisecond * time.Duration(-bl.freeFlow/(bl.bandwidth*1048/8)))
|
||||
time.Sleep(time.Millisecond * time.Duration(-bl.freeBytes/(bl.bw*1048/8)))
|
||||
}
|
||||
}
|
||||
|
||||
10
common.go
@@ -7,8 +7,10 @@ import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"time"
|
||||
)
|
||||
@@ -148,3 +150,11 @@ func execOutput(name string, args ...string) string {
|
||||
cmdGetOsName.Run()
|
||||
return cmdOut.String()
|
||||
}
|
||||
|
||||
func defaultNodeName() string {
|
||||
name, _ := os.Hostname()
|
||||
for len(name) < 8 {
|
||||
name = fmt.Sprintf("%s%d", name, rand.Int()%10)
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
131
config.go
@@ -2,7 +2,9 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
@@ -13,14 +15,14 @@ const IntValueNotSet int = -99999999
|
||||
|
||||
type AppConfig struct {
|
||||
// required
|
||||
AppName string
|
||||
Protocol string
|
||||
SrcPort int
|
||||
PeerNode string
|
||||
DstPort int
|
||||
DstHost string
|
||||
PeerUser string
|
||||
PeerPassword string
|
||||
AppName string
|
||||
Protocol string
|
||||
SrcPort int
|
||||
PeerNode string
|
||||
DstPort int
|
||||
DstHost string
|
||||
PeerUser string
|
||||
Enabled int // default:1
|
||||
// runtime info
|
||||
peerToken uint64
|
||||
peerNatType int
|
||||
@@ -28,30 +30,48 @@ type AppConfig struct {
|
||||
peerConeNatPort int
|
||||
retryNum int
|
||||
retryTime time.Time
|
||||
nextRetryTime time.Time
|
||||
shareBandwidth int
|
||||
}
|
||||
|
||||
// TODO: add loglevel, maxlogfilesize
|
||||
type Config struct {
|
||||
Network NetworkConfig `json:"network"`
|
||||
Apps []AppConfig `json:"apps"`
|
||||
Apps []*AppConfig `json:"apps"`
|
||||
LogLevel int
|
||||
|
||||
mtx sync.Mutex
|
||||
}
|
||||
|
||||
func (c *Config) add(app AppConfig) {
|
||||
func (c *Config) switchApp(app AppConfig, enabled int) {
|
||||
c.mtx.Lock()
|
||||
defer c.mtx.Unlock()
|
||||
if app.SrcPort == 0 || app.DstPort == 0 {
|
||||
return
|
||||
}
|
||||
for i := 0; i < len(c.Apps); i++ {
|
||||
if c.Apps[i].Protocol == app.Protocol && c.Apps[i].SrcPort == app.SrcPort {
|
||||
c.Apps[i].Enabled = enabled
|
||||
c.Apps[i].retryNum = 0
|
||||
c.Apps[i].nextRetryTime = time.Now()
|
||||
return
|
||||
}
|
||||
}
|
||||
c.Apps = append(c.Apps, app)
|
||||
}
|
||||
|
||||
func (c *Config) add(app AppConfig, override bool) {
|
||||
c.mtx.Lock()
|
||||
defer c.mtx.Unlock()
|
||||
if app.SrcPort == 0 || app.DstPort == 0 {
|
||||
gLog.Println(LevelERROR, "invalid app ", app)
|
||||
return
|
||||
}
|
||||
if override {
|
||||
for i := 0; i < len(c.Apps); i++ {
|
||||
if c.Apps[i].Protocol == app.Protocol && c.Apps[i].SrcPort == app.SrcPort {
|
||||
c.Apps[i] = &app // override it
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
c.Apps = append(c.Apps, &app)
|
||||
}
|
||||
|
||||
func (c *Config) delete(app AppConfig) {
|
||||
@@ -85,7 +105,7 @@ func (c *Config) load() error {
|
||||
defer c.mtx.Unlock()
|
||||
data, err := ioutil.ReadFile("config.json")
|
||||
if err != nil {
|
||||
gLog.Println(LevelERROR, "read config.json error:", err)
|
||||
// gLog.Println(LevelERROR, "read config.json error:", err)
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal(data, &c)
|
||||
@@ -97,12 +117,11 @@ func (c *Config) load() error {
|
||||
|
||||
type NetworkConfig struct {
|
||||
// local info
|
||||
Token uint64
|
||||
Node string
|
||||
User string
|
||||
Password string
|
||||
localIP string
|
||||
ipv6 string
|
||||
hostName string
|
||||
mac string
|
||||
os string
|
||||
publicIP string
|
||||
@@ -114,3 +133,81 @@ type NetworkConfig struct {
|
||||
UDPPort1 int
|
||||
UDPPort2 int
|
||||
}
|
||||
|
||||
func parseParams() {
|
||||
serverHost := flag.String("serverhost", "api.openp2p.cn", "server host ")
|
||||
// serverHost := flag.String("serverhost", "127.0.0.1", "server host ") // for debug
|
||||
node := flag.String("node", "", "node name. 8-31 characters")
|
||||
token := flag.Uint64("token", 0, "token")
|
||||
peerNode := flag.String("peernode", "", "peer node name that you want to connect")
|
||||
dstIP := flag.String("dstip", "127.0.0.1", "destination ip ")
|
||||
dstPort := flag.Int("dstport", 0, "destination port ")
|
||||
srcPort := flag.Int("srcport", 0, "source port ")
|
||||
protocol := flag.String("protocol", "tcp", "tcp or udp")
|
||||
appName := flag.String("appname", "", "app name")
|
||||
shareBandwidth := flag.Int("sharebandwidth", 10, "N mbps share bandwidth limit, private network no limit")
|
||||
daemonMode := flag.Bool("d", false, "daemonMode")
|
||||
logLevel := flag.Int("loglevel", 1, "0:debug 1:info 2:warn 3:error")
|
||||
flag.Parse()
|
||||
|
||||
config := AppConfig{Enabled: 1}
|
||||
config.PeerNode = *peerNode
|
||||
config.DstHost = *dstIP
|
||||
config.DstPort = *dstPort
|
||||
config.SrcPort = *srcPort
|
||||
config.Protocol = *protocol
|
||||
config.AppName = *appName
|
||||
gConf.load()
|
||||
if config.SrcPort != 0 {
|
||||
gConf.add(config, true)
|
||||
}
|
||||
gConf.mtx.Lock()
|
||||
|
||||
// spec paramters in commandline will always be used
|
||||
flag.Visit(func(f *flag.Flag) {
|
||||
if f.Name == "sharebandwidth" {
|
||||
gConf.Network.ShareBandwidth = *shareBandwidth
|
||||
}
|
||||
if f.Name == "node" {
|
||||
gConf.Network.Node = *node
|
||||
}
|
||||
if f.Name == "serverhost" {
|
||||
gConf.Network.ServerHost = *serverHost
|
||||
}
|
||||
if f.Name == "loglevel" {
|
||||
gConf.LogLevel = *logLevel
|
||||
}
|
||||
})
|
||||
|
||||
if gConf.Network.ServerHost == "" {
|
||||
gConf.Network.ServerHost = *serverHost
|
||||
}
|
||||
if gConf.Network.Node == "" {
|
||||
if *node == "" { // config and param's node both empty
|
||||
hostname := defaultNodeName()
|
||||
node = &hostname
|
||||
}
|
||||
gConf.Network.Node = *node
|
||||
}
|
||||
if *token != 0 {
|
||||
gConf.Network.Token = *token
|
||||
}
|
||||
if gConf.LogLevel == IntValueNotSet {
|
||||
gConf.LogLevel = *logLevel
|
||||
}
|
||||
if gConf.Network.ShareBandwidth == IntValueNotSet {
|
||||
gConf.Network.ShareBandwidth = *shareBandwidth
|
||||
}
|
||||
|
||||
gConf.Network.ServerPort = 27183
|
||||
gConf.Network.UDPPort1 = 27182
|
||||
gConf.Network.UDPPort2 = 27183
|
||||
gLog.setLevel(LogLevel(gConf.LogLevel))
|
||||
gConf.mtx.Unlock()
|
||||
gConf.save()
|
||||
if *daemonMode {
|
||||
d := daemon{}
|
||||
d.run()
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
138
daemon.go
@@ -5,7 +5,9 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/kardianos/service"
|
||||
@@ -64,7 +66,7 @@ func (d *daemon) run() {
|
||||
}
|
||||
for {
|
||||
// start worker
|
||||
gLog.Println(LevelINFO, "start worker process")
|
||||
gLog.Println(LevelINFO, "start worker process, args:", args)
|
||||
execSpec := &os.ProcAttr{Files: []*os.File{os.Stdin, os.Stdout, os.Stderr}}
|
||||
p, err := os.StartProcess(binPath, args, execSpec)
|
||||
if err != nil {
|
||||
@@ -104,60 +106,78 @@ func (d *daemon) Control(ctrlComm string, exeAbsPath string, args []string) erro
|
||||
|
||||
// examples:
|
||||
// listen:
|
||||
// ./openp2p install -node hhd1207-222 -user tenderiron -password 13760636579 -sharebandwidth 0
|
||||
// ./openp2p install -node hhd1207-222 -token YOUR-TOKEN -sharebandwidth 0
|
||||
// listen and build p2papp:
|
||||
// ./openp2p install -node hhd1207-222 -user tenderiron -password 13760636579 -sharebandwidth 0 -peernode hhdhome-n1 -dstip 127.0.0.1 -dstport 50022 -protocol tcp -srcport 22
|
||||
// ./openp2p install -node hhd1207-222 -token YOUR-TOKEN -sharebandwidth 0 -peernode hhdhome-n1 -dstip 127.0.0.1 -dstport 50022 -protocol tcp -srcport 22
|
||||
func install() {
|
||||
gLog = InitLogger(filepath.Dir(os.Args[0]), "openp2p-install", LevelDEBUG, 1024*1024, LogConsole)
|
||||
gLog.Println(LevelINFO, "openp2p start. version: ", OpenP2PVersion)
|
||||
gLog.Println(LevelINFO, "Contact: QQ Group: 16947733, Email: openp2p.cn@gmail.com")
|
||||
gLog.Println(LevelINFO, "install start")
|
||||
defer gLog.Println(LevelINFO, "install end")
|
||||
// auto uninstall
|
||||
err := os.MkdirAll(defaultInstallPath, 0775)
|
||||
|
||||
if err != nil {
|
||||
gLog.Printf(LevelERROR, "MkdirAll %s error:%s", defaultInstallPath, err)
|
||||
return
|
||||
}
|
||||
err = os.Chdir(defaultInstallPath)
|
||||
if err != nil {
|
||||
gLog.Println(LevelERROR, "cd error:", err)
|
||||
return
|
||||
}
|
||||
|
||||
uninstall()
|
||||
// save config file
|
||||
installFlag := flag.NewFlagSet("install", flag.ExitOnError)
|
||||
serverHost := installFlag.String("serverhost", "api.openp2p.cn", "server host ")
|
||||
// serverHost := flag.String("serverhost", "127.0.0.1", "server host ") // for debug
|
||||
user := installFlag.String("user", "", "user name. 8-31 characters")
|
||||
node := installFlag.String("node", "", "node name. 8-31 characters")
|
||||
password := installFlag.String("password", "", "user password. 8-31 characters")
|
||||
token := installFlag.Uint64("token", 0, "token")
|
||||
node := installFlag.String("node", "", "node name. 8-31 characters. if not set, it will be hostname")
|
||||
peerNode := installFlag.String("peernode", "", "peer node name that you want to connect")
|
||||
peerUser := installFlag.String("peeruser", "", "peer node user (default peeruser=user)")
|
||||
peerPassword := installFlag.String("peerpassword", "", "peer node password (default peerpassword=password)")
|
||||
dstIP := installFlag.String("dstip", "127.0.0.1", "destination ip ")
|
||||
dstPort := installFlag.Int("dstport", 0, "destination port ")
|
||||
srcPort := installFlag.Int("srcport", 0, "source port ")
|
||||
protocol := installFlag.String("protocol", "tcp", "tcp or udp")
|
||||
appName := flag.String("appname", "", "app name")
|
||||
installFlag.Bool("noshare", false, "deprecated. uses -sharebandwidth -1")
|
||||
shareBandwidth := installFlag.Int("sharebandwidth", 10, "N mbps share bandwidth limit, private node no limit")
|
||||
shareBandwidth := installFlag.Int("sharebandwidth", 10, "N mbps share bandwidth limit, private network no limit")
|
||||
logLevel := installFlag.Int("loglevel", 1, "0:debug 1:info 2:warn 3:error")
|
||||
installFlag.Parse(os.Args[2:])
|
||||
checkParams(*node, *user, *password)
|
||||
|
||||
gConf.load() // load old config. otherwise will clear all apps
|
||||
gConf.LogLevel = *logLevel
|
||||
gConf.Network.ServerHost = *serverHost
|
||||
gConf.Network.User = *user
|
||||
gConf.Network.Node = *node
|
||||
gConf.Network.Password = *password
|
||||
gConf.Network.ServerPort = 27182
|
||||
gConf.Network.Token = *token
|
||||
if *node != "" {
|
||||
if len(*node) < 8 {
|
||||
gLog.Println(LevelERROR, ErrNodeTooShort)
|
||||
os.Exit(9)
|
||||
}
|
||||
gConf.Network.Node = *node
|
||||
} else {
|
||||
if gConf.Network.Node == "" { // if node name not set. use os.Hostname
|
||||
gConf.Network.Node = defaultNodeName()
|
||||
}
|
||||
}
|
||||
gConf.Network.ServerPort = 27183
|
||||
gConf.Network.UDPPort1 = 27182
|
||||
gConf.Network.UDPPort2 = 27183
|
||||
gConf.Network.ShareBandwidth = *shareBandwidth
|
||||
config := AppConfig{}
|
||||
config := AppConfig{Enabled: 1}
|
||||
config.PeerNode = *peerNode
|
||||
config.PeerUser = *peerUser
|
||||
config.PeerPassword = *peerPassword
|
||||
config.DstHost = *dstIP
|
||||
config.DstPort = *dstPort
|
||||
config.SrcPort = *srcPort
|
||||
config.Protocol = *protocol
|
||||
config.AppName = *appName
|
||||
gConf.add(config)
|
||||
os.MkdirAll(defaultInstallPath, 0775)
|
||||
err := os.Chdir(defaultInstallPath)
|
||||
if err != nil {
|
||||
gLog.Println(LevelERROR, "cd error:", err)
|
||||
if config.SrcPort != 0 {
|
||||
gConf.add(config, true)
|
||||
}
|
||||
gConf.save()
|
||||
|
||||
targetPath := filepath.Join(defaultInstallPath, defaultBinName)
|
||||
d := daemon{}
|
||||
// copy files
|
||||
|
||||
targetPath := filepath.Join(defaultInstallPath, defaultBinName)
|
||||
binPath, _ := os.Executable()
|
||||
src, errFiles := os.Open(binPath) // can not use args[0], on Windows call openp2p is ok(=openp2p.exe)
|
||||
if errFiles != nil {
|
||||
@@ -180,14 +200,9 @@ func install() {
|
||||
dst.Close()
|
||||
|
||||
// install system service
|
||||
d := daemon{}
|
||||
|
||||
// args := []string{""}
|
||||
gLog.Println(LevelINFO, "targetPath:", targetPath)
|
||||
err = d.Control("install", targetPath, []string{"-d"})
|
||||
if err != nil {
|
||||
gLog.Println(LevelERROR, "install system service error:", err)
|
||||
} else {
|
||||
if err == nil {
|
||||
gLog.Println(LevelINFO, "install system service ok.")
|
||||
}
|
||||
time.Sleep(time.Second * 2)
|
||||
@@ -199,11 +214,45 @@ func install() {
|
||||
}
|
||||
}
|
||||
|
||||
func installByFilename() {
|
||||
params := strings.Split(filepath.Base(os.Args[0]), "-")
|
||||
if len(params) < 4 {
|
||||
return
|
||||
}
|
||||
serverHost := params[1]
|
||||
token := params[2]
|
||||
gLog.Println(LevelINFO, "install start")
|
||||
targetPath := os.Args[0]
|
||||
args := []string{"install"}
|
||||
args = append(args, "-serverhost")
|
||||
args = append(args, serverHost)
|
||||
args = append(args, "-token")
|
||||
args = append(args, token)
|
||||
env := os.Environ()
|
||||
cmd := exec.Command(targetPath, args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Env = env
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
gLog.Println(LevelERROR, "install by filename, start process error:", err)
|
||||
return
|
||||
}
|
||||
gLog.Println(LevelINFO, "install end")
|
||||
fmt.Println("Press the Any Key to exit")
|
||||
fmt.Scanln()
|
||||
os.Exit(0)
|
||||
}
|
||||
func uninstall() {
|
||||
gLog = InitLogger(filepath.Dir(os.Args[0]), "openp2p-install", LevelDEBUG, 1024*1024, LogFileAndConsole)
|
||||
gLog.Println(LevelINFO, "uninstall start")
|
||||
defer gLog.Println(LevelINFO, "uninstall end")
|
||||
d := daemon{}
|
||||
d.Control("stop", "", nil)
|
||||
err := d.Control("uninstall", "", nil)
|
||||
err := d.Control("stop", "", nil)
|
||||
if err != nil { // service maybe not install
|
||||
return
|
||||
}
|
||||
err = d.Control("uninstall", "", nil)
|
||||
if err != nil {
|
||||
gLog.Println(LevelERROR, "uninstall system service error:", err)
|
||||
} else {
|
||||
@@ -211,21 +260,6 @@ func uninstall() {
|
||||
}
|
||||
binPath := filepath.Join(defaultInstallPath, defaultBinName)
|
||||
os.Remove(binPath + "0")
|
||||
os.Rename(binPath, binPath+"0")
|
||||
os.RemoveAll(defaultInstallPath)
|
||||
}
|
||||
|
||||
func checkParams(node, user, password string) {
|
||||
if len(node) < 8 {
|
||||
gLog.Println(LevelERROR, "node name too short, it must >=8 charaters")
|
||||
os.Exit(9)
|
||||
}
|
||||
if len(user) < 8 {
|
||||
gLog.Println(LevelERROR, "user name too short, it must >=8 charaters")
|
||||
os.Exit(9)
|
||||
}
|
||||
if len(password) < 8 {
|
||||
gLog.Println(LevelERROR, "password too short, it must >=8 charaters")
|
||||
os.Exit(9)
|
||||
}
|
||||
os.Remove(binPath)
|
||||
// os.RemoveAll(defaultInstallPath) // reserve config.json
|
||||
}
|
||||
|
||||
BIN
doc/images/afterconnect_en.png
Normal file
|
After Width: | Height: | Size: 5.6 MiB |
BIN
doc/images/devices.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
doc/images/devices_en.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
doc/images/install.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
doc/images/install_en.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
doc/images/mstscconnect_en.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
doc/images/newapp.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
doc/images/newapp_en.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
doc/images/newappedit.png
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
doc/images/newappedit_en.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
doc/images/p2pappok.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
doc/images/p2pappok_en.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 98 KiB |
BIN
doc/images/register.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
doc/images/register_en.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
doc/images/stillrun.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
doc/images/stillrun_en.png
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
doc/images/win10warn.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
doc/images/win10warn_en.png
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
@@ -8,6 +8,9 @@ import (
|
||||
var (
|
||||
// ErrorS2S string = "s2s is not supported"
|
||||
// ErrorHandshake string = "handshake error"
|
||||
ErrorS2S = errors.New("s2s is not supported")
|
||||
ErrorHandshake = errors.New("handshake error")
|
||||
ErrorS2S = errors.New("s2s is not supported")
|
||||
ErrorHandshake = errors.New("handshake error")
|
||||
ErrorNewUser = errors.New("new user")
|
||||
ErrorLogin = errors.New("user or password not correct")
|
||||
ErrNodeTooShort = errors.New("node name too short, it must >=8 charaters")
|
||||
)
|
||||
|
||||
125
handlepush.go
@@ -8,8 +8,6 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -30,10 +28,10 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
|
||||
}
|
||||
gLog.Printf(LevelINFO, "%s is connecting...", req.From)
|
||||
gLog.Println(LevelDEBUG, "push connect response to ", req.From)
|
||||
// verify token or name&password
|
||||
if VerifyTOTP(req.Token, pn.config.User, pn.config.Password, time.Now().Unix()+(pn.serverTs-pn.localTs)) || // localTs may behind, auto adjust ts
|
||||
VerifyTOTP(req.Token, pn.config.User, pn.config.Password, time.Now().Unix()) ||
|
||||
(req.User == pn.config.User && req.Password == pn.config.Password) {
|
||||
// verify totp token or token
|
||||
if VerifyTOTP(req.Token, pn.config.Token, time.Now().Unix()+(pn.serverTs-pn.localTs)) || // localTs may behind, auto adjust ts
|
||||
VerifyTOTP(req.Token, pn.config.Token, time.Now().Unix()) ||
|
||||
(req.FromToken == pn.config.Token) {
|
||||
gLog.Printf(LevelINFO, "Access Granted\n")
|
||||
config := AppConfig{}
|
||||
config.peerNatType = req.NatType
|
||||
@@ -41,7 +39,7 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
|
||||
config.peerIP = req.FromIP
|
||||
config.PeerNode = req.From
|
||||
// share relay node will limit bandwidth
|
||||
if req.User != pn.config.User || req.Password != pn.config.Password {
|
||||
if req.FromToken != pn.config.Token {
|
||||
gLog.Printf(LevelINFO, "set share bandwidth %d mbps", pn.config.ShareBandwidth)
|
||||
config.shareBandwidth = pn.config.ShareBandwidth
|
||||
}
|
||||
@@ -79,9 +77,6 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
|
||||
config := AppConfig{}
|
||||
config.PeerNode = req.RelayName
|
||||
config.peerToken = req.RelayToken
|
||||
// set user password, maybe the relay node is your private node
|
||||
config.PeerUser = pn.config.User
|
||||
config.PeerPassword = pn.config.Password
|
||||
go func(r AddRelayTunnelReq) {
|
||||
t, errDt := pn.addDirectTunnel(config, 0)
|
||||
if errDt == nil {
|
||||
@@ -93,35 +88,49 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
|
||||
|
||||
}(req)
|
||||
case MsgPushUpdate:
|
||||
gLog.Println(LevelINFO, "MsgPushUpdate")
|
||||
update() // download new version first, then exec ./openp2p update
|
||||
targetPath := filepath.Join(defaultInstallPath, defaultBinName)
|
||||
args := []string{"update"}
|
||||
env := os.Environ()
|
||||
// Windows does not support exec syscall.
|
||||
if runtime.GOOS == "windows" {
|
||||
cmd := exec.Command(targetPath, args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Env = env
|
||||
err := cmd.Run()
|
||||
if err == nil {
|
||||
os.Exit(0)
|
||||
}
|
||||
return err
|
||||
cmd := exec.Command(targetPath, args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Env = env
|
||||
err := cmd.Run()
|
||||
if err == nil {
|
||||
os.Exit(0)
|
||||
}
|
||||
return syscall.Exec(targetPath, args, env)
|
||||
return err
|
||||
case MsgPushRestart:
|
||||
gLog.Println(LevelINFO, "MsgPushRestart")
|
||||
os.Exit(0)
|
||||
return err
|
||||
case MsgPushReportApps:
|
||||
gLog.Println(LevelINFO, "MsgPushReportApps")
|
||||
req := ReportApps{}
|
||||
// TODO: add the retrying apps
|
||||
gConf.mtx.Lock()
|
||||
defer gConf.mtx.Unlock()
|
||||
for _, config := range gConf.Apps {
|
||||
appActive := 0
|
||||
relayNode := ""
|
||||
relayMode := ""
|
||||
i, ok := pn.apps.Load(fmt.Sprintf("%s%d", config.Protocol, config.SrcPort))
|
||||
if ok {
|
||||
app := i.(*p2pApp)
|
||||
if app.isActive() {
|
||||
appActive = 1
|
||||
}
|
||||
relayNode = app.relayNode
|
||||
relayMode = app.relayMode
|
||||
}
|
||||
appInfo := AppInfo{
|
||||
AppName: config.AppName,
|
||||
Protocol: config.Protocol,
|
||||
SrcPort: config.SrcPort,
|
||||
// RelayNode: relayNode,
|
||||
AppName: config.AppName,
|
||||
Protocol: config.Protocol,
|
||||
SrcPort: config.SrcPort,
|
||||
RelayNode: relayNode,
|
||||
RelayMode: relayMode,
|
||||
PeerNode: config.PeerNode,
|
||||
DstHost: config.DstHost,
|
||||
DstPort: config.DstPort,
|
||||
@@ -129,29 +138,11 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
|
||||
PeerIP: config.peerIP,
|
||||
PeerNatType: config.peerNatType,
|
||||
RetryTime: config.retryTime.String(),
|
||||
IsActive: 1,
|
||||
IsActive: appActive,
|
||||
Enabled: config.Enabled,
|
||||
}
|
||||
req.Apps = append(req.Apps, appInfo)
|
||||
}
|
||||
// pn.apps.Range(func(_, i interface{}) bool {
|
||||
// app := i.(*p2pApp)
|
||||
// appInfo := AppInfo{
|
||||
// AppName: app.config.AppName,
|
||||
// Protocol: app.config.Protocol,
|
||||
// SrcPort: app.config.SrcPort,
|
||||
// RelayNode: app.relayNode,
|
||||
// PeerNode: app.config.PeerNode,
|
||||
// DstHost: app.config.DstHost,
|
||||
// DstPort: app.config.DstPort,
|
||||
// PeerUser: app.config.PeerUser,
|
||||
// PeerIP: app.config.peerIP,
|
||||
// PeerNatType: app.config.peerNatType,
|
||||
// RetryTime: app.config.retryTime.String(),
|
||||
// IsActive: 1,
|
||||
// }
|
||||
// req.Apps = append(req.Apps, appInfo)
|
||||
// return true
|
||||
// })
|
||||
pn.write(MsgReport, MsgReportApps, &req)
|
||||
case MsgPushEditApp:
|
||||
gLog.Println(LevelINFO, "MsgPushEditApp")
|
||||
@@ -161,7 +152,7 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
|
||||
gLog.Printf(LevelERROR, "wrong MsgPushEditApp:%s %s", err, string(msg[openP2PHeaderSize:]))
|
||||
return err
|
||||
}
|
||||
var oldConf AppConfig
|
||||
oldConf := AppConfig{Enabled: 1}
|
||||
// protocol0+srcPort0 exist, delApp
|
||||
oldConf.AppName = newApp.AppName
|
||||
oldConf.Protocol = newApp.Protocol0
|
||||
@@ -175,12 +166,42 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
|
||||
newConf := oldConf
|
||||
newConf.Protocol = newApp.Protocol
|
||||
newConf.SrcPort = newApp.SrcPort
|
||||
gConf.add(newConf)
|
||||
gConf.save()
|
||||
pn.DeleteApp(oldConf) // save quickly for the next request reportApplist
|
||||
gConf.add(newConf, false)
|
||||
gConf.save() // save quickly for the next request reportApplist
|
||||
pn.DeleteApp(oldConf) // DeleteApp may cost some times, execute at the end
|
||||
// autoReconnect will auto AddApp
|
||||
// pn.AddApp(config)
|
||||
// TODO: report result
|
||||
case MsgPushEditNode:
|
||||
gLog.Println(LevelINFO, "MsgPushEditNode")
|
||||
req := EditNode{}
|
||||
err := json.Unmarshal(msg[openP2PHeaderSize:], &req)
|
||||
if err != nil {
|
||||
gLog.Printf(LevelERROR, "wrong MsgPushEditNode:%s %s", err, string(msg[openP2PHeaderSize:]))
|
||||
return err
|
||||
}
|
||||
gConf.mtx.Lock()
|
||||
gConf.Network.Node = req.NewName
|
||||
gConf.Network.ShareBandwidth = req.Bandwidth
|
||||
gConf.mtx.Unlock()
|
||||
gConf.save()
|
||||
// TODO: hot reload
|
||||
os.Exit(0)
|
||||
case MsgPushSwitchApp:
|
||||
gLog.Println(LevelINFO, "MsgPushSwitchApp")
|
||||
app := AppInfo{}
|
||||
err := json.Unmarshal(msg[openP2PHeaderSize:], &app)
|
||||
if err != nil {
|
||||
gLog.Printf(LevelERROR, "wrong MsgPushSwitchApp:%s %s", err, string(msg[openP2PHeaderSize:]))
|
||||
return err
|
||||
}
|
||||
config := AppConfig{Enabled: app.Enabled, SrcPort: app.SrcPort, Protocol: app.Protocol}
|
||||
gLog.Println(LevelINFO, app.AppName, " switch to ", app.Enabled)
|
||||
gConf.switchApp(config, app.Enabled)
|
||||
if app.Enabled == 0 {
|
||||
// disable APP
|
||||
pn.DeleteApp(config)
|
||||
}
|
||||
default:
|
||||
pn.msgMapMtx.Lock()
|
||||
ch := pn.msgMap[pushHead.From]
|
||||
|
||||
4
log.go
@@ -110,10 +110,10 @@ func (vl *V8log) checkFile() {
|
||||
for l, logFile := range vl.files {
|
||||
f, e := logFile.Stat()
|
||||
if e != nil {
|
||||
break
|
||||
continue
|
||||
}
|
||||
if f.Size() <= vl.maxLogSize {
|
||||
break
|
||||
continue
|
||||
}
|
||||
logFile.Close()
|
||||
fname := f.Name()
|
||||
|
||||
95
openp2p.go
@@ -1,7 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
@@ -14,9 +13,7 @@ func main() {
|
||||
binDir := filepath.Dir(os.Args[0])
|
||||
os.Chdir(binDir) // for system service
|
||||
gLog = InitLogger(binDir, "openp2p", LevelDEBUG, 1024*1024, LogFileAndConsole)
|
||||
|
||||
// TODO: install sub command, deamon process
|
||||
// groups := flag.String("groups", "", "you could join in several groups. like: GroupName1:Password1;GroupName2:Password2; group name 8-31 characters")
|
||||
if len(os.Args) > 1 {
|
||||
switch os.Args[1] {
|
||||
case "version", "-v", "--version":
|
||||
@@ -24,7 +21,6 @@ func main() {
|
||||
return
|
||||
case "update":
|
||||
gLog = InitLogger(filepath.Dir(os.Args[0]), "openp2p", LevelDEBUG, 1024*1024, LogFileAndConsole)
|
||||
update()
|
||||
targetPath := filepath.Join(defaultInstallPath, defaultBinName)
|
||||
d := daemon{}
|
||||
err := d.Control("restart", targetPath, nil)
|
||||
@@ -41,95 +37,12 @@ func main() {
|
||||
uninstall()
|
||||
return
|
||||
}
|
||||
} else {
|
||||
installByFilename()
|
||||
}
|
||||
serverHost := flag.String("serverhost", "api.openp2p.cn", "server host ")
|
||||
// serverHost := flag.String("serverhost", "127.0.0.1", "server host ") // for debug
|
||||
user := flag.String("user", "", "user name. 8-31 characters")
|
||||
node := flag.String("node", "", "node name. 8-31 characters")
|
||||
password := flag.String("password", "", "user password. 8-31 characters")
|
||||
peerNode := flag.String("peernode", "", "peer node name that you want to connect")
|
||||
peerUser := flag.String("peeruser", "", "peer node user (default peeruser=user)")
|
||||
peerPassword := flag.String("peerpassword", "", "peer node password (default peerpassword=password)")
|
||||
dstIP := flag.String("dstip", "127.0.0.1", "destination ip ")
|
||||
dstPort := flag.Int("dstport", 0, "destination port ")
|
||||
srcPort := flag.Int("srcport", 0, "source port ")
|
||||
protocol := flag.String("protocol", "tcp", "tcp or udp")
|
||||
appName := flag.String("appname", "", "app name")
|
||||
flag.Bool("noshare", false, "deprecated. uses -sharebandwidth -1") // Deprecated, rm later
|
||||
shareBandwidth := flag.Int("sharebandwidth", 10, "N mbps share bandwidth limit, private node no limit")
|
||||
flag.Bool("f", false, "deprecated. config file") // Deprecated, rm later
|
||||
daemonMode := flag.Bool("d", false, "daemonMode")
|
||||
flag.Bool("bydaemon", false, "start by daemon") // Deprecated, rm later
|
||||
logLevel := flag.Int("loglevel", 1, "0:debug 1:info 2:warn 3:error")
|
||||
flag.Parse()
|
||||
|
||||
config := AppConfig{}
|
||||
config.PeerNode = *peerNode
|
||||
config.PeerUser = *peerUser
|
||||
config.PeerPassword = *peerPassword
|
||||
config.DstHost = *dstIP
|
||||
config.DstPort = *dstPort
|
||||
config.SrcPort = *srcPort
|
||||
config.Protocol = *protocol
|
||||
config.AppName = *appName
|
||||
// add command config first
|
||||
gConf.add(config)
|
||||
gConf.load()
|
||||
gConf.mtx.Lock()
|
||||
|
||||
// spec paramters in commandline will always be used
|
||||
flag.Visit(func(f *flag.Flag) {
|
||||
if f.Name == "sharebandwidth" {
|
||||
gConf.Network.ShareBandwidth = *shareBandwidth
|
||||
}
|
||||
if f.Name == "node" {
|
||||
gConf.Network.Node = *node
|
||||
}
|
||||
if f.Name == "user" {
|
||||
gConf.Network.User = *user
|
||||
}
|
||||
if f.Name == "password" {
|
||||
gConf.Network.Password = *password
|
||||
}
|
||||
if f.Name == "serverhost" {
|
||||
gConf.Network.ServerHost = *serverHost
|
||||
}
|
||||
if f.Name == "loglevel" {
|
||||
gConf.LogLevel = *logLevel
|
||||
}
|
||||
})
|
||||
|
||||
if gConf.Network.ServerHost == "" {
|
||||
gConf.Network.ServerHost = *serverHost
|
||||
}
|
||||
if gConf.Network.Node == "" {
|
||||
gConf.Network.Node = *node
|
||||
}
|
||||
if gConf.Network.User == "" {
|
||||
gConf.Network.User = *user
|
||||
}
|
||||
if gConf.Network.Password == "" {
|
||||
gConf.Network.Password = *password
|
||||
}
|
||||
if gConf.LogLevel == IntValueNotSet {
|
||||
gConf.LogLevel = *logLevel
|
||||
}
|
||||
if gConf.Network.ShareBandwidth == IntValueNotSet {
|
||||
gConf.Network.ShareBandwidth = *shareBandwidth
|
||||
}
|
||||
|
||||
gConf.Network.ServerPort = 27182
|
||||
gConf.Network.UDPPort1 = 27182
|
||||
gConf.Network.UDPPort2 = 27183
|
||||
gLog.Println(LevelINFO, "openp2p start. version: ", OpenP2PVersion)
|
||||
gLog.setLevel(LogLevel(gConf.LogLevel))
|
||||
gConf.mtx.Unlock()
|
||||
gConf.save()
|
||||
if *daemonMode {
|
||||
d := daemon{}
|
||||
d.run()
|
||||
return
|
||||
}
|
||||
gLog.Println(LevelINFO, "Contact: QQ Group: 16947733, Email: openp2p.cn@gmail.com")
|
||||
parseParams()
|
||||
gLog.Println(LevelINFO, &gConf)
|
||||
setFirewall()
|
||||
network := P2PNetworkInstance(&gConf.Network)
|
||||
|
||||
150
overlay.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
var ErrDeadlineExceeded error = &DeadlineExceededError{}
|
||||
|
||||
// DeadlineExceededError is returned for an expired deadline.
|
||||
type DeadlineExceededError struct{}
|
||||
|
||||
// Implement the net.Error interface.
|
||||
// The string is "i/o timeout" because that is what was returned
|
||||
// by earlier Go versions. Changing it may break programs that
|
||||
// match on error strings.
|
||||
func (e *DeadlineExceededError) Error() string { return "i/o timeout" }
|
||||
func (e *DeadlineExceededError) Timeout() bool { return true }
|
||||
func (e *DeadlineExceededError) Temporary() bool { return true }
|
||||
|
||||
// implement io.Writer
|
||||
type overlayConn struct {
|
||||
tunnel *P2PTunnel
|
||||
connTCP net.Conn
|
||||
id uint64
|
||||
rtid uint64
|
||||
running bool
|
||||
isClient bool
|
||||
appID uint64
|
||||
appKey uint64
|
||||
appKeyBytes []byte
|
||||
// for udp
|
||||
connUDP *net.UDPConn
|
||||
remoteAddr net.Addr
|
||||
udpRelayData chan []byte
|
||||
lastReadUDPTs time.Time
|
||||
}
|
||||
|
||||
func (oConn *overlayConn) run() {
|
||||
gLog.Printf(LevelDEBUG, "%d overlayConn run start", oConn.id)
|
||||
defer gLog.Printf(LevelDEBUG, "%d overlayConn run end", oConn.id)
|
||||
oConn.running = true
|
||||
oConn.lastReadUDPTs = time.Now()
|
||||
buffer := make([]byte, ReadBuffLen+PaddingSize)
|
||||
readBuf := buffer[:ReadBuffLen]
|
||||
encryptData := make([]byte, ReadBuffLen+PaddingSize) // 16 bytes for padding
|
||||
tunnelHead := new(bytes.Buffer)
|
||||
relayHead := new(bytes.Buffer)
|
||||
binary.Write(relayHead, binary.LittleEndian, oConn.rtid)
|
||||
binary.Write(tunnelHead, binary.LittleEndian, oConn.id)
|
||||
for oConn.running && oConn.tunnel.isRuning() {
|
||||
buff, dataLen, err := oConn.Read(readBuf)
|
||||
if err != nil {
|
||||
if ne, ok := err.(net.Error); ok && ne.Timeout() {
|
||||
continue
|
||||
}
|
||||
// overlay tcp connection normal close, debug log
|
||||
gLog.Printf(LevelDEBUG, "overlayConn %d read error:%s,close it", oConn.id, err)
|
||||
break
|
||||
}
|
||||
payload := buff[:dataLen]
|
||||
if oConn.appKey != 0 {
|
||||
payload, _ = encryptBytes(oConn.appKeyBytes, encryptData, buffer[:dataLen], dataLen)
|
||||
}
|
||||
writeBytes := append(tunnelHead.Bytes(), payload...)
|
||||
if oConn.rtid == 0 {
|
||||
oConn.tunnel.conn.WriteBytes(MsgP2P, MsgOverlayData, writeBytes)
|
||||
gLog.Printf(LevelDEBUG, "write overlay data to %d:%d bodylen=%d", oConn.rtid, oConn.id, len(writeBytes))
|
||||
} else {
|
||||
// write raley data
|
||||
all := append(relayHead.Bytes(), encodeHeader(MsgP2P, MsgOverlayData, uint32(len(writeBytes)))...)
|
||||
all = append(all, writeBytes...)
|
||||
oConn.tunnel.conn.WriteBytes(MsgP2P, MsgRelayData, all)
|
||||
gLog.Printf(LevelDEBUG, "write relay data to %d:%d bodylen=%d", oConn.rtid, oConn.id, len(writeBytes))
|
||||
}
|
||||
}
|
||||
if oConn.connTCP != nil {
|
||||
oConn.connTCP.Close()
|
||||
}
|
||||
if oConn.connUDP != nil {
|
||||
oConn.connUDP.Close()
|
||||
}
|
||||
oConn.tunnel.overlayConns.Delete(oConn.id)
|
||||
// notify peer disconnect
|
||||
if oConn.isClient {
|
||||
req := OverlayDisconnectReq{ID: oConn.id}
|
||||
if oConn.rtid == 0 {
|
||||
oConn.tunnel.conn.WriteMessage(MsgP2P, MsgOverlayDisconnectReq, &req)
|
||||
} else {
|
||||
// write relay data
|
||||
msg, _ := newMessage(MsgP2P, MsgOverlayDisconnectReq, &req)
|
||||
msgWithHead := append(relayHead.Bytes(), msg...)
|
||||
oConn.tunnel.conn.WriteBytes(MsgP2P, MsgRelayData, msgWithHead)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (oConn *overlayConn) Read(reuseBuff []byte) (buff []byte, n int, err error) {
|
||||
if oConn.connUDP != nil {
|
||||
if time.Now().After(oConn.lastReadUDPTs.Add(time.Minute * 5)) {
|
||||
err = errors.New("udp close")
|
||||
return
|
||||
}
|
||||
if oConn.remoteAddr != nil { // as server
|
||||
select {
|
||||
case buff = <-oConn.udpRelayData:
|
||||
n = len(buff)
|
||||
oConn.lastReadUDPTs = time.Now()
|
||||
case <-time.After(time.Second * 10):
|
||||
err = ErrDeadlineExceeded
|
||||
}
|
||||
} else { // as client
|
||||
oConn.connUDP.SetReadDeadline(time.Now().Add(5 * time.Second))
|
||||
n, _, err = oConn.connUDP.ReadFrom(reuseBuff)
|
||||
if err == nil {
|
||||
oConn.lastReadUDPTs = time.Now()
|
||||
}
|
||||
buff = reuseBuff
|
||||
}
|
||||
return
|
||||
}
|
||||
oConn.connTCP.SetReadDeadline(time.Now().Add(time.Second * 5))
|
||||
n, err = oConn.connTCP.Read(reuseBuff)
|
||||
buff = reuseBuff
|
||||
return
|
||||
}
|
||||
|
||||
// calling by p2pTunnel
|
||||
func (oConn *overlayConn) Write(buff []byte) (n int, err error) {
|
||||
// add mutex when multi-thread calling
|
||||
if oConn.connUDP != nil {
|
||||
if oConn.remoteAddr == nil {
|
||||
n, err = oConn.connUDP.Write(buff)
|
||||
} else {
|
||||
n, err = oConn.connUDP.WriteTo(buff, oConn.remoteAddr)
|
||||
}
|
||||
if err != nil {
|
||||
oConn.running = false
|
||||
}
|
||||
return
|
||||
}
|
||||
n, err = oConn.connTCP.Write(buff)
|
||||
if err != nil {
|
||||
oConn.running = false
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
// implement io.Writer
|
||||
type overlayTCP struct {
|
||||
tunnel *P2PTunnel
|
||||
conn net.Conn
|
||||
id uint64
|
||||
rtid uint64
|
||||
running bool
|
||||
isClient bool
|
||||
appID uint64
|
||||
appKey uint64
|
||||
appKeyBytes []byte
|
||||
}
|
||||
|
||||
func (otcp *overlayTCP) run() {
|
||||
gLog.Printf(LevelDEBUG, "%d overlayTCP run start", otcp.id)
|
||||
defer gLog.Printf(LevelDEBUG, "%d overlayTCP run end", otcp.id)
|
||||
otcp.running = true
|
||||
buffer := make([]byte, ReadBuffLen+PaddingSize)
|
||||
readBuf := buffer[:ReadBuffLen]
|
||||
encryptData := make([]byte, ReadBuffLen+PaddingSize) // 16 bytes for padding
|
||||
tunnelHead := new(bytes.Buffer)
|
||||
relayHead := new(bytes.Buffer)
|
||||
binary.Write(relayHead, binary.LittleEndian, otcp.rtid)
|
||||
binary.Write(tunnelHead, binary.LittleEndian, otcp.id)
|
||||
for otcp.running && otcp.tunnel.isRuning() {
|
||||
otcp.conn.SetReadDeadline(time.Now().Add(time.Second * 5))
|
||||
dataLen, err := otcp.conn.Read(readBuf)
|
||||
if err != nil {
|
||||
if ne, ok := err.(net.Error); ok && ne.Timeout() {
|
||||
continue
|
||||
}
|
||||
// overlay tcp connection normal close, debug log
|
||||
gLog.Printf(LevelDEBUG, "overlayTCP %d read error:%s,close it", otcp.id, err)
|
||||
break
|
||||
} else {
|
||||
payload := readBuf[:dataLen]
|
||||
if otcp.appKey != 0 {
|
||||
payload, _ = encryptBytes(otcp.appKeyBytes, encryptData, buffer[:dataLen], dataLen)
|
||||
}
|
||||
writeBytes := append(tunnelHead.Bytes(), payload...)
|
||||
if otcp.rtid == 0 {
|
||||
otcp.tunnel.conn.WriteBytes(MsgP2P, MsgOverlayData, writeBytes)
|
||||
} else {
|
||||
// write raley data
|
||||
all := append(relayHead.Bytes(), encodeHeader(MsgP2P, MsgOverlayData, uint32(len(writeBytes)))...)
|
||||
all = append(all, writeBytes...)
|
||||
otcp.tunnel.conn.WriteBytes(MsgP2P, MsgRelayData, all)
|
||||
gLog.Printf(LevelDEBUG, "write relay data to %d:%d bodylen=%d", otcp.rtid, otcp.id, len(writeBytes))
|
||||
}
|
||||
}
|
||||
}
|
||||
otcp.conn.Close()
|
||||
otcp.tunnel.overlayConns.Delete(otcp.id)
|
||||
// notify peer disconnect
|
||||
if otcp.isClient {
|
||||
req := OverlayDisconnectReq{ID: otcp.id}
|
||||
if otcp.rtid == 0 {
|
||||
otcp.tunnel.conn.WriteMessage(MsgP2P, MsgOverlayDisconnectReq, &req)
|
||||
} else {
|
||||
// write relay data
|
||||
msg, _ := newMessage(MsgP2P, MsgOverlayDisconnectReq, &req)
|
||||
msgWithHead := append(relayHead.Bytes(), msg...)
|
||||
otcp.tunnel.conn.WriteBytes(MsgP2P, MsgRelayData, msgWithHead)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// calling by p2pTunnel
|
||||
func (otcp *overlayTCP) Write(buff []byte) (n int, err error) {
|
||||
// add mutex when multi-thread calling
|
||||
n, err = otcp.conn.Write(buff)
|
||||
if err != nil {
|
||||
otcp.tunnel.overlayConns.Delete(otcp.id)
|
||||
}
|
||||
return
|
||||
}
|
||||
164
p2papp.go
@@ -6,22 +6,26 @@ import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type p2pApp struct {
|
||||
config AppConfig
|
||||
listener net.Listener
|
||||
tunnel *P2PTunnel
|
||||
rtid uint64
|
||||
relayNode string
|
||||
hbTime time.Time
|
||||
hbMtx sync.Mutex
|
||||
running bool
|
||||
id uint64
|
||||
key uint64
|
||||
wg sync.WaitGroup
|
||||
config AppConfig
|
||||
listener net.Listener
|
||||
listenerUDP *net.UDPConn
|
||||
tunnel *P2PTunnel
|
||||
rtid uint64
|
||||
relayNode string
|
||||
relayMode string
|
||||
hbTime time.Time
|
||||
hbMtx sync.Mutex
|
||||
running bool
|
||||
id uint64
|
||||
key uint64
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
func (app *p2pApp) isActive() bool {
|
||||
@@ -44,40 +48,43 @@ func (app *p2pApp) updateHeartbeat() {
|
||||
}
|
||||
|
||||
func (app *p2pApp) listenTCP() error {
|
||||
gLog.Printf(LevelDEBUG, "tcp accept on port %d start", app.config.SrcPort)
|
||||
defer gLog.Printf(LevelDEBUG, "tcp accept on port %d end", app.config.SrcPort)
|
||||
var err error
|
||||
app.listener, err = net.Listen("tcp4", fmt.Sprintf("0.0.0.0:%d", app.config.SrcPort))
|
||||
if err != nil {
|
||||
gLog.Printf(LevelERROR, "listen error:%s", err)
|
||||
return err
|
||||
}
|
||||
for {
|
||||
for app.running {
|
||||
conn, err := app.listener.Accept()
|
||||
if err != nil {
|
||||
gLog.Printf(LevelERROR, "%d accept error:%s", app.tunnel.id, err)
|
||||
if app.running {
|
||||
gLog.Printf(LevelERROR, "%d accept error:%s", app.tunnel.id, err)
|
||||
}
|
||||
break
|
||||
}
|
||||
otcp := overlayTCP{
|
||||
oConn := overlayConn{
|
||||
tunnel: app.tunnel,
|
||||
conn: conn,
|
||||
connTCP: conn,
|
||||
id: rand.Uint64(),
|
||||
isClient: true,
|
||||
rtid: app.rtid,
|
||||
appID: app.id,
|
||||
appKey: app.key,
|
||||
}
|
||||
// calc key bytes for encrypt
|
||||
if otcp.appKey != 0 {
|
||||
// pre-calc key bytes for encrypt
|
||||
if oConn.appKey != 0 {
|
||||
encryptKey := make([]byte, AESKeySize)
|
||||
binary.LittleEndian.PutUint64(encryptKey, otcp.appKey)
|
||||
binary.LittleEndian.PutUint64(encryptKey[8:], otcp.appKey)
|
||||
otcp.appKeyBytes = encryptKey
|
||||
binary.LittleEndian.PutUint64(encryptKey, oConn.appKey)
|
||||
binary.LittleEndian.PutUint64(encryptKey[8:], oConn.appKey)
|
||||
oConn.appKeyBytes = encryptKey
|
||||
}
|
||||
app.tunnel.overlayConns.Store(otcp.id, &otcp)
|
||||
gLog.Printf(LevelDEBUG, "Accept overlayID:%d", otcp.id)
|
||||
app.tunnel.overlayConns.Store(oConn.id, &oConn)
|
||||
gLog.Printf(LevelDEBUG, "Accept TCP overlayID:%d", oConn.id)
|
||||
// tell peer connect
|
||||
req := OverlayConnectReq{ID: otcp.id,
|
||||
User: app.config.PeerUser,
|
||||
Password: app.config.PeerPassword,
|
||||
req := OverlayConnectReq{ID: oConn.id,
|
||||
Token: app.tunnel.pn.config.Token,
|
||||
DstIP: app.config.DstHost,
|
||||
DstPort: app.config.DstPort,
|
||||
Protocol: app.config.Protocol,
|
||||
@@ -93,27 +100,117 @@ func (app *p2pApp) listenTCP() error {
|
||||
msgWithHead := append(relayHead.Bytes(), msg...)
|
||||
app.tunnel.conn.WriteBytes(MsgP2P, MsgRelayData, msgWithHead)
|
||||
}
|
||||
go oConn.run()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
go otcp.run()
|
||||
func (app *p2pApp) listenUDP() error {
|
||||
gLog.Printf(LevelDEBUG, "udp accept on port %d start", app.config.SrcPort)
|
||||
defer gLog.Printf(LevelDEBUG, "udp accept on port %d end", app.config.SrcPort)
|
||||
var err error
|
||||
app.listenerUDP, err = net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: app.config.SrcPort})
|
||||
if err != nil {
|
||||
gLog.Printf(LevelERROR, "listen error:%s", err)
|
||||
return err
|
||||
}
|
||||
buffer := make([]byte, 64*1024)
|
||||
udpID := make([]byte, 8)
|
||||
for {
|
||||
app.listenerUDP.SetReadDeadline(time.Now().Add(time.Second * 10))
|
||||
len, remoteAddr, err := app.listenerUDP.ReadFrom(buffer)
|
||||
if err != nil {
|
||||
if ne, ok := err.(net.Error); ok && ne.Timeout() {
|
||||
continue
|
||||
} else {
|
||||
gLog.Printf(LevelERROR, "udp read failed:%s", err)
|
||||
break
|
||||
}
|
||||
} else {
|
||||
b := bytes.Buffer{}
|
||||
b.Write(buffer[:len])
|
||||
// load from app.tunnel.overlayConns by remoteAddr error, new udp connection
|
||||
remoteIP := strings.Split(remoteAddr.String(), ":")[0]
|
||||
port, _ := strconv.Atoi(strings.Split(remoteAddr.String(), ":")[1])
|
||||
a := net.ParseIP(remoteIP)
|
||||
udpID[0] = a[0]
|
||||
udpID[1] = a[1]
|
||||
udpID[2] = a[2]
|
||||
udpID[3] = a[3]
|
||||
udpID[4] = byte(port)
|
||||
udpID[5] = byte(port >> 8)
|
||||
id := binary.LittleEndian.Uint64(udpID)
|
||||
s, ok := app.tunnel.overlayConns.Load(id)
|
||||
if !ok {
|
||||
oConn := overlayConn{
|
||||
tunnel: app.tunnel,
|
||||
connUDP: app.listenerUDP,
|
||||
remoteAddr: remoteAddr,
|
||||
udpRelayData: make(chan []byte, 1000),
|
||||
id: id,
|
||||
isClient: true,
|
||||
rtid: app.rtid,
|
||||
appID: app.id,
|
||||
appKey: app.key,
|
||||
}
|
||||
// calc key bytes for encrypt
|
||||
if oConn.appKey != 0 {
|
||||
encryptKey := make([]byte, AESKeySize)
|
||||
binary.LittleEndian.PutUint64(encryptKey, oConn.appKey)
|
||||
binary.LittleEndian.PutUint64(encryptKey[8:], oConn.appKey)
|
||||
oConn.appKeyBytes = encryptKey
|
||||
}
|
||||
app.tunnel.overlayConns.Store(oConn.id, &oConn)
|
||||
gLog.Printf(LevelDEBUG, "Accept UDP overlayID:%d", oConn.id)
|
||||
// tell peer connect
|
||||
req := OverlayConnectReq{ID: oConn.id,
|
||||
Token: app.tunnel.pn.config.Token,
|
||||
DstIP: app.config.DstHost,
|
||||
DstPort: app.config.DstPort,
|
||||
Protocol: app.config.Protocol,
|
||||
AppID: app.id,
|
||||
}
|
||||
if app.rtid == 0 {
|
||||
app.tunnel.conn.WriteMessage(MsgP2P, MsgOverlayConnectReq, &req)
|
||||
} else {
|
||||
req.RelayTunnelID = app.tunnel.id
|
||||
relayHead := new(bytes.Buffer)
|
||||
binary.Write(relayHead, binary.LittleEndian, app.rtid)
|
||||
msg, _ := newMessage(MsgP2P, MsgOverlayConnectReq, &req)
|
||||
msgWithHead := append(relayHead.Bytes(), msg...)
|
||||
app.tunnel.conn.WriteBytes(MsgP2P, MsgRelayData, msgWithHead)
|
||||
}
|
||||
go oConn.run()
|
||||
oConn.udpRelayData <- b.Bytes()
|
||||
}
|
||||
|
||||
// load from app.tunnel.overlayConns by remoteAddr ok, write relay data
|
||||
overlayConn, ok := s.(*overlayConn)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
overlayConn.udpRelayData <- b.Bytes()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (app *p2pApp) listen() error {
|
||||
gLog.Printf(LevelINFO, "LISTEN ON PORT %d START", app.config.SrcPort)
|
||||
defer gLog.Printf(LevelINFO, "LISTEN ON PORT %d START", app.config.SrcPort)
|
||||
gLog.Printf(LevelINFO, "LISTEN ON PORT %s:%d START", app.config.Protocol, app.config.SrcPort)
|
||||
defer gLog.Printf(LevelINFO, "LISTEN ON PORT %s:%d END", app.config.Protocol, app.config.SrcPort)
|
||||
app.wg.Add(1)
|
||||
defer app.wg.Done()
|
||||
app.running = true
|
||||
if app.rtid != 0 {
|
||||
go app.relayHeartbeatLoop()
|
||||
}
|
||||
for app.running {
|
||||
if app.config.Protocol == "tcp" {
|
||||
for app.tunnel.isRuning() && app.running {
|
||||
if app.config.Protocol == "udp" {
|
||||
app.listenUDP()
|
||||
} else {
|
||||
app.listenTCP()
|
||||
}
|
||||
time.Sleep(time.Second * 5)
|
||||
// TODO: listen UDP
|
||||
time.Sleep(time.Second * 10)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -123,6 +220,9 @@ func (app *p2pApp) close() {
|
||||
if app.listener != nil {
|
||||
app.listener.Close()
|
||||
}
|
||||
if app.listenerUDP != nil {
|
||||
app.listenerUDP.Close()
|
||||
}
|
||||
if app.tunnel != nil {
|
||||
app.tunnel.closeOverlayConns(app.id)
|
||||
}
|
||||
|
||||
113
p2pnetwork.go
@@ -7,10 +7,10 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -97,48 +97,47 @@ func (pn *P2PNetwork) runAll() {
|
||||
gConf.mtx.Lock()
|
||||
defer gConf.mtx.Unlock()
|
||||
for _, config := range gConf.Apps {
|
||||
// set default peer user password
|
||||
if config.PeerPassword == "" {
|
||||
config.PeerPassword = gConf.Network.Password
|
||||
if config.nextRetryTime.After(time.Now()) {
|
||||
continue
|
||||
}
|
||||
if config.PeerUser == "" {
|
||||
config.PeerUser = gConf.Network.User
|
||||
if config.Enabled == 0 {
|
||||
continue
|
||||
}
|
||||
if config.AppName == "" {
|
||||
config.AppName = fmt.Sprintf("%s%d", config.Protocol, config.SrcPort)
|
||||
}
|
||||
appExist := false
|
||||
appActive := false
|
||||
var appID uint64
|
||||
i, ok := pn.apps.Load(fmt.Sprintf("%s%d", config.Protocol, config.SrcPort))
|
||||
if ok {
|
||||
app := i.(*p2pApp)
|
||||
appExist = true
|
||||
appID = app.id
|
||||
if app.isActive() {
|
||||
appActive = true
|
||||
}
|
||||
}
|
||||
if appExist && appActive {
|
||||
continue
|
||||
}
|
||||
if appExist && !appActive {
|
||||
gLog.Printf(LevelINFO, "detect app %s disconnect, reconnecting...", config.AppName)
|
||||
pn.DeleteApp(config)
|
||||
if config.retryTime.Add(time.Minute * 15).Before(time.Now()) {
|
||||
config.retryNum = 0
|
||||
}
|
||||
config.retryNum++
|
||||
config.retryTime = time.Now()
|
||||
if config.retryNum > MaxRetry {
|
||||
gLog.Printf(LevelERROR, "app %s%d retry more than %d times, exit.", config.Protocol, config.SrcPort, MaxRetry)
|
||||
continue
|
||||
}
|
||||
}
|
||||
go pn.AddApp(config)
|
||||
if appExist {
|
||||
pn.DeleteApp(*config)
|
||||
}
|
||||
if config.retryNum > 0 {
|
||||
gLog.Printf(LevelINFO, "detect app %s(%d) disconnect, reconnecting the %d times...", config.AppName, appID, config.retryNum)
|
||||
if time.Now().Add(-time.Minute * 15).After(config.retryTime) { // normal lasts 15min
|
||||
config.retryNum = 0
|
||||
}
|
||||
}
|
||||
config.retryNum++
|
||||
config.retryTime = time.Now()
|
||||
increase := math.Pow(1.3, float64(config.retryNum))
|
||||
if increase > 900 {
|
||||
increase = 900
|
||||
}
|
||||
config.nextRetryTime = time.Now().Add(time.Second * time.Duration(increase)) // exponential increase retry time. 1.3^x
|
||||
pn.AddApp(*config)
|
||||
}
|
||||
}
|
||||
func (pn *P2PNetwork) autorunApp() {
|
||||
gLog.Println(LevelINFO, "autorunApp start")
|
||||
// TODO: use gConf to check reconnect
|
||||
for pn.running {
|
||||
time.Sleep(time.Second)
|
||||
if !pn.online {
|
||||
@@ -150,23 +149,23 @@ func (pn *P2PNetwork) autorunApp() {
|
||||
gLog.Println(LevelINFO, "autorunApp end")
|
||||
}
|
||||
|
||||
func (pn *P2PNetwork) addRelayTunnel(config AppConfig, appid uint64, appkey uint64) (*P2PTunnel, uint64, error) {
|
||||
func (pn *P2PNetwork) addRelayTunnel(config AppConfig, appid uint64, appkey uint64) (*P2PTunnel, uint64, string, error) {
|
||||
gLog.Printf(LevelINFO, "addRelayTunnel to %s start", config.PeerNode)
|
||||
defer gLog.Printf(LevelINFO, "addRelayTunnel to %s end", config.PeerNode)
|
||||
pn.write(MsgRelay, MsgRelayNodeReq, &RelayNodeReq{config.PeerNode})
|
||||
head, body := pn.read("", MsgRelay, MsgRelayNodeRsp, time.Second*10)
|
||||
if head == nil {
|
||||
return nil, 0, errors.New("read MsgRelayNodeRsp error")
|
||||
return nil, 0, "", errors.New("read MsgRelayNodeRsp error")
|
||||
}
|
||||
rsp := RelayNodeRsp{}
|
||||
err := json.Unmarshal(body, &rsp)
|
||||
if err != nil {
|
||||
gLog.Printf(LevelERROR, "wrong RelayNodeRsp:%s", err)
|
||||
return nil, 0, errors.New("unmarshal MsgRelayNodeRsp error")
|
||||
return nil, 0, "", errors.New("unmarshal MsgRelayNodeRsp error")
|
||||
}
|
||||
if rsp.RelayName == "" || rsp.RelayToken == 0 {
|
||||
gLog.Printf(LevelERROR, "MsgRelayNodeReq error")
|
||||
return nil, 0, errors.New("MsgRelayNodeReq error")
|
||||
return nil, 0, "", errors.New("MsgRelayNodeReq error")
|
||||
}
|
||||
gLog.Printf(LevelINFO, "got relay node:%s", rsp.RelayName)
|
||||
relayConfig := config
|
||||
@@ -175,7 +174,7 @@ func (pn *P2PNetwork) addRelayTunnel(config AppConfig, appid uint64, appkey uint
|
||||
t, err := pn.addDirectTunnel(relayConfig, 0)
|
||||
if err != nil {
|
||||
gLog.Println(LevelERROR, "direct connect error:", err)
|
||||
return nil, 0, err
|
||||
return nil, 0, "", err
|
||||
}
|
||||
// notify peer addRelayTunnel
|
||||
req := AddRelayTunnelReq{
|
||||
@@ -192,15 +191,15 @@ func (pn *P2PNetwork) addRelayTunnel(config AppConfig, appid uint64, appkey uint
|
||||
head, body = pn.read(config.PeerNode, MsgPush, MsgPushAddRelayTunnelRsp, PeerAddRelayTimeount) // TODO: const value
|
||||
if head == nil {
|
||||
gLog.Printf(LevelERROR, "read MsgPushAddRelayTunnelRsp error")
|
||||
return nil, 0, errors.New("read MsgPushAddRelayTunnelRsp error")
|
||||
return nil, 0, "", errors.New("read MsgPushAddRelayTunnelRsp error")
|
||||
}
|
||||
rspID := TunnelMsg{}
|
||||
err = json.Unmarshal(body, &rspID)
|
||||
if err != nil {
|
||||
gLog.Printf(LevelERROR, "wrong RelayNodeRsp:%s", err)
|
||||
return nil, 0, errors.New("unmarshal MsgRelayNodeRsp error")
|
||||
return nil, 0, "", errors.New("unmarshal MsgRelayNodeRsp error")
|
||||
}
|
||||
return t, rspID.ID, err
|
||||
return t, rspID.ID, rsp.Mode, err
|
||||
}
|
||||
|
||||
func (pn *P2PNetwork) AddApp(config AppConfig) error {
|
||||
@@ -220,24 +219,26 @@ func (pn *P2PNetwork) AddApp(config AppConfig) error {
|
||||
}
|
||||
appID := rand.Uint64()
|
||||
appKey := uint64(0)
|
||||
t, err := pn.addDirectTunnel(config, 0)
|
||||
var rtid uint64
|
||||
relayNode := ""
|
||||
relayMode := ""
|
||||
peerNatType := NATUnknown
|
||||
peerIP := ""
|
||||
errMsg := ""
|
||||
if err != nil && err == ErrorHandshake {
|
||||
gLog.Println(LevelERROR, "direct connect failed, try to relay")
|
||||
appKey = rand.Uint64()
|
||||
t, rtid, err = pn.addRelayTunnel(config, appID, appKey)
|
||||
if t != nil {
|
||||
relayNode = t.config.PeerNode
|
||||
}
|
||||
}
|
||||
t, err := pn.addDirectTunnel(config, 0)
|
||||
if t != nil {
|
||||
peerNatType = t.config.peerNatType
|
||||
peerIP = t.config.peerIP
|
||||
}
|
||||
if err != nil && err == ErrorHandshake {
|
||||
gLog.Println(LevelERROR, "direct connect failed, try to relay")
|
||||
appKey = rand.Uint64()
|
||||
t, rtid, relayMode, err = pn.addRelayTunnel(config, appID, appKey)
|
||||
if t != nil {
|
||||
relayNode = t.config.PeerNode
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
errMsg = err.Error()
|
||||
}
|
||||
@@ -249,7 +250,6 @@ func (pn *P2PNetwork) AddApp(config AppConfig) error {
|
||||
PeerNode: config.PeerNode,
|
||||
DstPort: config.DstPort,
|
||||
DstHost: config.DstHost,
|
||||
PeerUser: config.PeerUser,
|
||||
PeerNatType: peerNatType,
|
||||
PeerIP: peerIP,
|
||||
ShareBandwidth: pn.config.ShareBandwidth,
|
||||
@@ -257,7 +257,9 @@ func (pn *P2PNetwork) AddApp(config AppConfig) error {
|
||||
Version: OpenP2PVersion,
|
||||
}
|
||||
pn.write(MsgReport, MsgReportConnect, &req)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
app := p2pApp{
|
||||
id: appID,
|
||||
key: appKey,
|
||||
@@ -265,6 +267,7 @@ func (pn *P2PNetwork) AddApp(config AppConfig) error {
|
||||
config: config,
|
||||
rtid: rtid,
|
||||
relayNode: relayNode,
|
||||
relayMode: relayMode,
|
||||
hbTime: time.Now()}
|
||||
pn.apps.Store(fmt.Sprintf("%s%d", config.Protocol, config.SrcPort), &app)
|
||||
if err == nil {
|
||||
@@ -364,11 +367,6 @@ func (pn *P2PNetwork) init() error {
|
||||
gLog.Println(LevelINFO, "init start")
|
||||
var err error
|
||||
for {
|
||||
pn.config.hostName, err = os.Hostname()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
// detect nat type
|
||||
pn.config.publicIP, pn.config.natType, err = getNATType(pn.config.ServerHost, pn.config.UDPPort1, pn.config.UDPPort2)
|
||||
// TODO rm test s2s
|
||||
@@ -387,8 +385,7 @@ func (pn *P2PNetwork) init() error {
|
||||
u := url.URL{Scheme: "wss", Host: gatewayURL, Path: forwardPath}
|
||||
q := u.Query()
|
||||
q.Add("node", pn.config.Node)
|
||||
q.Add("user", pn.config.User)
|
||||
q.Add("password", pn.config.Password)
|
||||
q.Add("token", fmt.Sprintf("%d", pn.config.Token))
|
||||
q.Add("version", OpenP2PVersion)
|
||||
q.Add("nattype", fmt.Sprintf("%d", pn.config.natType))
|
||||
q.Add("sharebandwidth", fmt.Sprintf("%d", pn.config.ShareBandwidth))
|
||||
@@ -460,8 +457,15 @@ func (pn *P2PNetwork) handleMessage(t int, msg []byte) {
|
||||
pn.running = false
|
||||
} else {
|
||||
pn.serverTs = rsp.Ts
|
||||
pn.config.Token = rsp.Token
|
||||
pn.config.User = rsp.User
|
||||
gConf.mtx.Lock()
|
||||
gConf.Network.Token = rsp.Token
|
||||
gConf.Network.User = rsp.User
|
||||
gConf.mtx.Unlock()
|
||||
gConf.save()
|
||||
pn.localTs = time.Now().Unix()
|
||||
gLog.Printf(LevelINFO, "login ok. Server ts=%d, local ts=%d", rsp.Ts, pn.localTs)
|
||||
gLog.Printf(LevelINFO, "login ok. user=%s,Server ts=%d, local ts=%d", rsp.User, rsp.Ts, pn.localTs)
|
||||
}
|
||||
case MsgHeartbeat:
|
||||
gLog.Printf(LevelDEBUG, "P2PNetwork heartbeat ok")
|
||||
@@ -561,12 +565,15 @@ func (pn *P2PNetwork) read(node string, mainType uint16, subType uint16, timeout
|
||||
} else {
|
||||
nodeID = nodeNameToID(node)
|
||||
}
|
||||
pn.msgMapMtx.Lock()
|
||||
ch := pn.msgMap[nodeID]
|
||||
pn.msgMapMtx.Unlock()
|
||||
for {
|
||||
select {
|
||||
case <-time.After(timeout):
|
||||
gLog.Printf(LevelERROR, "wait msg%d:%d timeout", mainType, subType)
|
||||
return
|
||||
case msg := <-pn.msgMap[nodeID]:
|
||||
case msg := <-ch:
|
||||
head = &openP2PHeader{}
|
||||
err := binary.Read(bytes.NewReader(msg[:openP2PHeaderSize]), binary.LittleEndian, head)
|
||||
if err != nil {
|
||||
|
||||
80
p2ptunnel.go
@@ -55,10 +55,9 @@ func (t *P2PTunnel) connect() error {
|
||||
gLog.Printf(LevelDEBUG, "start p2pTunnel to %s ", t.config.PeerNode)
|
||||
t.isServer = false
|
||||
req := PushConnectReq{
|
||||
User: t.config.PeerUser,
|
||||
Password: t.config.PeerPassword,
|
||||
Token: t.config.peerToken,
|
||||
From: t.pn.config.Node,
|
||||
FromToken: t.pn.config.Token,
|
||||
FromIP: t.pn.config.publicIP,
|
||||
ConeNatPort: t.coneNatPort,
|
||||
NatType: t.pn.config.natType,
|
||||
@@ -277,7 +276,7 @@ func (t *P2PTunnel) readLoop() {
|
||||
gLog.Printf(LevelDEBUG, "%d tunnel not found overlay connection %d", t.id, overlayID)
|
||||
continue
|
||||
}
|
||||
overlayConn, ok := s.(*overlayTCP)
|
||||
overlayConn, ok := s.(*overlayConn)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
@@ -326,40 +325,42 @@ func (t *P2PTunnel) readLoop() {
|
||||
gLog.Printf(LevelERROR, "wrong MsgOverlayConnectReq:%s", err)
|
||||
continue
|
||||
}
|
||||
// app connect only accept user/password, avoid someone using the share relay node's token
|
||||
if req.User != t.pn.config.User || req.Password != t.pn.config.Password {
|
||||
gLog.Println(LevelERROR, "Access Denied:", req.User)
|
||||
// app connect only accept token(not relay totp token), avoid someone using the share relay node's token
|
||||
if req.Token != t.pn.config.Token {
|
||||
gLog.Println(LevelERROR, "Access Denied:", req.Token)
|
||||
continue
|
||||
}
|
||||
|
||||
overlayID := req.ID
|
||||
gLog.Printf(LevelDEBUG, "App:%d overlayID:%d connect %+v", req.AppID, overlayID, req)
|
||||
if req.Protocol == "tcp" {
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", req.DstIP, req.DstPort), time.Second*5)
|
||||
if err != nil {
|
||||
gLog.Println(LevelERROR, err)
|
||||
continue
|
||||
}
|
||||
otcp := overlayTCP{
|
||||
tunnel: t,
|
||||
conn: conn,
|
||||
id: overlayID,
|
||||
isClient: false,
|
||||
rtid: req.RelayTunnelID,
|
||||
appID: req.AppID,
|
||||
appKey: GetKey(req.AppID),
|
||||
}
|
||||
// calc key bytes for encrypt
|
||||
if otcp.appKey != 0 {
|
||||
encryptKey := make([]byte, 16)
|
||||
binary.LittleEndian.PutUint64(encryptKey, otcp.appKey)
|
||||
binary.LittleEndian.PutUint64(encryptKey[8:], otcp.appKey)
|
||||
otcp.appKeyBytes = encryptKey
|
||||
}
|
||||
|
||||
t.overlayConns.Store(otcp.id, &otcp)
|
||||
go otcp.run()
|
||||
oConn := overlayConn{
|
||||
tunnel: t,
|
||||
id: overlayID,
|
||||
isClient: false,
|
||||
rtid: req.RelayTunnelID,
|
||||
appID: req.AppID,
|
||||
appKey: GetKey(req.AppID),
|
||||
}
|
||||
if req.Protocol == "udp" {
|
||||
oConn.connUDP, err = net.DialUDP("udp", nil, &net.UDPAddr{IP: net.ParseIP(req.DstIP), Port: req.DstPort})
|
||||
} else {
|
||||
oConn.connTCP, err = net.DialTimeout("tcp", fmt.Sprintf("%s:%d", req.DstIP, req.DstPort), time.Second*5)
|
||||
}
|
||||
if err != nil {
|
||||
gLog.Println(LevelERROR, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// calc key bytes for encrypt
|
||||
if oConn.appKey != 0 {
|
||||
encryptKey := make([]byte, 16)
|
||||
binary.LittleEndian.PutUint64(encryptKey, oConn.appKey)
|
||||
binary.LittleEndian.PutUint64(encryptKey[8:], oConn.appKey)
|
||||
oConn.appKeyBytes = encryptKey
|
||||
}
|
||||
|
||||
t.overlayConns.Store(oConn.id, &oConn)
|
||||
go oConn.run()
|
||||
case MsgOverlayDisconnectReq:
|
||||
req := OverlayDisconnectReq{}
|
||||
err := json.Unmarshal(body, &req)
|
||||
@@ -371,8 +372,8 @@ func (t *P2PTunnel) readLoop() {
|
||||
gLog.Printf(LevelDEBUG, "%d disconnect overlay connection %d", t.id, overlayID)
|
||||
i, ok := t.overlayConns.Load(overlayID)
|
||||
if ok {
|
||||
otcp := i.(*overlayTCP)
|
||||
otcp.running = false
|
||||
oConn := i.(*overlayConn)
|
||||
oConn.running = false
|
||||
}
|
||||
default:
|
||||
}
|
||||
@@ -409,9 +410,16 @@ func (t *P2PTunnel) listen() error {
|
||||
|
||||
func (t *P2PTunnel) closeOverlayConns(appID uint64) {
|
||||
t.overlayConns.Range(func(_, i interface{}) bool {
|
||||
otcp := i.(*overlayTCP)
|
||||
if otcp.appID == appID {
|
||||
otcp.conn.Close()
|
||||
oConn := i.(*overlayConn)
|
||||
if oConn.appID == appID {
|
||||
if oConn.connTCP != nil {
|
||||
oConn.connTCP.Close()
|
||||
oConn.connTCP = nil
|
||||
}
|
||||
if oConn.connUDP != nil {
|
||||
oConn.connUDP.Close()
|
||||
oConn.connUDP = nil
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
34
protocol.go
@@ -10,7 +10,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const OpenP2PVersion = "0.99.0"
|
||||
const OpenP2PVersion = "1.3.0"
|
||||
const ProducnName string = "openp2p"
|
||||
|
||||
type openP2PHeader struct {
|
||||
@@ -80,6 +80,9 @@ const (
|
||||
MsgPushReportApps = 7
|
||||
MsgPushQuicConnect = 8
|
||||
MsgPushEditApp = 9
|
||||
MsgPushSwitchApp = 10
|
||||
MsgPushRestart = 11
|
||||
MsgPushEditNode = 12
|
||||
)
|
||||
|
||||
// MsgP2P sub type message
|
||||
@@ -114,7 +117,7 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
ReadBuffLen = 1024
|
||||
ReadBuffLen = 4096 // for UDP maybe not enough
|
||||
NetworkHeartbeatTime = time.Second * 30 // TODO: server no response hb, save flow
|
||||
TunnelHeartbeatTime = time.Second * 15
|
||||
TunnelIdleTimeout = time.Minute
|
||||
@@ -167,9 +170,8 @@ func nodeNameToID(name string) uint64 {
|
||||
|
||||
type PushConnectReq struct {
|
||||
From string `json:"from,omitempty"`
|
||||
User string `json:"user,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Token uint64 `json:"token,omitempty"`
|
||||
FromToken uint64 `json:"fromToken,omitempty"` //my token
|
||||
Token uint64 `json:"token,omitempty"` // totp token
|
||||
ConeNatPort int `json:"coneNatPort,omitempty"`
|
||||
NatType int `json:"natType,omitempty"`
|
||||
FromIP string `json:"fromIP,omitempty"`
|
||||
@@ -193,6 +195,8 @@ type PushRsp struct {
|
||||
type LoginRsp struct {
|
||||
Error int `json:"error,omitempty"`
|
||||
Detail string `json:"detail,omitempty"`
|
||||
User string `json:"user,omitempty"`
|
||||
Token uint64 `json:"token,omitempty"`
|
||||
Ts int64 `json:"ts,omitempty"`
|
||||
}
|
||||
|
||||
@@ -213,8 +217,7 @@ type P2PHandshakeReq struct {
|
||||
|
||||
type OverlayConnectReq struct {
|
||||
ID uint64 `json:"id,omitempty"`
|
||||
User string `json:"user,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Token uint64 `json:"token,omitempty"` // not totp token
|
||||
DstIP string `json:"dstIP,omitempty"`
|
||||
DstPort int `json:"dstPort,omitempty"`
|
||||
Protocol string `json:"protocol,omitempty"`
|
||||
@@ -233,6 +236,7 @@ type RelayNodeReq struct {
|
||||
}
|
||||
|
||||
type RelayNodeRsp struct {
|
||||
Mode string `json:"mode,omitempty"` // private,public
|
||||
RelayName string `json:"relayName,omitempty"`
|
||||
RelayToken uint64 `json:"relayToken,omitempty"`
|
||||
}
|
||||
@@ -291,9 +295,11 @@ type AppInfo struct {
|
||||
PeerIP string `json:"peerIP,omitempty"`
|
||||
ShareBandwidth int `json:"shareBandWidth,omitempty"`
|
||||
RelayNode string `json:"relayNode,omitempty"`
|
||||
RelayMode string `json:"relayMode,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
RetryTime string `json:"retryTime,omitempty"`
|
||||
IsActive int `json:"isActive,omitempty"`
|
||||
Enabled int `json:"enabled,omitempty"`
|
||||
}
|
||||
|
||||
type ReportApps struct {
|
||||
@@ -324,3 +330,17 @@ type NetInfo struct {
|
||||
ASNOrg string `json:"asn_org,omitempty"`
|
||||
Hostname string `json:"hostname,omitempty"`
|
||||
}
|
||||
|
||||
type ProfileInfo struct {
|
||||
User string `json:"user,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Email string `json:"email,omitempty"`
|
||||
Phone string `json:"phone,omitempty"`
|
||||
Token string `json:"token,omitempty"`
|
||||
Addtime string `json:"addtime,omitempty"`
|
||||
}
|
||||
|
||||
type EditNode struct {
|
||||
NewName string `json:"newName,omitempty"`
|
||||
Bandwidth int `json:"bandwidth,omitempty"`
|
||||
}
|
||||
|
||||
2
quic.go
@@ -99,7 +99,7 @@ func (conn *quicConn) Accept() error {
|
||||
}
|
||||
|
||||
func listenQuic(addr string, idleTimeout time.Duration) (*quicConn, error) {
|
||||
gLog.Println(LevelINFO, "quic listen on ", addr)
|
||||
gLog.Println(LevelDEBUG, "quic listen on ", addr)
|
||||
listener, err := quic.ListenAddr(addr, generateTLSConfig(),
|
||||
&quic.Config{Versions: quicVersion, MaxIdleTimeout: idleTimeout, DisablePathMTUDiscovery: true})
|
||||
if err != nil {
|
||||
|
||||
10
totp.go
@@ -8,9 +8,11 @@ import (
|
||||
)
|
||||
|
||||
const TOTPStep = 30 // 30s
|
||||
func GenTOTP(user string, password string, ts int64) uint64 {
|
||||
func GenTOTP(token uint64, ts int64) uint64 {
|
||||
step := ts / TOTPStep
|
||||
mac := hmac.New(sha256.New, []byte(user+password))
|
||||
tbuff := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(tbuff, token)
|
||||
mac := hmac.New(sha256.New, tbuff)
|
||||
b := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(b, uint64(step))
|
||||
mac.Write(b)
|
||||
@@ -19,11 +21,11 @@ func GenTOTP(user string, password string, ts int64) uint64 {
|
||||
return num
|
||||
}
|
||||
|
||||
func VerifyTOTP(code uint64, user string, password string, ts int64) bool {
|
||||
func VerifyTOTP(code uint64, token uint64, ts int64) bool {
|
||||
if code == 0 {
|
||||
return false
|
||||
}
|
||||
if code == GenTOTP(user, password, ts) || code == GenTOTP(user, password, ts-TOTPStep) || code == GenTOTP(user, password, ts+TOTPStep) {
|
||||
if code == GenTOTP(token, ts) || code == GenTOTP(token, ts-TOTPStep) || code == GenTOTP(token, ts+TOTPStep) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
14
totp_test.go
@@ -9,24 +9,24 @@ import (
|
||||
func TestTOTP(t *testing.T) {
|
||||
for i := 0; i < 20; i++ {
|
||||
ts := time.Now().Unix()
|
||||
code := GenTOTP("testuser1", "testpassword1", ts)
|
||||
code := GenTOTP(13666999958022769123, ts)
|
||||
t.Log(code)
|
||||
if !VerifyTOTP(code, "testuser1", "testpassword1", ts) {
|
||||
if !VerifyTOTP(code, 13666999958022769123, ts) {
|
||||
t.Error("TOTP error")
|
||||
}
|
||||
if !VerifyTOTP(code, "testuser1", "testpassword1", ts-10) {
|
||||
if !VerifyTOTP(code, 13666999958022769123, ts-10) {
|
||||
t.Error("TOTP error")
|
||||
}
|
||||
if !VerifyTOTP(code, "testuser1", "testpassword1", ts+10) {
|
||||
if !VerifyTOTP(code, 13666999958022769123, ts+10) {
|
||||
t.Error("TOTP error")
|
||||
}
|
||||
if VerifyTOTP(code, "testuser1", "testpassword1", ts+60) {
|
||||
if VerifyTOTP(code, 13666999958022769123, ts+60) {
|
||||
t.Error("TOTP error")
|
||||
}
|
||||
if VerifyTOTP(code, "testuser2", "testpassword1", ts+1) {
|
||||
if VerifyTOTP(code, 13666999958022769124, ts+1) {
|
||||
t.Error("TOTP error")
|
||||
}
|
||||
if VerifyTOTP(code, "testuser1", "testpassword2", ts+1) {
|
||||
if VerifyTOTP(code, 13666999958022769125, ts+1) {
|
||||
t.Error("TOTP error")
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
|
||||
@@ -27,7 +27,7 @@ func update() {
|
||||
}
|
||||
goos := runtime.GOOS
|
||||
goarch := runtime.GOARCH
|
||||
rsp, err := c.Get(fmt.Sprintf("https://openp2p.cn:27182/api/v1/update?fromver=%s&os=%s&arch=%s", OpenP2PVersion, goos, goarch))
|
||||
rsp, err := c.Get(fmt.Sprintf("https://openp2p.cn:27183/api/v1/update?fromver=%s&os=%s&arch=%s", OpenP2PVersion, goos, goarch))
|
||||
if err != nil {
|
||||
gLog.Println(LevelERROR, "update:query update list failed:", err)
|
||||
return
|
||||
|
||||