mirror of
https://github.com/openp2p-cn/openp2p.git
synced 2026-05-07 13:52:14 +08:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2af77668fe | ||
|
|
215feb8721 | ||
|
|
4a115fb3fa | ||
|
|
0fb3bc4e26 | ||
|
|
df23b30d2b | ||
|
|
f9b5073e0d | ||
|
|
9ea467c7b3 | ||
|
|
c0bad61eb6 | ||
|
|
bb32133038 | ||
|
|
532d3667ce |
15
README-ZH.md
15
README-ZH.md
@@ -23,7 +23,7 @@
|
||||
### 5. 跨平台
|
||||
因为轻量,所以很容易支持各个平台。支持主流的操作系统:Windows,Linux,MacOS;和主流的cpu架构:386、amd64、arm、arm64、mipsle、mipsle64、mips、mips64
|
||||
### 6. 高效
|
||||
P2P直连可以让你的设备跑满带宽。不论你的设备在任何网络环境,无论NAT1-4(Cone或Symmetric),都支持。依靠Quic协议优秀的拥塞算法,能在糟糕的网络环境获得高带宽低延时。
|
||||
P2P直连可以让你的设备跑满带宽。不论你的设备在任何网络环境,无论NAT1-4(Cone或Symmetric),UDP或TCP打洞,UPNP,IPv6都支持。依靠Quic协议优秀的拥塞算法,能在糟糕的网络环境获得高带宽低延时。
|
||||
|
||||
### 7. 二次开发
|
||||
基于OpenP2P只需数行代码,就能让原来只能局域网通信的程序,变成任何内网都能通信
|
||||
@@ -103,15 +103,15 @@ go mod tidy
|
||||
go build
|
||||
```
|
||||
|
||||
## TODO
|
||||
## RoadMap
|
||||
近期计划:
|
||||
1. 支持IPv6
|
||||
2. 支持随系统自动启动,安装成系统服务(100%)
|
||||
3. 提供一些免费服务器给特别差的网络,如广电网络(100%)
|
||||
4. 建立网站,用户可以在网站管理所有P2PApp和设备。查看设备在线状态,升级,增删查改重启P2PApp等(100%)
|
||||
1. ~~支持IPv6~~(100%)
|
||||
2. ~~支持随系统自动启动,安装成系统服务~~(100%)
|
||||
3. ~~提供一些免费服务器给特别差的网络,如广电网络~~(100%)
|
||||
4. ~~建立网站,用户可以在网站管理所有P2PApp和设备。查看设备在线状态,升级,增删查改重启P2PApp等~~(100%)
|
||||
5. 建立公众号,用户可在微信公众号管理所有P2PApp和设备
|
||||
6. 客户端提供WebUI
|
||||
7. 支持自有服务器高并发连接
|
||||
7. 支持自有服务器,开源服务器程序
|
||||
8. 共享节点调度模型优化,对不同的运营商优化
|
||||
9. 方便二次开发,提供API和lib
|
||||
10. 应用层支持UDP协议,实现很简单,但UDP应用较少暂不急(100%)
|
||||
@@ -119,6 +119,7 @@ go build
|
||||
12. 支持Android系统,让旧手机焕发青春变成移动网关
|
||||
13. 支持Windows网上邻居共享文件
|
||||
14. 内网直连优化,用处不大,估计就用户测试时用到
|
||||
15. ~~支持UPNP~~(100%)
|
||||
|
||||
远期计划:
|
||||
1. 利用区块链技术去中心化,让共享设备的用户有收益,从而促进更多用户共享,达到正向闭环。
|
||||
|
||||
17
README.md
17
README.md
@@ -25,7 +25,7 @@ The code is open source, the P2P tunnel uses TLS1.3+AES double encryption, and t
|
||||
Benefit from lightweight, it easily supports most of major OS, like Windows, Linux, MacOS, also most of CPU architecture, like 386、amd64、arm、arm64、mipsle、mipsle64、mips、mips64.
|
||||
|
||||
### 6. Efficient
|
||||
P2P direct connection lets your devices make good use of bandwidth. Your device can be connected in any network environments, even supports NAT1-4 (Cone or Symmetric). Relying on the excellent congestion algorithm of the Quic protocol, high bandwidth and low latency can be obtained in a bad network environment.
|
||||
P2P direct connection lets your devices make good use of bandwidth. Your device can be connected in any network environments, even supports NAT1-4 (Cone or Symmetric),UDP or TCP punching,UPNP,IPv6. Relying on the excellent congestion algorithm of the Quic protocol, high bandwidth and low latency can be obtained in a bad network environment.
|
||||
|
||||
### 7. Integration
|
||||
Your applicaiton can call OpenP2P with a few code to make any internal networks communicate with each other.
|
||||
@@ -111,22 +111,23 @@ go mod tidy
|
||||
go build
|
||||
```
|
||||
|
||||
## TODO
|
||||
## RoadMap
|
||||
Short-Term:
|
||||
1. Support IPv6.
|
||||
2. Support auto run when system boot, setup system service.(100%)
|
||||
3. Provide free servers to some low-performance network.(100%)
|
||||
4. Build website, users can manage all P2PApp and devices via it. View devices' online status, upgrade, restart or CURD P2PApp .(100%)
|
||||
1. ~~Support IPv6.~~(100%)
|
||||
2. ~~Support auto run when system boot, setup system service.~~(100%)
|
||||
3. ~~Provide free servers to some low-performance network.~~(100%)
|
||||
4. ~~Build website, users can manage all P2PApp and devices via it. View devices' online status, upgrade, restart or CURD P2PApp .~~(100%)
|
||||
5. Provide wechat official account, user can manage P2PApp nodes and deivce as same as website.
|
||||
6. Provide WebUI on client side.
|
||||
7. Support high concurrency on server side.
|
||||
7. Support private server, open source server program.
|
||||
8. Optimize our share scheduling model for different network operators.
|
||||
9. Provide REST APIs and libary for secondary development.
|
||||
10. Support UDP at application layer, it is easy to implement but not urgent due to only a few applicaitons using UDP protocol.(100%)
|
||||
10. ~~Support UDP at application layer, it is easy to implement but not urgent due to only a few applicaitons using UDP protocol.~~(100%)
|
||||
11. Support KCP protocol underlay, currently support Quic only. KCP focus on delay optimization,which has been widely used as game accelerator,it can sacrifice part of bandwidth to reduce timelag.
|
||||
12. Support Android platform, let the phones to be mobile gateway.
|
||||
13. Support SMB Windows neighborhood.
|
||||
14. Direct connection on intranet, for testing.
|
||||
15. ~~Support UPNP.~~(100%)
|
||||
|
||||
|
||||
Long-Term:
|
||||
|
||||
@@ -77,7 +77,7 @@ nohup ./openp2p -d -node OFFICEPC1 -token TOKEN &
|
||||
# update local client
|
||||
./openp2p update
|
||||
# update remote client
|
||||
curl --insecure 'https://openp2p.cn:27182/api/v1/device/YOUR-NODE-NAME/update?user=&password='
|
||||
curl --insecure 'https://api.openp2p.cn:27183/api/v1/device/YOUR-NODE-NAME/update?user=&password='
|
||||
```
|
||||
|
||||
Windows系统需要设置防火墙放行本程序,程序会自动设置,如果设置失败会影响连接功能。
|
||||
@@ -91,4 +91,9 @@ firewall-cmd --state
|
||||
## 卸载
|
||||
```
|
||||
./openp2p uninstall
|
||||
# 已安装时
|
||||
# windows
|
||||
C:\Program Files\OpenP2P\openp2p.exe uninstall
|
||||
# linux,macos
|
||||
sudo /usr/local/openp2p/openp2p uninstall
|
||||
```
|
||||
7
USAGE.md
7
USAGE.md
@@ -79,7 +79,7 @@ Configuration example
|
||||
# update local client
|
||||
./openp2p update
|
||||
# update remote client
|
||||
curl --insecure 'https://openp2p.cn:27182/api/v1/device/YOUR-NODE-NAME/update?user=&password='
|
||||
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.
|
||||
@@ -93,4 +93,9 @@ 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
|
||||
```
|
||||
23
common.go
23
common.go
@@ -17,6 +17,8 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const MinNodeNameLen = 8
|
||||
|
||||
func getmac(ip string) string {
|
||||
//get mac relative to the ip address which connected to the mq.
|
||||
ifaces, err := net.Interfaces()
|
||||
@@ -156,7 +158,7 @@ func execOutput(name string, args ...string) string {
|
||||
|
||||
func defaultNodeName() string {
|
||||
name, _ := os.Hostname()
|
||||
for len(name) < 8 {
|
||||
for len(name) < MinNodeNameLen {
|
||||
name = fmt.Sprintf("%s%d", name, rand.Int()%10)
|
||||
}
|
||||
return name
|
||||
@@ -188,6 +190,25 @@ func compareVersion(v1, v2 string) int {
|
||||
return LESS
|
||||
}
|
||||
|
||||
func parseMajorVer(ver string) int {
|
||||
v1Arr := strings.Split(ver, ".")
|
||||
if len(v1Arr) > 0 {
|
||||
n, _ := strconv.ParseInt(v1Arr[0], 10, 32)
|
||||
return int(n)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func IsIPv6(address string) bool {
|
||||
return strings.Count(address, ":") >= 2
|
||||
}
|
||||
|
||||
var letters = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-")
|
||||
|
||||
func randStr(n int) string {
|
||||
b := make([]byte, n)
|
||||
for i := range b {
|
||||
b[i] = letters[rand.Intn(len(letters))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
@@ -49,6 +49,11 @@ func assertCompareVersion(t *testing.T, v1 string, v2 string, result int) {
|
||||
t.Errorf("compare version %s %s fail\n", v1, v2)
|
||||
}
|
||||
}
|
||||
func assertParseMajorVer(t *testing.T, v string, result int) {
|
||||
if parseMajorVer(v) != result {
|
||||
t.Errorf("ParseMajorVer %s fail\n", v)
|
||||
}
|
||||
}
|
||||
func TestCompareVersion(t *testing.T) {
|
||||
// test =
|
||||
assertCompareVersion(t, "0.98.0", "0.98.0", EQUAL)
|
||||
@@ -69,3 +74,23 @@ func TestCompareVersion(t *testing.T) {
|
||||
assertCompareVersion(t, "", "1.5.0", LESS)
|
||||
|
||||
}
|
||||
|
||||
func TestParseMajorVer(t *testing.T) {
|
||||
|
||||
assertParseMajorVer(t, "0.98.0", 0)
|
||||
assertParseMajorVer(t, "0.98", 0)
|
||||
assertParseMajorVer(t, "1.4.0", 1)
|
||||
assertParseMajorVer(t, "1.5.0", 1)
|
||||
|
||||
assertParseMajorVer(t, "0.98.0.22345", 0)
|
||||
assertParseMajorVer(t, "1.98.0.12345", 1)
|
||||
assertParseMajorVer(t, "10.98.0.12345", 10)
|
||||
assertParseMajorVer(t, "1.4.0", 1)
|
||||
assertParseMajorVer(t, "1.4", 1)
|
||||
assertParseMajorVer(t, "1", 1)
|
||||
assertParseMajorVer(t, "2", 2)
|
||||
assertParseMajorVer(t, "3", 3)
|
||||
assertParseMajorVer(t, "2.1.0", 2)
|
||||
assertParseMajorVer(t, "3.0.0", 3)
|
||||
|
||||
}
|
||||
|
||||
80
config.go
80
config.go
@@ -11,8 +11,6 @@ import (
|
||||
|
||||
var gConf Config
|
||||
|
||||
const IntValueNotSet int = -99999999
|
||||
|
||||
type AppConfig struct {
|
||||
// required
|
||||
AppName string
|
||||
@@ -24,20 +22,23 @@ type AppConfig struct {
|
||||
PeerUser string
|
||||
Enabled int // default:1
|
||||
// runtime info
|
||||
peerVersion string
|
||||
peerToken uint64
|
||||
peerNatType int
|
||||
hasIPv4 int
|
||||
IPv6 string
|
||||
hasUPNPorNATPMP int
|
||||
peerIP string
|
||||
peerConeNatPort int
|
||||
retryNum int
|
||||
retryTime time.Time
|
||||
nextRetryTime time.Time
|
||||
shareBandwidth int
|
||||
errMsg string
|
||||
connectTime time.Time
|
||||
peerVersion string
|
||||
peerToken uint64
|
||||
peerNatType int
|
||||
hasIPv4 int
|
||||
peerIPv6 string
|
||||
hasUPNPorNATPMP int
|
||||
peerIP string
|
||||
peerConeNatPort int
|
||||
retryNum int
|
||||
retryTime time.Time
|
||||
nextRetryTime time.Time
|
||||
shareBandwidth int
|
||||
errMsg string
|
||||
connectTime time.Time
|
||||
fromToken uint64
|
||||
linkMode string
|
||||
isUnderlayServer int // TODO: bool?
|
||||
}
|
||||
|
||||
// TODO: add loglevel, maxlogfilesize
|
||||
@@ -104,10 +105,16 @@ func (c *Config) save() {
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
gConf.LogLevel = 1
|
||||
gConf.Network.ShareBandwidth = 10
|
||||
gConf.Network.ServerHost = "api.openp2p.cn"
|
||||
gConf.Network.ServerPort = WsPort
|
||||
|
||||
}
|
||||
|
||||
func (c *Config) load() error {
|
||||
c.mtx.Lock()
|
||||
c.LogLevel = IntValueNotSet
|
||||
c.Network.ShareBandwidth = IntValueNotSet
|
||||
defer c.mtx.Unlock()
|
||||
data, err := ioutil.ReadFile("config.json")
|
||||
if err != nil {
|
||||
@@ -148,13 +155,12 @@ type NetworkConfig struct {
|
||||
Node string
|
||||
User string
|
||||
localIP string
|
||||
ipv6 string
|
||||
mac string
|
||||
os string
|
||||
publicIP string
|
||||
natType int
|
||||
hasIPv4 int
|
||||
IPv6 string
|
||||
publicIPv6 string // must lowwer-case not save json
|
||||
hasUPNPorNATPMP int
|
||||
ShareBandwidth int
|
||||
// server info
|
||||
@@ -162,11 +168,13 @@ type NetworkConfig struct {
|
||||
ServerPort int
|
||||
UDPPort1 int
|
||||
UDPPort2 int
|
||||
TCPPort int
|
||||
}
|
||||
|
||||
func parseParams(subCommand string) {
|
||||
fset := flag.NewFlagSet(subCommand, flag.ExitOnError)
|
||||
serverHost := fset.String("serverhost", "api.openp2p.cn", "server host ")
|
||||
serverPort := fset.Int("serverport", WsPort, "server port ")
|
||||
// serverHost := flag.String("serverhost", "127.0.0.1", "server host ") // for debug
|
||||
token := fset.Uint64("token", 0, "token")
|
||||
node := fset.String("node", "", "node name. 8-31 characters. if not set, it will be hostname")
|
||||
@@ -174,13 +182,14 @@ func parseParams(subCommand string) {
|
||||
dstIP := fset.String("dstip", "127.0.0.1", "destination ip ")
|
||||
dstPort := fset.Int("dstport", 0, "destination port ")
|
||||
srcPort := fset.Int("srcport", 0, "source port ")
|
||||
tcpPort := fset.Int("tcpport", 0, "tcp port for upnp or publicip")
|
||||
protocol := fset.String("protocol", "tcp", "tcp or udp")
|
||||
appName := fset.String("appname", "", "app name")
|
||||
shareBandwidth := fset.Int("sharebandwidth", 10, "N mbps share bandwidth limit, private network no limit")
|
||||
daemonMode := fset.Bool("d", false, "daemonMode")
|
||||
notVerbose := fset.Bool("nv", false, "not log console")
|
||||
newconfig := fset.Bool("newconfig", false, "not load existing config.json")
|
||||
logLevel := fset.Int("loglevel", 1, "0:debug 1:info 2:warn 3:error")
|
||||
logLevel := fset.Int("loglevel", 0, "0:info 1:warn 2:error 3:debug")
|
||||
if subCommand == "" { // no subcommand
|
||||
fset.Parse(os.Args[1:])
|
||||
} else {
|
||||
@@ -197,7 +206,6 @@ func parseParams(subCommand string) {
|
||||
if !*newconfig {
|
||||
gConf.load() // load old config. otherwise will clear all apps
|
||||
}
|
||||
gConf.LogLevel = *logLevel
|
||||
if config.SrcPort != 0 {
|
||||
gConf.add(config, true)
|
||||
}
|
||||
@@ -217,16 +225,19 @@ func parseParams(subCommand string) {
|
||||
if f.Name == "loglevel" {
|
||||
gConf.LogLevel = *logLevel
|
||||
}
|
||||
if f.Name == "tcpport" {
|
||||
gConf.Network.TCPPort = *tcpPort
|
||||
}
|
||||
if f.Name == "token" {
|
||||
gConf.Network.Token = *token
|
||||
}
|
||||
})
|
||||
|
||||
if gConf.Network.ServerHost == "" {
|
||||
gConf.Network.ServerHost = *serverHost
|
||||
}
|
||||
if *token != 0 {
|
||||
gConf.Network.Token = *token
|
||||
}
|
||||
if *node != "" {
|
||||
if len(*node) < 8 {
|
||||
if len(*node) < MinNodeNameLen {
|
||||
gLog.Println(LvERROR, ErrNodeTooShort)
|
||||
os.Exit(9)
|
||||
}
|
||||
@@ -236,16 +247,17 @@ func parseParams(subCommand string) {
|
||||
gConf.Network.Node = defaultNodeName()
|
||||
}
|
||||
}
|
||||
if gConf.LogLevel == IntValueNotSet {
|
||||
gConf.LogLevel = *logLevel
|
||||
}
|
||||
if gConf.Network.ShareBandwidth == IntValueNotSet {
|
||||
gConf.Network.ShareBandwidth = *shareBandwidth
|
||||
if gConf.Network.TCPPort == 0 {
|
||||
if *tcpPort == 0 {
|
||||
p := int(nodeNameToID(gConf.Network.Node)%15000 + 50000)
|
||||
tcpPort = &p
|
||||
}
|
||||
gConf.Network.TCPPort = *tcpPort
|
||||
}
|
||||
|
||||
gConf.Network.ServerPort = 27183
|
||||
gConf.Network.UDPPort1 = 27182
|
||||
gConf.Network.UDPPort2 = 27183
|
||||
gConf.Network.ServerPort = *serverPort
|
||||
gConf.Network.UDPPort1 = UDPPort1
|
||||
gConf.Network.UDPPort2 = UDPPort2
|
||||
gLog.setLevel(LogLevel(gConf.LogLevel))
|
||||
if *notVerbose {
|
||||
gLog.setMode(LogFile)
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
{
|
||||
"network": {
|
||||
"Node": "YOUR_NODE_NAME",
|
||||
"User": "YOUR_USER_NAME",
|
||||
"Password": "YOUR_PASSWORD",
|
||||
"ServerHost": "openp2p.cn",
|
||||
"ServerPort": 27182,
|
||||
"Token": "YOUR_TOKEN",
|
||||
"ServerHost": "api.openp2p.cn",
|
||||
"ServerPort": 27183,
|
||||
"UDPPort1": 27182,
|
||||
"UDPPort2": 27183
|
||||
},
|
||||
|
||||
BIN
doc/images/p2p-debug.png
Normal file
BIN
doc/images/p2p-debug.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
BIN
doc/images/release-debug.png
Normal file
BIN
doc/images/release-debug.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
BIN
doc/images/vs2022-remote-debug-attach.png
Normal file
BIN
doc/images/vs2022-remote-debug-attach.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
73
doc/remote-debug-golang.md
Normal file
73
doc/remote-debug-golang.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# 1. 环境
|
||||
golang1.18.1
|
||||
调试端: win10+vscode
|
||||
被调试端: ubuntu20.04LTS+dlv
|
||||
## dlv安装
|
||||
参考官方文档https://github.com/go-delve/delve/tree/master/Documentation/installation
|
||||
```
|
||||
go install github.com/go-delve/delve/cmd/dlv@latest
|
||||
```
|
||||
|
||||
## 被调试端
|
||||
```
|
||||
cd /your-src-path #要确保两端源码一致
|
||||
dlv debug --headless --listen=:2345 --api-version=2
|
||||
# 如果失败可查看更多日志
|
||||
# dlv debug --headless --listen=:2345 --api-version=2 --log --log-output=rpc,dap,debugger
|
||||
```
|
||||
|
||||
## 调试端(vscode)
|
||||
```
|
||||
打开vscode,修改launch.json,增加下面远程调试配置
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "RemoteDebug",
|
||||
"type": "go",
|
||||
"request": "attach",
|
||||
"mode": "remote",
|
||||
"port": 2345,
|
||||
"host": "192.168.3.29",
|
||||
}
|
||||
]
|
||||
}
|
||||
按F5启动调试
|
||||
```
|
||||
|
||||
## 没有公网IP或不在同一个局域网,无法直连如何调试
|
||||
到https://openp2p.cn/注册一个用户获得token,两端安装一个客户端程序,可将被调试端的2345端口,通过p2p连接映射到调试端本地。
|
||||
p2p连接可通过web配置 https://github.com/openp2p-cn/openp2p/blob/master/README-ZH.md#%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8
|
||||
|
||||
也可以手动下载https://github.com/openp2p-cn/openp2p/releases 通过命令行手动配置
|
||||
|
||||
```
|
||||
# 注意替换下面YOUR-开头的参数改成自己的
|
||||
./openp2p -node YOUR-DEBUG-SERVER -token YOUR-TOKEN
|
||||
|
||||
openp2p.exe -node YOUR-DEBUG-CLIENT -token YOUR-TOKEN -peernode YOUR-DEBUG-SERVER -dstport 2345 -srcport 2345
|
||||
|
||||
2022/04/22 11:07:26 25680 INFO LISTEN ON PORT tcp:2345 START
|
||||
#显示这条日志说明成功了
|
||||
```
|
||||
|
||||
p2p端口映射完成后,把vscode的配置改成本地127.0.0.1,一样可以顺利调试。
|
||||
```
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "RemoteDebug",
|
||||
"type": "go",
|
||||
"request": "attach",
|
||||
"mode": "remote",
|
||||
"port": 2345,
|
||||
"host": "127.0.0.1",
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
# 参考
|
||||
https://github.com/golang/vscode-go/blob/master/docs/debugging.md#remote-debugging
|
||||
50
doc/remote-debug-vscpp.md
Normal file
50
doc/remote-debug-vscpp.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# 1. 环境
|
||||
visual studio 2022
|
||||
调试端: win10
|
||||
被调试端: win10
|
||||
## 程序编译
|
||||
一般远程调试我会选择release版本,然后将优化去掉即可,这样更接近真实版本。
|
||||

|
||||
|
||||
```
|
||||
go install github.com/go-delve/delve/cmd/dlv@latest
|
||||
```
|
||||
|
||||
## 运行远程调试器
|
||||
C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\Remote Debugger 拷贝到目标机器
|
||||
|
||||
如果调试x64程序则cd到Remote Debugger\x64目录
|
||||
|
||||
管理员方式打开cmd,执行
|
||||
```
|
||||
netsh advfirewall set allprofiles state off
|
||||
msvsmon.exe /noauth /anyuser /silent
|
||||
```
|
||||
|
||||
## visual studio
|
||||
|
||||
Attach远程进程,按下Ctrl+Atl+P
|
||||
|
||||

|
||||
|
||||
|
||||
## 没有公网IP或不在同一个局域网,无法直连如何调试
|
||||
到 https://openp2p.cn/ 注册一个用户获得token,两端安装一个客户端程序,可将被调试端的2345端口,通过p2p连接映射到调试端本地。
|
||||
p2p连接可通过web配置 https://github.com/openp2p-cn/openp2p/blob/master/README-ZH.md#%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8
|
||||
|
||||
也可以手动下载https://github.com/openp2p-cn/openp2p/releases 通过命令行手动配置
|
||||
|
||||
```
|
||||
# 注意替换下面YOUR-开头的参数改成自己的
|
||||
./openp2p -node YOUR-DEBUG-SERVER -token YOUR-TOKEN
|
||||
|
||||
openp2p.exe -node YOUR-DEBUG-CLIENT -token YOUR-TOKEN -peernode YOUR-DEBUG-SERVER -dstport 4026 -srcport 4026
|
||||
|
||||
2022/04/22 11:07:26 25680 INFO LISTEN ON PORT tcp:4026 START
|
||||
#显示这条日志说明成功了
|
||||
```
|
||||
|
||||

|
||||
|
||||
可以顺利远程调试
|
||||
```
|
||||
13
errorcode.go
13
errorcode.go
@@ -8,9 +8,12 @@ import (
|
||||
var (
|
||||
// ErrorS2S string = "s2s is not supported"
|
||||
// ErrorHandshake string = "handshake error"
|
||||
ErrorS2S = errors.New("s2s is not supported")
|
||||
ErrorHandshake = errors.New("handshake error")
|
||||
ErrorNewUser = errors.New("new user")
|
||||
ErrorLogin = errors.New("user or password not correct")
|
||||
ErrNodeTooShort = errors.New("node name too short, it must >=8 charaters")
|
||||
ErrorS2S = errors.New("s2s is not supported")
|
||||
ErrorHandshake = errors.New("handshake error")
|
||||
ErrorNewUser = errors.New("new user")
|
||||
ErrorLogin = errors.New("user or password not correct")
|
||||
ErrNodeTooShort = errors.New("node name too short, it must >=8 charaters")
|
||||
ErrPeerOffline = errors.New("peer offline")
|
||||
ErrMsgFormat = errors.New("message format wrong")
|
||||
ErrVersionNotCompatible = errors.New("version not compatible")
|
||||
)
|
||||
|
||||
3
go.mod
3
go.mod
@@ -6,7 +6,8 @@ require (
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/kardianos/service v1.2.0
|
||||
github.com/lucas-clemente/quic-go v0.27.0
|
||||
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34
|
||||
github.com/openp2p-cn/go-reuseport v0.3.2
|
||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
@@ -19,7 +19,7 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
|
||||
}
|
||||
gLog.Printf(LvDEBUG, "handle push msg type:%d, push header:%+v", subType, pushHead)
|
||||
switch subType {
|
||||
case MsgPushConnectReq:
|
||||
case MsgPushConnectReq: // TODO: handle a msg move to a new function
|
||||
req := PushConnectReq{}
|
||||
err := json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req)
|
||||
if err != nil {
|
||||
@@ -28,10 +28,20 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
|
||||
}
|
||||
gLog.Printf(LvINFO, "%s is connecting...", req.From)
|
||||
gLog.Println(LvDEBUG, "push connect response to ", req.From)
|
||||
if compareVersion(req.Version, LeastSupportVersion) == LESS {
|
||||
gLog.Println(LvERROR, ErrVersionNotCompatible.Error(), ":", req.From)
|
||||
rsp := PushConnectRsp{
|
||||
Error: 10,
|
||||
Detail: ErrVersionNotCompatible.Error(),
|
||||
To: req.From,
|
||||
From: pn.config.Node,
|
||||
}
|
||||
pn.push(req.From, MsgPushConnectRsp, rsp)
|
||||
return ErrVersionNotCompatible
|
||||
}
|
||||
// verify totp token or token
|
||||
if VerifyTOTP(req.Token, pn.config.Token, time.Now().Unix()+(pn.serverTs-pn.localTs)) || // localTs may behind, auto adjust ts
|
||||
VerifyTOTP(req.Token, pn.config.Token, time.Now().Unix()) ||
|
||||
(req.FromToken == pn.config.Token) {
|
||||
VerifyTOTP(req.Token, pn.config.Token, time.Now().Unix()) {
|
||||
gLog.Printf(LvINFO, "Access Granted\n")
|
||||
config := AppConfig{}
|
||||
config.peerNatType = req.NatType
|
||||
@@ -39,8 +49,14 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
|
||||
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
|
||||
// share relay node will limit bandwidth
|
||||
if req.FromToken != pn.config.Token {
|
||||
if req.Token != pn.config.Token {
|
||||
gLog.Printf(LvINFO, "set share bandwidth %d mbps", pn.config.ShareBandwidth)
|
||||
config.shareBandwidth = pn.config.ShareBandwidth
|
||||
}
|
||||
@@ -97,7 +113,7 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
|
||||
SaveKey(req.AppID, req.AppKey)
|
||||
case MsgPushUpdate:
|
||||
gLog.Println(LvINFO, "MsgPushUpdate")
|
||||
update() // download new version first, then exec ./openp2p update
|
||||
update(pn.config.ServerHost, pn.config.ServerPort) // download new version first, then exec ./openp2p update
|
||||
targetPath := filepath.Join(defaultInstallPath, defaultBinName)
|
||||
args := []string{"update"}
|
||||
env := os.Environ()
|
||||
@@ -124,6 +140,7 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
|
||||
appActive := 0
|
||||
relayNode := ""
|
||||
relayMode := ""
|
||||
linkMode := LinkModeUDPPunch
|
||||
i, ok := pn.apps.Load(fmt.Sprintf("%s%d", config.Protocol, config.SrcPort))
|
||||
if ok {
|
||||
app := i.(*p2pApp)
|
||||
@@ -132,6 +149,7 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
|
||||
}
|
||||
relayNode = app.relayNode
|
||||
relayMode = app.relayMode
|
||||
linkMode = app.tunnel.linkModeWeb
|
||||
}
|
||||
appInfo := AppInfo{
|
||||
AppName: config.AppName,
|
||||
@@ -140,6 +158,7 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
|
||||
SrcPort: config.SrcPort,
|
||||
RelayNode: relayNode,
|
||||
RelayMode: relayMode,
|
||||
LinkMode: linkMode,
|
||||
PeerNode: config.PeerNode,
|
||||
DstHost: config.DstHost,
|
||||
DstPort: config.DstPort,
|
||||
@@ -154,6 +173,49 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
|
||||
req.Apps = append(req.Apps, appInfo)
|
||||
}
|
||||
pn.write(MsgReport, MsgReportApps, &req)
|
||||
case MsgPushReportLog:
|
||||
gLog.Println(LvINFO, "MsgPushReportLog")
|
||||
req := ReportLogReq{}
|
||||
err := json.Unmarshal(msg[openP2PHeaderSize:], &req)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "wrong MsgPushReportLog:%s %s", err, string(msg[openP2PHeaderSize:]))
|
||||
return err
|
||||
}
|
||||
if req.FileName == "" {
|
||||
req.FileName = "openp2p.log"
|
||||
}
|
||||
f, err := os.Open(filepath.Join("log", req.FileName))
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "read log file error:", err)
|
||||
break
|
||||
}
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if req.Offset == 0 && fi.Size() > 4096 {
|
||||
req.Offset = fi.Size() - 4096
|
||||
}
|
||||
if req.Len <= 0 {
|
||||
req.Len = 4096
|
||||
}
|
||||
f.Seek(req.Offset, 0)
|
||||
if req.Len > 1024*1024 { // too large
|
||||
break
|
||||
}
|
||||
buff := make([]byte, req.Len)
|
||||
readLength, err := f.Read(buff)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "read log content error:", err)
|
||||
break
|
||||
}
|
||||
rsp := ReportLogRsp{}
|
||||
rsp.Content = string(buff[:readLength])
|
||||
rsp.FileName = req.FileName
|
||||
rsp.Total = fi.Size()
|
||||
rsp.Len = req.Len
|
||||
pn.write(MsgReport, MsgPushReportLog, &rsp)
|
||||
case MsgPushEditApp:
|
||||
gLog.Println(LvINFO, "MsgPushEditApp")
|
||||
newApp := AppInfo{}
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
func handshakeC2C(t *P2PTunnel) (err error) {
|
||||
gLog.Printf(LvDEBUG, "handshakeC2C %s:%d:%d to %s:%d", t.pn.config.Node, t.coneLocalPort, t.coneNatPort, t.config.peerIP, t.config.peerConeNatPort)
|
||||
defer gLog.Printf(LvDEBUG, "handshakeC2C ok")
|
||||
defer gLog.Printf(LvDEBUG, "handshakeC2C end")
|
||||
conn, err := net.ListenUDP("udp", t.la)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -45,6 +45,7 @@ func handshakeC2C(t *P2PTunnel) (err error) {
|
||||
}
|
||||
if head.MainType == MsgP2P && head.SubType == MsgPunchHandshakeAck {
|
||||
gLog.Printf(LvDEBUG, "read %d handshake ack ", t.id)
|
||||
gLog.Printf(LvINFO, "handshakeC2C ok")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -54,9 +55,10 @@ func handshakeC2C(t *P2PTunnel) (err error) {
|
||||
_, err = UDPWrite(conn, t.ra, MsgP2P, MsgPunchHandshakeAck, P2PHandshakeReq{ID: t.id})
|
||||
if err != nil {
|
||||
gLog.Println(LvDEBUG, "handshakeC2C write MsgPunchHandshakeAck error", err)
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
gLog.Printf(LvINFO, "handshakeC2C ok")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -115,6 +117,7 @@ func handshakeC2S(t *P2PTunnel) error {
|
||||
_, err = UDPWrite(conn, dst, MsgP2P, MsgPunchHandshakeAck, P2PHandshakeReq{ID: t.id})
|
||||
return err
|
||||
}
|
||||
gLog.Printf(LvINFO, "handshakeC2S ok")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -175,6 +178,7 @@ func handshakeS2C(t *P2PTunnel) error {
|
||||
return fmt.Errorf("wait handshake failed")
|
||||
case la := <-gotCh:
|
||||
gLog.Println(LvDEBUG, "symmetric handshake ok", la)
|
||||
gLog.Printf(LvINFO, "handshakeS2C ok")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
// ./openp2p install -node hhd1207-222 -token YOUR-TOKEN -sharebandwidth 0 -peernode hhdhome-n1 -dstip 127.0.0.1 -dstport 50022 -protocol tcp -srcport 22
|
||||
func install() {
|
||||
gLog.Println(LvINFO, "openp2p start. version: ", OpenP2PVersion)
|
||||
gLog.Println(LvINFO, "Contact: QQ Group: 16947733, Email: openp2p.cn@gmail.com")
|
||||
gLog.Println(LvINFO, "Contact: QQ: 477503927, Email: openp2p.cn@gmail.com")
|
||||
gLog.Println(LvINFO, "install start")
|
||||
defer gLog.Println(LvINFO, "install end")
|
||||
// auto uninstall
|
||||
@@ -102,6 +102,7 @@ func installByFilename() {
|
||||
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)
|
||||
|
||||
92
nat.go
92
nat.go
@@ -6,12 +6,55 @@ import (
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
reuse "github.com/openp2p-cn/go-reuseport"
|
||||
)
|
||||
|
||||
var echoConn *net.UDPConn
|
||||
|
||||
func natTCP(serverHost string, serverPort int, localPort int) (publicIP string, publicPort 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", localPort), fmt.Sprintf("%s:%d", serverHost, serverPort), time.Second*5)
|
||||
// conn, err := net.Dial("tcp4", fmt.Sprintf("%s:%d", serverHost, serverPort))
|
||||
if err != nil {
|
||||
fmt.Printf("Dial tcp4 %s:%d error:%s", serverHost, serverPort, err)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
_, 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(time.Second * 5))
|
||||
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, echoPort int) (publicIP string, hasPublicIP int, hasUPNPorNATPMP int, publicPort int, err error) {
|
||||
conn, err := net.ListenPacket("udp", fmt.Sprintf(":%d", localPort))
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "natTest listen udp error:", err)
|
||||
return "", 0, 0, 0, err
|
||||
}
|
||||
defer conn.Close()
|
||||
@@ -48,7 +91,7 @@ func natTest(serverHost string, serverPort int, localPort int, echoPort int) (pu
|
||||
if i == 1 {
|
||||
// test upnp or nat-pmp
|
||||
nat, err := Discover()
|
||||
if err != nil {
|
||||
if err != nil || nat == nil {
|
||||
gLog.Println(LvDEBUG, "could not perform UPNP discover:", err)
|
||||
break
|
||||
}
|
||||
@@ -59,10 +102,12 @@ func natTest(serverHost string, serverPort int, localPort int, echoPort int) (pu
|
||||
}
|
||||
log.Println("PublicIP:", ext)
|
||||
|
||||
externalPort, err := nat.AddPortMapping("udp", echoPort, echoPort, "openp2p", 60)
|
||||
externalPort, err := nat.AddPortMapping("udp", echoPort, echoPort, "openp2p", 30)
|
||||
if err != nil {
|
||||
gLog.Println(LvDEBUG, "could not add udp UPNP port mapping", externalPort)
|
||||
break
|
||||
} else {
|
||||
nat.AddPortMapping("tcp", echoPort, echoPort, "openp2p", 604800)
|
||||
}
|
||||
}
|
||||
gLog.Printf(LvDEBUG, "public ip test start %s:%d", natRsp.IP, echoPort)
|
||||
@@ -96,48 +141,53 @@ func natTest(serverHost string, serverPort int, localPort int, echoPort int) (pu
|
||||
return natRsp.IP, hasPublicIP, hasUPNPorNATPMP, natRsp.Port, nil
|
||||
}
|
||||
|
||||
func getNATType(host string, udp1 int, udp2 int) (publicIP string, NATType int, hasUPNPorNATPMP int, err error) {
|
||||
func getNATType(host string, udp1 int, udp2 int) (publicIP string, NATType int, hasIPvr int, hasUPNPorNATPMP int, err error) {
|
||||
// the random local port may be used by other.
|
||||
localPort := int(rand.Uint32()%10000 + 50000)
|
||||
echoPort := int(rand.Uint32()%10000 + 50000)
|
||||
localPort := int(rand.Uint32()%15000 + 50000)
|
||||
echoPort := P2PNetworkInstance(nil).config.TCPPort
|
||||
go echo(echoPort)
|
||||
ip1, hasPublicIP, hasUPNPorNATPMP, port1, err := natTest(host, udp1, localPort, echoPort)
|
||||
// _, natPort := natTCP(host, 27181, localPort)
|
||||
// gLog.Println(LvINFO, "nattcp:", natPort)
|
||||
// _, natPort = natTCP(host, 27180, localPort)
|
||||
// gLog.Println(LvINFO, "nattcp:", natPort)
|
||||
ip1, hasIPv4, hasUPNPorNATPMP, port1, err := natTest(host, udp1, localPort, echoPort)
|
||||
gLog.Printf(LvDEBUG, "local port:%d nat port:%d", localPort, port1)
|
||||
if err != nil {
|
||||
return "", 0, hasUPNPorNATPMP, err
|
||||
return "", 0, hasIPv4, hasUPNPorNATPMP, err
|
||||
}
|
||||
if hasPublicIP == 1 || hasUPNPorNATPMP == 1 {
|
||||
return ip1, NATNone, hasUPNPorNATPMP, nil
|
||||
if echoConn != nil {
|
||||
echoConn.Close()
|
||||
echoConn = nil
|
||||
}
|
||||
ip2, _, _, port2, err := natTest(host, udp2, localPort, 0) // 2rd nat test not need testing publicip
|
||||
// if hasPublicIP == 1 || hasUPNPorNATPMP == 1 {
|
||||
// return ip1, NATNone, hasUPNPorNATPMP, nil
|
||||
// }
|
||||
_, _, _, port2, err := natTest(host, udp2, localPort, 0) // 2rd nat test not need testing publicip
|
||||
gLog.Printf(LvDEBUG, "local port:%d nat port:%d", localPort, port2)
|
||||
if err != nil {
|
||||
return "", 0, hasUPNPorNATPMP, err
|
||||
}
|
||||
if ip1 != ip2 {
|
||||
return "", 0, hasUPNPorNATPMP, fmt.Errorf("ip have changed, please retry again")
|
||||
return "", 0, hasIPv4, hasUPNPorNATPMP, err
|
||||
}
|
||||
natType := NATSymmetric
|
||||
if port1 == port2 {
|
||||
natType = NATCone
|
||||
}
|
||||
//TODO: NATNone
|
||||
return ip1, natType, hasUPNPorNATPMP, nil
|
||||
return ip1, natType, hasIPv4, hasUPNPorNATPMP, nil
|
||||
}
|
||||
|
||||
func echo(echoPort int) {
|
||||
conn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: echoPort})
|
||||
var err error
|
||||
echoConn, err = net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: echoPort})
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "echo server listen error:", err)
|
||||
return
|
||||
}
|
||||
buf := make([]byte, 1600)
|
||||
defer conn.Close()
|
||||
// close outside for breaking the ReadFromUDP
|
||||
// wait 5s for echo testing
|
||||
conn.SetReadDeadline(time.Now().Add(time.Second * 30))
|
||||
n, addr, err := conn.ReadFromUDP(buf)
|
||||
echoConn.SetReadDeadline(time.Now().Add(time.Second * 30))
|
||||
n, addr, err := echoConn.ReadFromUDP(buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
conn.WriteToUDP(buf[0:n], addr)
|
||||
echoConn.WriteToUDP(buf[0:n], addr)
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ func main() {
|
||||
}
|
||||
parseParams("")
|
||||
gLog.Println(LvINFO, "openp2p start. version: ", OpenP2PVersion)
|
||||
gLog.Println(LvINFO, "Contact: QQ Group: 16947733, Email: openp2p.cn@gmail.com")
|
||||
gLog.Println(LvINFO, "Contact: QQ: 477503927, Email: openp2p.cn@gmail.com")
|
||||
|
||||
if gConf.daemonMode {
|
||||
d := daemon{}
|
||||
|
||||
144
p2pnetwork.go
144
p2pnetwork.go
@@ -9,6 +9,7 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -135,6 +136,7 @@ func (pn *P2PNetwork) runAll() {
|
||||
}
|
||||
config.nextRetryTime = time.Now().Add(time.Second * time.Duration(increase)) // exponential increase retry time. 1.3^x
|
||||
config.connectTime = time.Now()
|
||||
config.peerToken = pn.config.Token
|
||||
gConf.mtx.Unlock() // AddApp will take a period of time
|
||||
err := pn.AddApp(*config)
|
||||
gConf.mtx.Lock()
|
||||
@@ -159,6 +161,7 @@ func (pn *P2PNetwork) autorunApp() {
|
||||
func (pn *P2PNetwork) addRelayTunnel(config AppConfig) (*P2PTunnel, uint64, string, error) {
|
||||
gLog.Printf(LvINFO, "addRelayTunnel to %s start", config.PeerNode)
|
||||
defer gLog.Printf(LvINFO, "addRelayTunnel to %s end", config.PeerNode)
|
||||
// request a relay node or specify manually(TODO)
|
||||
pn.write(MsgRelay, MsgRelayNodeReq, &RelayNodeReq{config.PeerNode})
|
||||
head, body := pn.read("", MsgRelay, MsgRelayNodeRsp, time.Second*10)
|
||||
if head == nil {
|
||||
@@ -178,6 +181,7 @@ func (pn *P2PNetwork) addRelayTunnel(config AppConfig) (*P2PTunnel, uint64, stri
|
||||
relayConfig := config
|
||||
relayConfig.PeerNode = rsp.RelayName
|
||||
relayConfig.peerToken = rsp.RelayToken
|
||||
///
|
||||
t, err := pn.addDirectTunnel(relayConfig, 0)
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "direct connect error:", err)
|
||||
@@ -236,6 +240,8 @@ func (pn *P2PNetwork) AddApp(config AppConfig) error {
|
||||
peerNatType = t.config.peerNatType
|
||||
peerIP = t.config.peerIP
|
||||
}
|
||||
// TODO: if tcp failed, should try udp punching, nattype should refactor also, when NATNONE and failed we don't know the peerNatType
|
||||
|
||||
if err != nil && err == ErrorHandshake {
|
||||
gLog.Println(LvERROR, "direct connect failed, try to relay")
|
||||
t, rtid, relayMode, err = pn.addRelayTunnel(config)
|
||||
@@ -340,46 +346,113 @@ func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (*P2PTunnel,
|
||||
}
|
||||
return true
|
||||
})
|
||||
if exist {
|
||||
return t, nil
|
||||
}
|
||||
// create tunnel if not exist
|
||||
if !exist {
|
||||
t = &P2PTunnel{pn: pn,
|
||||
config: config,
|
||||
id: tid,
|
||||
t = &P2PTunnel{pn: pn,
|
||||
config: config,
|
||||
id: tid,
|
||||
}
|
||||
pn.msgMapMtx.Lock()
|
||||
pn.msgMap[nodeNameToID(config.PeerNode)] = make(chan []byte, 50)
|
||||
pn.msgMapMtx.Unlock()
|
||||
// server side
|
||||
if !isClient {
|
||||
err := pn.newTunnel(t, tid, isClient)
|
||||
return t, err // always return
|
||||
}
|
||||
// client side
|
||||
// peer info
|
||||
initErr := t.requestPeerInfo()
|
||||
if initErr != nil {
|
||||
gLog.Println(LvERROR, "init error:", initErr)
|
||||
return nil, initErr
|
||||
}
|
||||
err := ErrorHandshake
|
||||
// try TCP6
|
||||
if IsIPv6(t.config.peerIPv6) && IsIPv6(t.pn.config.publicIPv6) {
|
||||
gLog.Println(LvINFO, "try TCP6")
|
||||
t.config.linkMode = LinkModeTCP6
|
||||
t.config.isUnderlayServer = 0
|
||||
if err = pn.newTunnel(t, tid, isClient); err == nil {
|
||||
return t, nil
|
||||
}
|
||||
pn.msgMapMtx.Lock()
|
||||
pn.msgMap[nodeNameToID(config.PeerNode)] = make(chan []byte, 50)
|
||||
pn.msgMapMtx.Unlock()
|
||||
t.init()
|
||||
if isClient {
|
||||
if err := t.connect(); err != nil {
|
||||
gLog.Println(LvERROR, "p2pTunnel connect error:", err)
|
||||
return t, err
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: try UDP6
|
||||
|
||||
// try TCP4
|
||||
if t.config.hasIPv4 == 1 || t.pn.config.hasIPv4 == 1 || t.config.hasUPNPorNATPMP == 1 || t.pn.config.hasUPNPorNATPMP == 1 {
|
||||
gLog.Println(LvINFO, "try TCP4")
|
||||
t.config.linkMode = LinkModeTCP4
|
||||
if t.config.hasIPv4 == 1 || t.config.hasUPNPorNATPMP == 1 {
|
||||
t.config.isUnderlayServer = 0
|
||||
} else {
|
||||
if err := t.listen(); err != nil {
|
||||
gLog.Println(LvERROR, "p2pTunnel listen error:", err)
|
||||
return t, err
|
||||
}
|
||||
t.config.isUnderlayServer = 1
|
||||
}
|
||||
if err = pn.newTunnel(t, tid, isClient); err == nil {
|
||||
return t, nil
|
||||
}
|
||||
}
|
||||
// TODO: try UDP4
|
||||
|
||||
// try TCPPunch
|
||||
if t.config.peerNatType == NATCone && t.pn.config.natType == NATCone { // TODO: support c2s
|
||||
gLog.Println(LvINFO, "try TCP4 Punch")
|
||||
t.config.linkMode = LinkModeTCPPunch
|
||||
t.config.isUnderlayServer = 0
|
||||
if err = pn.newTunnel(t, tid, isClient); err == nil {
|
||||
return t, nil
|
||||
}
|
||||
}
|
||||
// try UDPPunch
|
||||
if t.config.peerNatType == NATCone || t.pn.config.natType == NATCone {
|
||||
gLog.Println(LvINFO, "try UDP4 Punch")
|
||||
t.config.linkMode = LinkModeUDPPunch
|
||||
t.config.isUnderlayServer = 0
|
||||
if err = pn.newTunnel(t, tid, isClient); err == nil {
|
||||
return t, nil
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (pn *P2PNetwork) newTunnel(t *P2PTunnel, tid uint64, isClient bool) error {
|
||||
t.initPort()
|
||||
if isClient {
|
||||
if err := t.connect(); err != nil {
|
||||
gLog.Println(LvERROR, "p2pTunnel connect error:", err)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := t.listen(); err != nil {
|
||||
gLog.Println(LvERROR, "p2pTunnel listen error:", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
// store it when success
|
||||
gLog.Printf(LvDEBUG, "store tunnel %d", tid)
|
||||
pn.allTunnels.Store(tid, t)
|
||||
return t, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pn *P2PNetwork) init() error {
|
||||
gLog.Println(LvINFO, "init start")
|
||||
var err error
|
||||
for {
|
||||
// detect nat type
|
||||
pn.config.publicIP, pn.config.natType, pn.config.hasUPNPorNATPMP, err = getNATType(pn.config.ServerHost, pn.config.UDPPort1, pn.config.UDPPort2)
|
||||
pn.config.publicIP, pn.config.natType, pn.config.hasIPv4, pn.config.hasUPNPorNATPMP, err = getNATType(pn.config.ServerHost, pn.config.UDPPort1, pn.config.UDPPort2)
|
||||
// for testcase
|
||||
if strings.Contains(pn.config.Node, "openp2pS2STest") {
|
||||
pn.config.natType = NATSymmetric
|
||||
pn.config.hasIPv4 = 0
|
||||
pn.config.hasUPNPorNATPMP = 0
|
||||
|
||||
}
|
||||
if strings.Contains(pn.config.Node, "openp2pC2CTest") {
|
||||
pn.config.natType = NATCone
|
||||
pn.config.hasIPv4 = 0
|
||||
pn.config.hasUPNPorNATPMP = 0
|
||||
}
|
||||
if err != nil {
|
||||
gLog.Println(LvDEBUG, "detect NAT type error:", err)
|
||||
@@ -387,10 +460,10 @@ func (pn *P2PNetwork) init() error {
|
||||
}
|
||||
gLog.Println(LvDEBUG, "detect NAT type:", pn.config.natType, " publicIP:", pn.config.publicIP)
|
||||
gatewayURL := fmt.Sprintf("%s:%d", pn.config.ServerHost, pn.config.ServerPort)
|
||||
forwardPath := "/openp2p/v1/login"
|
||||
uri := "/openp2p/v1/login"
|
||||
config := tls.Config{InsecureSkipVerify: true} // let's encrypt root cert "DST Root CA X3" expired at 2021/09/29. many old system(windows server 2008 etc) will not trust our cert
|
||||
websocket.DefaultDialer.TLSClientConfig = &config
|
||||
u := url.URL{Scheme: "wss", Host: gatewayURL, Path: forwardPath}
|
||||
u := url.URL{Scheme: "wss", Host: gatewayURL, Path: uri}
|
||||
q := u.Query()
|
||||
q.Add("node", pn.config.Node)
|
||||
q.Add("token", fmt.Sprintf("%d", pn.config.Token))
|
||||
@@ -429,7 +502,7 @@ func (pn *P2PNetwork) init() error {
|
||||
gLog.Println(LvDEBUG, "netinfo:", rsp)
|
||||
if rsp != nil && rsp.Country != "" {
|
||||
if IsIPv6(rsp.IP.String()) {
|
||||
pn.config.ipv6 = rsp.IP.String()
|
||||
pn.config.publicIPv6 = rsp.IP.String()
|
||||
req.IPv6 = rsp.IP.String()
|
||||
}
|
||||
req.NetInfo = *rsp
|
||||
@@ -471,9 +544,12 @@ func (pn *P2PNetwork) handleMessage(t int, msg []byte) {
|
||||
pn.config.User = rsp.User
|
||||
gConf.setToken(rsp.Token)
|
||||
gConf.setUser(rsp.User)
|
||||
if len(rsp.Node) >= MinNodeNameLen {
|
||||
gConf.setNode(rsp.Node)
|
||||
}
|
||||
gConf.save()
|
||||
pn.localTs = time.Now().Unix()
|
||||
gLog.Printf(LvINFO, "login ok. user=%s,Server ts=%d, local ts=%d", rsp.User, rsp.Ts, pn.localTs)
|
||||
gLog.Printf(LvINFO, "login ok. user=%s,node=%s,Server ts=%d, local ts=%d", rsp.User, rsp.Node, rsp.Ts, pn.localTs)
|
||||
}
|
||||
case MsgHeartbeat:
|
||||
gLog.Printf(LvDEBUG, "P2PNetwork heartbeat ok")
|
||||
@@ -611,3 +687,23 @@ func (pn *P2PNetwork) updateAppHeartbeat(appID uint64) {
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
func (pn *P2PNetwork) refreshIPv6() {
|
||||
if !IsIPv6(pn.config.publicIPv6) { // not support ipv6, not refresh
|
||||
return
|
||||
}
|
||||
client := &http.Client{Timeout: time.Second * 10}
|
||||
r, err := client.Get("http://6.ipw.cn")
|
||||
if err != nil {
|
||||
gLog.Println(LvINFO, "refreshIPv6 error:", err)
|
||||
return
|
||||
}
|
||||
defer r.Body.Close()
|
||||
buf := make([]byte, 1024)
|
||||
n, err := r.Body.Read(buf)
|
||||
if n <= 0 {
|
||||
gLog.Println(LvINFO, "netInfo error:", err, n)
|
||||
return
|
||||
}
|
||||
pn.config.publicIPv6 = string(buf[:n])
|
||||
}
|
||||
|
||||
226
p2ptunnel.go
226
p2ptunnel.go
@@ -28,37 +28,64 @@ type P2PTunnel struct {
|
||||
tunnelServer bool // different from underlayServer
|
||||
coneLocalPort int
|
||||
coneNatPort int
|
||||
linkModeWeb string // use config.linkmode
|
||||
}
|
||||
|
||||
func (t *P2PTunnel) init() {
|
||||
func (t *P2PTunnel) requestPeerInfo() error {
|
||||
// request peer info
|
||||
t.pn.write(MsgQuery, MsgQueryPeerInfoReq, &QueryPeerInfoReq{t.config.peerToken, t.config.PeerNode})
|
||||
head, body := t.pn.read("", MsgQuery, MsgQueryPeerInfoRsp, time.Second*10)
|
||||
if head == nil {
|
||||
return ErrPeerOffline
|
||||
}
|
||||
rsp := QueryPeerInfoRsp{}
|
||||
err := json.Unmarshal(body, &rsp)
|
||||
if err != nil {
|
||||
gLog.Printf(LvERROR, "wrong QueryPeerInfoRsp:%s", err)
|
||||
return ErrMsgFormat
|
||||
}
|
||||
if rsp.Online == 0 {
|
||||
return ErrPeerOffline
|
||||
}
|
||||
if compareVersion(rsp.Version, LeastSupportVersion) == LESS {
|
||||
return ErrVersionNotCompatible
|
||||
}
|
||||
t.config.peerVersion = rsp.Version
|
||||
t.config.hasIPv4 = rsp.HasIPv4
|
||||
t.config.peerIP = rsp.IPv4
|
||||
t.config.peerIPv6 = rsp.IPv6
|
||||
t.config.hasUPNPorNATPMP = rsp.HasUPNPorNATPMP
|
||||
t.config.peerNatType = rsp.NatType
|
||||
///
|
||||
return nil
|
||||
}
|
||||
func (t *P2PTunnel) initPort() {
|
||||
t.running = true
|
||||
t.hbMtx.Lock()
|
||||
t.hbTime = time.Now()
|
||||
t.hbMtx.Unlock()
|
||||
t.hbTimeRelay = time.Now().Add(time.Second * 600) // TODO: test fake time
|
||||
localPort := int(rand.Uint32()%10000 + 50000)
|
||||
if t.pn.config.natType == NATCone {
|
||||
// prepare one random cone hole
|
||||
_, _, _, port1, _ := natTest(t.pn.config.ServerHost, t.pn.config.UDPPort1, localPort, 0)
|
||||
t.coneLocalPort = localPort
|
||||
t.coneNatPort = port1
|
||||
t.la = &net.UDPAddr{IP: net.ParseIP(t.pn.config.localIP), Port: t.coneLocalPort}
|
||||
} else {
|
||||
t.coneLocalPort = localPort
|
||||
t.coneNatPort = localPort // symmetric doesn't need coneNatPort
|
||||
if t.pn.config.hasUPNPorNATPMP == 1 {
|
||||
nat, err := Discover()
|
||||
if err != nil {
|
||||
gLog.Println(LvDEBUG, "could not perform UPNP discover:", err)
|
||||
} else {
|
||||
externalPort, err := nat.AddPortMapping("tcp", localPort, localPort, "openp2p", 30) // timeout the connection still alive, make the timeout short
|
||||
if err != nil {
|
||||
gLog.Println(LvDEBUG, "could not add udp UPNP port mapping", externalPort)
|
||||
}
|
||||
}
|
||||
}
|
||||
t.la = &net.UDPAddr{IP: net.ParseIP(t.pn.config.localIP), Port: t.coneLocalPort}
|
||||
localPort := int(rand.Uint32()%15000 + 50000) // if the process has bug, will add many upnp port. use specify p2p port by param
|
||||
if t.config.linkMode == LinkModeTCP6 {
|
||||
t.pn.refreshIPv6()
|
||||
}
|
||||
if t.config.linkMode == LinkModeTCP6 || t.config.linkMode == LinkModeTCP4 {
|
||||
t.coneLocalPort = t.pn.config.TCPPort
|
||||
t.coneNatPort = t.pn.config.TCPPort // symmetric doesn't need coneNatPort
|
||||
}
|
||||
if t.config.linkMode == LinkModeUDPPunch {
|
||||
// prepare one random cone hole
|
||||
_, _, _, natPort, _ := natTest(t.pn.config.ServerHost, t.pn.config.UDPPort1, localPort, 0)
|
||||
t.coneLocalPort = localPort
|
||||
t.coneNatPort = natPort
|
||||
}
|
||||
if t.config.linkMode == LinkModeTCPPunch {
|
||||
// prepare one random cone hole
|
||||
_, natPort := natTCP(t.pn.config.ServerHost, IfconfigPort1, localPort)
|
||||
t.coneLocalPort = localPort
|
||||
t.coneNatPort = natPort
|
||||
}
|
||||
t.la = &net.UDPAddr{IP: net.ParseIP(t.pn.config.localIP), Port: t.coneLocalPort}
|
||||
gLog.Printf(LvDEBUG, "prepare punching port %d:%d", t.coneLocalPort, t.coneNatPort)
|
||||
}
|
||||
|
||||
@@ -67,18 +94,22 @@ func (t *P2PTunnel) connect() error {
|
||||
t.tunnelServer = false
|
||||
appKey := uint64(0)
|
||||
req := PushConnectReq{
|
||||
Token: t.config.peerToken,
|
||||
From: t.pn.config.Node,
|
||||
FromToken: t.pn.config.Token,
|
||||
FromIP: t.pn.config.publicIP,
|
||||
ConeNatPort: t.coneNatPort,
|
||||
NatType: t.pn.config.natType,
|
||||
HasIPv4: t.pn.config.hasIPv4,
|
||||
IPv6: t.pn.config.IPv6,
|
||||
HasUPNPorNATPMP: t.pn.config.hasUPNPorNATPMP,
|
||||
ID: t.id,
|
||||
AppKey: appKey,
|
||||
Version: OpenP2PVersion,
|
||||
Token: t.config.peerToken,
|
||||
From: t.pn.config.Node,
|
||||
FromIP: t.pn.config.publicIP,
|
||||
ConeNatPort: t.coneNatPort,
|
||||
NatType: t.pn.config.natType,
|
||||
HasIPv4: t.pn.config.hasIPv4,
|
||||
IPv6: t.pn.config.publicIPv6,
|
||||
HasUPNPorNATPMP: t.pn.config.hasUPNPorNATPMP,
|
||||
ID: t.id,
|
||||
AppKey: appKey,
|
||||
Version: OpenP2PVersion,
|
||||
LinkMode: t.config.linkMode,
|
||||
IsUnderlayServer: t.config.isUnderlayServer ^ 1,
|
||||
}
|
||||
if req.Token == 0 { // no relay token
|
||||
req.Token = t.pn.config.Token
|
||||
}
|
||||
t.pn.push(t.config.PeerNode, MsgPushConnectReq, req)
|
||||
head, body := t.pn.read(t.config.PeerNode, MsgPush, MsgPushConnectRsp, time.Second*10)
|
||||
@@ -97,7 +128,7 @@ func (t *P2PTunnel) connect() error {
|
||||
}
|
||||
t.config.peerNatType = rsp.NatType
|
||||
t.config.hasIPv4 = rsp.HasIPv4
|
||||
t.config.IPv6 = rsp.IPv6
|
||||
t.config.peerIPv6 = rsp.IPv6
|
||||
t.config.hasUPNPorNATPMP = rsp.HasUPNPorNATPMP
|
||||
t.config.peerVersion = rsp.Version
|
||||
t.config.peerConeNatPort = rsp.ConeNatPort
|
||||
@@ -158,7 +189,7 @@ func (t *P2PTunnel) close() {
|
||||
}
|
||||
|
||||
func (t *P2PTunnel) start() error {
|
||||
if !t.isSupportTCP() {
|
||||
if t.config.linkMode == LinkModeUDPPunch {
|
||||
if err := t.handshake(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -172,7 +203,7 @@ func (t *P2PTunnel) start() error {
|
||||
}
|
||||
|
||||
func (t *P2PTunnel) handshake() error {
|
||||
if t.config.peerConeNatPort > 0 {
|
||||
if t.config.peerConeNatPort > 0 { // only peer is cone should prepare t.ra
|
||||
var err error
|
||||
t.ra, err = net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", t.config.peerIP, t.config.peerConeNatPort))
|
||||
if err != nil {
|
||||
@@ -182,7 +213,7 @@ func (t *P2PTunnel) handshake() error {
|
||||
gLog.Println(LvDEBUG, "handshake to ", t.config.PeerNode)
|
||||
var err error
|
||||
// TODO: handle NATNone, nodes with public ip has no punching
|
||||
if (t.pn.config.natType == NATCone && t.config.peerNatType == NATCone) || (t.pn.config.natType == NATNone || t.config.peerNatType == NATNone) {
|
||||
if t.pn.config.natType == NATCone && t.config.peerNatType == NATCone {
|
||||
err = handshakeC2C(t)
|
||||
} else if t.config.peerNatType == NATSymmetric && t.pn.config.natType == NATSymmetric {
|
||||
err = ErrorS2S
|
||||
@@ -203,28 +234,22 @@ func (t *P2PTunnel) handshake() error {
|
||||
}
|
||||
|
||||
func (t *P2PTunnel) connectUnderlay() (err error) {
|
||||
if !t.isSupportTCP() {
|
||||
t.conn, err = t.connectUnderlayQuic()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// TODO: udp or tcp first?
|
||||
// prepare a la ra for udp
|
||||
// t.conn, err = t.connectUnderlayQuic()
|
||||
// TODO: support ipv6
|
||||
// if t.pn.config.hasIPv4 == 1 || t.config.hasIPv4 == 1 {
|
||||
switch t.config.linkMode {
|
||||
case LinkModeTCP6:
|
||||
t.conn, err = t.connectUnderlayTCP6()
|
||||
case LinkModeTCP4:
|
||||
t.conn, err = t.connectUnderlayTCP()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// }
|
||||
// if IsIPv6(t.pn.config.IPv6) && IsIPv6(t.config.IPv6) { // both have ipv6
|
||||
// t.conn, err = t.connectUnderlayTCP6()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
case LinkModeTCPPunch:
|
||||
t.conn, err = t.connectUnderlayTCP()
|
||||
case LinkModeUDPPunch:
|
||||
t.conn, err = t.connectUnderlayQuic()
|
||||
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if t.conn == nil {
|
||||
return errors.New("connect underlay error")
|
||||
}
|
||||
t.setRun(true)
|
||||
go t.readLoop()
|
||||
@@ -236,7 +261,7 @@ func (t *P2PTunnel) connectUnderlayQuic() (c underlay, err error) {
|
||||
gLog.Println(LvINFO, "connectUnderlayQuic start")
|
||||
defer gLog.Println(LvINFO, "connectUnderlayQuic end")
|
||||
var qConn *underlayQUIC
|
||||
if t.isUnderlayServer() {
|
||||
if t.config.isUnderlayServer == 1 {
|
||||
time.Sleep(time.Millisecond * 10) // punching udp port will need some times in some env
|
||||
qConn, err = listenQuic(t.la.String(), TunnelIdleTimeout)
|
||||
if err != nil {
|
||||
@@ -289,6 +314,7 @@ func (t *P2PTunnel) connectUnderlayQuic() (c underlay, err error) {
|
||||
|
||||
gLog.Println(LvINFO, "rtt=", time.Since(handshakeBegin))
|
||||
gLog.Println(LvDEBUG, "quic connection ok")
|
||||
t.linkModeWeb = LinkModeUDPPunch
|
||||
return qConn, nil
|
||||
}
|
||||
|
||||
@@ -297,37 +323,36 @@ func (t *P2PTunnel) connectUnderlayTCP() (c underlay, err error) {
|
||||
gLog.Println(LvINFO, "connectUnderlayTCP start")
|
||||
defer gLog.Println(LvINFO, "connectUnderlayTCP end")
|
||||
var qConn *underlayTCP
|
||||
if t.isUnderlayServer() {
|
||||
if t.config.isUnderlayServer == 1 {
|
||||
t.pn.push(t.config.PeerNode, MsgPushUnderlayConnect, nil)
|
||||
qConn, err = listenTCP(t.coneNatPort, TunnelIdleTimeout)
|
||||
qConn, err = listenTCP(t.config.peerIP, t.config.peerConeNatPort, t.coneLocalPort, t.config.linkMode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("listen TCP error:%s", err)
|
||||
}
|
||||
|
||||
_, buff, err := qConn.ReadBuffer()
|
||||
if err != nil {
|
||||
qConn.listener.Close()
|
||||
return nil, fmt.Errorf("read start msg error:%s", err)
|
||||
}
|
||||
if buff != nil {
|
||||
gLog.Println(LvDEBUG, string(buff))
|
||||
}
|
||||
qConn.WriteBytes(MsgP2P, MsgTunnelHandshakeAck, []byte("OpenP2P,hello2"))
|
||||
gLog.Println(LvDEBUG, "TCP connection ok")
|
||||
gLog.Println(LvINFO, "TCP connection ok")
|
||||
return qConn, nil
|
||||
}
|
||||
|
||||
//else
|
||||
t.pn.read(t.config.PeerNode, MsgPush, MsgPushUnderlayConnect, time.Second*5)
|
||||
gLog.Println(LvDEBUG, "TCP dial to ", t.ra.String())
|
||||
qConn, err = dialTCP(t.config.peerIP, t.config.peerConeNatPort)
|
||||
gLog.Println(LvDEBUG, "TCP dial to ", t.config.peerIP, ":", t.config.peerConeNatPort)
|
||||
qConn, err = dialTCP(t.config.peerIP, t.config.peerConeNatPort, t.coneLocalPort, t.config.linkMode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("TCP dial to %s error:%s", t.ra.String(), err)
|
||||
return nil, fmt.Errorf("TCP dial to %s:%d error:%s", t.config.peerIP, t.config.peerConeNatPort, err)
|
||||
}
|
||||
handshakeBegin := time.Now()
|
||||
qConn.WriteBytes(MsgP2P, MsgTunnelHandshake, []byte("OpenP2P,hello"))
|
||||
_, buff, err := qConn.ReadBuffer()
|
||||
if err != nil {
|
||||
qConn.listener.Close()
|
||||
return nil, fmt.Errorf("read MsgTunnelHandshake error:%s", err)
|
||||
}
|
||||
if buff != nil {
|
||||
@@ -335,19 +360,20 @@ func (t *P2PTunnel) connectUnderlayTCP() (c underlay, err error) {
|
||||
}
|
||||
|
||||
gLog.Println(LvINFO, "rtt=", time.Since(handshakeBegin))
|
||||
gLog.Println(LvDEBUG, "TCP connection ok")
|
||||
gLog.Println(LvINFO, "TCP connection ok")
|
||||
t.linkModeWeb = LinkModeIPv4
|
||||
return qConn, nil
|
||||
}
|
||||
|
||||
func (t *P2PTunnel) connectUnderlayTCP6() (c underlay, err error) {
|
||||
gLog.Println(LvINFO, "connectUnderlayTCP start")
|
||||
defer gLog.Println(LvINFO, "connectUnderlayTCP end")
|
||||
gLog.Println(LvINFO, "connectUnderlayTCP6 start")
|
||||
defer gLog.Println(LvINFO, "connectUnderlayTCP6 end")
|
||||
var qConn *underlayTCP6
|
||||
if t.isUnderlayServer() {
|
||||
if t.config.isUnderlayServer == 1 {
|
||||
t.pn.push(t.config.PeerNode, MsgPushUnderlayConnect, nil)
|
||||
qConn, err = listenTCP6(t.coneNatPort, TunnelIdleTimeout)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("listen TCP error:%s", err)
|
||||
return nil, fmt.Errorf("listen TCP6 error:%s", err)
|
||||
}
|
||||
_, buff, err := qConn.ReadBuffer()
|
||||
if err != nil {
|
||||
@@ -358,16 +384,16 @@ func (t *P2PTunnel) connectUnderlayTCP6() (c underlay, err error) {
|
||||
gLog.Println(LvDEBUG, string(buff))
|
||||
}
|
||||
qConn.WriteBytes(MsgP2P, MsgTunnelHandshakeAck, []byte("OpenP2P,hello2"))
|
||||
gLog.Println(LvDEBUG, "TCP connection ok")
|
||||
gLog.Println(LvDEBUG, "TCP6 connection ok")
|
||||
return qConn, nil
|
||||
}
|
||||
|
||||
//else
|
||||
t.pn.read(t.config.PeerNode, MsgPush, MsgPushUnderlayConnect, time.Second*5)
|
||||
gLog.Println(LvDEBUG, "TCP dial to ", t.ra.String())
|
||||
qConn, err = dialTCP6(t.config.IPv6, t.config.peerConeNatPort)
|
||||
gLog.Println(LvDEBUG, "TCP6 dial to ", t.config.peerIPv6)
|
||||
qConn, err = dialTCP6(t.config.peerIPv6, t.config.peerConeNatPort)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("TCP dial to %s error:%s", t.ra.String(), err)
|
||||
return nil, fmt.Errorf("TCP6 dial to %s:%d error:%s", t.config.peerIPv6, t.config.peerConeNatPort, err)
|
||||
}
|
||||
handshakeBegin := time.Now()
|
||||
qConn.WriteBytes(MsgP2P, MsgTunnelHandshake, []byte("OpenP2P,hello"))
|
||||
@@ -381,7 +407,8 @@ func (t *P2PTunnel) connectUnderlayTCP6() (c underlay, err error) {
|
||||
}
|
||||
|
||||
gLog.Println(LvINFO, "rtt=", time.Since(handshakeBegin))
|
||||
gLog.Println(LvDEBUG, "TCP connection ok")
|
||||
gLog.Println(LvDEBUG, "TCP6 connection ok")
|
||||
t.linkModeWeb = LinkModeIPv6
|
||||
return qConn, nil
|
||||
}
|
||||
|
||||
@@ -551,19 +578,25 @@ func (t *P2PTunnel) heartbeatLoop() {
|
||||
func (t *P2PTunnel) listen() error {
|
||||
// notify client to connect
|
||||
rsp := PushConnectRsp{
|
||||
Error: 0,
|
||||
Detail: "connect ok",
|
||||
To: t.config.PeerNode,
|
||||
From: t.pn.config.Node,
|
||||
NatType: t.pn.config.natType,
|
||||
HasIPv4: t.pn.config.hasIPv4,
|
||||
IPv6: t.pn.config.IPv6,
|
||||
Error: 0,
|
||||
Detail: "connect ok",
|
||||
To: t.config.PeerNode,
|
||||
From: t.pn.config.Node,
|
||||
NatType: t.pn.config.natType,
|
||||
HasIPv4: t.pn.config.hasIPv4,
|
||||
// IPv6: t.pn.config.IPv6,
|
||||
HasUPNPorNATPMP: t.pn.config.hasUPNPorNATPMP,
|
||||
FromIP: t.pn.config.publicIP,
|
||||
ConeNatPort: t.coneNatPort,
|
||||
ID: t.id,
|
||||
Version: OpenP2PVersion,
|
||||
}
|
||||
// only private node set ipv6
|
||||
if t.config.fromToken == t.pn.config.Token {
|
||||
t.pn.refreshIPv6()
|
||||
rsp.IPv6 = t.pn.config.publicIPv6
|
||||
}
|
||||
|
||||
t.pn.push(t.config.PeerNode, MsgPushConnectRsp, rsp)
|
||||
gLog.Printf(LvDEBUG, "p2ptunnel wait for connecting")
|
||||
t.tunnelServer = true
|
||||
@@ -586,24 +619,3 @@ func (t *P2PTunnel) closeOverlayConns(appID uint64) {
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func (t *P2PTunnel) isUnderlayServer() bool {
|
||||
if t.pn.config.natType == NATNone && t.config.peerNatType != NATNone {
|
||||
return true
|
||||
}
|
||||
if t.pn.config.natType != NATNone && t.config.peerNatType == NATNone {
|
||||
return false
|
||||
}
|
||||
// NAT or both has public IP
|
||||
return t.tunnelServer
|
||||
}
|
||||
|
||||
func (t *P2PTunnel) isSupportTCP() bool {
|
||||
if t.config.peerVersion == "" || compareVersion(t.config.peerVersion, LeastSupportTCPVersion) == LESS {
|
||||
return false
|
||||
}
|
||||
if t.pn.config.natType == NATNone || t.config.peerNatType == NATNone {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
90
protocol.go
90
protocol.go
@@ -10,9 +10,17 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const OpenP2PVersion = "1.5.6"
|
||||
const OpenP2PVersion = "3.4.0"
|
||||
const ProducnName string = "openp2p"
|
||||
const LeastSupportTCPVersion = "1.5.0"
|
||||
const LeastSupportVersion = "3.0.0"
|
||||
|
||||
const (
|
||||
IfconfigPort1 = 27180
|
||||
IfconfigPort2 = 27181
|
||||
WsPort = 27183
|
||||
UDPPort1 = 27182
|
||||
UDPPort2 = 27183
|
||||
)
|
||||
|
||||
type openP2PHeader struct {
|
||||
DataLen uint32
|
||||
@@ -68,6 +76,7 @@ const (
|
||||
MsgP2P = 4
|
||||
MsgRelay = 5
|
||||
MsgReport = 6
|
||||
MsgQuery = 7
|
||||
)
|
||||
|
||||
// TODO: seperate node push and web push.
|
||||
@@ -86,6 +95,7 @@ const (
|
||||
MsgPushRestart = 11
|
||||
MsgPushEditNode = 12
|
||||
MsgPushAPPKey = 13
|
||||
MsgPushReportLog = 14
|
||||
)
|
||||
|
||||
// MsgP2P sub type message
|
||||
@@ -117,6 +127,7 @@ const (
|
||||
MsgReportQuery
|
||||
MsgReportConnect
|
||||
MsgReportApps
|
||||
MsgReportLog
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -137,7 +148,7 @@ const (
|
||||
PublicIPEchoTimeout = time.Second * 1
|
||||
NatTestTimeout = time.Second * 10
|
||||
ClientAPITimeout = time.Second * 10
|
||||
MaxDirectTry = 5
|
||||
MaxDirectTry = 3
|
||||
)
|
||||
|
||||
// NATNone has public ip
|
||||
@@ -155,6 +166,23 @@ const (
|
||||
UderlayTCP = "tcp"
|
||||
)
|
||||
|
||||
// linkmode
|
||||
const (
|
||||
LinkModeUDPPunch = "udppunch"
|
||||
LinkModeTCPPunch = "tcppunch"
|
||||
LinkModeIPv4 = "ipv4" // for web
|
||||
LinkModeIPv6 = "ipv6" // for web
|
||||
LinkModeTCP6 = "tcp6"
|
||||
LinkModeTCP4 = "tcp4"
|
||||
LinkModeUDP6 = "udp6"
|
||||
LinkModeUDP4 = "udp4"
|
||||
)
|
||||
|
||||
const (
|
||||
MsgQueryPeerInfoReq = iota
|
||||
MsgQueryPeerInfoRsp
|
||||
)
|
||||
|
||||
func newMessage(mainType uint16, subType uint16, packet interface{}) ([]byte, error) {
|
||||
data, err := json.Marshal(packet)
|
||||
if err != nil {
|
||||
@@ -180,18 +208,20 @@ func nodeNameToID(name string) uint64 {
|
||||
}
|
||||
|
||||
type PushConnectReq struct {
|
||||
From string `json:"from,omitempty"`
|
||||
FromToken uint64 `json:"fromToken,omitempty"` //my token
|
||||
Version string `json:"version,omitempty"`
|
||||
Token uint64 `json:"token,omitempty"` // totp token
|
||||
ConeNatPort int `json:"coneNatPort,omitempty"` // if isPublic, is public port
|
||||
NatType int `json:"natType,omitempty"`
|
||||
HasIPv4 int `json:"hasIPv4,omitempty"`
|
||||
IPv6 string `json:"IPv6,omitempty"`
|
||||
HasUPNPorNATPMP int `json:"hasUPNPorNATPMP,omitempty"`
|
||||
FromIP string `json:"fromIP,omitempty"`
|
||||
ID uint64 `json:"id,omitempty"`
|
||||
AppKey uint64 `json:"appKey,omitempty"` // for underlay tcp
|
||||
From string `json:"from,omitempty"`
|
||||
FromToken uint64 `json:"fromToken,omitempty"` // deprecated
|
||||
Version string `json:"version,omitempty"`
|
||||
Token uint64 `json:"token,omitempty"` // if public totp token
|
||||
ConeNatPort int `json:"coneNatPort,omitempty"` // if isPublic, is public port
|
||||
NatType int `json:"natType,omitempty"`
|
||||
HasIPv4 int `json:"hasIPv4,omitempty"`
|
||||
IPv6 string `json:"IPv6,omitempty"`
|
||||
HasUPNPorNATPMP int `json:"hasUPNPorNATPMP,omitempty"`
|
||||
FromIP string `json:"fromIP,omitempty"`
|
||||
ID uint64 `json:"id,omitempty"`
|
||||
AppKey uint64 `json:"appKey,omitempty"` // for underlay tcp
|
||||
LinkMode string `json:"linkMode,omitempty"`
|
||||
IsUnderlayServer int `json:"isServer,omitempty"` // Requset spec peer is server
|
||||
}
|
||||
type PushConnectRsp struct {
|
||||
Error int `json:"error,omitempty"`
|
||||
@@ -200,7 +230,7 @@ type PushConnectRsp struct {
|
||||
Detail string `json:"detail,omitempty"`
|
||||
NatType int `json:"natType,omitempty"`
|
||||
HasIPv4 int `json:"hasIPv4,omitempty"`
|
||||
IPv6 string `json:"IPv6,omitempty"`
|
||||
IPv6 string `json:"IPv6,omitempty"` // if public relay node, ipv6 not set
|
||||
HasUPNPorNATPMP int `json:"hasUPNPorNATPMP,omitempty"`
|
||||
ConeNatPort int `json:"coneNatPort,omitempty"` //it's not only cone, but also upnp or nat-pmp hole
|
||||
FromIP string `json:"fromIP,omitempty"`
|
||||
@@ -216,6 +246,7 @@ type LoginRsp struct {
|
||||
Error int `json:"error,omitempty"`
|
||||
Detail string `json:"detail,omitempty"`
|
||||
User string `json:"user,omitempty"`
|
||||
Node string `json:"node,omitempty"`
|
||||
Token uint64 `json:"token,omitempty"`
|
||||
Ts int64 `json:"ts,omitempty"`
|
||||
}
|
||||
@@ -323,6 +354,7 @@ type AppInfo struct {
|
||||
ShareBandwidth int `json:"shareBandWidth,omitempty"`
|
||||
RelayNode string `json:"relayNode,omitempty"`
|
||||
RelayMode string `json:"relayMode,omitempty"`
|
||||
LinkMode string `json:"linkMode,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
RetryTime string `json:"retryTime,omitempty"`
|
||||
ConnectTime string `json:"connectTime,omitempty"`
|
||||
@@ -334,6 +366,18 @@ type ReportApps struct {
|
||||
Apps []AppInfo
|
||||
}
|
||||
|
||||
type ReportLogReq struct {
|
||||
FileName string `json:"fileName,omitempty"`
|
||||
Offset int64 `json:"offset,omitempty"`
|
||||
Len int64 `json:"len,omitempty"`
|
||||
}
|
||||
type ReportLogRsp struct {
|
||||
FileName string `json:"fileName,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
Len int64 `json:"len,omitempty"`
|
||||
Total int64 `json:"total,omitempty"`
|
||||
}
|
||||
|
||||
type UpdateInfo struct {
|
||||
Error int `json:"error,omitempty"`
|
||||
ErrorDetail string `json:"errorDetail,omitempty"`
|
||||
@@ -372,3 +416,17 @@ type EditNode struct {
|
||||
NewName string `json:"newName,omitempty"`
|
||||
Bandwidth int `json:"bandwidth,omitempty"`
|
||||
}
|
||||
|
||||
type QueryPeerInfoReq struct {
|
||||
Token uint64 `json:"token,omitempty"` // if public totp token
|
||||
PeerNode string `json:"peerNode,omitempty"`
|
||||
}
|
||||
type QueryPeerInfoRsp struct {
|
||||
Online int `json:"online,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
NatType int `json:"natType,omitempty"`
|
||||
IPv4 string `json:"IPv4,omitempty"`
|
||||
HasIPv4 int `json:"hasIPv4,omitempty"` // has public ipv4
|
||||
IPv6 string `json:"IPv6,omitempty"` // if public relay node, ipv6 not set
|
||||
HasUPNPorNATPMP int `json:"hasUPNPorNATPMP,omitempty"`
|
||||
}
|
||||
|
||||
151
quic.go
151
quic.go
@@ -1,151 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/lucas-clemente/quic-go"
|
||||
)
|
||||
|
||||
//quic.DialContext do not support version 44,disable it
|
||||
var quicVersion []quic.VersionNumber
|
||||
|
||||
type quicConn struct {
|
||||
listener quic.Listener
|
||||
writeMtx *sync.Mutex
|
||||
quic.Stream
|
||||
quic.Session
|
||||
}
|
||||
|
||||
func (conn *quicConn) ReadMessage() (*openP2PHeader, []byte, error) {
|
||||
headBuf := make([]byte, openP2PHeaderSize)
|
||||
_, err := io.ReadFull(conn, headBuf)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
head, err := decodeHeader(headBuf)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
dataBuf := make([]byte, head.DataLen)
|
||||
_, err = io.ReadFull(conn, dataBuf)
|
||||
return head, dataBuf, err
|
||||
}
|
||||
|
||||
func (conn *quicConn) WriteBytes(mainType uint16, subType uint16, data []byte) error {
|
||||
writeBytes := append(encodeHeader(mainType, subType, uint32(len(data))), data...)
|
||||
conn.writeMtx.Lock()
|
||||
_, err := conn.Write(writeBytes)
|
||||
conn.writeMtx.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
func (conn *quicConn) WriteBuffer(data []byte) error {
|
||||
conn.writeMtx.Lock()
|
||||
_, err := conn.Write(data)
|
||||
conn.writeMtx.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
func (conn *quicConn) WriteMessage(mainType uint16, subType uint16, packet interface{}) error {
|
||||
// TODO: call newMessage
|
||||
data, err := json.Marshal(packet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
writeBytes := append(encodeHeader(mainType, subType, uint32(len(data))), data...)
|
||||
conn.writeMtx.Lock()
|
||||
_, err = conn.Write(writeBytes)
|
||||
conn.writeMtx.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
func (conn *quicConn) Close() error {
|
||||
conn.Stream.CancelRead(1)
|
||||
conn.Session.CloseWithError(0, "")
|
||||
return nil
|
||||
}
|
||||
func (conn *quicConn) CloseListener() {
|
||||
if conn.listener != nil {
|
||||
conn.listener.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (conn *quicConn) Accept() error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
||||
defer cancel()
|
||||
sess, err := conn.listener.Accept(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stream, err := sess.AcceptStream(context.Background())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conn.Stream = stream
|
||||
conn.Session = sess
|
||||
return nil
|
||||
}
|
||||
|
||||
func listenQuic(addr string, idleTimeout time.Duration) (*quicConn, error) {
|
||||
gLog.Println(LevelDEBUG, "quic listen on ", addr)
|
||||
listener, err := quic.ListenAddr(addr, generateTLSConfig(),
|
||||
&quic.Config{Versions: quicVersion, MaxIdleTimeout: idleTimeout, DisablePathMTUDiscovery: true})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("quic.ListenAddr error:%s", err)
|
||||
}
|
||||
return &quicConn{listener: listener, writeMtx: &sync.Mutex{}}, nil
|
||||
}
|
||||
|
||||
func dialQuic(conn *net.UDPConn, remoteAddr *net.UDPAddr, idleTimeout time.Duration) (*quicConn, error) {
|
||||
tlsConf := &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
NextProtos: []string{"openp2pv1"},
|
||||
}
|
||||
session, err := quic.DialContext(context.Background(), conn, remoteAddr, conn.LocalAddr().String(), tlsConf,
|
||||
&quic.Config{Versions: quicVersion, MaxIdleTimeout: idleTimeout, DisablePathMTUDiscovery: true})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("quic.DialContext error:%s", err)
|
||||
}
|
||||
stream, err := session.OpenStreamSync(context.Background())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("OpenStreamSync error:%s", err)
|
||||
}
|
||||
qConn := &quicConn{nil, &sync.Mutex{}, stream, session}
|
||||
return qConn, nil
|
||||
}
|
||||
|
||||
// Setup a bare-bones TLS config for the server
|
||||
func generateTLSConfig() *tls.Config {
|
||||
key, err := rsa.GenerateKey(rand.Reader, 1024)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
template := x509.Certificate{SerialNumber: big.NewInt(1)}
|
||||
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
|
||||
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER})
|
||||
|
||||
tlsCert, err := tls.X509KeyPair(certPEM, keyPEM)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &tls.Config{
|
||||
Certificates: []tls.Certificate{tlsCert},
|
||||
NextProtos: []string{"openp2pv1"},
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultInstallPath = "/usr/local/openp2p"
|
||||
defaultBinName = "openp2p"
|
||||
)
|
||||
|
||||
func getOsName() (osName string) {
|
||||
output := execOutput("sw_vers", "-productVersion")
|
||||
osName = "Mac OS X " + strings.TrimSpace(output)
|
||||
return
|
||||
}
|
||||
|
||||
func setRLimit() error {
|
||||
var limit syscall.Rlimit
|
||||
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
|
||||
return err
|
||||
}
|
||||
limit.Cur = 10240
|
||||
if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setFirewall() {
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultInstallPath = "/usr/local/openp2p"
|
||||
defaultBinName = "openp2p"
|
||||
)
|
||||
|
||||
func getOsName() (osName string) {
|
||||
var sysnamePath string
|
||||
sysnamePath = "/etc/redhat-release"
|
||||
_, err := os.Stat(sysnamePath)
|
||||
if err != nil && os.IsNotExist(err) {
|
||||
str := "PRETTY_NAME="
|
||||
f, err := os.Open("/etc/os-release")
|
||||
if err != nil && os.IsNotExist(err) {
|
||||
str = "DISTRIB_ID="
|
||||
f, err = os.Open("/etc/openwrt_release")
|
||||
}
|
||||
if err == nil {
|
||||
buf := bufio.NewReader(f)
|
||||
for {
|
||||
line, err := buf.ReadString('\n')
|
||||
if err == nil {
|
||||
line = strings.TrimSpace(line)
|
||||
pos := strings.Count(line, str)
|
||||
if pos > 0 {
|
||||
len1 := len([]rune(str)) + 1
|
||||
rs := []rune(line)
|
||||
osName = string(rs[len1 : (len(rs))-1])
|
||||
break
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
buff, err := ioutil.ReadFile(sysnamePath)
|
||||
if err == nil {
|
||||
osName = string(bytes.TrimSpace(buff))
|
||||
}
|
||||
}
|
||||
if osName == "" {
|
||||
osName = "Linux"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setRLimit() error {
|
||||
var limit syscall.Rlimit
|
||||
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
|
||||
return err
|
||||
}
|
||||
limit.Max = 1024 * 1024
|
||||
limit.Cur = limit.Max
|
||||
if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setFirewall() {
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/sys/windows/registry"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultInstallPath = "C:\\Program Files\\OpenP2P"
|
||||
defaultBinName = "openp2p.exe"
|
||||
)
|
||||
|
||||
func getOsName() (osName string) {
|
||||
k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE|registry.WOW64_64KEY)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer k.Close()
|
||||
pn, _, err := k.GetStringValue("ProductName")
|
||||
if err == nil {
|
||||
osName = pn
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setRLimit() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func setFirewall() {
|
||||
fullPath, err := filepath.Abs(os.Args[0])
|
||||
if err != nil {
|
||||
gLog.Println(LevelERROR, "add firewall error:", err)
|
||||
return
|
||||
}
|
||||
isXP := false
|
||||
osName := getOsName()
|
||||
if strings.Contains(osName, "XP") || strings.Contains(osName, "2003") {
|
||||
isXP = true
|
||||
}
|
||||
if isXP {
|
||||
exec.Command("cmd.exe", `/c`, fmt.Sprintf(`netsh firewall del allowedprogram "%s"`, fullPath)).Run()
|
||||
exec.Command("cmd.exe", `/c`, fmt.Sprintf(`netsh firewall add allowedprogram "%s" "%s" ENABLE`, ProducnName, fullPath)).Run()
|
||||
} else { // win7 or later
|
||||
exec.Command("cmd.exe", `/c`, fmt.Sprintf(`netsh advfirewall firewall del rule name="%s"`, ProducnName)).Run()
|
||||
exec.Command("cmd.exe", `/c`, fmt.Sprintf(`netsh advfirewall firewall add rule name="%s" dir=in action=allow program="%s" enable=yes`, ProducnName, fullPath)).Run()
|
||||
}
|
||||
}
|
||||
3
totp.go
3
totp.go
@@ -25,6 +25,9 @@ func VerifyTOTP(code uint64, token uint64, ts int64) bool {
|
||||
if code == 0 {
|
||||
return false
|
||||
}
|
||||
if code == token {
|
||||
return true
|
||||
}
|
||||
if code == GenTOTP(token, ts) || code == GenTOTP(token, ts-TOTPStep) || code == GenTOTP(token, ts+TOTPStep) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -7,10 +7,11 @@ import (
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
reuse "github.com/openp2p-cn/go-reuseport"
|
||||
)
|
||||
|
||||
type underlayTCP struct {
|
||||
listener net.Listener
|
||||
writeMtx *sync.Mutex
|
||||
net.Conn
|
||||
}
|
||||
@@ -66,13 +67,20 @@ func (conn *underlayTCP) Close() error {
|
||||
return conn.Conn.Close()
|
||||
}
|
||||
|
||||
func listenTCP(port int, idleTimeout time.Duration) (*underlayTCP, error) {
|
||||
addr, _ := net.ResolveTCPAddr("tcp", fmt.Sprintf("0.0.0.0:%d", port))
|
||||
func listenTCP(host string, port int, localPort int, mode string) (*underlayTCP, error) {
|
||||
if mode == LinkModeTCPPunch {
|
||||
c, err := reuse.DialTimeout("tcp", fmt.Sprintf("0.0.0.0:%d", localPort), fmt.Sprintf("%s:%d", host, port), SymmetricHandshakeAckTimeout) // TODO: timeout
|
||||
if err != nil {
|
||||
gLog.Println(LvDEBUG, "send tcp punch: ", err)
|
||||
return nil, err
|
||||
}
|
||||
return &underlayTCP{writeMtx: &sync.Mutex{}, Conn: c}, nil
|
||||
}
|
||||
addr, _ := net.ResolveTCPAddr("tcp", fmt.Sprintf("0.0.0.0:%d", localPort))
|
||||
l, err := net.ListenTCP("tcp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer l.Close()
|
||||
l.SetDeadline(time.Now().Add(SymmetricHandshakeAckTimeout))
|
||||
c, err := l.Accept()
|
||||
defer l.Close()
|
||||
@@ -82,11 +90,19 @@ func listenTCP(port int, idleTimeout time.Duration) (*underlayTCP, error) {
|
||||
return &underlayTCP{writeMtx: &sync.Mutex{}, Conn: c}, nil
|
||||
}
|
||||
|
||||
func dialTCP(host string, port int) (*underlayTCP, error) {
|
||||
c, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", host, port), SymmetricHandshakeAckTimeout)
|
||||
func dialTCP(host string, port int, localPort int, mode string) (*underlayTCP, error) {
|
||||
var c net.Conn
|
||||
var err error
|
||||
if mode == LinkModeTCPPunch {
|
||||
c, err = reuse.DialTimeout("tcp", fmt.Sprintf("0.0.0.0:%d", localPort), fmt.Sprintf("%s:%d", host, port), SymmetricHandshakeAckTimeout)
|
||||
} else {
|
||||
c, err = net.DialTimeout("tcp", fmt.Sprintf("%s:%d", host, port), SymmetricHandshakeAckTimeout)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("Dial %s:%d error:%s", host, port, err)
|
||||
gLog.Printf(LvERROR, "Dial %s:%d error:%s", host, port, err)
|
||||
return nil, err
|
||||
}
|
||||
gLog.Printf(LvDEBUG, "Dial %s:%d OK", host, port)
|
||||
return &underlayTCP{writeMtx: &sync.Mutex{}, Conn: c}, nil
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ func (conn *underlayTCP6) Close() error {
|
||||
}
|
||||
|
||||
func listenTCP6(port int, idleTimeout time.Duration) (*underlayTCP6, error) {
|
||||
addr, _ := net.ResolveTCPAddr("tcp6", fmt.Sprintf("0.0.0.0:%d", port))
|
||||
addr, _ := net.ResolveTCPAddr("tcp6", fmt.Sprintf("[::]:%d", port))
|
||||
l, err := net.ListenTCP("tcp6", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -83,9 +83,9 @@ func listenTCP6(port int, idleTimeout time.Duration) (*underlayTCP6, error) {
|
||||
}
|
||||
|
||||
func dialTCP6(host string, port int) (*underlayTCP6, error) {
|
||||
c, err := net.DialTimeout("tcp6", fmt.Sprintf("%s:%d", host, port), SymmetricHandshakeAckTimeout)
|
||||
c, err := net.DialTimeout("tcp6", fmt.Sprintf("[%s]:%d", host, port), SymmetricHandshakeAckTimeout)
|
||||
if err != nil {
|
||||
fmt.Printf("Dial %s:%d error:%s", host, port, err)
|
||||
gLog.Printf(LvERROR, "Dial %s:%d error:%s", host, port, err)
|
||||
return nil, err
|
||||
}
|
||||
return &underlayTCP6{writeMtx: &sync.Mutex{}, Conn: c}, nil
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func update() {
|
||||
func update(host string, port int) {
|
||||
gLog.Println(LvINFO, "update start")
|
||||
defer gLog.Println(LvINFO, "update end")
|
||||
c := http.Client{
|
||||
@@ -27,7 +27,7 @@ func update() {
|
||||
}
|
||||
goos := runtime.GOOS
|
||||
goarch := runtime.GOARCH
|
||||
rsp, err := c.Get(fmt.Sprintf("https://openp2p.cn:27183/api/v1/update?fromver=%s&os=%s&arch=%s", OpenP2PVersion, goos, goarch))
|
||||
rsp, err := c.Get(fmt.Sprintf("https://%s:%d/api/v1/update?fromver=%s&os=%s&arch=%s", host, port, OpenP2PVersion, goos, goarch))
|
||||
if err != nil {
|
||||
gLog.Println(LvERROR, "update:query update list failed:", err)
|
||||
return
|
||||
|
||||
41
upnp.go
41
upnp.go
@@ -1,12 +1,8 @@
|
||||
/*
|
||||
Taken from taipei-torrent
|
||||
|
||||
Just enough UPnP to be able to forward ports
|
||||
Taken from taipei-torrent And fix some bugs
|
||||
*/
|
||||
package main
|
||||
|
||||
// BUG(jae): TODO: use syscalls to get actual ourIP. http://pastebin.com/9exZG4rh
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
@@ -34,11 +30,12 @@ type NAT interface {
|
||||
}
|
||||
|
||||
func Discover() (nat NAT, err error) {
|
||||
localIP := localIPv4()
|
||||
ssdp, err := net.ResolveUDPAddr("udp4", "239.255.255.250:1900")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
conn, err := net.ListenPacket("udp4", ":0")
|
||||
conn, err := net.ListenPacket("udp4", fmt.Sprintf("%s:0", localIP))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -67,6 +64,7 @@ func Discover() (nat NAT, err error) {
|
||||
var n int
|
||||
_, _, err = socket.ReadFromUDP(answerBytes)
|
||||
if err != nil {
|
||||
gLog.Println(LvDEBUG, "UPNP discover error:", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -98,12 +96,10 @@ func Discover() (nat NAT, err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var ourIP net.IP
|
||||
ourIP, err = localIPv4()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
nat = &upnpNAT{serviceURL: serviceURL, ourIP: ourIP.String(), urnDomain: urnDomain}
|
||||
nat = &upnpNAT{serviceURL: serviceURL, ourIP: localIP, urnDomain: urnDomain}
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -174,29 +170,14 @@ func getChildService(d *Device, serviceType string) *UPNPService {
|
||||
return nil
|
||||
}
|
||||
|
||||
func localIPv4() (net.IP, error) {
|
||||
tt, err := net.Interfaces()
|
||||
func localIPv4() string { // TODO: multi nic will wrong
|
||||
conn, err := net.Dial("udp", "8.8.8.8:80")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return ""
|
||||
}
|
||||
for _, t := range tt {
|
||||
aa, err := t.Addrs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, a := range aa {
|
||||
ipnet, ok := a.(*net.IPNet)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
v4 := ipnet.IP.To4()
|
||||
if v4 == nil || v4[0] == 127 { // loopback address
|
||||
continue
|
||||
}
|
||||
return v4, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("cannot find local IP address")
|
||||
defer conn.Close()
|
||||
localAddr := conn.LocalAddr().(*net.UDPAddr)
|
||||
return localAddr.IP.String()
|
||||
}
|
||||
|
||||
func getServiceURL(rootURL string) (url, urnDomain string, err error) {
|
||||
|
||||
Reference in New Issue
Block a user