mirror of
https://github.com/openp2p-cn/openp2p.git
synced 2025-09-26 20:51:15 +08:00
LF
This commit is contained in:
216
USAGE-ZH.md
216
USAGE-ZH.md
@@ -1,108 +1,108 @@
|
||||
# 手动运行说明
|
||||
大部分情况通过<https://console.openp2p.cn> 操作即可。有些情况需要手动运行
|
||||
> :warning: 本文所有命令, Windows环境使用"openp2p.exe", Linux环境使用"./openp2p"
|
||||
|
||||
|
||||
## 安装和监听
|
||||
```
|
||||
./openp2p install -node OFFICEPC1 -token TOKEN
|
||||
或
|
||||
./openp2p -d -node OFFICEPC1 -token TOKEN
|
||||
# 注意Windows系统把“./openp2p” 换成“openp2p.exe”
|
||||
```
|
||||
>* install: 安装模式【推荐】,会安装成系统服务,这样它就能随系统自动启动
|
||||
>* -d: daemon模式。发现worker进程意外退出就会自动启动新的worker进程
|
||||
>* -node: 独一无二的节点名字,唯一标识
|
||||
>* -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 -token TOKEN -appname OfficeWindowsRemote -peernode OFFICEPC1 -dstip 127.0.0.1 -dstport 3389 -srcport 23389
|
||||
使用配置文件,建立多个P2PApp
|
||||
./openp2p -d
|
||||
```
|
||||
>* -appname: 这个P2P应用名字
|
||||
>* -peernode: 目标节点名字
|
||||
>* -dstip: 目标服务地址,默认本机127.0.0.1
|
||||
>* -dstport: 目标服务端口,常见的如windows远程桌面3389,Linux ssh 22
|
||||
>* -protocol: 目标服务协议 tcp、udp
|
||||
|
||||
## 配置文件
|
||||
一般保存在当前目录,安装模式下会保存到 `C:\Program Files\OpenP2P\config.json` 或 `/usr/local/openp2p/config.json`
|
||||
希望修改参数,或者配置多个P2PApp可手动修改配置文件
|
||||
|
||||
配置实例
|
||||
```
|
||||
{
|
||||
"network": {
|
||||
"Node": "YOUR-NODE-NAME",
|
||||
"Token": "TOKEN",
|
||||
"ShareBandwidth": 0,
|
||||
"ServerHost": "api.openp2p.cn",
|
||||
"ServerPort": 27183,
|
||||
"UDPPort1": 27182,
|
||||
"UDPPort2": 27183
|
||||
},
|
||||
"apps": [
|
||||
{
|
||||
"AppName": "OfficeWindowsPC",
|
||||
"Protocol": "tcp",
|
||||
"SrcPort": 23389,
|
||||
"PeerNode": "OFFICEPC1",
|
||||
"DstPort": 3389,
|
||||
"DstHost": "localhost",
|
||||
},
|
||||
{
|
||||
"AppName": "OfficeServerSSH",
|
||||
"Protocol": "tcp",
|
||||
"SrcPort": 22,
|
||||
"PeerNode": "OFFICEPC1",
|
||||
"DstPort": 22,
|
||||
"DstHost": "192.168.1.5",
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 升级客户端
|
||||
```
|
||||
# update local client
|
||||
./openp2p update
|
||||
# update remote client
|
||||
curl --insecure 'https://api.openp2p.cn:27183/api/v1/device/YOUR-NODE-NAME/update?user=&password='
|
||||
```
|
||||
|
||||
Windows系统需要设置防火墙放行本程序,程序会自动设置,如果设置失败会影响连接功能。
|
||||
Linux系统(Ubuntu和CentOS7)的防火墙默认配置均不会有影响,如果不行可尝试关闭防火墙
|
||||
```
|
||||
systemctl stop firewalld.service
|
||||
systemctl start firewalld.service
|
||||
firewall-cmd --state
|
||||
```
|
||||
## 停止
|
||||
TODO: windows linux macos
|
||||
## 卸载
|
||||
```
|
||||
./openp2p uninstall
|
||||
# 已安装时
|
||||
# windows
|
||||
C:\Program Files\OpenP2P\openp2p.exe uninstall
|
||||
# linux,macos
|
||||
sudo /usr/local/openp2p/openp2p uninstall
|
||||
```
|
||||
|
||||
## Docker运行
|
||||
```
|
||||
# 把YOUR-TOKEN和YOUR-NODE-NAME替换成自己的
|
||||
docker run -d --restart=always --net host --name openp2p-client -e OPENP2P_TOKEN=YOUR-TOKEN -e OPENP2P_NODE=YOUR-NODE-NAME openp2pcn/openp2p-client:latest
|
||||
OR
|
||||
docker run -d --restart=always --net host --name openp2p-client openp2pcn/openp2p-client:latest -token YOUR-TOKEN -node YOUR-NODE-NAME
|
||||
```
|
||||
# 手动运行说明
|
||||
大部分情况通过<https://console.openp2p.cn> 操作即可。有些情况需要手动运行
|
||||
> :warning: 本文所有命令, Windows环境使用"openp2p.exe", Linux环境使用"./openp2p"
|
||||
|
||||
|
||||
## 安装和监听
|
||||
```
|
||||
./openp2p install -node OFFICEPC1 -token TOKEN
|
||||
或
|
||||
./openp2p -d -node OFFICEPC1 -token TOKEN
|
||||
# 注意Windows系统把“./openp2p” 换成“openp2p.exe”
|
||||
```
|
||||
>* install: 安装模式【推荐】,会安装成系统服务,这样它就能随系统自动启动
|
||||
>* -d: daemon模式。发现worker进程意外退出就会自动启动新的worker进程
|
||||
>* -node: 独一无二的节点名字,唯一标识
|
||||
>* -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 -token TOKEN -appname OfficeWindowsRemote -peernode OFFICEPC1 -dstip 127.0.0.1 -dstport 3389 -srcport 23389
|
||||
使用配置文件,建立多个P2PApp
|
||||
./openp2p -d
|
||||
```
|
||||
>* -appname: 这个P2P应用名字
|
||||
>* -peernode: 目标节点名字
|
||||
>* -dstip: 目标服务地址,默认本机127.0.0.1
|
||||
>* -dstport: 目标服务端口,常见的如windows远程桌面3389,Linux ssh 22
|
||||
>* -protocol: 目标服务协议 tcp、udp
|
||||
|
||||
## 配置文件
|
||||
一般保存在当前目录,安装模式下会保存到 `C:\Program Files\OpenP2P\config.json` 或 `/usr/local/openp2p/config.json`
|
||||
希望修改参数,或者配置多个P2PApp可手动修改配置文件
|
||||
|
||||
配置实例
|
||||
```
|
||||
{
|
||||
"network": {
|
||||
"Node": "YOUR-NODE-NAME",
|
||||
"Token": "TOKEN",
|
||||
"ShareBandwidth": 0,
|
||||
"ServerHost": "api.openp2p.cn",
|
||||
"ServerPort": 27183,
|
||||
"UDPPort1": 27182,
|
||||
"UDPPort2": 27183
|
||||
},
|
||||
"apps": [
|
||||
{
|
||||
"AppName": "OfficeWindowsPC",
|
||||
"Protocol": "tcp",
|
||||
"SrcPort": 23389,
|
||||
"PeerNode": "OFFICEPC1",
|
||||
"DstPort": 3389,
|
||||
"DstHost": "localhost",
|
||||
},
|
||||
{
|
||||
"AppName": "OfficeServerSSH",
|
||||
"Protocol": "tcp",
|
||||
"SrcPort": 22,
|
||||
"PeerNode": "OFFICEPC1",
|
||||
"DstPort": 22,
|
||||
"DstHost": "192.168.1.5",
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 升级客户端
|
||||
```
|
||||
# update local client
|
||||
./openp2p update
|
||||
# update remote client
|
||||
curl --insecure 'https://api.openp2p.cn:27183/api/v1/device/YOUR-NODE-NAME/update?user=&password='
|
||||
```
|
||||
|
||||
Windows系统需要设置防火墙放行本程序,程序会自动设置,如果设置失败会影响连接功能。
|
||||
Linux系统(Ubuntu和CentOS7)的防火墙默认配置均不会有影响,如果不行可尝试关闭防火墙
|
||||
```
|
||||
systemctl stop firewalld.service
|
||||
systemctl start firewalld.service
|
||||
firewall-cmd --state
|
||||
```
|
||||
## 停止
|
||||
TODO: windows linux macos
|
||||
## 卸载
|
||||
```
|
||||
./openp2p uninstall
|
||||
# 已安装时
|
||||
# windows
|
||||
C:\Program Files\OpenP2P\openp2p.exe uninstall
|
||||
# linux,macos
|
||||
sudo /usr/local/openp2p/openp2p uninstall
|
||||
```
|
||||
|
||||
## Docker运行
|
||||
```
|
||||
# 把YOUR-TOKEN和YOUR-NODE-NAME替换成自己的
|
||||
docker run -d --restart=always --net host --name openp2p-client -e OPENP2P_TOKEN=YOUR-TOKEN -e OPENP2P_NODE=YOUR-NODE-NAME openp2pcn/openp2p-client:latest
|
||||
OR
|
||||
docker run -d --restart=always --net host --name openp2p-client openp2pcn/openp2p-client:latest -token YOUR-TOKEN -node YOUR-NODE-NAME
|
||||
```
|
||||
|
216
USAGE.md
216
USAGE.md
@@ -1,109 +1,109 @@
|
||||
|
||||
|
||||
# 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 -token TOKEN
|
||||
Or
|
||||
./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
|
||||
>* -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 -token TOKEN -appname OfficeWindowsRemote -peernode OFFICEPC1 -dstip 127.0.0.1 -dstport 3389 -srcport 23389
|
||||
Create multiple P2PApp by config file
|
||||
./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
|
||||
|
||||
## 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`
|
||||
If you want to modify the parameters, or configure multiple P2PApps, you can manually modify the configuration file
|
||||
|
||||
Configuration example
|
||||
```
|
||||
{
|
||||
"network": {
|
||||
"Node": "YOUR-NODE-NAME",
|
||||
"Token": "TOKEN",
|
||||
"ShareBandwidth": 0,
|
||||
"ServerHost": "api.openp2p.cn",
|
||||
"ServerPort": 27183,
|
||||
"UDPPort1": 27182,
|
||||
"UDPPort2": 27183
|
||||
},
|
||||
"apps": [
|
||||
{
|
||||
"AppName": "OfficeWindowsPC",
|
||||
"Protocol": "tcp",
|
||||
"SrcPort": 23389,
|
||||
"PeerNode": "OFFICEPC1",
|
||||
"DstPort": 3389,
|
||||
"DstHost": "localhost",
|
||||
},
|
||||
{
|
||||
"AppName": "OfficeServerSSH",
|
||||
"Protocol": "tcp",
|
||||
"SrcPort": 22,
|
||||
"PeerNode": "OFFICEPC1",
|
||||
"DstPort": 22,
|
||||
"DstHost": "192.168.1.5",
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
## Client update
|
||||
```
|
||||
# update local client
|
||||
./openp2p update
|
||||
# update remote client
|
||||
curl --insecure 'https://api.openp2p.cn:27183/api/v1/device/YOUR-NODE-NAME/update?user=&password='
|
||||
```
|
||||
|
||||
Windows system needs to set up firewall for this program, the program will automatically set the firewall, if the setting fails, the UDP punching will be affected.
|
||||
The default firewall configuration of Linux system (Ubuntu and CentOS7) will not have any effect, if not, you can try to turn off the firewall
|
||||
```
|
||||
systemctl stop firewalld.service
|
||||
systemctl start firewalld.service
|
||||
firewall-cmd --state
|
||||
```
|
||||
|
||||
## Uninstall
|
||||
```
|
||||
./openp2p uninstall
|
||||
# when already installed
|
||||
# windows
|
||||
C:\Program Files\OpenP2P\openp2p.exe uninstall
|
||||
# linux,macos
|
||||
sudo /usr/local/openp2p/openp2p uninstall
|
||||
```
|
||||
|
||||
## Run with Docker
|
||||
```
|
||||
# Replace YOUR-TOKEN and YOUR-NODE-NAME with yours
|
||||
docker run -d --net host --name openp2p-client -e OPENP2P_TOKEN=YOUR-TOKEN -e OPENP2P_NODE=YOUR-NODE-NAME openp2pcn/openp2p-client:latest
|
||||
OR
|
||||
docker run -d --net host --name openp2p-client openp2pcn/openp2p-client:latest -token YOUR-TOKEN -node YOUR-NODE-NAME
|
||||
|
||||
|
||||
# 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 -token TOKEN
|
||||
Or
|
||||
./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
|
||||
>* -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 -token TOKEN -appname OfficeWindowsRemote -peernode OFFICEPC1 -dstip 127.0.0.1 -dstport 3389 -srcport 23389
|
||||
Create multiple P2PApp by config file
|
||||
./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
|
||||
|
||||
## 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`
|
||||
If you want to modify the parameters, or configure multiple P2PApps, you can manually modify the configuration file
|
||||
|
||||
Configuration example
|
||||
```
|
||||
{
|
||||
"network": {
|
||||
"Node": "YOUR-NODE-NAME",
|
||||
"Token": "TOKEN",
|
||||
"ShareBandwidth": 0,
|
||||
"ServerHost": "api.openp2p.cn",
|
||||
"ServerPort": 27183,
|
||||
"UDPPort1": 27182,
|
||||
"UDPPort2": 27183
|
||||
},
|
||||
"apps": [
|
||||
{
|
||||
"AppName": "OfficeWindowsPC",
|
||||
"Protocol": "tcp",
|
||||
"SrcPort": 23389,
|
||||
"PeerNode": "OFFICEPC1",
|
||||
"DstPort": 3389,
|
||||
"DstHost": "localhost",
|
||||
},
|
||||
{
|
||||
"AppName": "OfficeServerSSH",
|
||||
"Protocol": "tcp",
|
||||
"SrcPort": 22,
|
||||
"PeerNode": "OFFICEPC1",
|
||||
"DstPort": 22,
|
||||
"DstHost": "192.168.1.5",
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
## Client update
|
||||
```
|
||||
# update local client
|
||||
./openp2p update
|
||||
# update remote client
|
||||
curl --insecure 'https://api.openp2p.cn:27183/api/v1/device/YOUR-NODE-NAME/update?user=&password='
|
||||
```
|
||||
|
||||
Windows system needs to set up firewall for this program, the program will automatically set the firewall, if the setting fails, the UDP punching will be affected.
|
||||
The default firewall configuration of Linux system (Ubuntu and CentOS7) will not have any effect, if not, you can try to turn off the firewall
|
||||
```
|
||||
systemctl stop firewalld.service
|
||||
systemctl start firewalld.service
|
||||
firewall-cmd --state
|
||||
```
|
||||
|
||||
## Uninstall
|
||||
```
|
||||
./openp2p uninstall
|
||||
# when already installed
|
||||
# windows
|
||||
C:\Program Files\OpenP2P\openp2p.exe uninstall
|
||||
# linux,macos
|
||||
sudo /usr/local/openp2p/openp2p uninstall
|
||||
```
|
||||
|
||||
## Run with Docker
|
||||
```
|
||||
# Replace YOUR-TOKEN and YOUR-NODE-NAME with yours
|
||||
docker run -d --net host --name openp2p-client -e OPENP2P_TOKEN=YOUR-TOKEN -e OPENP2P_NODE=YOUR-NODE-NAME openp2pcn/openp2p-client:latest
|
||||
OR
|
||||
docker run -d --net host --name openp2p-client openp2pcn/openp2p-client:latest -token YOUR-TOKEN -node YOUR-NODE-NAME
|
||||
```
|
@@ -1,9 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
op "openp2p/core"
|
||||
)
|
||||
|
||||
func main() {
|
||||
op.Run()
|
||||
}
|
||||
package main
|
||||
|
||||
import (
|
||||
op "openp2p/core"
|
||||
)
|
||||
|
||||
func main() {
|
||||
op.Run()
|
||||
}
|
||||
|
230
core/daemon.go
230
core/daemon.go
@@ -1,115 +1,115 @@
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/openp2p-cn/service"
|
||||
)
|
||||
|
||||
type daemon struct {
|
||||
running bool
|
||||
proc *os.Process
|
||||
}
|
||||
|
||||
func (d *daemon) Start(s service.Service) error {
|
||||
gLog.Println(LvINFO, "daemon start")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *daemon) Stop(s service.Service) error {
|
||||
gLog.Println(LvINFO, "service stop")
|
||||
d.running = false
|
||||
if d.proc != nil {
|
||||
gLog.Println(LvINFO, "stop worker")
|
||||
d.proc.Kill()
|
||||
}
|
||||
if service.Interactive() {
|
||||
gLog.Println(LvINFO, "stop daemon")
|
||||
os.Exit(0)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *daemon) run() {
|
||||
gLog.Println(LvINFO, "daemon run start")
|
||||
defer gLog.Println(LvINFO, "daemon run end")
|
||||
d.running = true
|
||||
binPath, _ := os.Executable()
|
||||
mydir, err := os.Getwd()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
gLog.Println(LvINFO, mydir)
|
||||
conf := &service.Config{
|
||||
Name: ProductName,
|
||||
DisplayName: ProductName,
|
||||
Description: ProductName,
|
||||
Executable: binPath,
|
||||
}
|
||||
|
||||
s, _ := service.New(d, conf)
|
||||
go s.Run()
|
||||
var args []string
|
||||
// rm -d parameter
|
||||
for i := 0; i < len(os.Args); i++ {
|
||||
if os.Args[i] == "-d" {
|
||||
args = append(os.Args[0:i], os.Args[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
args = append(args, "-nv")
|
||||
for {
|
||||
// start worker
|
||||
tmpDump := filepath.Join("log", "dump.log.tmp")
|
||||
dumpFile := filepath.Join("log", "dump.log")
|
||||
f, err := os.Create(filepath.Join(tmpDump))
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "start worker error:%s", err)
|
||||
return
|
||||
}
|
||||
gLog.Println(LvINFO, "start worker process, args:", args)
|
||||
execSpec := &os.ProcAttr{Env: append(os.Environ(), "GOTRACEBACK=crash"), Files: []*os.File{os.Stdin, os.Stdout, f}}
|
||||
p, err := os.StartProcess(binPath, args, execSpec)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "start worker error:%s", err)
|
||||
return
|
||||
}
|
||||
d.proc = p
|
||||
_, _ = p.Wait()
|
||||
f.Close()
|
||||
time.Sleep(time.Second)
|
||||
err = os.Rename(tmpDump, dumpFile)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "rename dump error:%s", err)
|
||||
}
|
||||
if !d.running {
|
||||
return
|
||||
}
|
||||
gLog.Printf(LvERROR, "worker stop, restart it after 10s")
|
||||
time.Sleep(time.Second * 10)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *daemon) Control(ctrlComm string, exeAbsPath string, args []string) error {
|
||||
svcConfig := &service.Config{
|
||||
Name: ProductName,
|
||||
DisplayName: ProductName,
|
||||
Description: ProductName,
|
||||
Executable: exeAbsPath,
|
||||
Arguments: args,
|
||||
}
|
||||
|
||||
s, e := service.New(d, svcConfig)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
e = service.Control(s, ctrlComm)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/openp2p-cn/service"
|
||||
)
|
||||
|
||||
type daemon struct {
|
||||
running bool
|
||||
proc *os.Process
|
||||
}
|
||||
|
||||
func (d *daemon) Start(s service.Service) error {
|
||||
gLog.Println(LvINFO, "daemon start")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *daemon) Stop(s service.Service) error {
|
||||
gLog.Println(LvINFO, "service stop")
|
||||
d.running = false
|
||||
if d.proc != nil {
|
||||
gLog.Println(LvINFO, "stop worker")
|
||||
d.proc.Kill()
|
||||
}
|
||||
if service.Interactive() {
|
||||
gLog.Println(LvINFO, "stop daemon")
|
||||
os.Exit(0)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *daemon) run() {
|
||||
gLog.Println(LvINFO, "daemon run start")
|
||||
defer gLog.Println(LvINFO, "daemon run end")
|
||||
d.running = true
|
||||
binPath, _ := os.Executable()
|
||||
mydir, err := os.Getwd()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
gLog.Println(LvINFO, mydir)
|
||||
conf := &service.Config{
|
||||
Name: ProductName,
|
||||
DisplayName: ProductName,
|
||||
Description: ProductName,
|
||||
Executable: binPath,
|
||||
}
|
||||
|
||||
s, _ := service.New(d, conf)
|
||||
go s.Run()
|
||||
var args []string
|
||||
// rm -d parameter
|
||||
for i := 0; i < len(os.Args); i++ {
|
||||
if os.Args[i] == "-d" {
|
||||
args = append(os.Args[0:i], os.Args[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
args = append(args, "-nv")
|
||||
for {
|
||||
// start worker
|
||||
tmpDump := filepath.Join("log", "dump.log.tmp")
|
||||
dumpFile := filepath.Join("log", "dump.log")
|
||||
f, err := os.Create(filepath.Join(tmpDump))
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "start worker error:%s", err)
|
||||
return
|
||||
}
|
||||
gLog.Println(LvINFO, "start worker process, args:", args)
|
||||
execSpec := &os.ProcAttr{Env: append(os.Environ(), "GOTRACEBACK=crash"), Files: []*os.File{os.Stdin, os.Stdout, f}}
|
||||
p, err := os.StartProcess(binPath, args, execSpec)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "start worker error:%s", err)
|
||||
return
|
||||
}
|
||||
d.proc = p
|
||||
_, _ = p.Wait()
|
||||
f.Close()
|
||||
time.Sleep(time.Second)
|
||||
err = os.Rename(tmpDump, dumpFile)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "rename dump error:%s", err)
|
||||
}
|
||||
if !d.running {
|
||||
return
|
||||
}
|
||||
gLog.Printf(LvERROR, "worker stop, restart it after 10s")
|
||||
time.Sleep(time.Second * 10)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *daemon) Control(ctrlComm string, exeAbsPath string, args []string) error {
|
||||
svcConfig := &service.Config{
|
||||
Name: ProductName,
|
||||
DisplayName: ProductName,
|
||||
Description: ProductName,
|
||||
Executable: exeAbsPath,
|
||||
Arguments: args,
|
||||
}
|
||||
|
||||
s, e := service.New(d, svcConfig)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
e = service.Control(s, ctrlComm)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@@ -1,482 +1,482 @@
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/openp2p-cn/totp"
|
||||
)
|
||||
|
||||
func handlePush(subType uint16, msg []byte) error {
|
||||
pushHead := PushHeader{}
|
||||
err := binary.Read(bytes.NewReader(msg[openP2PHeaderSize:openP2PHeaderSize+PushHeaderSize]), binary.LittleEndian, &pushHead)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gLog.Printf(LvDEBUG, "handle push msg type:%d, push header:%+v", subType, pushHead)
|
||||
switch subType {
|
||||
case MsgPushConnectReq:
|
||||
err = handleConnectReq(msg)
|
||||
case MsgPushRsp:
|
||||
rsp := PushRsp{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &rsp); err != nil {
|
||||
gLog.Printf(LvERROR, "wrong pushRsp:%s", err)
|
||||
return err
|
||||
}
|
||||
if rsp.Error == 0 {
|
||||
gLog.Printf(LvDEBUG, "push ok, detail:%s", rsp.Detail)
|
||||
} else {
|
||||
gLog.Printf(LvERROR, "push error:%d, detail:%s", rsp.Error, rsp.Detail)
|
||||
}
|
||||
case MsgPushAddRelayTunnelReq:
|
||||
req := AddRelayTunnelReq{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req); err != nil {
|
||||
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(req), err)
|
||||
return err
|
||||
}
|
||||
config := AppConfig{}
|
||||
config.PeerNode = req.RelayName
|
||||
config.peerToken = req.RelayToken
|
||||
config.relayMode = req.RelayMode
|
||||
go func(r AddRelayTunnelReq) {
|
||||
t, errDt := GNetwork.addDirectTunnel(config, 0)
|
||||
if errDt == nil {
|
||||
// notify peer relay ready
|
||||
msg := TunnelMsg{ID: t.id}
|
||||
GNetwork.push(r.From, MsgPushAddRelayTunnelRsp, msg)
|
||||
appConfig := config
|
||||
appConfig.PeerNode = req.From
|
||||
} else {
|
||||
gLog.Printf(LvERROR, "addDirectTunnel error:%s", errDt)
|
||||
GNetwork.push(r.From, MsgPushAddRelayTunnelRsp, "error") // compatible with old version client, trigger unmarshal error
|
||||
}
|
||||
}(req)
|
||||
case MsgPushServerSideSaveMemApp:
|
||||
req := ServerSideSaveMemApp{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req); err != nil {
|
||||
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(req), err)
|
||||
return err
|
||||
}
|
||||
gLog.Println(LvDEBUG, "handle MsgPushServerSideSaveMemApp:", prettyJson(req))
|
||||
var existTunnel *P2PTunnel
|
||||
i, ok := GNetwork.allTunnels.Load(req.TunnelID)
|
||||
if !ok {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
i, ok = GNetwork.allTunnels.Load(req.TunnelID) // retry sometimes will receive MsgPushServerSideSaveMemApp but p2ptunnel not store yet.
|
||||
if !ok {
|
||||
gLog.Println(LvERROR, "handle MsgPushServerSideSaveMemApp error:", ErrMemAppTunnelNotFound)
|
||||
return ErrMemAppTunnelNotFound
|
||||
}
|
||||
}
|
||||
existTunnel = i.(*P2PTunnel)
|
||||
peerID := NodeNameToID(req.From)
|
||||
existApp, appok := GNetwork.apps.Load(peerID)
|
||||
if appok {
|
||||
app := existApp.(*p2pApp)
|
||||
app.config.AppName = fmt.Sprintf("%d", peerID)
|
||||
app.id = req.AppID
|
||||
app.setRelayTunnelID(req.RelayTunnelID)
|
||||
app.relayMode = req.RelayMode
|
||||
app.hbTimeRelay = time.Now()
|
||||
if req.RelayTunnelID == 0 {
|
||||
app.setDirectTunnel(existTunnel)
|
||||
} else {
|
||||
app.setRelayTunnel(existTunnel)
|
||||
}
|
||||
gLog.Println(LvDEBUG, "find existing memapp, update it")
|
||||
} else {
|
||||
appConfig := existTunnel.config
|
||||
appConfig.SrcPort = 0
|
||||
appConfig.Protocol = ""
|
||||
appConfig.AppName = fmt.Sprintf("%d", peerID)
|
||||
appConfig.PeerNode = req.From
|
||||
app := p2pApp{
|
||||
id: req.AppID,
|
||||
config: appConfig,
|
||||
relayMode: req.RelayMode,
|
||||
running: true,
|
||||
hbTimeRelay: time.Now(),
|
||||
}
|
||||
if req.RelayTunnelID == 0 {
|
||||
app.setDirectTunnel(existTunnel)
|
||||
} else {
|
||||
app.setRelayTunnel(existTunnel)
|
||||
app.setRelayTunnelID(req.RelayTunnelID)
|
||||
}
|
||||
if req.RelayTunnelID != 0 {
|
||||
app.relayNode = req.Node
|
||||
}
|
||||
GNetwork.apps.Store(NodeNameToID(req.From), &app)
|
||||
}
|
||||
|
||||
return nil
|
||||
case MsgPushAPPKey:
|
||||
req := APPKeySync{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req); err != nil {
|
||||
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(req), err)
|
||||
return err
|
||||
}
|
||||
SaveKey(req.AppID, req.AppKey)
|
||||
case MsgPushUpdate:
|
||||
gLog.Println(LvINFO, "MsgPushUpdate")
|
||||
err := update(gConf.Network.ServerHost, gConf.Network.ServerPort)
|
||||
if err == nil {
|
||||
os.Exit(0)
|
||||
}
|
||||
return err
|
||||
case MsgPushRestart:
|
||||
gLog.Println(LvINFO, "MsgPushRestart")
|
||||
os.Exit(0)
|
||||
return err
|
||||
case MsgPushReportApps:
|
||||
err = handleReportApps()
|
||||
case MsgPushReportMemApps:
|
||||
err = handleReportMemApps()
|
||||
case MsgPushReportLog:
|
||||
err = handleLog(msg)
|
||||
case MsgPushReportGoroutine:
|
||||
err = handleReportGoroutine()
|
||||
case MsgPushCheckRemoteService:
|
||||
err = handleCheckRemoteService(msg)
|
||||
case MsgPushEditApp:
|
||||
err = handleEditApp(msg)
|
||||
case MsgPushEditNode:
|
||||
gLog.Println(LvINFO, "MsgPushEditNode")
|
||||
req := EditNode{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &req); err != nil {
|
||||
gLog.Printf(LvERROR, "wrong %v:%s %s", reflect.TypeOf(req), err, string(msg[openP2PHeaderSize:]))
|
||||
return err
|
||||
}
|
||||
gConf.setNode(req.NewName)
|
||||
gConf.setShareBandwidth(req.Bandwidth)
|
||||
os.Exit(0)
|
||||
case MsgPushSwitchApp:
|
||||
gLog.Println(LvINFO, "MsgPushSwitchApp")
|
||||
app := AppInfo{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &app); err != nil {
|
||||
gLog.Printf(LvERROR, "wrong %v:%s %s", reflect.TypeOf(app), err, string(msg[openP2PHeaderSize:]))
|
||||
return err
|
||||
}
|
||||
config := AppConfig{Enabled: app.Enabled, SrcPort: app.SrcPort, Protocol: app.Protocol}
|
||||
gLog.Println(LvINFO, app.AppName, " switch to ", app.Enabled)
|
||||
gConf.switchApp(config, app.Enabled)
|
||||
if app.Enabled == 0 {
|
||||
// disable APP
|
||||
GNetwork.DeleteApp(config)
|
||||
}
|
||||
case MsgPushDstNodeOnline:
|
||||
gLog.Println(LvINFO, "MsgPushDstNodeOnline")
|
||||
req := PushDstNodeOnline{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &req); err != nil {
|
||||
gLog.Printf(LvERROR, "wrong %v:%s %s", reflect.TypeOf(req), err, string(msg[openP2PHeaderSize:]))
|
||||
return err
|
||||
}
|
||||
gLog.Println(LvINFO, "retry peerNode ", req.Node)
|
||||
gConf.retryApp(req.Node)
|
||||
default:
|
||||
i, ok := GNetwork.msgMap.Load(pushHead.From)
|
||||
if !ok {
|
||||
return ErrMsgChannelNotFound
|
||||
}
|
||||
ch := i.(chan msgCtx)
|
||||
ch <- msgCtx{data: msg, ts: time.Now()}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func handleEditApp(msg []byte) (err error) {
|
||||
gLog.Println(LvINFO, "MsgPushEditApp")
|
||||
newApp := AppInfo{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &newApp); err != nil {
|
||||
gLog.Printf(LvERROR, "wrong %v:%s %s", reflect.TypeOf(newApp), err, string(msg[openP2PHeaderSize:]))
|
||||
return err
|
||||
}
|
||||
oldConf := AppConfig{Enabled: 1}
|
||||
// protocol0+srcPort0 exist, delApp
|
||||
oldConf.AppName = newApp.AppName
|
||||
oldConf.Protocol = newApp.Protocol0
|
||||
oldConf.Whitelist = newApp.Whitelist
|
||||
oldConf.SrcPort = newApp.SrcPort0
|
||||
oldConf.PeerNode = newApp.PeerNode
|
||||
oldConf.DstHost = newApp.DstHost
|
||||
oldConf.DstPort = newApp.DstPort
|
||||
if newApp.Protocol0 != "" && newApp.SrcPort0 != 0 { // not edit
|
||||
gConf.delete(oldConf)
|
||||
}
|
||||
|
||||
// AddApp
|
||||
newConf := oldConf
|
||||
newConf.Protocol = newApp.Protocol
|
||||
newConf.SrcPort = newApp.SrcPort
|
||||
newConf.RelayNode = newApp.SpecRelayNode
|
||||
newConf.PunchPriority = newApp.PunchPriority
|
||||
gConf.add(newConf, false)
|
||||
if newApp.Protocol0 != "" && newApp.SrcPort0 != 0 { // not edit
|
||||
GNetwork.DeleteApp(oldConf) // DeleteApp may cost some times, execute at the end
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleConnectReq(msg []byte) (err error) {
|
||||
req := PushConnectReq{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req); err != nil {
|
||||
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(req), err)
|
||||
return err
|
||||
}
|
||||
gLog.Printf(LvDEBUG, "%s is connecting...", req.From)
|
||||
gLog.Println(LvDEBUG, "push connect response to ", req.From)
|
||||
if compareVersion(req.Version, LeastSupportVersion) < 0 {
|
||||
gLog.Println(LvERROR, ErrVersionNotCompatible.Error(), ":", req.From)
|
||||
rsp := PushConnectRsp{
|
||||
Error: 10,
|
||||
Detail: ErrVersionNotCompatible.Error(),
|
||||
To: req.From,
|
||||
From: gConf.Network.Node,
|
||||
}
|
||||
GNetwork.push(req.From, MsgPushConnectRsp, rsp)
|
||||
return ErrVersionNotCompatible
|
||||
}
|
||||
// verify totp token or token
|
||||
t := totp.TOTP{Step: totp.RelayTOTPStep}
|
||||
if t.Verify(req.Token, gConf.Network.Token, time.Now().Unix()-GNetwork.dt/int64(time.Second)) { // localTs may behind, auto adjust ts
|
||||
gLog.Printf(LvINFO, "Access Granted")
|
||||
config := AppConfig{}
|
||||
config.peerNatType = req.NatType
|
||||
config.peerConeNatPort = req.ConeNatPort
|
||||
config.peerIP = req.FromIP
|
||||
config.PeerNode = req.From
|
||||
config.peerVersion = req.Version
|
||||
config.fromToken = req.Token
|
||||
config.peerIPv6 = req.IPv6
|
||||
config.hasIPv4 = req.HasIPv4
|
||||
config.hasUPNPorNATPMP = req.HasUPNPorNATPMP
|
||||
config.linkMode = req.LinkMode
|
||||
config.isUnderlayServer = req.IsUnderlayServer
|
||||
config.UnderlayProtocol = req.UnderlayProtocol
|
||||
// share relay node will limit bandwidth
|
||||
if req.Token != gConf.Network.Token {
|
||||
gLog.Printf(LvINFO, "set share bandwidth %d mbps", gConf.Network.ShareBandwidth)
|
||||
config.shareBandwidth = gConf.Network.ShareBandwidth
|
||||
}
|
||||
// go GNetwork.AddTunnel(config, req.ID)
|
||||
go func() {
|
||||
GNetwork.addDirectTunnel(config, req.ID)
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
gLog.Println(LvERROR, "Access Denied:", req.From)
|
||||
rsp := PushConnectRsp{
|
||||
Error: 1,
|
||||
Detail: fmt.Sprintf("connect to %s error: Access Denied", gConf.Network.Node),
|
||||
To: req.From,
|
||||
From: gConf.Network.Node,
|
||||
}
|
||||
return GNetwork.push(req.From, MsgPushConnectRsp, rsp)
|
||||
}
|
||||
|
||||
func handleReportApps() (err error) {
|
||||
gLog.Println(LvINFO, "MsgPushReportApps")
|
||||
req := ReportApps{}
|
||||
gConf.mtx.Lock()
|
||||
defer gConf.mtx.Unlock()
|
||||
|
||||
for _, config := range gConf.Apps {
|
||||
appActive := 0
|
||||
relayNode := ""
|
||||
specRelayNode := ""
|
||||
relayMode := ""
|
||||
linkMode := LinkModeUDPPunch
|
||||
var connectTime string
|
||||
var retryTime string
|
||||
var app *p2pApp
|
||||
i, ok := GNetwork.apps.Load(config.ID())
|
||||
if ok {
|
||||
app = i.(*p2pApp)
|
||||
if app.isActive() {
|
||||
appActive = 1
|
||||
}
|
||||
if app.config.SrcPort == 0 { // memapp
|
||||
continue
|
||||
}
|
||||
specRelayNode = app.config.RelayNode
|
||||
if !app.isDirect() { // TODO: should always report relay node for app edit
|
||||
relayNode = app.relayNode
|
||||
relayMode = app.relayMode
|
||||
}
|
||||
|
||||
if app.Tunnel() != nil {
|
||||
linkMode = app.Tunnel().linkModeWeb
|
||||
}
|
||||
retryTime = app.RetryTime().Local().Format("2006-01-02T15:04:05-0700")
|
||||
connectTime = app.ConnectTime().Local().Format("2006-01-02T15:04:05-0700")
|
||||
|
||||
}
|
||||
appInfo := AppInfo{
|
||||
AppName: config.AppName,
|
||||
Error: config.errMsg,
|
||||
Protocol: config.Protocol,
|
||||
PunchPriority: config.PunchPriority,
|
||||
Whitelist: config.Whitelist,
|
||||
SrcPort: config.SrcPort,
|
||||
RelayNode: relayNode,
|
||||
SpecRelayNode: specRelayNode,
|
||||
RelayMode: relayMode,
|
||||
LinkMode: linkMode,
|
||||
PeerNode: config.PeerNode,
|
||||
DstHost: config.DstHost,
|
||||
DstPort: config.DstPort,
|
||||
PeerUser: config.PeerUser,
|
||||
PeerIP: config.peerIP,
|
||||
PeerNatType: config.peerNatType,
|
||||
RetryTime: retryTime,
|
||||
ConnectTime: connectTime,
|
||||
IsActive: appActive,
|
||||
Enabled: config.Enabled,
|
||||
}
|
||||
req.Apps = append(req.Apps, appInfo)
|
||||
}
|
||||
return GNetwork.write(MsgReport, MsgReportApps, &req)
|
||||
|
||||
}
|
||||
|
||||
func handleReportMemApps() (err error) {
|
||||
gLog.Println(LvINFO, "handleReportMemApps")
|
||||
req := ReportApps{}
|
||||
gConf.mtx.Lock()
|
||||
defer gConf.mtx.Unlock()
|
||||
GNetwork.sdwan.sysRoute.Range(func(key, value interface{}) bool {
|
||||
node := value.(*sdwanNode)
|
||||
appActive := 0
|
||||
relayMode := ""
|
||||
var connectTime string
|
||||
var retryTime string
|
||||
|
||||
i, ok := GNetwork.apps.Load(node.id)
|
||||
var app *p2pApp
|
||||
if ok {
|
||||
app = i.(*p2pApp)
|
||||
if app.isActive() {
|
||||
appActive = 1
|
||||
}
|
||||
if !app.isDirect() {
|
||||
relayMode = app.relayMode
|
||||
}
|
||||
retryTime = app.RetryTime().Local().Format("2006-01-02T15:04:05-0700")
|
||||
connectTime = app.ConnectTime().Local().Format("2006-01-02T15:04:05-0700")
|
||||
}
|
||||
appInfo := AppInfo{
|
||||
RelayMode: relayMode,
|
||||
PeerNode: node.name,
|
||||
IsActive: appActive,
|
||||
Enabled: 1,
|
||||
}
|
||||
if app != nil {
|
||||
appInfo.AppName = app.config.AppName
|
||||
appInfo.Error = app.config.errMsg
|
||||
appInfo.Protocol = app.config.Protocol
|
||||
appInfo.Whitelist = app.config.Whitelist
|
||||
appInfo.SrcPort = app.config.SrcPort
|
||||
if !app.isDirect() {
|
||||
appInfo.RelayNode = app.relayNode
|
||||
}
|
||||
|
||||
if app.Tunnel() != nil {
|
||||
appInfo.LinkMode = app.Tunnel().linkModeWeb
|
||||
}
|
||||
appInfo.DstHost = app.config.DstHost
|
||||
appInfo.DstPort = app.config.DstPort
|
||||
appInfo.PeerUser = app.config.PeerUser
|
||||
appInfo.PeerIP = app.config.peerIP
|
||||
appInfo.PeerNatType = app.config.peerNatType
|
||||
appInfo.RetryTime = retryTime
|
||||
appInfo.ConnectTime = connectTime
|
||||
}
|
||||
req.Apps = append(req.Apps, appInfo)
|
||||
return true
|
||||
})
|
||||
gLog.Println(LvDEBUG, "handleReportMemApps res:", prettyJson(req))
|
||||
return GNetwork.write(MsgReport, MsgReportMemApps, &req)
|
||||
}
|
||||
|
||||
func handleLog(msg []byte) (err error) {
|
||||
gLog.Println(LvDEBUG, "MsgPushReportLog")
|
||||
const defaultLen = 1024 * 128
|
||||
const maxLen = 1024 * 1024
|
||||
req := ReportLogReq{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &req); err != nil {
|
||||
gLog.Printf(LvERROR, "wrong %v:%s %s", reflect.TypeOf(req), err, string(msg[openP2PHeaderSize:]))
|
||||
return err
|
||||
}
|
||||
if req.FileName == "" {
|
||||
req.FileName = "openp2p.log"
|
||||
} else {
|
||||
req.FileName = sanitizeFileName(req.FileName)
|
||||
}
|
||||
f, err := os.Open(filepath.Join("log", req.FileName))
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "read log file error:", err)
|
||||
return err
|
||||
}
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if req.Offset > fi.Size() {
|
||||
req.Offset = fi.Size() - defaultLen
|
||||
}
|
||||
// verify input parameters
|
||||
if req.Offset < 0 {
|
||||
req.Offset = 0
|
||||
}
|
||||
if req.Len <= 0 || req.Len > maxLen {
|
||||
req.Len = defaultLen
|
||||
}
|
||||
|
||||
f.Seek(req.Offset, 0)
|
||||
buff := make([]byte, req.Len)
|
||||
readLength, err := f.Read(buff)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "read log content error:", err)
|
||||
return err
|
||||
}
|
||||
rsp := ReportLogRsp{}
|
||||
rsp.Content = string(buff[:readLength])
|
||||
rsp.FileName = req.FileName
|
||||
rsp.Total = fi.Size()
|
||||
rsp.Len = req.Len
|
||||
return GNetwork.write(MsgReport, MsgPushReportLog, &rsp)
|
||||
}
|
||||
|
||||
func handleReportGoroutine() (err error) {
|
||||
gLog.Println(LvDEBUG, "handleReportGoroutine")
|
||||
buf := make([]byte, 1024*128)
|
||||
stackLen := runtime.Stack(buf, true)
|
||||
return GNetwork.write(MsgReport, MsgPushReportLog, string(buf[:stackLen]))
|
||||
}
|
||||
|
||||
func handleCheckRemoteService(msg []byte) (err error) {
|
||||
gLog.Println(LvDEBUG, "handleCheckRemoteService")
|
||||
req := CheckRemoteService{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &req); err != nil {
|
||||
gLog.Printf(LvERROR, "wrong %v:%s %s", reflect.TypeOf(req), err, string(msg[openP2PHeaderSize:]))
|
||||
return err
|
||||
}
|
||||
rsp := PushRsp{Error: 0}
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", req.Host, req.Port), time.Second*3)
|
||||
if err != nil {
|
||||
rsp.Error = 1
|
||||
rsp.Detail = ErrRemoteServiceUnable.Error()
|
||||
} else {
|
||||
conn.Close()
|
||||
}
|
||||
return GNetwork.write(MsgReport, MsgReportResponse, rsp)
|
||||
}
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/openp2p-cn/totp"
|
||||
)
|
||||
|
||||
func handlePush(subType uint16, msg []byte) error {
|
||||
pushHead := PushHeader{}
|
||||
err := binary.Read(bytes.NewReader(msg[openP2PHeaderSize:openP2PHeaderSize+PushHeaderSize]), binary.LittleEndian, &pushHead)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gLog.Printf(LvDEBUG, "handle push msg type:%d, push header:%+v", subType, pushHead)
|
||||
switch subType {
|
||||
case MsgPushConnectReq:
|
||||
err = handleConnectReq(msg)
|
||||
case MsgPushRsp:
|
||||
rsp := PushRsp{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &rsp); err != nil {
|
||||
gLog.Printf(LvERROR, "wrong pushRsp:%s", err)
|
||||
return err
|
||||
}
|
||||
if rsp.Error == 0 {
|
||||
gLog.Printf(LvDEBUG, "push ok, detail:%s", rsp.Detail)
|
||||
} else {
|
||||
gLog.Printf(LvERROR, "push error:%d, detail:%s", rsp.Error, rsp.Detail)
|
||||
}
|
||||
case MsgPushAddRelayTunnelReq:
|
||||
req := AddRelayTunnelReq{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req); err != nil {
|
||||
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(req), err)
|
||||
return err
|
||||
}
|
||||
config := AppConfig{}
|
||||
config.PeerNode = req.RelayName
|
||||
config.peerToken = req.RelayToken
|
||||
config.relayMode = req.RelayMode
|
||||
go func(r AddRelayTunnelReq) {
|
||||
t, errDt := GNetwork.addDirectTunnel(config, 0)
|
||||
if errDt == nil {
|
||||
// notify peer relay ready
|
||||
msg := TunnelMsg{ID: t.id}
|
||||
GNetwork.push(r.From, MsgPushAddRelayTunnelRsp, msg)
|
||||
appConfig := config
|
||||
appConfig.PeerNode = req.From
|
||||
} else {
|
||||
gLog.Printf(LvERROR, "addDirectTunnel error:%s", errDt)
|
||||
GNetwork.push(r.From, MsgPushAddRelayTunnelRsp, "error") // compatible with old version client, trigger unmarshal error
|
||||
}
|
||||
}(req)
|
||||
case MsgPushServerSideSaveMemApp:
|
||||
req := ServerSideSaveMemApp{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req); err != nil {
|
||||
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(req), err)
|
||||
return err
|
||||
}
|
||||
gLog.Println(LvDEBUG, "handle MsgPushServerSideSaveMemApp:", prettyJson(req))
|
||||
var existTunnel *P2PTunnel
|
||||
i, ok := GNetwork.allTunnels.Load(req.TunnelID)
|
||||
if !ok {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
i, ok = GNetwork.allTunnels.Load(req.TunnelID) // retry sometimes will receive MsgPushServerSideSaveMemApp but p2ptunnel not store yet.
|
||||
if !ok {
|
||||
gLog.Println(LvERROR, "handle MsgPushServerSideSaveMemApp error:", ErrMemAppTunnelNotFound)
|
||||
return ErrMemAppTunnelNotFound
|
||||
}
|
||||
}
|
||||
existTunnel = i.(*P2PTunnel)
|
||||
peerID := NodeNameToID(req.From)
|
||||
existApp, appok := GNetwork.apps.Load(peerID)
|
||||
if appok {
|
||||
app := existApp.(*p2pApp)
|
||||
app.config.AppName = fmt.Sprintf("%d", peerID)
|
||||
app.id = req.AppID
|
||||
app.setRelayTunnelID(req.RelayTunnelID)
|
||||
app.relayMode = req.RelayMode
|
||||
app.hbTimeRelay = time.Now()
|
||||
if req.RelayTunnelID == 0 {
|
||||
app.setDirectTunnel(existTunnel)
|
||||
} else {
|
||||
app.setRelayTunnel(existTunnel)
|
||||
}
|
||||
gLog.Println(LvDEBUG, "find existing memapp, update it")
|
||||
} else {
|
||||
appConfig := existTunnel.config
|
||||
appConfig.SrcPort = 0
|
||||
appConfig.Protocol = ""
|
||||
appConfig.AppName = fmt.Sprintf("%d", peerID)
|
||||
appConfig.PeerNode = req.From
|
||||
app := p2pApp{
|
||||
id: req.AppID,
|
||||
config: appConfig,
|
||||
relayMode: req.RelayMode,
|
||||
running: true,
|
||||
hbTimeRelay: time.Now(),
|
||||
}
|
||||
if req.RelayTunnelID == 0 {
|
||||
app.setDirectTunnel(existTunnel)
|
||||
} else {
|
||||
app.setRelayTunnel(existTunnel)
|
||||
app.setRelayTunnelID(req.RelayTunnelID)
|
||||
}
|
||||
if req.RelayTunnelID != 0 {
|
||||
app.relayNode = req.Node
|
||||
}
|
||||
GNetwork.apps.Store(NodeNameToID(req.From), &app)
|
||||
}
|
||||
|
||||
return nil
|
||||
case MsgPushAPPKey:
|
||||
req := APPKeySync{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req); err != nil {
|
||||
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(req), err)
|
||||
return err
|
||||
}
|
||||
SaveKey(req.AppID, req.AppKey)
|
||||
case MsgPushUpdate:
|
||||
gLog.Println(LvINFO, "MsgPushUpdate")
|
||||
err := update(gConf.Network.ServerHost, gConf.Network.ServerPort)
|
||||
if err == nil {
|
||||
os.Exit(0)
|
||||
}
|
||||
return err
|
||||
case MsgPushRestart:
|
||||
gLog.Println(LvINFO, "MsgPushRestart")
|
||||
os.Exit(0)
|
||||
return err
|
||||
case MsgPushReportApps:
|
||||
err = handleReportApps()
|
||||
case MsgPushReportMemApps:
|
||||
err = handleReportMemApps()
|
||||
case MsgPushReportLog:
|
||||
err = handleLog(msg)
|
||||
case MsgPushReportGoroutine:
|
||||
err = handleReportGoroutine()
|
||||
case MsgPushCheckRemoteService:
|
||||
err = handleCheckRemoteService(msg)
|
||||
case MsgPushEditApp:
|
||||
err = handleEditApp(msg)
|
||||
case MsgPushEditNode:
|
||||
gLog.Println(LvINFO, "MsgPushEditNode")
|
||||
req := EditNode{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &req); err != nil {
|
||||
gLog.Printf(LvERROR, "wrong %v:%s %s", reflect.TypeOf(req), err, string(msg[openP2PHeaderSize:]))
|
||||
return err
|
||||
}
|
||||
gConf.setNode(req.NewName)
|
||||
gConf.setShareBandwidth(req.Bandwidth)
|
||||
os.Exit(0)
|
||||
case MsgPushSwitchApp:
|
||||
gLog.Println(LvINFO, "MsgPushSwitchApp")
|
||||
app := AppInfo{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &app); err != nil {
|
||||
gLog.Printf(LvERROR, "wrong %v:%s %s", reflect.TypeOf(app), err, string(msg[openP2PHeaderSize:]))
|
||||
return err
|
||||
}
|
||||
config := AppConfig{Enabled: app.Enabled, SrcPort: app.SrcPort, Protocol: app.Protocol}
|
||||
gLog.Println(LvINFO, app.AppName, " switch to ", app.Enabled)
|
||||
gConf.switchApp(config, app.Enabled)
|
||||
if app.Enabled == 0 {
|
||||
// disable APP
|
||||
GNetwork.DeleteApp(config)
|
||||
}
|
||||
case MsgPushDstNodeOnline:
|
||||
gLog.Println(LvINFO, "MsgPushDstNodeOnline")
|
||||
req := PushDstNodeOnline{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &req); err != nil {
|
||||
gLog.Printf(LvERROR, "wrong %v:%s %s", reflect.TypeOf(req), err, string(msg[openP2PHeaderSize:]))
|
||||
return err
|
||||
}
|
||||
gLog.Println(LvINFO, "retry peerNode ", req.Node)
|
||||
gConf.retryApp(req.Node)
|
||||
default:
|
||||
i, ok := GNetwork.msgMap.Load(pushHead.From)
|
||||
if !ok {
|
||||
return ErrMsgChannelNotFound
|
||||
}
|
||||
ch := i.(chan msgCtx)
|
||||
ch <- msgCtx{data: msg, ts: time.Now()}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func handleEditApp(msg []byte) (err error) {
|
||||
gLog.Println(LvINFO, "MsgPushEditApp")
|
||||
newApp := AppInfo{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &newApp); err != nil {
|
||||
gLog.Printf(LvERROR, "wrong %v:%s %s", reflect.TypeOf(newApp), err, string(msg[openP2PHeaderSize:]))
|
||||
return err
|
||||
}
|
||||
oldConf := AppConfig{Enabled: 1}
|
||||
// protocol0+srcPort0 exist, delApp
|
||||
oldConf.AppName = newApp.AppName
|
||||
oldConf.Protocol = newApp.Protocol0
|
||||
oldConf.Whitelist = newApp.Whitelist
|
||||
oldConf.SrcPort = newApp.SrcPort0
|
||||
oldConf.PeerNode = newApp.PeerNode
|
||||
oldConf.DstHost = newApp.DstHost
|
||||
oldConf.DstPort = newApp.DstPort
|
||||
if newApp.Protocol0 != "" && newApp.SrcPort0 != 0 { // not edit
|
||||
gConf.delete(oldConf)
|
||||
}
|
||||
|
||||
// AddApp
|
||||
newConf := oldConf
|
||||
newConf.Protocol = newApp.Protocol
|
||||
newConf.SrcPort = newApp.SrcPort
|
||||
newConf.RelayNode = newApp.SpecRelayNode
|
||||
newConf.PunchPriority = newApp.PunchPriority
|
||||
gConf.add(newConf, false)
|
||||
if newApp.Protocol0 != "" && newApp.SrcPort0 != 0 { // not edit
|
||||
GNetwork.DeleteApp(oldConf) // DeleteApp may cost some times, execute at the end
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleConnectReq(msg []byte) (err error) {
|
||||
req := PushConnectReq{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req); err != nil {
|
||||
gLog.Printf(LvERROR, "wrong %v:%s", reflect.TypeOf(req), err)
|
||||
return err
|
||||
}
|
||||
gLog.Printf(LvDEBUG, "%s is connecting...", req.From)
|
||||
gLog.Println(LvDEBUG, "push connect response to ", req.From)
|
||||
if compareVersion(req.Version, LeastSupportVersion) < 0 {
|
||||
gLog.Println(LvERROR, ErrVersionNotCompatible.Error(), ":", req.From)
|
||||
rsp := PushConnectRsp{
|
||||
Error: 10,
|
||||
Detail: ErrVersionNotCompatible.Error(),
|
||||
To: req.From,
|
||||
From: gConf.Network.Node,
|
||||
}
|
||||
GNetwork.push(req.From, MsgPushConnectRsp, rsp)
|
||||
return ErrVersionNotCompatible
|
||||
}
|
||||
// verify totp token or token
|
||||
t := totp.TOTP{Step: totp.RelayTOTPStep}
|
||||
if t.Verify(req.Token, gConf.Network.Token, time.Now().Unix()-GNetwork.dt/int64(time.Second)) { // localTs may behind, auto adjust ts
|
||||
gLog.Printf(LvINFO, "Access Granted")
|
||||
config := AppConfig{}
|
||||
config.peerNatType = req.NatType
|
||||
config.peerConeNatPort = req.ConeNatPort
|
||||
config.peerIP = req.FromIP
|
||||
config.PeerNode = req.From
|
||||
config.peerVersion = req.Version
|
||||
config.fromToken = req.Token
|
||||
config.peerIPv6 = req.IPv6
|
||||
config.hasIPv4 = req.HasIPv4
|
||||
config.hasUPNPorNATPMP = req.HasUPNPorNATPMP
|
||||
config.linkMode = req.LinkMode
|
||||
config.isUnderlayServer = req.IsUnderlayServer
|
||||
config.UnderlayProtocol = req.UnderlayProtocol
|
||||
// share relay node will limit bandwidth
|
||||
if req.Token != gConf.Network.Token {
|
||||
gLog.Printf(LvINFO, "set share bandwidth %d mbps", gConf.Network.ShareBandwidth)
|
||||
config.shareBandwidth = gConf.Network.ShareBandwidth
|
||||
}
|
||||
// go GNetwork.AddTunnel(config, req.ID)
|
||||
go func() {
|
||||
GNetwork.addDirectTunnel(config, req.ID)
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
gLog.Println(LvERROR, "Access Denied:", req.From)
|
||||
rsp := PushConnectRsp{
|
||||
Error: 1,
|
||||
Detail: fmt.Sprintf("connect to %s error: Access Denied", gConf.Network.Node),
|
||||
To: req.From,
|
||||
From: gConf.Network.Node,
|
||||
}
|
||||
return GNetwork.push(req.From, MsgPushConnectRsp, rsp)
|
||||
}
|
||||
|
||||
func handleReportApps() (err error) {
|
||||
gLog.Println(LvINFO, "MsgPushReportApps")
|
||||
req := ReportApps{}
|
||||
gConf.mtx.Lock()
|
||||
defer gConf.mtx.Unlock()
|
||||
|
||||
for _, config := range gConf.Apps {
|
||||
appActive := 0
|
||||
relayNode := ""
|
||||
specRelayNode := ""
|
||||
relayMode := ""
|
||||
linkMode := LinkModeUDPPunch
|
||||
var connectTime string
|
||||
var retryTime string
|
||||
var app *p2pApp
|
||||
i, ok := GNetwork.apps.Load(config.ID())
|
||||
if ok {
|
||||
app = i.(*p2pApp)
|
||||
if app.isActive() {
|
||||
appActive = 1
|
||||
}
|
||||
if app.config.SrcPort == 0 { // memapp
|
||||
continue
|
||||
}
|
||||
specRelayNode = app.config.RelayNode
|
||||
if !app.isDirect() { // TODO: should always report relay node for app edit
|
||||
relayNode = app.relayNode
|
||||
relayMode = app.relayMode
|
||||
}
|
||||
|
||||
if app.Tunnel() != nil {
|
||||
linkMode = app.Tunnel().linkModeWeb
|
||||
}
|
||||
retryTime = app.RetryTime().Local().Format("2006-01-02T15:04:05-0700")
|
||||
connectTime = app.ConnectTime().Local().Format("2006-01-02T15:04:05-0700")
|
||||
|
||||
}
|
||||
appInfo := AppInfo{
|
||||
AppName: config.AppName,
|
||||
Error: config.errMsg,
|
||||
Protocol: config.Protocol,
|
||||
PunchPriority: config.PunchPriority,
|
||||
Whitelist: config.Whitelist,
|
||||
SrcPort: config.SrcPort,
|
||||
RelayNode: relayNode,
|
||||
SpecRelayNode: specRelayNode,
|
||||
RelayMode: relayMode,
|
||||
LinkMode: linkMode,
|
||||
PeerNode: config.PeerNode,
|
||||
DstHost: config.DstHost,
|
||||
DstPort: config.DstPort,
|
||||
PeerUser: config.PeerUser,
|
||||
PeerIP: config.peerIP,
|
||||
PeerNatType: config.peerNatType,
|
||||
RetryTime: retryTime,
|
||||
ConnectTime: connectTime,
|
||||
IsActive: appActive,
|
||||
Enabled: config.Enabled,
|
||||
}
|
||||
req.Apps = append(req.Apps, appInfo)
|
||||
}
|
||||
return GNetwork.write(MsgReport, MsgReportApps, &req)
|
||||
|
||||
}
|
||||
|
||||
func handleReportMemApps() (err error) {
|
||||
gLog.Println(LvINFO, "handleReportMemApps")
|
||||
req := ReportApps{}
|
||||
gConf.mtx.Lock()
|
||||
defer gConf.mtx.Unlock()
|
||||
GNetwork.sdwan.sysRoute.Range(func(key, value interface{}) bool {
|
||||
node := value.(*sdwanNode)
|
||||
appActive := 0
|
||||
relayMode := ""
|
||||
var connectTime string
|
||||
var retryTime string
|
||||
|
||||
i, ok := GNetwork.apps.Load(node.id)
|
||||
var app *p2pApp
|
||||
if ok {
|
||||
app = i.(*p2pApp)
|
||||
if app.isActive() {
|
||||
appActive = 1
|
||||
}
|
||||
if !app.isDirect() {
|
||||
relayMode = app.relayMode
|
||||
}
|
||||
retryTime = app.RetryTime().Local().Format("2006-01-02T15:04:05-0700")
|
||||
connectTime = app.ConnectTime().Local().Format("2006-01-02T15:04:05-0700")
|
||||
}
|
||||
appInfo := AppInfo{
|
||||
RelayMode: relayMode,
|
||||
PeerNode: node.name,
|
||||
IsActive: appActive,
|
||||
Enabled: 1,
|
||||
}
|
||||
if app != nil {
|
||||
appInfo.AppName = app.config.AppName
|
||||
appInfo.Error = app.config.errMsg
|
||||
appInfo.Protocol = app.config.Protocol
|
||||
appInfo.Whitelist = app.config.Whitelist
|
||||
appInfo.SrcPort = app.config.SrcPort
|
||||
if !app.isDirect() {
|
||||
appInfo.RelayNode = app.relayNode
|
||||
}
|
||||
|
||||
if app.Tunnel() != nil {
|
||||
appInfo.LinkMode = app.Tunnel().linkModeWeb
|
||||
}
|
||||
appInfo.DstHost = app.config.DstHost
|
||||
appInfo.DstPort = app.config.DstPort
|
||||
appInfo.PeerUser = app.config.PeerUser
|
||||
appInfo.PeerIP = app.config.peerIP
|
||||
appInfo.PeerNatType = app.config.peerNatType
|
||||
appInfo.RetryTime = retryTime
|
||||
appInfo.ConnectTime = connectTime
|
||||
}
|
||||
req.Apps = append(req.Apps, appInfo)
|
||||
return true
|
||||
})
|
||||
gLog.Println(LvDEBUG, "handleReportMemApps res:", prettyJson(req))
|
||||
return GNetwork.write(MsgReport, MsgReportMemApps, &req)
|
||||
}
|
||||
|
||||
func handleLog(msg []byte) (err error) {
|
||||
gLog.Println(LvDEBUG, "MsgPushReportLog")
|
||||
const defaultLen = 1024 * 128
|
||||
const maxLen = 1024 * 1024
|
||||
req := ReportLogReq{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &req); err != nil {
|
||||
gLog.Printf(LvERROR, "wrong %v:%s %s", reflect.TypeOf(req), err, string(msg[openP2PHeaderSize:]))
|
||||
return err
|
||||
}
|
||||
if req.FileName == "" {
|
||||
req.FileName = "openp2p.log"
|
||||
} else {
|
||||
req.FileName = sanitizeFileName(req.FileName)
|
||||
}
|
||||
f, err := os.Open(filepath.Join("log", req.FileName))
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "read log file error:", err)
|
||||
return err
|
||||
}
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if req.Offset > fi.Size() {
|
||||
req.Offset = fi.Size() - defaultLen
|
||||
}
|
||||
// verify input parameters
|
||||
if req.Offset < 0 {
|
||||
req.Offset = 0
|
||||
}
|
||||
if req.Len <= 0 || req.Len > maxLen {
|
||||
req.Len = defaultLen
|
||||
}
|
||||
|
||||
f.Seek(req.Offset, 0)
|
||||
buff := make([]byte, req.Len)
|
||||
readLength, err := f.Read(buff)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "read log content error:", err)
|
||||
return err
|
||||
}
|
||||
rsp := ReportLogRsp{}
|
||||
rsp.Content = string(buff[:readLength])
|
||||
rsp.FileName = req.FileName
|
||||
rsp.Total = fi.Size()
|
||||
rsp.Len = req.Len
|
||||
return GNetwork.write(MsgReport, MsgPushReportLog, &rsp)
|
||||
}
|
||||
|
||||
func handleReportGoroutine() (err error) {
|
||||
gLog.Println(LvDEBUG, "handleReportGoroutine")
|
||||
buf := make([]byte, 1024*128)
|
||||
stackLen := runtime.Stack(buf, true)
|
||||
return GNetwork.write(MsgReport, MsgPushReportLog, string(buf[:stackLen]))
|
||||
}
|
||||
|
||||
func handleCheckRemoteService(msg []byte) (err error) {
|
||||
gLog.Println(LvDEBUG, "handleCheckRemoteService")
|
||||
req := CheckRemoteService{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &req); err != nil {
|
||||
gLog.Printf(LvERROR, "wrong %v:%s %s", reflect.TypeOf(req), err, string(msg[openP2PHeaderSize:]))
|
||||
return err
|
||||
}
|
||||
rsp := PushRsp{Error: 0}
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", req.Host, req.Port), time.Second*3)
|
||||
if err != nil {
|
||||
rsp.Error = 1
|
||||
rsp.Detail = ErrRemoteServiceUnable.Error()
|
||||
} else {
|
||||
conn.Close()
|
||||
}
|
||||
return GNetwork.write(MsgReport, MsgReportResponse, rsp)
|
||||
}
|
||||
|
248
core/install.go
248
core/install.go
@@ -1,124 +1,124 @@
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func install() {
|
||||
gLog.Println(LvINFO, "openp2p start. version: ", OpenP2PVersion)
|
||||
gLog.Println(LvINFO, "Contact: QQ group 16947733, Email openp2p.cn@gmail.com")
|
||||
gLog.Println(LvINFO, "install start")
|
||||
defer gLog.Println(LvINFO, "install end")
|
||||
// auto uninstall
|
||||
err := os.MkdirAll(defaultInstallPath, 0775)
|
||||
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "MkdirAll %s error:%s", defaultInstallPath, err)
|
||||
return
|
||||
}
|
||||
err = os.Chdir(defaultInstallPath)
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "cd error:", err)
|
||||
return
|
||||
}
|
||||
|
||||
uninstall()
|
||||
// save config file
|
||||
parseParams("install", "")
|
||||
targetPath := filepath.Join(defaultInstallPath, defaultBinName)
|
||||
d := daemon{}
|
||||
// copy files
|
||||
|
||||
binPath, _ := os.Executable()
|
||||
src, errFiles := os.Open(binPath) // can not use args[0], on Windows call openp2p is ok(=openp2p.exe)
|
||||
if errFiles != nil {
|
||||
gLog.Printf(LvERROR, "os.OpenFile %s error:%s", os.Args[0], errFiles)
|
||||
return
|
||||
}
|
||||
|
||||
dst, errFiles := os.OpenFile(targetPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0775)
|
||||
if errFiles != nil {
|
||||
gLog.Printf(LvERROR, "os.OpenFile %s error:%s", targetPath, errFiles)
|
||||
return
|
||||
}
|
||||
|
||||
_, errFiles = io.Copy(dst, src)
|
||||
if errFiles != nil {
|
||||
gLog.Printf(LvERROR, "io.Copy error:%s", errFiles)
|
||||
return
|
||||
}
|
||||
src.Close()
|
||||
dst.Close()
|
||||
|
||||
// install system service
|
||||
gLog.Println(LvINFO, "targetPath:", targetPath)
|
||||
err = d.Control("install", targetPath, []string{"-d"})
|
||||
if err == nil {
|
||||
gLog.Println(LvINFO, "install system service ok.")
|
||||
}
|
||||
time.Sleep(time.Second * 2)
|
||||
err = d.Control("start", targetPath, []string{"-d"})
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "start openp2p service error:", err)
|
||||
} else {
|
||||
gLog.Println(LvINFO, "start openp2p service ok.")
|
||||
}
|
||||
gLog.Println(LvINFO, "Visit WebUI on https://console.openp2p.cn")
|
||||
}
|
||||
|
||||
func installByFilename() {
|
||||
params := strings.Split(filepath.Base(os.Args[0]), "-")
|
||||
if len(params) < 4 {
|
||||
return
|
||||
}
|
||||
serverHost := params[1]
|
||||
token := params[2]
|
||||
gLog.Println(LvINFO, "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(LvERROR, "install by filename, start process error:", err)
|
||||
return
|
||||
}
|
||||
gLog.Println(LvINFO, "install end")
|
||||
gLog.Println(LvINFO, "Visit WebUI on https://console.openp2p.cn")
|
||||
fmt.Println("Press the Any Key to exit")
|
||||
fmt.Scanln()
|
||||
os.Exit(0)
|
||||
}
|
||||
func uninstall() {
|
||||
gLog.Println(LvINFO, "uninstall start")
|
||||
defer gLog.Println(LvINFO, "uninstall end")
|
||||
d := daemon{}
|
||||
err := d.Control("stop", "", nil)
|
||||
if err != nil { // service maybe not install
|
||||
return
|
||||
}
|
||||
err = d.Control("uninstall", "", nil)
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "uninstall system service error:", err)
|
||||
} else {
|
||||
gLog.Println(LvINFO, "uninstall system service ok.")
|
||||
}
|
||||
binPath := filepath.Join(defaultInstallPath, defaultBinName)
|
||||
os.Remove(binPath + "0")
|
||||
os.Remove(binPath)
|
||||
// os.RemoveAll(defaultInstallPath) // reserve config.json
|
||||
}
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func install() {
|
||||
gLog.Println(LvINFO, "openp2p start. version: ", OpenP2PVersion)
|
||||
gLog.Println(LvINFO, "Contact: QQ group 16947733, Email openp2p.cn@gmail.com")
|
||||
gLog.Println(LvINFO, "install start")
|
||||
defer gLog.Println(LvINFO, "install end")
|
||||
// auto uninstall
|
||||
err := os.MkdirAll(defaultInstallPath, 0775)
|
||||
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "MkdirAll %s error:%s", defaultInstallPath, err)
|
||||
return
|
||||
}
|
||||
err = os.Chdir(defaultInstallPath)
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "cd error:", err)
|
||||
return
|
||||
}
|
||||
|
||||
uninstall()
|
||||
// save config file
|
||||
parseParams("install", "")
|
||||
targetPath := filepath.Join(defaultInstallPath, defaultBinName)
|
||||
d := daemon{}
|
||||
// copy files
|
||||
|
||||
binPath, _ := os.Executable()
|
||||
src, errFiles := os.Open(binPath) // can not use args[0], on Windows call openp2p is ok(=openp2p.exe)
|
||||
if errFiles != nil {
|
||||
gLog.Printf(LvERROR, "os.OpenFile %s error:%s", os.Args[0], errFiles)
|
||||
return
|
||||
}
|
||||
|
||||
dst, errFiles := os.OpenFile(targetPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0775)
|
||||
if errFiles != nil {
|
||||
gLog.Printf(LvERROR, "os.OpenFile %s error:%s", targetPath, errFiles)
|
||||
return
|
||||
}
|
||||
|
||||
_, errFiles = io.Copy(dst, src)
|
||||
if errFiles != nil {
|
||||
gLog.Printf(LvERROR, "io.Copy error:%s", errFiles)
|
||||
return
|
||||
}
|
||||
src.Close()
|
||||
dst.Close()
|
||||
|
||||
// install system service
|
||||
gLog.Println(LvINFO, "targetPath:", targetPath)
|
||||
err = d.Control("install", targetPath, []string{"-d"})
|
||||
if err == nil {
|
||||
gLog.Println(LvINFO, "install system service ok.")
|
||||
}
|
||||
time.Sleep(time.Second * 2)
|
||||
err = d.Control("start", targetPath, []string{"-d"})
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "start openp2p service error:", err)
|
||||
} else {
|
||||
gLog.Println(LvINFO, "start openp2p service ok.")
|
||||
}
|
||||
gLog.Println(LvINFO, "Visit WebUI on https://console.openp2p.cn")
|
||||
}
|
||||
|
||||
func installByFilename() {
|
||||
params := strings.Split(filepath.Base(os.Args[0]), "-")
|
||||
if len(params) < 4 {
|
||||
return
|
||||
}
|
||||
serverHost := params[1]
|
||||
token := params[2]
|
||||
gLog.Println(LvINFO, "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(LvERROR, "install by filename, start process error:", err)
|
||||
return
|
||||
}
|
||||
gLog.Println(LvINFO, "install end")
|
||||
gLog.Println(LvINFO, "Visit WebUI on https://console.openp2p.cn")
|
||||
fmt.Println("Press the Any Key to exit")
|
||||
fmt.Scanln()
|
||||
os.Exit(0)
|
||||
}
|
||||
func uninstall() {
|
||||
gLog.Println(LvINFO, "uninstall start")
|
||||
defer gLog.Println(LvINFO, "uninstall end")
|
||||
d := daemon{}
|
||||
err := d.Control("stop", "", nil)
|
||||
if err != nil { // service maybe not install
|
||||
return
|
||||
}
|
||||
err = d.Control("uninstall", "", nil)
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "uninstall system service error:", err)
|
||||
} else {
|
||||
gLog.Println(LvINFO, "uninstall system service ok.")
|
||||
}
|
||||
binPath := filepath.Join(defaultInstallPath, defaultBinName)
|
||||
os.Remove(binPath + "0")
|
||||
os.Remove(binPath)
|
||||
// os.RemoveAll(defaultInstallPath) // reserve config.json
|
||||
}
|
||||
|
148
core/iptables.go
148
core/iptables.go
@@ -1,74 +1,74 @@
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func allowTunForward() {
|
||||
if runtime.GOOS != "linux" { // only support Linux
|
||||
return
|
||||
}
|
||||
exec.Command("sh", "-c", `iptables -t filter -D FORWARD -i optun -j ACCEPT`).Run()
|
||||
exec.Command("sh", "-c", `iptables -t filter -D FORWARD -o optun -j ACCEPT`).Run()
|
||||
err := exec.Command("sh", "-c", `iptables -t filter -I FORWARD -i optun -j ACCEPT`).Run()
|
||||
if err != nil {
|
||||
log.Println("allow foward in error:", err)
|
||||
}
|
||||
err = exec.Command("sh", "-c", `iptables -t filter -I FORWARD -o optun -j ACCEPT`).Run()
|
||||
if err != nil {
|
||||
log.Println("allow foward out error:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func clearSNATRule() {
|
||||
if runtime.GOOS != "linux" {
|
||||
return
|
||||
}
|
||||
execCommand("iptables", true, "-t", "nat", "-D", "POSTROUTING", "-j", "OPSDWAN")
|
||||
execCommand("iptables", true, "-t", "nat", "-F", "OPSDWAN")
|
||||
execCommand("iptables", true, "-t", "nat", "-X", "OPSDWAN")
|
||||
}
|
||||
|
||||
func initSNATRule(localNet string) {
|
||||
if runtime.GOOS != "linux" {
|
||||
return
|
||||
}
|
||||
clearSNATRule()
|
||||
|
||||
err := execCommand("iptables", true, "-t", "nat", "-N", "OPSDWAN")
|
||||
if err != nil {
|
||||
log.Println("iptables new sdwan chain error:", err)
|
||||
return
|
||||
}
|
||||
err = execCommand("iptables", true, "-t", "nat", "-A", "POSTROUTING", "-j", "OPSDWAN")
|
||||
if err != nil {
|
||||
log.Println("iptables append postrouting error:", err)
|
||||
return
|
||||
}
|
||||
err = execCommand("iptables", true, "-t", "nat", "-A", "OPSDWAN",
|
||||
"-o", "optun", "!", "-s", localNet, "-j", "MASQUERADE")
|
||||
if err != nil {
|
||||
log.Println("add optun snat error:", err)
|
||||
return
|
||||
}
|
||||
err = execCommand("iptables", true, "-t", "nat", "-A", "OPSDWAN", "!", "-o", "optun",
|
||||
"-s", localNet, "-j", "MASQUERADE")
|
||||
if err != nil {
|
||||
log.Println("add optun snat error:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func addSNATRule(target string) {
|
||||
if runtime.GOOS != "linux" {
|
||||
return
|
||||
}
|
||||
err := execCommand("iptables", true, "-t", "nat", "-A", "OPSDWAN", "!", "-o", "optun",
|
||||
"-s", target, "-j", "MASQUERADE")
|
||||
if err != nil {
|
||||
log.Println("iptables add optun snat error:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func allowTunForward() {
|
||||
if runtime.GOOS != "linux" { // only support Linux
|
||||
return
|
||||
}
|
||||
exec.Command("sh", "-c", `iptables -t filter -D FORWARD -i optun -j ACCEPT`).Run()
|
||||
exec.Command("sh", "-c", `iptables -t filter -D FORWARD -o optun -j ACCEPT`).Run()
|
||||
err := exec.Command("sh", "-c", `iptables -t filter -I FORWARD -i optun -j ACCEPT`).Run()
|
||||
if err != nil {
|
||||
log.Println("allow foward in error:", err)
|
||||
}
|
||||
err = exec.Command("sh", "-c", `iptables -t filter -I FORWARD -o optun -j ACCEPT`).Run()
|
||||
if err != nil {
|
||||
log.Println("allow foward out error:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func clearSNATRule() {
|
||||
if runtime.GOOS != "linux" {
|
||||
return
|
||||
}
|
||||
execCommand("iptables", true, "-t", "nat", "-D", "POSTROUTING", "-j", "OPSDWAN")
|
||||
execCommand("iptables", true, "-t", "nat", "-F", "OPSDWAN")
|
||||
execCommand("iptables", true, "-t", "nat", "-X", "OPSDWAN")
|
||||
}
|
||||
|
||||
func initSNATRule(localNet string) {
|
||||
if runtime.GOOS != "linux" {
|
||||
return
|
||||
}
|
||||
clearSNATRule()
|
||||
|
||||
err := execCommand("iptables", true, "-t", "nat", "-N", "OPSDWAN")
|
||||
if err != nil {
|
||||
log.Println("iptables new sdwan chain error:", err)
|
||||
return
|
||||
}
|
||||
err = execCommand("iptables", true, "-t", "nat", "-A", "POSTROUTING", "-j", "OPSDWAN")
|
||||
if err != nil {
|
||||
log.Println("iptables append postrouting error:", err)
|
||||
return
|
||||
}
|
||||
err = execCommand("iptables", true, "-t", "nat", "-A", "OPSDWAN",
|
||||
"-o", "optun", "!", "-s", localNet, "-j", "MASQUERADE")
|
||||
if err != nil {
|
||||
log.Println("add optun snat error:", err)
|
||||
return
|
||||
}
|
||||
err = execCommand("iptables", true, "-t", "nat", "-A", "OPSDWAN", "!", "-o", "optun",
|
||||
"-s", localNet, "-j", "MASQUERADE")
|
||||
if err != nil {
|
||||
log.Println("add optun snat error:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func addSNATRule(target string) {
|
||||
if runtime.GOOS != "linux" {
|
||||
return
|
||||
}
|
||||
err := execCommand("iptables", true, "-t", "nat", "-A", "OPSDWAN", "!", "-o", "optun",
|
||||
"-s", target, "-j", "MASQUERADE")
|
||||
if err != nil {
|
||||
log.Println("iptables add optun snat error:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
378
core/nat.go
378
core/nat.go
@@ -1,189 +1,189 @@
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
reuse "github.com/openp2p-cn/go-reuseport"
|
||||
)
|
||||
|
||||
func natTCP(serverHost string, serverPort int) (publicIP string, publicPort int, localPort int) {
|
||||
// dialer := &net.Dialer{
|
||||
// LocalAddr: &net.TCPAddr{
|
||||
// IP: net.ParseIP("0.0.0.0"),
|
||||
// Port: localPort,
|
||||
// },
|
||||
// }
|
||||
conn, err := reuse.DialTimeout("tcp4", fmt.Sprintf("%s:%d", "0.0.0.0", 0), fmt.Sprintf("%s:%d", serverHost, serverPort), NatTestTimeout)
|
||||
// conn, err := net.Dial("tcp4", fmt.Sprintf("%s:%d", serverHost, serverPort))
|
||||
// log.Println(LvINFO, conn.LocalAddr())
|
||||
if err != nil {
|
||||
fmt.Printf("Dial tcp4 %s:%d error:%s", serverHost, serverPort, err)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
localPort, _ = strconv.Atoi(strings.Split(conn.LocalAddr().String(), ":")[1])
|
||||
_, wrerr := conn.Write([]byte("1"))
|
||||
if wrerr != nil {
|
||||
fmt.Printf("Write error: %s\n", wrerr)
|
||||
return
|
||||
}
|
||||
b := make([]byte, 1000)
|
||||
conn.SetReadDeadline(time.Now().Add(NatTestTimeout))
|
||||
n, rderr := conn.Read(b)
|
||||
if rderr != nil {
|
||||
fmt.Printf("Read error: %s\n", rderr)
|
||||
return
|
||||
}
|
||||
arr := strings.Split(string(b[:n]), ":")
|
||||
if len(arr) < 2 {
|
||||
return
|
||||
}
|
||||
publicIP = arr[0]
|
||||
port, _ := strconv.ParseInt(arr[1], 10, 32)
|
||||
publicPort = int(port)
|
||||
return
|
||||
|
||||
}
|
||||
func natTest(serverHost string, serverPort int, localPort int) (publicIP string, publicPort int, err error) {
|
||||
gLog.Println(LvDEBUG, "natTest start")
|
||||
defer gLog.Println(LvDEBUG, "natTest end")
|
||||
conn, err := net.ListenPacket("udp", fmt.Sprintf(":%d", localPort))
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "natTest listen udp error:", err)
|
||||
return "", 0, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
dst, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", serverHost, serverPort))
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
|
||||
// The connection can write data to the desired address.
|
||||
msg, err := newMessage(MsgNATDetect, 0, nil)
|
||||
_, err = conn.WriteTo(msg, dst)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
deadline := time.Now().Add(NatTestTimeout)
|
||||
err = conn.SetReadDeadline(deadline)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
buffer := make([]byte, 1024)
|
||||
nRead, _, err := conn.ReadFrom(buffer)
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "NAT detect error:", err)
|
||||
return "", 0, err
|
||||
}
|
||||
natRsp := NatDetectRsp{}
|
||||
json.Unmarshal(buffer[openP2PHeaderSize:nRead], &natRsp)
|
||||
|
||||
return natRsp.IP, natRsp.Port, nil
|
||||
}
|
||||
|
||||
func getNATType(host string, udp1 int, udp2 int) (publicIP string, NATType int, err error) {
|
||||
// the random local port may be used by other.
|
||||
localPort := int(rand.Uint32()%15000 + 50000)
|
||||
|
||||
ip1, port1, err := natTest(host, udp1, localPort)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
_, port2, err := natTest(host, udp2, localPort) // 2rd nat test not need testing publicip
|
||||
gLog.Printf(LvDEBUG, "local port:%d nat port:%d", localPort, port2)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
natType := NATSymmetric
|
||||
if port1 == port2 {
|
||||
natType = NATCone
|
||||
}
|
||||
return ip1, natType, nil
|
||||
}
|
||||
|
||||
func publicIPTest(publicIP string, echoPort int) (hasPublicIP int, hasUPNPorNATPMP int) {
|
||||
if publicIP == "" || echoPort == 0 {
|
||||
return
|
||||
}
|
||||
var echoConn *net.UDPConn
|
||||
gLog.Println(LvDEBUG, "echo server start")
|
||||
var err error
|
||||
echoConn, err = net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: echoPort})
|
||||
if err != nil { // listen error
|
||||
gLog.Println(LvERROR, "echo server listen error:", err)
|
||||
return
|
||||
}
|
||||
defer echoConn.Close()
|
||||
go func() {
|
||||
// close outside for breaking the ReadFromUDP
|
||||
// wait 30s for echo testing
|
||||
buf := make([]byte, 1600)
|
||||
echoConn.SetReadDeadline(time.Now().Add(time.Second * 30))
|
||||
n, addr, err := echoConn.ReadFromUDP(buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
echoConn.WriteToUDP(buf[0:n], addr)
|
||||
gLog.Println(LvDEBUG, "echo server end")
|
||||
}()
|
||||
// testing for public ip
|
||||
for i := 0; i < 2; i++ {
|
||||
if i == 1 {
|
||||
// test upnp or nat-pmp
|
||||
gLog.Println(LvDEBUG, "upnp test start")
|
||||
nat, err := Discover()
|
||||
if err != nil || nat == nil {
|
||||
gLog.Println(LvDEBUG, "could not perform UPNP discover:", err)
|
||||
break
|
||||
}
|
||||
ext, err := nat.GetExternalAddress()
|
||||
if err != nil {
|
||||
gLog.Println(LvDEBUG, "could not perform UPNP external address:", err)
|
||||
break
|
||||
}
|
||||
gLog.Println(LvINFO, "PublicIP:", ext)
|
||||
|
||||
externalPort, err := nat.AddPortMapping("udp", echoPort, echoPort, "openp2p", 30) // 30 seconds fot upnp testing
|
||||
if err != nil {
|
||||
gLog.Println(LvDEBUG, "could not add udp UPNP port mapping", externalPort)
|
||||
break
|
||||
} else {
|
||||
nat.AddPortMapping("tcp", echoPort, echoPort, "openp2p", 604800) // 7 days for tcp connection
|
||||
}
|
||||
}
|
||||
gLog.Printf(LvDEBUG, "public ip test start %s:%d", publicIP, echoPort)
|
||||
conn, err := net.ListenUDP("udp", nil)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
defer conn.Close()
|
||||
dst, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", publicIP, echoPort))
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
conn.WriteTo([]byte("echo"), dst)
|
||||
buf := make([]byte, 1600)
|
||||
|
||||
// wait for echo testing
|
||||
conn.SetReadDeadline(time.Now().Add(PublicIPEchoTimeout))
|
||||
_, _, err = conn.ReadFromUDP(buf)
|
||||
if err == nil {
|
||||
if i == 1 {
|
||||
gLog.Println(LvDEBUG, "UPNP or NAT-PMP:YES")
|
||||
hasUPNPorNATPMP = 1
|
||||
} else {
|
||||
gLog.Println(LvDEBUG, "public ip:YES")
|
||||
hasPublicIP = 1
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
reuse "github.com/openp2p-cn/go-reuseport"
|
||||
)
|
||||
|
||||
func natTCP(serverHost string, serverPort int) (publicIP string, publicPort int, localPort int) {
|
||||
// dialer := &net.Dialer{
|
||||
// LocalAddr: &net.TCPAddr{
|
||||
// IP: net.ParseIP("0.0.0.0"),
|
||||
// Port: localPort,
|
||||
// },
|
||||
// }
|
||||
conn, err := reuse.DialTimeout("tcp4", fmt.Sprintf("%s:%d", "0.0.0.0", 0), fmt.Sprintf("%s:%d", serverHost, serverPort), NatTestTimeout)
|
||||
// conn, err := net.Dial("tcp4", fmt.Sprintf("%s:%d", serverHost, serverPort))
|
||||
// log.Println(LvINFO, conn.LocalAddr())
|
||||
if err != nil {
|
||||
fmt.Printf("Dial tcp4 %s:%d error:%s", serverHost, serverPort, err)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
localPort, _ = strconv.Atoi(strings.Split(conn.LocalAddr().String(), ":")[1])
|
||||
_, wrerr := conn.Write([]byte("1"))
|
||||
if wrerr != nil {
|
||||
fmt.Printf("Write error: %s\n", wrerr)
|
||||
return
|
||||
}
|
||||
b := make([]byte, 1000)
|
||||
conn.SetReadDeadline(time.Now().Add(NatTestTimeout))
|
||||
n, rderr := conn.Read(b)
|
||||
if rderr != nil {
|
||||
fmt.Printf("Read error: %s\n", rderr)
|
||||
return
|
||||
}
|
||||
arr := strings.Split(string(b[:n]), ":")
|
||||
if len(arr) < 2 {
|
||||
return
|
||||
}
|
||||
publicIP = arr[0]
|
||||
port, _ := strconv.ParseInt(arr[1], 10, 32)
|
||||
publicPort = int(port)
|
||||
return
|
||||
|
||||
}
|
||||
func natTest(serverHost string, serverPort int, localPort int) (publicIP string, publicPort int, err error) {
|
||||
gLog.Println(LvDEBUG, "natTest start")
|
||||
defer gLog.Println(LvDEBUG, "natTest end")
|
||||
conn, err := net.ListenPacket("udp", fmt.Sprintf(":%d", localPort))
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "natTest listen udp error:", err)
|
||||
return "", 0, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
dst, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", serverHost, serverPort))
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
|
||||
// The connection can write data to the desired address.
|
||||
msg, err := newMessage(MsgNATDetect, 0, nil)
|
||||
_, err = conn.WriteTo(msg, dst)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
deadline := time.Now().Add(NatTestTimeout)
|
||||
err = conn.SetReadDeadline(deadline)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
buffer := make([]byte, 1024)
|
||||
nRead, _, err := conn.ReadFrom(buffer)
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "NAT detect error:", err)
|
||||
return "", 0, err
|
||||
}
|
||||
natRsp := NatDetectRsp{}
|
||||
json.Unmarshal(buffer[openP2PHeaderSize:nRead], &natRsp)
|
||||
|
||||
return natRsp.IP, natRsp.Port, nil
|
||||
}
|
||||
|
||||
func getNATType(host string, udp1 int, udp2 int) (publicIP string, NATType int, err error) {
|
||||
// the random local port may be used by other.
|
||||
localPort := int(rand.Uint32()%15000 + 50000)
|
||||
|
||||
ip1, port1, err := natTest(host, udp1, localPort)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
_, port2, err := natTest(host, udp2, localPort) // 2rd nat test not need testing publicip
|
||||
gLog.Printf(LvDEBUG, "local port:%d nat port:%d", localPort, port2)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
natType := NATSymmetric
|
||||
if port1 == port2 {
|
||||
natType = NATCone
|
||||
}
|
||||
return ip1, natType, nil
|
||||
}
|
||||
|
||||
func publicIPTest(publicIP string, echoPort int) (hasPublicIP int, hasUPNPorNATPMP int) {
|
||||
if publicIP == "" || echoPort == 0 {
|
||||
return
|
||||
}
|
||||
var echoConn *net.UDPConn
|
||||
gLog.Println(LvDEBUG, "echo server start")
|
||||
var err error
|
||||
echoConn, err = net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: echoPort})
|
||||
if err != nil { // listen error
|
||||
gLog.Println(LvERROR, "echo server listen error:", err)
|
||||
return
|
||||
}
|
||||
defer echoConn.Close()
|
||||
go func() {
|
||||
// close outside for breaking the ReadFromUDP
|
||||
// wait 30s for echo testing
|
||||
buf := make([]byte, 1600)
|
||||
echoConn.SetReadDeadline(time.Now().Add(time.Second * 30))
|
||||
n, addr, err := echoConn.ReadFromUDP(buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
echoConn.WriteToUDP(buf[0:n], addr)
|
||||
gLog.Println(LvDEBUG, "echo server end")
|
||||
}()
|
||||
// testing for public ip
|
||||
for i := 0; i < 2; i++ {
|
||||
if i == 1 {
|
||||
// test upnp or nat-pmp
|
||||
gLog.Println(LvDEBUG, "upnp test start")
|
||||
nat, err := Discover()
|
||||
if err != nil || nat == nil {
|
||||
gLog.Println(LvDEBUG, "could not perform UPNP discover:", err)
|
||||
break
|
||||
}
|
||||
ext, err := nat.GetExternalAddress()
|
||||
if err != nil {
|
||||
gLog.Println(LvDEBUG, "could not perform UPNP external address:", err)
|
||||
break
|
||||
}
|
||||
gLog.Println(LvINFO, "PublicIP:", ext)
|
||||
|
||||
externalPort, err := nat.AddPortMapping("udp", echoPort, echoPort, "openp2p", 30) // 30 seconds fot upnp testing
|
||||
if err != nil {
|
||||
gLog.Println(LvDEBUG, "could not add udp UPNP port mapping", externalPort)
|
||||
break
|
||||
} else {
|
||||
nat.AddPortMapping("tcp", echoPort, echoPort, "openp2p", 604800) // 7 days for tcp connection
|
||||
}
|
||||
}
|
||||
gLog.Printf(LvDEBUG, "public ip test start %s:%d", publicIP, echoPort)
|
||||
conn, err := net.ListenUDP("udp", nil)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
defer conn.Close()
|
||||
dst, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", publicIP, echoPort))
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
conn.WriteTo([]byte("echo"), dst)
|
||||
buf := make([]byte, 1600)
|
||||
|
||||
// wait for echo testing
|
||||
conn.SetReadDeadline(time.Now().Add(PublicIPEchoTimeout))
|
||||
_, _, err = conn.ReadFromUDP(buf)
|
||||
if err == nil {
|
||||
if i == 1 {
|
||||
gLog.Println(LvDEBUG, "UPNP or NAT-PMP:YES")
|
||||
hasUPNPorNATPMP = 1
|
||||
} else {
|
||||
gLog.Println(LvDEBUG, "public ip:YES")
|
||||
hasPublicIP = 1
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
242
core/openp2p.go
242
core/openp2p.go
@@ -1,121 +1,121 @@
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
var GNetwork *P2PNetwork
|
||||
|
||||
func Run() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
baseDir := filepath.Dir(os.Args[0])
|
||||
os.Chdir(baseDir) // for system service
|
||||
gLog = NewLogger(baseDir, ProductName, LvDEBUG, 1024*1024, LogFile|LogConsole)
|
||||
if len(os.Args) > 1 {
|
||||
switch os.Args[1] {
|
||||
case "version", "-v", "--version":
|
||||
fmt.Println(OpenP2PVersion)
|
||||
return
|
||||
case "install":
|
||||
install()
|
||||
return
|
||||
case "uninstall":
|
||||
uninstall()
|
||||
return
|
||||
}
|
||||
} else {
|
||||
installByFilename()
|
||||
}
|
||||
parseParams("", "")
|
||||
gLog.Println(LvINFO, "openp2p start. version: ", OpenP2PVersion)
|
||||
gLog.Println(LvINFO, "Contact: QQ group 16947733, Email openp2p.cn@gmail.com")
|
||||
|
||||
if gConf.daemonMode {
|
||||
d := daemon{}
|
||||
d.run()
|
||||
return
|
||||
}
|
||||
|
||||
gLog.Println(LvINFO, &gConf)
|
||||
setFirewall()
|
||||
err := setRLimit()
|
||||
if err != nil {
|
||||
gLog.Println(LvINFO, "setRLimit error:", err)
|
||||
}
|
||||
GNetwork = P2PNetworkInstance()
|
||||
if ok := GNetwork.Connect(30000); !ok {
|
||||
gLog.Println(LvERROR, "P2PNetwork login error")
|
||||
return
|
||||
}
|
||||
// gLog.Println(LvINFO, "waiting for connection...")
|
||||
forever := make(chan bool)
|
||||
<-forever
|
||||
}
|
||||
|
||||
// for Android app
|
||||
// gomobile not support uint64 exported to java
|
||||
|
||||
func RunAsModule(baseDir string, token string, bw int, logLevel int) *P2PNetwork {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
os.Chdir(baseDir) // for system service
|
||||
gLog = NewLogger(baseDir, ProductName, LvINFO, 1024*1024, LogFile|LogConsole)
|
||||
|
||||
parseParams("", "")
|
||||
|
||||
n, err := strconv.ParseUint(token, 10, 64)
|
||||
if err == nil && n > 0 {
|
||||
gConf.setToken(n)
|
||||
}
|
||||
if n <= 0 && gConf.Network.Token == 0 { // not input token
|
||||
return nil
|
||||
}
|
||||
// gLog.setLevel(LogLevel(logLevel))
|
||||
gConf.setShareBandwidth(bw)
|
||||
gLog.Println(LvINFO, "openp2p start. version: ", OpenP2PVersion)
|
||||
gLog.Println(LvINFO, "Contact: QQ group 16947733, Email openp2p.cn@gmail.com")
|
||||
gLog.Println(LvINFO, &gConf)
|
||||
|
||||
GNetwork = P2PNetworkInstance()
|
||||
if ok := GNetwork.Connect(30000); !ok {
|
||||
gLog.Println(LvERROR, "P2PNetwork login error")
|
||||
return nil
|
||||
}
|
||||
// gLog.Println(LvINFO, "waiting for connection...")
|
||||
return GNetwork
|
||||
}
|
||||
|
||||
func RunCmd(cmd string) {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
baseDir := filepath.Dir(os.Args[0])
|
||||
os.Chdir(baseDir) // for system service
|
||||
gLog = NewLogger(baseDir, ProductName, LvINFO, 1024*1024, LogFile|LogConsole)
|
||||
|
||||
parseParams("", cmd)
|
||||
setFirewall()
|
||||
err := setRLimit()
|
||||
if err != nil {
|
||||
gLog.Println(LvINFO, "setRLimit error:", err)
|
||||
}
|
||||
GNetwork = P2PNetworkInstance()
|
||||
if ok := GNetwork.Connect(30000); !ok {
|
||||
gLog.Println(LvERROR, "P2PNetwork login error")
|
||||
return
|
||||
}
|
||||
forever := make(chan bool)
|
||||
<-forever
|
||||
}
|
||||
|
||||
func GetToken(baseDir string) string {
|
||||
os.Chdir(baseDir)
|
||||
gConf.load()
|
||||
return fmt.Sprintf("%d", gConf.Network.Token)
|
||||
}
|
||||
|
||||
func Stop() {
|
||||
os.Exit(0)
|
||||
}
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
var GNetwork *P2PNetwork
|
||||
|
||||
func Run() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
baseDir := filepath.Dir(os.Args[0])
|
||||
os.Chdir(baseDir) // for system service
|
||||
gLog = NewLogger(baseDir, ProductName, LvDEBUG, 1024*1024, LogFile|LogConsole)
|
||||
if len(os.Args) > 1 {
|
||||
switch os.Args[1] {
|
||||
case "version", "-v", "--version":
|
||||
fmt.Println(OpenP2PVersion)
|
||||
return
|
||||
case "install":
|
||||
install()
|
||||
return
|
||||
case "uninstall":
|
||||
uninstall()
|
||||
return
|
||||
}
|
||||
} else {
|
||||
installByFilename()
|
||||
}
|
||||
parseParams("", "")
|
||||
gLog.Println(LvINFO, "openp2p start. version: ", OpenP2PVersion)
|
||||
gLog.Println(LvINFO, "Contact: QQ group 16947733, Email openp2p.cn@gmail.com")
|
||||
|
||||
if gConf.daemonMode {
|
||||
d := daemon{}
|
||||
d.run()
|
||||
return
|
||||
}
|
||||
|
||||
gLog.Println(LvINFO, &gConf)
|
||||
setFirewall()
|
||||
err := setRLimit()
|
||||
if err != nil {
|
||||
gLog.Println(LvINFO, "setRLimit error:", err)
|
||||
}
|
||||
GNetwork = P2PNetworkInstance()
|
||||
if ok := GNetwork.Connect(30000); !ok {
|
||||
gLog.Println(LvERROR, "P2PNetwork login error")
|
||||
return
|
||||
}
|
||||
// gLog.Println(LvINFO, "waiting for connection...")
|
||||
forever := make(chan bool)
|
||||
<-forever
|
||||
}
|
||||
|
||||
// for Android app
|
||||
// gomobile not support uint64 exported to java
|
||||
|
||||
func RunAsModule(baseDir string, token string, bw int, logLevel int) *P2PNetwork {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
os.Chdir(baseDir) // for system service
|
||||
gLog = NewLogger(baseDir, ProductName, LvINFO, 1024*1024, LogFile|LogConsole)
|
||||
|
||||
parseParams("", "")
|
||||
|
||||
n, err := strconv.ParseUint(token, 10, 64)
|
||||
if err == nil && n > 0 {
|
||||
gConf.setToken(n)
|
||||
}
|
||||
if n <= 0 && gConf.Network.Token == 0 { // not input token
|
||||
return nil
|
||||
}
|
||||
// gLog.setLevel(LogLevel(logLevel))
|
||||
gConf.setShareBandwidth(bw)
|
||||
gLog.Println(LvINFO, "openp2p start. version: ", OpenP2PVersion)
|
||||
gLog.Println(LvINFO, "Contact: QQ group 16947733, Email openp2p.cn@gmail.com")
|
||||
gLog.Println(LvINFO, &gConf)
|
||||
|
||||
GNetwork = P2PNetworkInstance()
|
||||
if ok := GNetwork.Connect(30000); !ok {
|
||||
gLog.Println(LvERROR, "P2PNetwork login error")
|
||||
return nil
|
||||
}
|
||||
// gLog.Println(LvINFO, "waiting for connection...")
|
||||
return GNetwork
|
||||
}
|
||||
|
||||
func RunCmd(cmd string) {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
baseDir := filepath.Dir(os.Args[0])
|
||||
os.Chdir(baseDir) // for system service
|
||||
gLog = NewLogger(baseDir, ProductName, LvINFO, 1024*1024, LogFile|LogConsole)
|
||||
|
||||
parseParams("", cmd)
|
||||
setFirewall()
|
||||
err := setRLimit()
|
||||
if err != nil {
|
||||
gLog.Println(LvINFO, "setRLimit error:", err)
|
||||
}
|
||||
GNetwork = P2PNetworkInstance()
|
||||
if ok := GNetwork.Connect(30000); !ok {
|
||||
gLog.Println(LvERROR, "P2PNetwork login error")
|
||||
return
|
||||
}
|
||||
forever := make(chan bool)
|
||||
<-forever
|
||||
}
|
||||
|
||||
func GetToken(baseDir string) string {
|
||||
os.Chdir(baseDir)
|
||||
gConf.load()
|
||||
return fmt.Sprintf("%d", gConf.Network.Token)
|
||||
}
|
||||
|
||||
func Stop() {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
@@ -1,20 +1,20 @@
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"github.com/openp2p-cn/wireguard-go/tun"
|
||||
)
|
||||
|
||||
var AndroidSDWANConfig chan []byte
|
||||
|
||||
type optun struct {
|
||||
tunName string
|
||||
dev tun.Device
|
||||
}
|
||||
|
||||
func (t *optun) Stop() error {
|
||||
t.dev.Close()
|
||||
return nil
|
||||
}
|
||||
func init() {
|
||||
AndroidSDWANConfig = make(chan []byte, 1)
|
||||
}
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"github.com/openp2p-cn/wireguard-go/tun"
|
||||
)
|
||||
|
||||
var AndroidSDWANConfig chan []byte
|
||||
|
||||
type optun struct {
|
||||
tunName string
|
||||
dev tun.Device
|
||||
}
|
||||
|
||||
func (t *optun) Stop() error {
|
||||
t.dev.Close()
|
||||
return nil
|
||||
}
|
||||
func init() {
|
||||
AndroidSDWANConfig = make(chan []byte, 1)
|
||||
}
|
||||
|
@@ -1,85 +1,85 @@
|
||||
// optun_android.go
|
||||
//go:build android
|
||||
// +build android
|
||||
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
const (
|
||||
tunIfaceName = "optun"
|
||||
PIHeaderSize = 0
|
||||
)
|
||||
|
||||
var AndroidReadTun chan []byte // TODO: multi channel
|
||||
var AndroidWriteTun chan []byte
|
||||
|
||||
func (t *optun) Start(localAddr string, detail *SDWANInfo) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *optun) Read(bufs [][]byte, sizes []int, offset int) (n int, err error) {
|
||||
bufs[0] = <-AndroidReadTun
|
||||
sizes[0] = len(bufs[0])
|
||||
return 1, nil
|
||||
}
|
||||
|
||||
func (t *optun) Write(bufs [][]byte, offset int) (int, error) {
|
||||
AndroidWriteTun <- bufs[0]
|
||||
return len(bufs[0]), nil
|
||||
}
|
||||
|
||||
func AndroidRead(data []byte, len int) {
|
||||
head := PacketHeader{}
|
||||
parseHeader(data, &head)
|
||||
gLog.Printf(LvDev, "AndroidRead tun dst ip=%s,len=%d", net.IP{byte(head.dst >> 24), byte(head.dst >> 16), byte(head.dst >> 8), byte(head.dst)}.String(), len)
|
||||
buf := make([]byte, len)
|
||||
copy(buf, data)
|
||||
AndroidReadTun <- buf
|
||||
}
|
||||
|
||||
func AndroidWrite(buf []byte) int {
|
||||
p := <-AndroidWriteTun
|
||||
copy(buf, p)
|
||||
return len(p)
|
||||
}
|
||||
|
||||
func GetAndroidSDWANConfig(buf []byte) int {
|
||||
p := <-AndroidSDWANConfig
|
||||
copy(buf, p)
|
||||
gLog.Printf(LvINFO, "AndroidSDWANConfig=%s", p)
|
||||
return len(p)
|
||||
}
|
||||
|
||||
func GetAndroidNodeName() string {
|
||||
gLog.Printf(LvINFO, "GetAndroidNodeName=%s", gConf.Network.Node)
|
||||
return gConf.Network.Node
|
||||
}
|
||||
|
||||
func setTunAddr(ifname, localAddr, remoteAddr string, wintun interface{}) error {
|
||||
// TODO:
|
||||
return nil
|
||||
}
|
||||
|
||||
func addRoute(dst, gw, ifname string) error {
|
||||
// TODO:
|
||||
return nil
|
||||
}
|
||||
|
||||
func delRoute(dst, gw string) error {
|
||||
// TODO:
|
||||
return nil
|
||||
}
|
||||
|
||||
func delRoutesByGateway(gateway string) error {
|
||||
// TODO:
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
AndroidReadTun = make(chan []byte, 1000)
|
||||
AndroidWriteTun = make(chan []byte, 1000)
|
||||
}
|
||||
// optun_android.go
|
||||
//go:build android
|
||||
// +build android
|
||||
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
const (
|
||||
tunIfaceName = "optun"
|
||||
PIHeaderSize = 0
|
||||
)
|
||||
|
||||
var AndroidReadTun chan []byte // TODO: multi channel
|
||||
var AndroidWriteTun chan []byte
|
||||
|
||||
func (t *optun) Start(localAddr string, detail *SDWANInfo) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *optun) Read(bufs [][]byte, sizes []int, offset int) (n int, err error) {
|
||||
bufs[0] = <-AndroidReadTun
|
||||
sizes[0] = len(bufs[0])
|
||||
return 1, nil
|
||||
}
|
||||
|
||||
func (t *optun) Write(bufs [][]byte, offset int) (int, error) {
|
||||
AndroidWriteTun <- bufs[0]
|
||||
return len(bufs[0]), nil
|
||||
}
|
||||
|
||||
func AndroidRead(data []byte, len int) {
|
||||
head := PacketHeader{}
|
||||
parseHeader(data, &head)
|
||||
gLog.Printf(LvDev, "AndroidRead tun dst ip=%s,len=%d", net.IP{byte(head.dst >> 24), byte(head.dst >> 16), byte(head.dst >> 8), byte(head.dst)}.String(), len)
|
||||
buf := make([]byte, len)
|
||||
copy(buf, data)
|
||||
AndroidReadTun <- buf
|
||||
}
|
||||
|
||||
func AndroidWrite(buf []byte) int {
|
||||
p := <-AndroidWriteTun
|
||||
copy(buf, p)
|
||||
return len(p)
|
||||
}
|
||||
|
||||
func GetAndroidSDWANConfig(buf []byte) int {
|
||||
p := <-AndroidSDWANConfig
|
||||
copy(buf, p)
|
||||
gLog.Printf(LvINFO, "AndroidSDWANConfig=%s", p)
|
||||
return len(p)
|
||||
}
|
||||
|
||||
func GetAndroidNodeName() string {
|
||||
gLog.Printf(LvINFO, "GetAndroidNodeName=%s", gConf.Network.Node)
|
||||
return gConf.Network.Node
|
||||
}
|
||||
|
||||
func setTunAddr(ifname, localAddr, remoteAddr string, wintun interface{}) error {
|
||||
// TODO:
|
||||
return nil
|
||||
}
|
||||
|
||||
func addRoute(dst, gw, ifname string) error {
|
||||
// TODO:
|
||||
return nil
|
||||
}
|
||||
|
||||
func delRoute(dst, gw string) error {
|
||||
// TODO:
|
||||
return nil
|
||||
}
|
||||
|
||||
func delRoutesByGateway(gateway string) error {
|
||||
// TODO:
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
AndroidReadTun = make(chan []byte, 1000)
|
||||
AndroidWriteTun = make(chan []byte, 1000)
|
||||
}
|
||||
|
@@ -1,133 +1,133 @@
|
||||
//go:build !android
|
||||
// +build !android
|
||||
|
||||
// optun_linux.go
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/openp2p-cn/wireguard-go/tun"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
const (
|
||||
tunIfaceName = "optun"
|
||||
PIHeaderSize = 0
|
||||
)
|
||||
|
||||
var previousIP = ""
|
||||
|
||||
func (t *optun) Start(localAddr string, detail *SDWANInfo) error {
|
||||
var err error
|
||||
t.tunName = tunIfaceName
|
||||
t.dev, err = tun.CreateTUN(t.tunName, 1420)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *optun) Read(bufs [][]byte, sizes []int, offset int) (n int, err error) {
|
||||
return t.dev.Read(bufs, sizes, offset)
|
||||
}
|
||||
|
||||
func (t *optun) Write(bufs [][]byte, offset int) (int, error) {
|
||||
return t.dev.Write(bufs, offset)
|
||||
}
|
||||
|
||||
func setTunAddr(ifname, localAddr, remoteAddr string, wintun interface{}) error {
|
||||
ifce, err := netlink.LinkByName(ifname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
netlink.LinkSetMTU(ifce, 1375)
|
||||
netlink.LinkSetTxQLen(ifce, 100)
|
||||
netlink.LinkSetUp(ifce)
|
||||
|
||||
ln, err := netlink.ParseIPNet(localAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ln.Mask = net.CIDRMask(32, 32)
|
||||
rn, err := netlink.ParseIPNet(remoteAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rn.Mask = net.CIDRMask(32, 32)
|
||||
|
||||
addr := &netlink.Addr{
|
||||
IPNet: ln,
|
||||
Peer: rn,
|
||||
}
|
||||
if previousIP != "" {
|
||||
lnDel, err := netlink.ParseIPNet(previousIP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lnDel.Mask = net.CIDRMask(32, 32)
|
||||
|
||||
addrDel := &netlink.Addr{
|
||||
IPNet: lnDel,
|
||||
Peer: rn,
|
||||
}
|
||||
netlink.AddrDel(ifce, addrDel)
|
||||
}
|
||||
previousIP = localAddr
|
||||
return netlink.AddrAdd(ifce, addr)
|
||||
}
|
||||
|
||||
func addRoute(dst, gw, ifname string) error {
|
||||
_, networkid, err := net.ParseCIDR(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ipGW := net.ParseIP(gw)
|
||||
if ipGW == nil {
|
||||
return fmt.Errorf("parse gateway %s failed", gw)
|
||||
}
|
||||
route := &netlink.Route{
|
||||
Dst: networkid,
|
||||
Gw: ipGW,
|
||||
}
|
||||
return netlink.RouteAdd(route)
|
||||
}
|
||||
|
||||
func delRoute(dst, gw string) error {
|
||||
_, networkid, err := net.ParseCIDR(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
route := &netlink.Route{
|
||||
Dst: networkid,
|
||||
}
|
||||
return netlink.RouteDel(route)
|
||||
}
|
||||
|
||||
func delRoutesByGateway(gateway string) error {
|
||||
cmd := exec.Command("route", "-n")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lines := strings.Split(string(output), "\n")
|
||||
for _, line := range lines {
|
||||
if !strings.Contains(line, gateway) {
|
||||
continue
|
||||
}
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) >= 8 && fields[1] == "0.0.0.0" && fields[7] == gateway {
|
||||
delCmd := exec.Command("route", "del", "-net", fields[0], "gw", gateway)
|
||||
err := delCmd.Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Delete route ok: %s %s %s\n", fields[0], fields[1], gateway)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
//go:build !android
|
||||
// +build !android
|
||||
|
||||
// optun_linux.go
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/openp2p-cn/wireguard-go/tun"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
const (
|
||||
tunIfaceName = "optun"
|
||||
PIHeaderSize = 0
|
||||
)
|
||||
|
||||
var previousIP = ""
|
||||
|
||||
func (t *optun) Start(localAddr string, detail *SDWANInfo) error {
|
||||
var err error
|
||||
t.tunName = tunIfaceName
|
||||
t.dev, err = tun.CreateTUN(t.tunName, 1420)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *optun) Read(bufs [][]byte, sizes []int, offset int) (n int, err error) {
|
||||
return t.dev.Read(bufs, sizes, offset)
|
||||
}
|
||||
|
||||
func (t *optun) Write(bufs [][]byte, offset int) (int, error) {
|
||||
return t.dev.Write(bufs, offset)
|
||||
}
|
||||
|
||||
func setTunAddr(ifname, localAddr, remoteAddr string, wintun interface{}) error {
|
||||
ifce, err := netlink.LinkByName(ifname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
netlink.LinkSetMTU(ifce, 1375)
|
||||
netlink.LinkSetTxQLen(ifce, 100)
|
||||
netlink.LinkSetUp(ifce)
|
||||
|
||||
ln, err := netlink.ParseIPNet(localAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ln.Mask = net.CIDRMask(32, 32)
|
||||
rn, err := netlink.ParseIPNet(remoteAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rn.Mask = net.CIDRMask(32, 32)
|
||||
|
||||
addr := &netlink.Addr{
|
||||
IPNet: ln,
|
||||
Peer: rn,
|
||||
}
|
||||
if previousIP != "" {
|
||||
lnDel, err := netlink.ParseIPNet(previousIP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lnDel.Mask = net.CIDRMask(32, 32)
|
||||
|
||||
addrDel := &netlink.Addr{
|
||||
IPNet: lnDel,
|
||||
Peer: rn,
|
||||
}
|
||||
netlink.AddrDel(ifce, addrDel)
|
||||
}
|
||||
previousIP = localAddr
|
||||
return netlink.AddrAdd(ifce, addr)
|
||||
}
|
||||
|
||||
func addRoute(dst, gw, ifname string) error {
|
||||
_, networkid, err := net.ParseCIDR(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ipGW := net.ParseIP(gw)
|
||||
if ipGW == nil {
|
||||
return fmt.Errorf("parse gateway %s failed", gw)
|
||||
}
|
||||
route := &netlink.Route{
|
||||
Dst: networkid,
|
||||
Gw: ipGW,
|
||||
}
|
||||
return netlink.RouteAdd(route)
|
||||
}
|
||||
|
||||
func delRoute(dst, gw string) error {
|
||||
_, networkid, err := net.ParseCIDR(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
route := &netlink.Route{
|
||||
Dst: networkid,
|
||||
}
|
||||
return netlink.RouteDel(route)
|
||||
}
|
||||
|
||||
func delRoutesByGateway(gateway string) error {
|
||||
cmd := exec.Command("route", "-n")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lines := strings.Split(string(output), "\n")
|
||||
for _, line := range lines {
|
||||
if !strings.Contains(line, gateway) {
|
||||
continue
|
||||
}
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) >= 8 && fields[1] == "0.0.0.0" && fields[7] == gateway {
|
||||
delCmd := exec.Command("route", "del", "-net", fields[0], "gw", gateway)
|
||||
err := delCmd.Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Delete route ok: %s %s %s\n", fields[0], fields[1], gateway)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -1,142 +1,142 @@
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/openp2p-cn/wireguard-go/tun"
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
||||
)
|
||||
|
||||
const (
|
||||
tunIfaceName = "optun"
|
||||
PIHeaderSize = 0
|
||||
)
|
||||
|
||||
func (t *optun) Start(localAddr string, detail *SDWANInfo) error {
|
||||
// check wintun.dll
|
||||
tmpFile := filepath.Dir(os.Args[0]) + "/wintun.dll"
|
||||
fs, err := os.Stat(tmpFile)
|
||||
if err != nil || fs.Size() == 0 {
|
||||
url := fmt.Sprintf("https://openp2p.cn/download/v1/latest/wintun/%s/wintun.dll", runtime.GOARCH)
|
||||
err = downloadFile(url, "", tmpFile)
|
||||
if err != nil {
|
||||
os.Remove(tmpFile)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
t.tunName = tunIfaceName
|
||||
|
||||
uuid := &windows.GUID{
|
||||
Data1: 0xf411e821,
|
||||
Data2: 0xb310,
|
||||
Data3: 0x4567,
|
||||
Data4: [8]byte{0x80, 0x42, 0x83, 0x7e, 0xf4, 0x56, 0xce, 0x13},
|
||||
}
|
||||
t.dev, err = tun.CreateTUNWithRequestedGUID(t.tunName, uuid, 1420)
|
||||
if err != nil { // retry
|
||||
t.dev, err = tun.CreateTUNWithRequestedGUID(t.tunName, uuid, 1420)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *optun) Read(bufs [][]byte, sizes []int, offset int) (n int, err error) {
|
||||
return t.dev.Read(bufs, sizes, offset)
|
||||
}
|
||||
|
||||
func (t *optun) Write(bufs [][]byte, offset int) (int, error) {
|
||||
return t.dev.Write(bufs, offset)
|
||||
}
|
||||
|
||||
func setTunAddr(ifname, localAddr, remoteAddr string, wintun interface{}) error {
|
||||
nativeTunDevice := wintun.(*tun.NativeTun)
|
||||
link := winipcfg.LUID(nativeTunDevice.LUID())
|
||||
ip, err := netip.ParsePrefix(localAddr)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "ParsePrefix error:%s, luid:%d,localAddr:%s", err, nativeTunDevice.LUID(), localAddr)
|
||||
return err
|
||||
}
|
||||
err = link.SetIPAddresses([]netip.Prefix{ip})
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "SetIPAddresses error:%s, netip.Prefix:%+v", err, []netip.Prefix{ip})
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func addRoute(dst, gw, ifname string) error {
|
||||
_, dstNet, err := net.ParseCIDR(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i, err := net.InterfaceByName(ifname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params := make([]string, 0)
|
||||
params = append(params, "add")
|
||||
params = append(params, dstNet.IP.String())
|
||||
params = append(params, "mask")
|
||||
params = append(params, net.IP(dstNet.Mask).String())
|
||||
params = append(params, gw)
|
||||
params = append(params, "if")
|
||||
params = append(params, strconv.Itoa(i.Index))
|
||||
// gLogger.Println(LevelINFO, "windows add route params:", params)
|
||||
execCommand("route", true, params...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func delRoute(dst, gw string) error {
|
||||
_, dstNet, err := net.ParseCIDR(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params := make([]string, 0)
|
||||
params = append(params, "delete")
|
||||
params = append(params, dstNet.IP.String())
|
||||
params = append(params, "mask")
|
||||
params = append(params, net.IP(dstNet.Mask).String())
|
||||
params = append(params, gw)
|
||||
// gLogger.Println(LevelINFO, "windows delete route params:", params)
|
||||
execCommand("route", true, params...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func delRoutesByGateway(gateway string) error {
|
||||
cmd := exec.Command("route", "print", "-4")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lines := strings.Split(string(output), "\n")
|
||||
for _, line := range lines {
|
||||
if !strings.Contains(line, gateway) {
|
||||
continue
|
||||
}
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) >= 5 {
|
||||
cmd := exec.Command("route", "delete", fields[0], "mask", fields[1], gateway)
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
fmt.Println("Delete route error:", err)
|
||||
}
|
||||
fmt.Printf("Delete route ok: %s %s %s\n", fields[0], fields[1], gateway)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/openp2p-cn/wireguard-go/tun"
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
||||
)
|
||||
|
||||
const (
|
||||
tunIfaceName = "optun"
|
||||
PIHeaderSize = 0
|
||||
)
|
||||
|
||||
func (t *optun) Start(localAddr string, detail *SDWANInfo) error {
|
||||
// check wintun.dll
|
||||
tmpFile := filepath.Dir(os.Args[0]) + "/wintun.dll"
|
||||
fs, err := os.Stat(tmpFile)
|
||||
if err != nil || fs.Size() == 0 {
|
||||
url := fmt.Sprintf("https://openp2p.cn/download/v1/latest/wintun/%s/wintun.dll", runtime.GOARCH)
|
||||
err = downloadFile(url, "", tmpFile)
|
||||
if err != nil {
|
||||
os.Remove(tmpFile)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
t.tunName = tunIfaceName
|
||||
|
||||
uuid := &windows.GUID{
|
||||
Data1: 0xf411e821,
|
||||
Data2: 0xb310,
|
||||
Data3: 0x4567,
|
||||
Data4: [8]byte{0x80, 0x42, 0x83, 0x7e, 0xf4, 0x56, 0xce, 0x13},
|
||||
}
|
||||
t.dev, err = tun.CreateTUNWithRequestedGUID(t.tunName, uuid, 1420)
|
||||
if err != nil { // retry
|
||||
t.dev, err = tun.CreateTUNWithRequestedGUID(t.tunName, uuid, 1420)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *optun) Read(bufs [][]byte, sizes []int, offset int) (n int, err error) {
|
||||
return t.dev.Read(bufs, sizes, offset)
|
||||
}
|
||||
|
||||
func (t *optun) Write(bufs [][]byte, offset int) (int, error) {
|
||||
return t.dev.Write(bufs, offset)
|
||||
}
|
||||
|
||||
func setTunAddr(ifname, localAddr, remoteAddr string, wintun interface{}) error {
|
||||
nativeTunDevice := wintun.(*tun.NativeTun)
|
||||
link := winipcfg.LUID(nativeTunDevice.LUID())
|
||||
ip, err := netip.ParsePrefix(localAddr)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "ParsePrefix error:%s, luid:%d,localAddr:%s", err, nativeTunDevice.LUID(), localAddr)
|
||||
return err
|
||||
}
|
||||
err = link.SetIPAddresses([]netip.Prefix{ip})
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "SetIPAddresses error:%s, netip.Prefix:%+v", err, []netip.Prefix{ip})
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func addRoute(dst, gw, ifname string) error {
|
||||
_, dstNet, err := net.ParseCIDR(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i, err := net.InterfaceByName(ifname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params := make([]string, 0)
|
||||
params = append(params, "add")
|
||||
params = append(params, dstNet.IP.String())
|
||||
params = append(params, "mask")
|
||||
params = append(params, net.IP(dstNet.Mask).String())
|
||||
params = append(params, gw)
|
||||
params = append(params, "if")
|
||||
params = append(params, strconv.Itoa(i.Index))
|
||||
// gLogger.Println(LevelINFO, "windows add route params:", params)
|
||||
execCommand("route", true, params...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func delRoute(dst, gw string) error {
|
||||
_, dstNet, err := net.ParseCIDR(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params := make([]string, 0)
|
||||
params = append(params, "delete")
|
||||
params = append(params, dstNet.IP.String())
|
||||
params = append(params, "mask")
|
||||
params = append(params, net.IP(dstNet.Mask).String())
|
||||
params = append(params, gw)
|
||||
// gLogger.Println(LevelINFO, "windows delete route params:", params)
|
||||
execCommand("route", true, params...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func delRoutesByGateway(gateway string) error {
|
||||
cmd := exec.Command("route", "print", "-4")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lines := strings.Split(string(output), "\n")
|
||||
for _, line := range lines {
|
||||
if !strings.Contains(line, gateway) {
|
||||
continue
|
||||
}
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) >= 5 {
|
||||
cmd := exec.Command("route", "delete", fields[0], "mask", fields[1], gateway)
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
fmt.Println("Delete route error:", err)
|
||||
}
|
||||
fmt.Printf("Delete route ok: %s %s %s\n", fields[0], fields[1], gateway)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
1952
core/p2pnetwork.go
1952
core/p2pnetwork.go
File diff suppressed because it is too large
Load Diff
1612
core/p2ptunnel.go
1612
core/p2ptunnel.go
File diff suppressed because it is too large
Load Diff
584
core/sdwan.go
584
core/sdwan.go
@@ -1,292 +1,292 @@
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type PacketHeader struct {
|
||||
version int
|
||||
// src uint32
|
||||
// prot uint8
|
||||
protocol byte
|
||||
dst uint32
|
||||
port uint16
|
||||
}
|
||||
|
||||
func parseHeader(b []byte, h *PacketHeader) error {
|
||||
if len(b) < 20 {
|
||||
return fmt.Errorf("small packet")
|
||||
}
|
||||
h.version = int(b[0] >> 4)
|
||||
h.protocol = byte(b[9])
|
||||
if h.version == 4 {
|
||||
h.dst = binary.BigEndian.Uint32(b[16:20])
|
||||
} else if h.version != 6 {
|
||||
return fmt.Errorf("unknown version in ip header:%d", h.version)
|
||||
}
|
||||
if h.protocol == 6 || h.protocol == 17 { // TCP or UDP
|
||||
h.port = binary.BigEndian.Uint16(b[22:24])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type sdwanNode struct {
|
||||
name string
|
||||
id uint64
|
||||
}
|
||||
|
||||
type p2pSDWAN struct {
|
||||
nodeName string
|
||||
tun *optun
|
||||
sysRoute sync.Map // ip:sdwanNode
|
||||
subnet *net.IPNet
|
||||
gateway net.IP
|
||||
virtualIP *net.IPNet
|
||||
internalRoute *IPTree
|
||||
}
|
||||
|
||||
func (s *p2pSDWAN) init(name string) error {
|
||||
if gConf.getSDWAN().Gateway == "" {
|
||||
gLog.Println(LvDEBUG, "not in sdwan clear all ")
|
||||
}
|
||||
if s.internalRoute == nil {
|
||||
s.internalRoute = NewIPTree("")
|
||||
}
|
||||
|
||||
s.nodeName = name
|
||||
s.gateway, s.subnet, _ = net.ParseCIDR(gConf.getSDWAN().Gateway)
|
||||
for _, node := range gConf.getDelNodes() {
|
||||
gLog.Println(LvDEBUG, "deal deleted node: ", node.Name)
|
||||
delRoute(node.IP, s.gateway.String())
|
||||
s.internalRoute.Del(node.IP, node.IP)
|
||||
ipNum, _ := inetAtoN(node.IP)
|
||||
s.sysRoute.Delete(ipNum)
|
||||
gConf.delete(AppConfig{SrcPort: 0, PeerNode: node.Name})
|
||||
GNetwork.DeleteApp(AppConfig{SrcPort: 0, PeerNode: node.Name})
|
||||
arr := strings.Split(node.Resource, ",")
|
||||
for _, r := range arr {
|
||||
_, ipnet, err := net.ParseCIDR(r)
|
||||
if err != nil {
|
||||
// fmt.Println("Error parsing CIDR:", err)
|
||||
continue
|
||||
}
|
||||
if ipnet.Contains(net.ParseIP(gConf.Network.localIP)) { // local ip and resource in the same lan
|
||||
continue
|
||||
}
|
||||
minIP := ipnet.IP
|
||||
maxIP := make(net.IP, len(minIP))
|
||||
copy(maxIP, minIP)
|
||||
for i := range minIP {
|
||||
maxIP[i] = minIP[i] | ^ipnet.Mask[i]
|
||||
}
|
||||
s.internalRoute.Del(minIP.String(), maxIP.String())
|
||||
delRoute(ipnet.String(), s.gateway.String())
|
||||
}
|
||||
}
|
||||
for _, node := range gConf.getAddNodes() {
|
||||
gLog.Println(LvDEBUG, "deal add node: ", node.Name)
|
||||
ipNet := &net.IPNet{
|
||||
IP: net.ParseIP(node.IP),
|
||||
Mask: s.subnet.Mask,
|
||||
}
|
||||
if node.Name == s.nodeName {
|
||||
s.virtualIP = ipNet
|
||||
gLog.Println(LvINFO, "start tun ", ipNet.String())
|
||||
err := s.StartTun()
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "start tun error:", err)
|
||||
return err
|
||||
}
|
||||
gLog.Println(LvINFO, "start tun ok")
|
||||
allowTunForward()
|
||||
addRoute(s.subnet.String(), s.gateway.String(), s.tun.tunName)
|
||||
// addRoute("255.255.255.255/32", s.gateway.String(), s.tun.tunName) // for broadcast
|
||||
// addRoute("224.0.0.0/4", s.gateway.String(), s.tun.tunName) // for multicast
|
||||
initSNATRule(s.subnet.String()) // for network resource
|
||||
continue
|
||||
}
|
||||
ip, err := inetAtoN(ipNet.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.sysRoute.Store(ip, &sdwanNode{name: node.Name, id: NodeNameToID(node.Name)})
|
||||
s.internalRoute.AddIntIP(ip, ip, &sdwanNode{name: node.Name, id: NodeNameToID(node.Name)})
|
||||
}
|
||||
for _, node := range gConf.getAddNodes() {
|
||||
if node.Name == s.nodeName { // not deal resource itself
|
||||
continue
|
||||
}
|
||||
if len(node.Resource) > 0 {
|
||||
gLog.Printf(LvINFO, "deal add node: %s resource: %s", node.Name, node.Resource)
|
||||
arr := strings.Split(node.Resource, ",")
|
||||
for _, r := range arr {
|
||||
// add internal route
|
||||
_, ipnet, err := net.ParseCIDR(r)
|
||||
if err != nil {
|
||||
fmt.Println("Error parsing CIDR:", err)
|
||||
continue
|
||||
}
|
||||
if ipnet.Contains(net.ParseIP(gConf.Network.localIP)) { // local ip and resource in the same lan
|
||||
continue
|
||||
}
|
||||
minIP := ipnet.IP
|
||||
maxIP := make(net.IP, len(minIP))
|
||||
copy(maxIP, minIP)
|
||||
for i := range minIP {
|
||||
maxIP[i] = minIP[i] | ^ipnet.Mask[i]
|
||||
}
|
||||
s.internalRoute.Add(minIP.String(), maxIP.String(), &sdwanNode{name: node.Name, id: NodeNameToID(node.Name)})
|
||||
// add sys route
|
||||
addRoute(ipnet.String(), s.gateway.String(), s.tun.tunName)
|
||||
}
|
||||
}
|
||||
}
|
||||
gConf.retryAllMemApp()
|
||||
gLog.Printf(LvINFO, "sdwan init ok")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *p2pSDWAN) run() {
|
||||
s.sysRoute.Range(func(key, value interface{}) bool {
|
||||
node := value.(*sdwanNode)
|
||||
GNetwork.ConnectNode(node.name)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func (s *p2pSDWAN) readNodeLoop() {
|
||||
gLog.Printf(LvDEBUG, "sdwan readNodeLoop start")
|
||||
defer gLog.Printf(LvDEBUG, "sdwan readNodeLoop end")
|
||||
writeBuff := make([][]byte, 1)
|
||||
for {
|
||||
nd := GNetwork.ReadNode(time.Second * 10) // TODO: read multi packet
|
||||
if nd == nil {
|
||||
gLog.Printf(LvDev, "waiting for node data")
|
||||
continue
|
||||
}
|
||||
head := PacketHeader{}
|
||||
parseHeader(nd.Data, &head)
|
||||
gLog.Printf(LvDev, "write tun dst ip=%s,len=%d", net.IP{byte(head.dst >> 24), byte(head.dst >> 16), byte(head.dst >> 8), byte(head.dst)}.String(), len(nd.Data))
|
||||
if PIHeaderSize == 0 {
|
||||
writeBuff[0] = nd.Data
|
||||
} else {
|
||||
writeBuff[0] = make([]byte, PIHeaderSize+len(nd.Data))
|
||||
copy(writeBuff[0][PIHeaderSize:], nd.Data)
|
||||
}
|
||||
|
||||
len, err := s.tun.Write(writeBuff, PIHeaderSize)
|
||||
if err != nil {
|
||||
gLog.Printf(LvDEBUG, "write tun dst ip=%s,len=%d,error:%s", net.IP{byte(head.dst >> 24), byte(head.dst >> 16), byte(head.dst >> 8), byte(head.dst)}.String(), len, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func isBroadcastOrMulticast(ipUint32 uint32, subnet *net.IPNet) bool {
|
||||
// return ipUint32 == 0xffffffff || (byte(ipUint32) == 0xff) || (ipUint32>>28 == 0xe)
|
||||
return ipUint32 == 0xffffffff || (ipUint32>>28 == 0xe) // 225.255.255.255/32, 224.0.0.0/4
|
||||
}
|
||||
|
||||
func (s *p2pSDWAN) routeTunPacket(p []byte, head *PacketHeader) {
|
||||
var node *sdwanNode
|
||||
// v, ok := s.routes.Load(ih.dst)
|
||||
v, ok := s.internalRoute.Load(head.dst)
|
||||
if !ok || v == nil {
|
||||
if isBroadcastOrMulticast(head.dst, s.subnet) {
|
||||
gLog.Printf(LvDev, "multicast ip=%s", net.IP{byte(head.dst >> 24), byte(head.dst >> 16), byte(head.dst >> 8), byte(head.dst)}.String())
|
||||
GNetwork.WriteBroadcast(p)
|
||||
}
|
||||
return
|
||||
} else {
|
||||
node = v.(*sdwanNode)
|
||||
}
|
||||
|
||||
err := GNetwork.WriteNode(node.id, p)
|
||||
if err != nil {
|
||||
gLog.Printf(LvDev, "write packet to %s fail: %s", node.name, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *p2pSDWAN) readTunLoop() {
|
||||
gLog.Printf(LvDEBUG, "sdwan readTunLoop start")
|
||||
defer gLog.Printf(LvDEBUG, "sdwan readTunLoop end")
|
||||
readBuff := make([][]byte, ReadTunBuffNum)
|
||||
for i := 0; i < ReadTunBuffNum; i++ {
|
||||
readBuff[i] = make([]byte, ReadTunBuffSize+PIHeaderSize)
|
||||
}
|
||||
readBuffSize := make([]int, ReadTunBuffNum)
|
||||
ih := PacketHeader{}
|
||||
for {
|
||||
n, err := s.tun.Read(readBuff, readBuffSize, PIHeaderSize)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "read tun fail: ", err)
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
if readBuffSize[i] > ReadTunBuffSize {
|
||||
gLog.Printf(LvERROR, "read tun overflow: len=", readBuffSize[i])
|
||||
continue
|
||||
}
|
||||
parseHeader(readBuff[i][PIHeaderSize:readBuffSize[i]+PIHeaderSize], &ih)
|
||||
gLog.Printf(LvDev, "read tun dst ip=%s,len=%d", net.IP{byte(ih.dst >> 24), byte(ih.dst >> 16), byte(ih.dst >> 8), byte(ih.dst)}.String(), readBuffSize[0])
|
||||
s.routeTunPacket(readBuff[i][PIHeaderSize:readBuffSize[i]+PIHeaderSize], &ih)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *p2pSDWAN) StartTun() error {
|
||||
sdwan := gConf.getSDWAN()
|
||||
if s.tun == nil {
|
||||
tun := &optun{}
|
||||
err := tun.Start(s.virtualIP.String(), &sdwan)
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "open tun fail:", err)
|
||||
return err
|
||||
}
|
||||
s.tun = tun
|
||||
go s.readTunLoop()
|
||||
go s.readNodeLoop() // multi-thread read will cause packets out of order, resulting in slower speeds
|
||||
}
|
||||
err := setTunAddr(s.tun.tunName, s.virtualIP.String(), sdwan.Gateway, s.tun.dev)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "setTunAddr error:%s,%s,%s,%s", err, s.tun.tunName, s.virtualIP.String(), sdwan.Gateway)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleSDWAN(subType uint16, msg []byte) error {
|
||||
gLog.Printf(LvDEBUG, "handle sdwan msg type:%d", subType)
|
||||
var err error
|
||||
switch subType {
|
||||
case MsgSDWANInfoRsp:
|
||||
rsp := SDWANInfo{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &rsp); err != nil {
|
||||
return ErrMsgFormat
|
||||
}
|
||||
gLog.Println(LvINFO, "sdwan init:", prettyJson(rsp))
|
||||
if runtime.GOOS == "android" {
|
||||
AndroidSDWANConfig <- msg[openP2PHeaderSize:]
|
||||
}
|
||||
// GNetwork.sdwan.detail = &rsp
|
||||
gConf.setSDWAN(rsp)
|
||||
err = GNetwork.sdwan.init(gConf.Network.Node)
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "sdwan init fail: ", err)
|
||||
if GNetwork.sdwan.tun != nil {
|
||||
GNetwork.sdwan.tun.Stop()
|
||||
GNetwork.sdwan.tun = nil
|
||||
return err
|
||||
}
|
||||
}
|
||||
go GNetwork.sdwan.run()
|
||||
default:
|
||||
}
|
||||
return err
|
||||
}
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type PacketHeader struct {
|
||||
version int
|
||||
// src uint32
|
||||
// prot uint8
|
||||
protocol byte
|
||||
dst uint32
|
||||
port uint16
|
||||
}
|
||||
|
||||
func parseHeader(b []byte, h *PacketHeader) error {
|
||||
if len(b) < 20 {
|
||||
return fmt.Errorf("small packet")
|
||||
}
|
||||
h.version = int(b[0] >> 4)
|
||||
h.protocol = byte(b[9])
|
||||
if h.version == 4 {
|
||||
h.dst = binary.BigEndian.Uint32(b[16:20])
|
||||
} else if h.version != 6 {
|
||||
return fmt.Errorf("unknown version in ip header:%d", h.version)
|
||||
}
|
||||
if h.protocol == 6 || h.protocol == 17 { // TCP or UDP
|
||||
h.port = binary.BigEndian.Uint16(b[22:24])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type sdwanNode struct {
|
||||
name string
|
||||
id uint64
|
||||
}
|
||||
|
||||
type p2pSDWAN struct {
|
||||
nodeName string
|
||||
tun *optun
|
||||
sysRoute sync.Map // ip:sdwanNode
|
||||
subnet *net.IPNet
|
||||
gateway net.IP
|
||||
virtualIP *net.IPNet
|
||||
internalRoute *IPTree
|
||||
}
|
||||
|
||||
func (s *p2pSDWAN) init(name string) error {
|
||||
if gConf.getSDWAN().Gateway == "" {
|
||||
gLog.Println(LvDEBUG, "not in sdwan clear all ")
|
||||
}
|
||||
if s.internalRoute == nil {
|
||||
s.internalRoute = NewIPTree("")
|
||||
}
|
||||
|
||||
s.nodeName = name
|
||||
s.gateway, s.subnet, _ = net.ParseCIDR(gConf.getSDWAN().Gateway)
|
||||
for _, node := range gConf.getDelNodes() {
|
||||
gLog.Println(LvDEBUG, "deal deleted node: ", node.Name)
|
||||
delRoute(node.IP, s.gateway.String())
|
||||
s.internalRoute.Del(node.IP, node.IP)
|
||||
ipNum, _ := inetAtoN(node.IP)
|
||||
s.sysRoute.Delete(ipNum)
|
||||
gConf.delete(AppConfig{SrcPort: 0, PeerNode: node.Name})
|
||||
GNetwork.DeleteApp(AppConfig{SrcPort: 0, PeerNode: node.Name})
|
||||
arr := strings.Split(node.Resource, ",")
|
||||
for _, r := range arr {
|
||||
_, ipnet, err := net.ParseCIDR(r)
|
||||
if err != nil {
|
||||
// fmt.Println("Error parsing CIDR:", err)
|
||||
continue
|
||||
}
|
||||
if ipnet.Contains(net.ParseIP(gConf.Network.localIP)) { // local ip and resource in the same lan
|
||||
continue
|
||||
}
|
||||
minIP := ipnet.IP
|
||||
maxIP := make(net.IP, len(minIP))
|
||||
copy(maxIP, minIP)
|
||||
for i := range minIP {
|
||||
maxIP[i] = minIP[i] | ^ipnet.Mask[i]
|
||||
}
|
||||
s.internalRoute.Del(minIP.String(), maxIP.String())
|
||||
delRoute(ipnet.String(), s.gateway.String())
|
||||
}
|
||||
}
|
||||
for _, node := range gConf.getAddNodes() {
|
||||
gLog.Println(LvDEBUG, "deal add node: ", node.Name)
|
||||
ipNet := &net.IPNet{
|
||||
IP: net.ParseIP(node.IP),
|
||||
Mask: s.subnet.Mask,
|
||||
}
|
||||
if node.Name == s.nodeName {
|
||||
s.virtualIP = ipNet
|
||||
gLog.Println(LvINFO, "start tun ", ipNet.String())
|
||||
err := s.StartTun()
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "start tun error:", err)
|
||||
return err
|
||||
}
|
||||
gLog.Println(LvINFO, "start tun ok")
|
||||
allowTunForward()
|
||||
addRoute(s.subnet.String(), s.gateway.String(), s.tun.tunName)
|
||||
// addRoute("255.255.255.255/32", s.gateway.String(), s.tun.tunName) // for broadcast
|
||||
// addRoute("224.0.0.0/4", s.gateway.String(), s.tun.tunName) // for multicast
|
||||
initSNATRule(s.subnet.String()) // for network resource
|
||||
continue
|
||||
}
|
||||
ip, err := inetAtoN(ipNet.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.sysRoute.Store(ip, &sdwanNode{name: node.Name, id: NodeNameToID(node.Name)})
|
||||
s.internalRoute.AddIntIP(ip, ip, &sdwanNode{name: node.Name, id: NodeNameToID(node.Name)})
|
||||
}
|
||||
for _, node := range gConf.getAddNodes() {
|
||||
if node.Name == s.nodeName { // not deal resource itself
|
||||
continue
|
||||
}
|
||||
if len(node.Resource) > 0 {
|
||||
gLog.Printf(LvINFO, "deal add node: %s resource: %s", node.Name, node.Resource)
|
||||
arr := strings.Split(node.Resource, ",")
|
||||
for _, r := range arr {
|
||||
// add internal route
|
||||
_, ipnet, err := net.ParseCIDR(r)
|
||||
if err != nil {
|
||||
fmt.Println("Error parsing CIDR:", err)
|
||||
continue
|
||||
}
|
||||
if ipnet.Contains(net.ParseIP(gConf.Network.localIP)) { // local ip and resource in the same lan
|
||||
continue
|
||||
}
|
||||
minIP := ipnet.IP
|
||||
maxIP := make(net.IP, len(minIP))
|
||||
copy(maxIP, minIP)
|
||||
for i := range minIP {
|
||||
maxIP[i] = minIP[i] | ^ipnet.Mask[i]
|
||||
}
|
||||
s.internalRoute.Add(minIP.String(), maxIP.String(), &sdwanNode{name: node.Name, id: NodeNameToID(node.Name)})
|
||||
// add sys route
|
||||
addRoute(ipnet.String(), s.gateway.String(), s.tun.tunName)
|
||||
}
|
||||
}
|
||||
}
|
||||
gConf.retryAllMemApp()
|
||||
gLog.Printf(LvINFO, "sdwan init ok")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *p2pSDWAN) run() {
|
||||
s.sysRoute.Range(func(key, value interface{}) bool {
|
||||
node := value.(*sdwanNode)
|
||||
GNetwork.ConnectNode(node.name)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func (s *p2pSDWAN) readNodeLoop() {
|
||||
gLog.Printf(LvDEBUG, "sdwan readNodeLoop start")
|
||||
defer gLog.Printf(LvDEBUG, "sdwan readNodeLoop end")
|
||||
writeBuff := make([][]byte, 1)
|
||||
for {
|
||||
nd := GNetwork.ReadNode(time.Second * 10) // TODO: read multi packet
|
||||
if nd == nil {
|
||||
gLog.Printf(LvDev, "waiting for node data")
|
||||
continue
|
||||
}
|
||||
head := PacketHeader{}
|
||||
parseHeader(nd.Data, &head)
|
||||
gLog.Printf(LvDev, "write tun dst ip=%s,len=%d", net.IP{byte(head.dst >> 24), byte(head.dst >> 16), byte(head.dst >> 8), byte(head.dst)}.String(), len(nd.Data))
|
||||
if PIHeaderSize == 0 {
|
||||
writeBuff[0] = nd.Data
|
||||
} else {
|
||||
writeBuff[0] = make([]byte, PIHeaderSize+len(nd.Data))
|
||||
copy(writeBuff[0][PIHeaderSize:], nd.Data)
|
||||
}
|
||||
|
||||
len, err := s.tun.Write(writeBuff, PIHeaderSize)
|
||||
if err != nil {
|
||||
gLog.Printf(LvDEBUG, "write tun dst ip=%s,len=%d,error:%s", net.IP{byte(head.dst >> 24), byte(head.dst >> 16), byte(head.dst >> 8), byte(head.dst)}.String(), len, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func isBroadcastOrMulticast(ipUint32 uint32, subnet *net.IPNet) bool {
|
||||
// return ipUint32 == 0xffffffff || (byte(ipUint32) == 0xff) || (ipUint32>>28 == 0xe)
|
||||
return ipUint32 == 0xffffffff || (ipUint32>>28 == 0xe) // 225.255.255.255/32, 224.0.0.0/4
|
||||
}
|
||||
|
||||
func (s *p2pSDWAN) routeTunPacket(p []byte, head *PacketHeader) {
|
||||
var node *sdwanNode
|
||||
// v, ok := s.routes.Load(ih.dst)
|
||||
v, ok := s.internalRoute.Load(head.dst)
|
||||
if !ok || v == nil {
|
||||
if isBroadcastOrMulticast(head.dst, s.subnet) {
|
||||
gLog.Printf(LvDev, "multicast ip=%s", net.IP{byte(head.dst >> 24), byte(head.dst >> 16), byte(head.dst >> 8), byte(head.dst)}.String())
|
||||
GNetwork.WriteBroadcast(p)
|
||||
}
|
||||
return
|
||||
} else {
|
||||
node = v.(*sdwanNode)
|
||||
}
|
||||
|
||||
err := GNetwork.WriteNode(node.id, p)
|
||||
if err != nil {
|
||||
gLog.Printf(LvDev, "write packet to %s fail: %s", node.name, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *p2pSDWAN) readTunLoop() {
|
||||
gLog.Printf(LvDEBUG, "sdwan readTunLoop start")
|
||||
defer gLog.Printf(LvDEBUG, "sdwan readTunLoop end")
|
||||
readBuff := make([][]byte, ReadTunBuffNum)
|
||||
for i := 0; i < ReadTunBuffNum; i++ {
|
||||
readBuff[i] = make([]byte, ReadTunBuffSize+PIHeaderSize)
|
||||
}
|
||||
readBuffSize := make([]int, ReadTunBuffNum)
|
||||
ih := PacketHeader{}
|
||||
for {
|
||||
n, err := s.tun.Read(readBuff, readBuffSize, PIHeaderSize)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "read tun fail: ", err)
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
if readBuffSize[i] > ReadTunBuffSize {
|
||||
gLog.Printf(LvERROR, "read tun overflow: len=", readBuffSize[i])
|
||||
continue
|
||||
}
|
||||
parseHeader(readBuff[i][PIHeaderSize:readBuffSize[i]+PIHeaderSize], &ih)
|
||||
gLog.Printf(LvDev, "read tun dst ip=%s,len=%d", net.IP{byte(ih.dst >> 24), byte(ih.dst >> 16), byte(ih.dst >> 8), byte(ih.dst)}.String(), readBuffSize[0])
|
||||
s.routeTunPacket(readBuff[i][PIHeaderSize:readBuffSize[i]+PIHeaderSize], &ih)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *p2pSDWAN) StartTun() error {
|
||||
sdwan := gConf.getSDWAN()
|
||||
if s.tun == nil {
|
||||
tun := &optun{}
|
||||
err := tun.Start(s.virtualIP.String(), &sdwan)
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "open tun fail:", err)
|
||||
return err
|
||||
}
|
||||
s.tun = tun
|
||||
go s.readTunLoop()
|
||||
go s.readNodeLoop() // multi-thread read will cause packets out of order, resulting in slower speeds
|
||||
}
|
||||
err := setTunAddr(s.tun.tunName, s.virtualIP.String(), sdwan.Gateway, s.tun.dev)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "setTunAddr error:%s,%s,%s,%s", err, s.tun.tunName, s.virtualIP.String(), sdwan.Gateway)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleSDWAN(subType uint16, msg []byte) error {
|
||||
gLog.Printf(LvDEBUG, "handle sdwan msg type:%d", subType)
|
||||
var err error
|
||||
switch subType {
|
||||
case MsgSDWANInfoRsp:
|
||||
rsp := SDWANInfo{}
|
||||
if err = json.Unmarshal(msg[openP2PHeaderSize:], &rsp); err != nil {
|
||||
return ErrMsgFormat
|
||||
}
|
||||
gLog.Println(LvINFO, "sdwan init:", prettyJson(rsp))
|
||||
if runtime.GOOS == "android" {
|
||||
AndroidSDWANConfig <- msg[openP2PHeaderSize:]
|
||||
}
|
||||
// GNetwork.sdwan.detail = &rsp
|
||||
gConf.setSDWAN(rsp)
|
||||
err = GNetwork.sdwan.init(gConf.Network.Node)
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "sdwan init fail: ", err)
|
||||
if GNetwork.sdwan.tun != nil {
|
||||
GNetwork.sdwan.tun.Stop()
|
||||
GNetwork.sdwan.tun = nil
|
||||
return err
|
||||
}
|
||||
}
|
||||
go GNetwork.sdwan.run()
|
||||
default:
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
478
core/update.go
478
core/update.go
@@ -1,239 +1,239 @@
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"archive/zip"
|
||||
"compress/gzip"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
func update(host string, port int) error {
|
||||
gLog.Println(LvINFO, "update start")
|
||||
defer gLog.Println(LvINFO, "update end")
|
||||
caCertPool, err := x509.SystemCertPool()
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "Failed to load system root CAs:", err)
|
||||
} else {
|
||||
caCertPool = x509.NewCertPool()
|
||||
}
|
||||
caCertPool.AppendCertsFromPEM([]byte(rootCA))
|
||||
caCertPool.AppendCertsFromPEM([]byte(ISRGRootX1))
|
||||
|
||||
c := http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{RootCAs: caCertPool,
|
||||
InsecureSkipVerify: false},
|
||||
},
|
||||
Timeout: time.Second * 30,
|
||||
}
|
||||
goos := runtime.GOOS
|
||||
goarch := runtime.GOARCH
|
||||
rsp, err := c.Get(fmt.Sprintf("https://%s:%d/api/v1/update?fromver=%s&os=%s&arch=%s&user=%s&node=%s", host, port, OpenP2PVersion, goos, goarch, url.QueryEscape(gConf.Network.User), url.QueryEscape(gConf.Network.Node)))
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "update:query update list failed:", err)
|
||||
return err
|
||||
}
|
||||
defer rsp.Body.Close()
|
||||
if rsp.StatusCode != http.StatusOK {
|
||||
gLog.Println(LvERROR, "get update info error:", rsp.Status)
|
||||
return err
|
||||
}
|
||||
rspBuf, err := ioutil.ReadAll(rsp.Body)
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "update:read update list failed:", err)
|
||||
return err
|
||||
}
|
||||
updateInfo := UpdateInfo{}
|
||||
if err = json.Unmarshal(rspBuf, &updateInfo); err != nil {
|
||||
gLog.Println(LvERROR, rspBuf, " update info decode error:", err)
|
||||
return err
|
||||
}
|
||||
if updateInfo.Error != 0 {
|
||||
gLog.Println(LvERROR, "update error:", updateInfo.Error, updateInfo.ErrorDetail)
|
||||
return err
|
||||
}
|
||||
err = updateFile(updateInfo.Url, "", "openp2p")
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "update: download failed:", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func downloadFile(url string, checksum string, dstFile string) error {
|
||||
output, err := os.OpenFile(dstFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0776)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "OpenFile %s error:%s", dstFile, err)
|
||||
return err
|
||||
}
|
||||
caCertPool, err := x509.SystemCertPool()
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "Failed to load system root CAs:", err)
|
||||
} else {
|
||||
caCertPool = x509.NewCertPool()
|
||||
}
|
||||
caCertPool.AppendCertsFromPEM([]byte(rootCA))
|
||||
caCertPool.AppendCertsFromPEM([]byte(ISRGRootX1))
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
RootCAs: caCertPool,
|
||||
InsecureSkipVerify: false},
|
||||
}
|
||||
client := &http.Client{Transport: tr}
|
||||
response, err := client.Get(url)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "download url %s error:%s", url, err)
|
||||
output.Close()
|
||||
return err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
n, err := io.Copy(output, response.Body)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "io.Copy error:%s", err)
|
||||
output.Close()
|
||||
return err
|
||||
}
|
||||
output.Sync()
|
||||
output.Close()
|
||||
gLog.Println(LvINFO, "download ", url, " ok")
|
||||
gLog.Printf(LvINFO, "size: %d bytes", n)
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateFile(url string, checksum string, dst string) error {
|
||||
gLog.Println(LvINFO, "download ", url)
|
||||
tmpFile := filepath.Dir(os.Args[0]) + "/openp2p.tmp"
|
||||
err := downloadFile(url, checksum, tmpFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
backupFile := os.Args[0] + "0"
|
||||
err = os.Rename(os.Args[0], backupFile) // the old daemon process was using the 0 file, so it will prevent override it
|
||||
if err != nil {
|
||||
gLog.Printf(LvINFO, " rename %s error:%s, retry 1", os.Args[0], err)
|
||||
backupFile = os.Args[0] + "1"
|
||||
err = os.Rename(os.Args[0], backupFile)
|
||||
if err != nil {
|
||||
gLog.Printf(LvINFO, " rename %s error:%s", os.Args[0], err)
|
||||
}
|
||||
}
|
||||
// extract
|
||||
gLog.Println(LvINFO, "extract files")
|
||||
err = extract(filepath.Dir(os.Args[0]), tmpFile)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "extract error:%s. revert rename", err)
|
||||
os.Rename(backupFile, os.Args[0])
|
||||
return err
|
||||
}
|
||||
os.Remove(tmpFile)
|
||||
return nil
|
||||
}
|
||||
|
||||
func extract(dst, src string) (err error) {
|
||||
if runtime.GOOS == "windows" {
|
||||
return unzip(dst, src)
|
||||
} else {
|
||||
return extractTgz(dst, src)
|
||||
}
|
||||
}
|
||||
|
||||
func unzip(dst, src string) (err error) {
|
||||
archive, err := zip.OpenReader(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer archive.Close()
|
||||
|
||||
for _, f := range archive.File {
|
||||
filePath := filepath.Join(dst, f.Name)
|
||||
fmt.Println("unzipping file ", filePath)
|
||||
if f.FileInfo().IsDir() {
|
||||
fmt.Println("creating directory...")
|
||||
os.MkdirAll(filePath, os.ModePerm)
|
||||
continue
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
dstFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fileInArchive, err := f.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.Copy(dstFile, fileInArchive); err != nil {
|
||||
return err
|
||||
}
|
||||
dstFile.Close()
|
||||
fileInArchive.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractTgz(dst, src string) error {
|
||||
gzipStream, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
uncompressedStream, err := gzip.NewReader(gzipStream)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tarReader := tar.NewReader(uncompressedStream)
|
||||
for {
|
||||
header, err := tarReader.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch header.Typeflag {
|
||||
case tar.TypeDir:
|
||||
if err := os.Mkdir(header.Name, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
case tar.TypeReg:
|
||||
filePath := filepath.Join(dst, header.Name)
|
||||
outFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.FileMode(header.Mode))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer outFile.Close()
|
||||
if _, err := io.Copy(outFile, tarReader); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func cleanTempFiles() {
|
||||
tmpFile := os.Args[0] + "0"
|
||||
if _, err := os.Stat(tmpFile); err == nil {
|
||||
if err := os.Remove(tmpFile); err != nil {
|
||||
gLog.Printf(LvDEBUG, " remove %s error:%s", tmpFile, err)
|
||||
}
|
||||
}
|
||||
tmpFile = os.Args[0] + "1"
|
||||
if _, err := os.Stat(tmpFile); err == nil {
|
||||
if err := os.Remove(tmpFile); err != nil {
|
||||
gLog.Printf(LvDEBUG, " remove %s error:%s", tmpFile, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
package openp2p
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"archive/zip"
|
||||
"compress/gzip"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
func update(host string, port int) error {
|
||||
gLog.Println(LvINFO, "update start")
|
||||
defer gLog.Println(LvINFO, "update end")
|
||||
caCertPool, err := x509.SystemCertPool()
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "Failed to load system root CAs:", err)
|
||||
} else {
|
||||
caCertPool = x509.NewCertPool()
|
||||
}
|
||||
caCertPool.AppendCertsFromPEM([]byte(rootCA))
|
||||
caCertPool.AppendCertsFromPEM([]byte(ISRGRootX1))
|
||||
|
||||
c := http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{RootCAs: caCertPool,
|
||||
InsecureSkipVerify: false},
|
||||
},
|
||||
Timeout: time.Second * 30,
|
||||
}
|
||||
goos := runtime.GOOS
|
||||
goarch := runtime.GOARCH
|
||||
rsp, err := c.Get(fmt.Sprintf("https://%s:%d/api/v1/update?fromver=%s&os=%s&arch=%s&user=%s&node=%s", host, port, OpenP2PVersion, goos, goarch, url.QueryEscape(gConf.Network.User), url.QueryEscape(gConf.Network.Node)))
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "update:query update list failed:", err)
|
||||
return err
|
||||
}
|
||||
defer rsp.Body.Close()
|
||||
if rsp.StatusCode != http.StatusOK {
|
||||
gLog.Println(LvERROR, "get update info error:", rsp.Status)
|
||||
return err
|
||||
}
|
||||
rspBuf, err := ioutil.ReadAll(rsp.Body)
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "update:read update list failed:", err)
|
||||
return err
|
||||
}
|
||||
updateInfo := UpdateInfo{}
|
||||
if err = json.Unmarshal(rspBuf, &updateInfo); err != nil {
|
||||
gLog.Println(LvERROR, rspBuf, " update info decode error:", err)
|
||||
return err
|
||||
}
|
||||
if updateInfo.Error != 0 {
|
||||
gLog.Println(LvERROR, "update error:", updateInfo.Error, updateInfo.ErrorDetail)
|
||||
return err
|
||||
}
|
||||
err = updateFile(updateInfo.Url, "", "openp2p")
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "update: download failed:", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func downloadFile(url string, checksum string, dstFile string) error {
|
||||
output, err := os.OpenFile(dstFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0776)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "OpenFile %s error:%s", dstFile, err)
|
||||
return err
|
||||
}
|
||||
caCertPool, err := x509.SystemCertPool()
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "Failed to load system root CAs:", err)
|
||||
} else {
|
||||
caCertPool = x509.NewCertPool()
|
||||
}
|
||||
caCertPool.AppendCertsFromPEM([]byte(rootCA))
|
||||
caCertPool.AppendCertsFromPEM([]byte(ISRGRootX1))
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
RootCAs: caCertPool,
|
||||
InsecureSkipVerify: false},
|
||||
}
|
||||
client := &http.Client{Transport: tr}
|
||||
response, err := client.Get(url)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "download url %s error:%s", url, err)
|
||||
output.Close()
|
||||
return err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
n, err := io.Copy(output, response.Body)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "io.Copy error:%s", err)
|
||||
output.Close()
|
||||
return err
|
||||
}
|
||||
output.Sync()
|
||||
output.Close()
|
||||
gLog.Println(LvINFO, "download ", url, " ok")
|
||||
gLog.Printf(LvINFO, "size: %d bytes", n)
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateFile(url string, checksum string, dst string) error {
|
||||
gLog.Println(LvINFO, "download ", url)
|
||||
tmpFile := filepath.Dir(os.Args[0]) + "/openp2p.tmp"
|
||||
err := downloadFile(url, checksum, tmpFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
backupFile := os.Args[0] + "0"
|
||||
err = os.Rename(os.Args[0], backupFile) // the old daemon process was using the 0 file, so it will prevent override it
|
||||
if err != nil {
|
||||
gLog.Printf(LvINFO, " rename %s error:%s, retry 1", os.Args[0], err)
|
||||
backupFile = os.Args[0] + "1"
|
||||
err = os.Rename(os.Args[0], backupFile)
|
||||
if err != nil {
|
||||
gLog.Printf(LvINFO, " rename %s error:%s", os.Args[0], err)
|
||||
}
|
||||
}
|
||||
// extract
|
||||
gLog.Println(LvINFO, "extract files")
|
||||
err = extract(filepath.Dir(os.Args[0]), tmpFile)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "extract error:%s. revert rename", err)
|
||||
os.Rename(backupFile, os.Args[0])
|
||||
return err
|
||||
}
|
||||
os.Remove(tmpFile)
|
||||
return nil
|
||||
}
|
||||
|
||||
func extract(dst, src string) (err error) {
|
||||
if runtime.GOOS == "windows" {
|
||||
return unzip(dst, src)
|
||||
} else {
|
||||
return extractTgz(dst, src)
|
||||
}
|
||||
}
|
||||
|
||||
func unzip(dst, src string) (err error) {
|
||||
archive, err := zip.OpenReader(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer archive.Close()
|
||||
|
||||
for _, f := range archive.File {
|
||||
filePath := filepath.Join(dst, f.Name)
|
||||
fmt.Println("unzipping file ", filePath)
|
||||
if f.FileInfo().IsDir() {
|
||||
fmt.Println("creating directory...")
|
||||
os.MkdirAll(filePath, os.ModePerm)
|
||||
continue
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
dstFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fileInArchive, err := f.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.Copy(dstFile, fileInArchive); err != nil {
|
||||
return err
|
||||
}
|
||||
dstFile.Close()
|
||||
fileInArchive.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractTgz(dst, src string) error {
|
||||
gzipStream, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
uncompressedStream, err := gzip.NewReader(gzipStream)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tarReader := tar.NewReader(uncompressedStream)
|
||||
for {
|
||||
header, err := tarReader.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch header.Typeflag {
|
||||
case tar.TypeDir:
|
||||
if err := os.Mkdir(header.Name, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
case tar.TypeReg:
|
||||
filePath := filepath.Join(dst, header.Name)
|
||||
outFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.FileMode(header.Mode))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer outFile.Close()
|
||||
if _, err := io.Copy(outFile, tarReader); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func cleanTempFiles() {
|
||||
tmpFile := os.Args[0] + "0"
|
||||
if _, err := os.Stat(tmpFile); err == nil {
|
||||
if err := os.Remove(tmpFile); err != nil {
|
||||
gLog.Printf(LvDEBUG, " remove %s error:%s", tmpFile, err)
|
||||
}
|
||||
}
|
||||
tmpFile = os.Args[0] + "1"
|
||||
if _, err := os.Stat(tmpFile); err == nil {
|
||||
if err := os.Remove(tmpFile); err != nil {
|
||||
gLog.Printf(LvDEBUG, " remove %s error:%s", tmpFile, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,18 +1,18 @@
|
||||
package main
|
||||
|
||||
// On Windows env
|
||||
// cd lib
|
||||
// go build -o openp2p.dll -buildmode=c-shared openp2p.go
|
||||
// caller example see example/dll
|
||||
import (
|
||||
op "openp2p/core"
|
||||
)
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
}
|
||||
|
||||
//export RunCmd
|
||||
func RunCmd(cmd *C.char) {
|
||||
op.RunCmd(C.GoString(cmd))
|
||||
}
|
||||
package main
|
||||
|
||||
// On Windows env
|
||||
// cd lib
|
||||
// go build -o openp2p.dll -buildmode=c-shared openp2p.go
|
||||
// caller example see example/dll
|
||||
import (
|
||||
op "openp2p/core"
|
||||
)
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
}
|
||||
|
||||
//export RunCmd
|
||||
func RunCmd(cmd *C.char) {
|
||||
op.RunCmd(C.GoString(cmd))
|
||||
}
|
||||
|
Reference in New Issue
Block a user