Compare commits

...

1 Commits

Author SHA1 Message Date
TenderIronh
532d3667ce support ipv6 2022-05-15 13:08:56 +08:00
13 changed files with 131 additions and 78 deletions

View File

@@ -23,7 +23,7 @@
### 5. 跨平台 ### 5. 跨平台
因为轻量所以很容易支持各个平台。支持主流的操作系统Windows,Linux,MacOS和主流的cpu架构386、amd64、arm、arm64、mipsle、mipsle64、mips、mips64 因为轻量所以很容易支持各个平台。支持主流的操作系统Windows,Linux,MacOS和主流的cpu架构386、amd64、arm、arm64、mipsle、mipsle64、mips、mips64
### 6. 高效 ### 6. 高效
P2P直连可以让你的设备跑满带宽。不论你的设备在任何网络环境无论NAT1-4Cone或Symmetric都支持。依靠Quic协议优秀的拥塞算法能在糟糕的网络环境获得高带宽低延时。 P2P直连可以让你的设备跑满带宽。不论你的设备在任何网络环境无论NAT1-4Cone或SymmetricUPNP,IPv6都支持。依靠Quic协议优秀的拥塞算法能在糟糕的网络环境获得高带宽低延时。
### 7. 二次开发 ### 7. 二次开发
基于OpenP2P只需数行代码就能让原来只能局域网通信的程序变成任何内网都能通信 基于OpenP2P只需数行代码就能让原来只能局域网通信的程序变成任何内网都能通信
@@ -105,7 +105,7 @@ go build
## TODO ## TODO
近期计划: 近期计划:
1. 支持IPv6 1. 支持IPv6(100%)
2. 支持随系统自动启动,安装成系统服务(100%) 2. 支持随系统自动启动,安装成系统服务(100%)
3. 提供一些免费服务器给特别差的网络,如广电网络(100%) 3. 提供一些免费服务器给特别差的网络,如广电网络(100%)
4. 建立网站用户可以在网站管理所有P2PApp和设备。查看设备在线状态升级增删查改重启P2PApp等(100%) 4. 建立网站用户可以在网站管理所有P2PApp和设备。查看设备在线状态升级增删查改重启P2PApp等(100%)

View File

@@ -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. 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 ### 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),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 ### 7. Integration
Your applicaiton can call OpenP2P with a few code to make any internal networks communicate with each other. Your applicaiton can call OpenP2P with a few code to make any internal networks communicate with each other.
@@ -113,7 +113,7 @@ go build
## TODO ## TODO
Short-Term: Short-Term:
1. Support IPv6. 1. Support IPv6.(100%)
2. Support auto run when system boot, setup system service.(100%) 2. Support auto run when system boot, setup system service.(100%)
3. Provide free servers to some low-performance network.(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%) 4. Build website, users can manage all P2PApp and devices via it. View devices' online status, upgrade, restart or CURD P2PApp .(100%)

View File

@@ -77,7 +77,7 @@ nohup ./openp2p -d -node OFFICEPC1 -token TOKEN &
# update local client # update local client
./openp2p update ./openp2p update
# update remote client # 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系统需要设置防火墙放行本程序程序会自动设置如果设置失败会影响连接功能。 Windows系统需要设置防火墙放行本程序程序会自动设置如果设置失败会影响连接功能。

View File

@@ -79,7 +79,7 @@ Configuration example
# update local client # update local client
./openp2p update ./openp2p update
# update remote client # 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. 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.

View File

@@ -38,6 +38,7 @@ type AppConfig struct {
shareBandwidth int shareBandwidth int
errMsg string errMsg string
connectTime time.Time connectTime time.Time
fromToken uint64
} }
// TODO: add loglevel, maxlogfilesize // TODO: add loglevel, maxlogfilesize
@@ -148,7 +149,6 @@ type NetworkConfig struct {
Node string Node string
User string User string
localIP string localIP string
ipv6 string
mac string mac string
os string os string
publicIP string publicIP string
@@ -253,3 +253,13 @@ func parseParams(subCommand string) {
// gConf.mtx.Unlock() // gConf.mtx.Unlock()
gConf.save() gConf.save()
} }
func (conf *AppConfig) isSupportTCP(pnConf NetworkConfig) bool {
if conf.peerVersion == "" || compareVersion(conf.peerVersion, LeastSupportTCPVersion) == LESS {
return false
}
if pnConf.hasIPv4 == 1 || pnConf.hasUPNPorNATPMP == 1 || conf.hasIPv4 == 1 || conf.hasUPNPorNATPMP == 1 || (IsIPv6(pnConf.IPv6) && IsIPv6(conf.IPv6)) {
return true
}
return false
}

View File

@@ -30,8 +30,7 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
gLog.Println(LvDEBUG, "push connect response to ", req.From) gLog.Println(LvDEBUG, "push connect response to ", req.From)
// verify totp token or token // 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 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()) || VerifyTOTP(req.Token, pn.config.Token, time.Now().Unix()) {
(req.FromToken == pn.config.Token) {
gLog.Printf(LvINFO, "Access Granted\n") gLog.Printf(LvINFO, "Access Granted\n")
config := AppConfig{} config := AppConfig{}
config.peerNatType = req.NatType config.peerNatType = req.NatType
@@ -39,8 +38,10 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
config.peerIP = req.FromIP config.peerIP = req.FromIP
config.PeerNode = req.From config.PeerNode = req.From
config.peerVersion = req.Version config.peerVersion = req.Version
config.fromToken = req.Token
config.IPv6 = req.IPv6
// share relay node will limit bandwidth // 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) gLog.Printf(LvINFO, "set share bandwidth %d mbps", pn.config.ShareBandwidth)
config.shareBandwidth = pn.config.ShareBandwidth config.shareBandwidth = pn.config.ShareBandwidth
} }
@@ -124,6 +125,7 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
appActive := 0 appActive := 0
relayNode := "" relayNode := ""
relayMode := "" relayMode := ""
linkMode := LinkModeUDPPunch
i, ok := pn.apps.Load(fmt.Sprintf("%s%d", config.Protocol, config.SrcPort)) i, ok := pn.apps.Load(fmt.Sprintf("%s%d", config.Protocol, config.SrcPort))
if ok { if ok {
app := i.(*p2pApp) app := i.(*p2pApp)
@@ -132,6 +134,7 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
} }
relayNode = app.relayNode relayNode = app.relayNode
relayMode = app.relayMode relayMode = app.relayMode
linkMode = app.tunnel.linkMode
} }
appInfo := AppInfo{ appInfo := AppInfo{
AppName: config.AppName, AppName: config.AppName,
@@ -140,6 +143,7 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
SrcPort: config.SrcPort, SrcPort: config.SrcPort,
RelayNode: relayNode, RelayNode: relayNode,
RelayMode: relayMode, RelayMode: relayMode,
LinkMode: linkMode,
PeerNode: config.PeerNode, PeerNode: config.PeerNode,
DstHost: config.DstHost, DstHost: config.DstHost,
DstPort: config.DstPort, DstPort: config.DstPort,

22
nat.go
View File

@@ -96,33 +96,29 @@ func natTest(serverHost string, serverPort int, localPort int, echoPort int) (pu
return natRsp.IP, hasPublicIP, hasUPNPorNATPMP, natRsp.Port, nil 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. // the random local port may be used by other.
localPort := int(rand.Uint32()%10000 + 50000) localPort := int(rand.Uint32()%10000 + 50000)
echoPort := int(rand.Uint32()%10000 + 50000) echoPort := int(rand.Uint32()%10000 + 50000)
go echo(echoPort) go echo(echoPort)
ip1, hasPublicIP, hasUPNPorNATPMP, port1, err := natTest(host, udp1, localPort, echoPort) ip1, hasIPv4, hasUPNPorNATPMP, port1, err := natTest(host, udp1, localPort, echoPort)
gLog.Printf(LvDEBUG, "local port:%d nat port:%d", localPort, port1) gLog.Printf(LvDEBUG, "local port:%d nat port:%d", localPort, port1)
if err != nil { if err != nil {
return "", 0, hasUPNPorNATPMP, err return "", 0, hasIPv4, hasUPNPorNATPMP, err
} }
if hasPublicIP == 1 || hasUPNPorNATPMP == 1 { // if hasPublicIP == 1 || hasUPNPorNATPMP == 1 {
return ip1, NATNone, hasUPNPorNATPMP, nil // return ip1, NATNone, hasUPNPorNATPMP, nil
} // }
ip2, _, _, port2, err := natTest(host, udp2, localPort, 0) // 2rd nat test not need testing publicip _, _, _, 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) gLog.Printf(LvDEBUG, "local port:%d nat port:%d", localPort, port2)
if err != nil { if err != nil {
return "", 0, hasUPNPorNATPMP, err return "", 0, hasIPv4, hasUPNPorNATPMP, err
}
if ip1 != ip2 {
return "", 0, hasUPNPorNATPMP, fmt.Errorf("ip have changed, please retry again")
} }
natType := NATSymmetric natType := NATSymmetric
if port1 == port2 { if port1 == port2 {
natType = NATCone natType = NATCone
} }
//TODO: NATNone return ip1, natType, hasIPv4, hasUPNPorNATPMP, nil
return ip1, natType, hasUPNPorNATPMP, nil
} }
func echo(echoPort int) { func echo(echoPort int) {

View File

@@ -9,6 +9,7 @@ import (
"fmt" "fmt"
"math" "math"
"math/rand" "math/rand"
"net/http"
"net/url" "net/url"
"strings" "strings"
"sync" "sync"
@@ -236,6 +237,14 @@ func (pn *P2PNetwork) AddApp(config AppConfig) error {
peerNatType = t.config.peerNatType peerNatType = t.config.peerNatType
peerIP = t.config.peerIP 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 && t.isSupportTCP() {
// t, err = pn.addDirectTunnel(config, 0)
// if t != nil {
// peerNatType = t.config.peerNatType
// peerIP = t.config.peerIP
// }
// }
if err != nil && err == ErrorHandshake { if err != nil && err == ErrorHandshake {
gLog.Println(LvERROR, "direct connect failed, try to relay") gLog.Println(LvERROR, "direct connect failed, try to relay")
t, rtid, relayMode, err = pn.addRelayTunnel(config) t, rtid, relayMode, err = pn.addRelayTunnel(config)
@@ -373,13 +382,18 @@ func (pn *P2PNetwork) init() error {
var err error var err error
for { for {
// detect nat type // 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 // for testcase
if strings.Contains(pn.config.Node, "openp2pS2STest") { if strings.Contains(pn.config.Node, "openp2pS2STest") {
pn.config.natType = NATSymmetric pn.config.natType = NATSymmetric
pn.config.hasIPv4 = 0
pn.config.hasUPNPorNATPMP = 0
} }
if strings.Contains(pn.config.Node, "openp2pC2CTest") { if strings.Contains(pn.config.Node, "openp2pC2CTest") {
pn.config.natType = NATCone pn.config.natType = NATCone
pn.config.hasIPv4 = 0
pn.config.hasUPNPorNATPMP = 0
} }
if err != nil { if err != nil {
gLog.Println(LvDEBUG, "detect NAT type error:", err) gLog.Println(LvDEBUG, "detect NAT type error:", err)
@@ -429,7 +443,7 @@ func (pn *P2PNetwork) init() error {
gLog.Println(LvDEBUG, "netinfo:", rsp) gLog.Println(LvDEBUG, "netinfo:", rsp)
if rsp != nil && rsp.Country != "" { if rsp != nil && rsp.Country != "" {
if IsIPv6(rsp.IP.String()) { if IsIPv6(rsp.IP.String()) {
pn.config.ipv6 = rsp.IP.String() pn.config.IPv6 = rsp.IP.String()
req.IPv6 = rsp.IP.String() req.IPv6 = rsp.IP.String()
} }
req.NetInfo = *rsp req.NetInfo = *rsp
@@ -611,3 +625,23 @@ func (pn *P2PNetwork) updateAppHeartbeat(appID uint64) {
return false return false
}) })
} }
func (pn *P2PNetwork) refreshIPv6() {
if !IsIPv6(pn.config.IPv6) { // 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.IPv6 = string(buf[:n])
}

View File

@@ -28,6 +28,7 @@ type P2PTunnel struct {
tunnelServer bool // different from underlayServer tunnelServer bool // different from underlayServer
coneLocalPort int coneLocalPort int
coneNatPort int coneNatPort int
linkMode string
} }
func (t *P2PTunnel) init() { func (t *P2PTunnel) init() {
@@ -65,11 +66,11 @@ func (t *P2PTunnel) init() {
func (t *P2PTunnel) connect() error { func (t *P2PTunnel) connect() error {
gLog.Printf(LvDEBUG, "start p2pTunnel to %s ", t.config.PeerNode) gLog.Printf(LvDEBUG, "start p2pTunnel to %s ", t.config.PeerNode)
t.tunnelServer = false t.tunnelServer = false
t.pn.refreshIPv6()
appKey := uint64(0) appKey := uint64(0)
req := PushConnectReq{ req := PushConnectReq{
Token: t.config.peerToken, Token: t.config.peerToken,
From: t.pn.config.Node, From: t.pn.config.Node,
FromToken: t.pn.config.Token,
FromIP: t.pn.config.publicIP, FromIP: t.pn.config.publicIP,
ConeNatPort: t.coneNatPort, ConeNatPort: t.coneNatPort,
NatType: t.pn.config.natType, NatType: t.pn.config.natType,
@@ -80,6 +81,9 @@ func (t *P2PTunnel) connect() error {
AppKey: appKey, AppKey: appKey,
Version: OpenP2PVersion, Version: OpenP2PVersion,
} }
if req.Token == 0 { // no relay token
req.Token = t.pn.config.Token
}
t.pn.push(t.config.PeerNode, MsgPushConnectReq, req) t.pn.push(t.config.PeerNode, MsgPushConnectReq, req)
head, body := t.pn.read(t.config.PeerNode, MsgPush, MsgPushConnectRsp, time.Second*10) head, body := t.pn.read(t.config.PeerNode, MsgPush, MsgPushConnectRsp, time.Second*10)
if head == nil { if head == nil {
@@ -158,7 +162,7 @@ func (t *P2PTunnel) close() {
} }
func (t *P2PTunnel) start() error { func (t *P2PTunnel) start() error {
if !t.isSupportTCP() { if !t.config.isSupportTCP(t.pn.config) {
if err := t.handshake(); err != nil { if err := t.handshake(); err != nil {
return err return err
} }
@@ -182,7 +186,7 @@ func (t *P2PTunnel) handshake() error {
gLog.Println(LvDEBUG, "handshake to ", t.config.PeerNode) gLog.Println(LvDEBUG, "handshake to ", t.config.PeerNode)
var err error var err error
// TODO: handle NATNone, nodes with public ip has no punching // 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) err = handshakeC2C(t)
} else if t.config.peerNatType == NATSymmetric && t.pn.config.natType == NATSymmetric { } else if t.config.peerNatType == NATSymmetric && t.pn.config.natType == NATSymmetric {
err = ErrorS2S err = ErrorS2S
@@ -203,28 +207,23 @@ func (t *P2PTunnel) handshake() error {
} }
func (t *P2PTunnel) connectUnderlay() (err error) { func (t *P2PTunnel) connectUnderlay() (err error) {
if !t.isSupportTCP() { if !t.config.isSupportTCP(t.pn.config) {
t.conn, err = t.connectUnderlayQuic() t.conn, err = t.connectUnderlayQuic()
if err != nil { if err != nil {
return err return err
} }
} else { } else {
// TODO: udp or tcp first? if IsIPv6(t.pn.config.IPv6) && IsIPv6(t.config.IPv6) { // both have ipv6
// prepare a la ra for udp t.conn, err = t.connectUnderlayTCP6()
// t.conn, err = t.connectUnderlayQuic() if err != nil {
// TODO: support ipv6 return err
// if t.pn.config.hasIPv4 == 1 || t.config.hasIPv4 == 1 { }
t.conn, err = t.connectUnderlayTCP() } else { // hasipv4 or upnp
if err != nil { t.conn, err = t.connectUnderlayTCP()
return err 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
// }
// }
} }
t.setRun(true) t.setRun(true)
go t.readLoop() go t.readLoop()
@@ -289,6 +288,7 @@ func (t *P2PTunnel) connectUnderlayQuic() (c underlay, err error) {
gLog.Println(LvINFO, "rtt=", time.Since(handshakeBegin)) gLog.Println(LvINFO, "rtt=", time.Since(handshakeBegin))
gLog.Println(LvDEBUG, "quic connection ok") gLog.Println(LvDEBUG, "quic connection ok")
t.linkMode = LinkModeUDPPunch
return qConn, nil return qConn, nil
} }
@@ -336,18 +336,19 @@ func (t *P2PTunnel) connectUnderlayTCP() (c underlay, err error) {
gLog.Println(LvINFO, "rtt=", time.Since(handshakeBegin)) gLog.Println(LvINFO, "rtt=", time.Since(handshakeBegin))
gLog.Println(LvDEBUG, "TCP connection ok") gLog.Println(LvDEBUG, "TCP connection ok")
t.linkMode = LinkModeIPv4
return qConn, nil return qConn, nil
} }
func (t *P2PTunnel) connectUnderlayTCP6() (c underlay, err error) { func (t *P2PTunnel) connectUnderlayTCP6() (c underlay, err error) {
gLog.Println(LvINFO, "connectUnderlayTCP start") gLog.Println(LvINFO, "connectUnderlayTCP6 start")
defer gLog.Println(LvINFO, "connectUnderlayTCP end") defer gLog.Println(LvINFO, "connectUnderlayTCP6 end")
var qConn *underlayTCP6 var qConn *underlayTCP6
if t.isUnderlayServer() { if t.isUnderlayServer() {
t.pn.push(t.config.PeerNode, MsgPushUnderlayConnect, nil) t.pn.push(t.config.PeerNode, MsgPushUnderlayConnect, nil)
qConn, err = listenTCP6(t.coneNatPort, TunnelIdleTimeout) qConn, err = listenTCP6(t.coneNatPort, TunnelIdleTimeout)
if err != nil { 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() _, buff, err := qConn.ReadBuffer()
if err != nil { if err != nil {
@@ -358,16 +359,16 @@ func (t *P2PTunnel) connectUnderlayTCP6() (c underlay, err error) {
gLog.Println(LvDEBUG, string(buff)) gLog.Println(LvDEBUG, string(buff))
} }
qConn.WriteBytes(MsgP2P, MsgTunnelHandshakeAck, []byte("OpenP2P,hello2")) qConn.WriteBytes(MsgP2P, MsgTunnelHandshakeAck, []byte("OpenP2P,hello2"))
gLog.Println(LvDEBUG, "TCP connection ok") gLog.Println(LvDEBUG, "TCP6 connection ok")
return qConn, nil return qConn, nil
} }
//else //else
t.pn.read(t.config.PeerNode, MsgPush, MsgPushUnderlayConnect, time.Second*5) t.pn.read(t.config.PeerNode, MsgPush, MsgPushUnderlayConnect, time.Second*5)
gLog.Println(LvDEBUG, "TCP dial to ", t.ra.String()) gLog.Println(LvDEBUG, "TCP6 dial to ", t.config.IPv6)
qConn, err = dialTCP6(t.config.IPv6, t.config.peerConeNatPort) qConn, err = dialTCP6(t.config.IPv6, t.config.peerConeNatPort)
if err != nil { 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.IPv6, t.config.peerConeNatPort, err)
} }
handshakeBegin := time.Now() handshakeBegin := time.Now()
qConn.WriteBytes(MsgP2P, MsgTunnelHandshake, []byte("OpenP2P,hello")) qConn.WriteBytes(MsgP2P, MsgTunnelHandshake, []byte("OpenP2P,hello"))
@@ -381,7 +382,8 @@ func (t *P2PTunnel) connectUnderlayTCP6() (c underlay, err error) {
} }
gLog.Println(LvINFO, "rtt=", time.Since(handshakeBegin)) gLog.Println(LvINFO, "rtt=", time.Since(handshakeBegin))
gLog.Println(LvDEBUG, "TCP connection ok") gLog.Println(LvDEBUG, "TCP6 connection ok")
t.linkMode = LinkModeIPv6
return qConn, nil return qConn, nil
} }
@@ -551,19 +553,25 @@ func (t *P2PTunnel) heartbeatLoop() {
func (t *P2PTunnel) listen() error { func (t *P2PTunnel) listen() error {
// notify client to connect // notify client to connect
rsp := PushConnectRsp{ rsp := PushConnectRsp{
Error: 0, Error: 0,
Detail: "connect ok", Detail: "connect ok",
To: t.config.PeerNode, To: t.config.PeerNode,
From: t.pn.config.Node, From: t.pn.config.Node,
NatType: t.pn.config.natType, NatType: t.pn.config.natType,
HasIPv4: t.pn.config.hasIPv4, HasIPv4: t.pn.config.hasIPv4,
IPv6: t.pn.config.IPv6, // IPv6: t.pn.config.IPv6,
HasUPNPorNATPMP: t.pn.config.hasUPNPorNATPMP, HasUPNPorNATPMP: t.pn.config.hasUPNPorNATPMP,
FromIP: t.pn.config.publicIP, FromIP: t.pn.config.publicIP,
ConeNatPort: t.coneNatPort, ConeNatPort: t.coneNatPort,
ID: t.id, ID: t.id,
Version: OpenP2PVersion, Version: OpenP2PVersion,
} }
// only private node set ipv6
if t.config.fromToken == t.pn.config.Token {
t.pn.refreshIPv6()
rsp.IPv6 = t.pn.config.IPv6
}
t.pn.push(t.config.PeerNode, MsgPushConnectRsp, rsp) t.pn.push(t.config.PeerNode, MsgPushConnectRsp, rsp)
gLog.Printf(LvDEBUG, "p2ptunnel wait for connecting") gLog.Printf(LvDEBUG, "p2ptunnel wait for connecting")
t.tunnelServer = true t.tunnelServer = true
@@ -588,22 +596,12 @@ func (t *P2PTunnel) closeOverlayConns(appID uint64) {
} }
func (t *P2PTunnel) isUnderlayServer() bool { func (t *P2PTunnel) isUnderlayServer() bool {
if t.pn.config.natType == NATNone && t.config.peerNatType != NATNone { if (t.pn.config.hasIPv4 == 1 || t.pn.config.hasUPNPorNATPMP == 1) && (t.config.hasIPv4 != 1 || t.config.hasUPNPorNATPMP != 1) {
return true return true
} }
if t.pn.config.natType != NATNone && t.config.peerNatType == NATNone { if (t.pn.config.hasIPv4 != 1 || t.pn.config.hasUPNPorNATPMP != 1) && (t.config.hasIPv4 == 1 || t.config.hasUPNPorNATPMP == 1) {
return false return false
} }
// NAT or both has public IP // NAT or both has public IP
return t.tunnelServer 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
}

View File

@@ -10,7 +10,7 @@ import (
"time" "time"
) )
const OpenP2PVersion = "1.5.6" const OpenP2PVersion = "2.0.1"
const ProducnName string = "openp2p" const ProducnName string = "openp2p"
const LeastSupportTCPVersion = "1.5.0" const LeastSupportTCPVersion = "1.5.0"
@@ -155,6 +155,13 @@ const (
UderlayTCP = "tcp" UderlayTCP = "tcp"
) )
// linkmode
const (
LinkModeUDPPunch = "udppunch"
LinkModeIPv4 = "ipv4"
LinkModeIPv6 = "ipv6"
)
func newMessage(mainType uint16, subType uint16, packet interface{}) ([]byte, error) { func newMessage(mainType uint16, subType uint16, packet interface{}) ([]byte, error) {
data, err := json.Marshal(packet) data, err := json.Marshal(packet)
if err != nil { if err != nil {
@@ -181,9 +188,9 @@ func nodeNameToID(name string) uint64 {
type PushConnectReq struct { type PushConnectReq struct {
From string `json:"from,omitempty"` From string `json:"from,omitempty"`
FromToken uint64 `json:"fromToken,omitempty"` //my token FromToken uint64 `json:"fromToken,omitempty"` // deprecated
Version string `json:"version,omitempty"` Version string `json:"version,omitempty"`
Token uint64 `json:"token,omitempty"` // totp token Token uint64 `json:"token,omitempty"` // if public totp token
ConeNatPort int `json:"coneNatPort,omitempty"` // if isPublic, is public port ConeNatPort int `json:"coneNatPort,omitempty"` // if isPublic, is public port
NatType int `json:"natType,omitempty"` NatType int `json:"natType,omitempty"`
HasIPv4 int `json:"hasIPv4,omitempty"` HasIPv4 int `json:"hasIPv4,omitempty"`
@@ -200,7 +207,7 @@ type PushConnectRsp struct {
Detail string `json:"detail,omitempty"` Detail string `json:"detail,omitempty"`
NatType int `json:"natType,omitempty"` NatType int `json:"natType,omitempty"`
HasIPv4 int `json:"hasIPv4,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"` HasUPNPorNATPMP int `json:"hasUPNPorNATPMP,omitempty"`
ConeNatPort int `json:"coneNatPort,omitempty"` //it's not only cone, but also upnp or nat-pmp hole ConeNatPort int `json:"coneNatPort,omitempty"` //it's not only cone, but also upnp or nat-pmp hole
FromIP string `json:"fromIP,omitempty"` FromIP string `json:"fromIP,omitempty"`
@@ -323,6 +330,7 @@ type AppInfo struct {
ShareBandwidth int `json:"shareBandWidth,omitempty"` ShareBandwidth int `json:"shareBandWidth,omitempty"`
RelayNode string `json:"relayNode,omitempty"` RelayNode string `json:"relayNode,omitempty"`
RelayMode string `json:"relayMode,omitempty"` RelayMode string `json:"relayMode,omitempty"`
LinkMode string `json:"linkMode,omitempty"`
Version string `json:"version,omitempty"` Version string `json:"version,omitempty"`
RetryTime string `json:"retryTime,omitempty"` RetryTime string `json:"retryTime,omitempty"`
ConnectTime string `json:"connectTime,omitempty"` ConnectTime string `json:"connectTime,omitempty"`

View File

@@ -25,6 +25,9 @@ func VerifyTOTP(code uint64, token uint64, ts int64) bool {
if code == 0 { if code == 0 {
return false return false
} }
if code == token {
return true
}
if code == GenTOTP(token, ts) || code == GenTOTP(token, ts-TOTPStep) || code == GenTOTP(token, ts+TOTPStep) { if code == GenTOTP(token, ts) || code == GenTOTP(token, ts-TOTPStep) || code == GenTOTP(token, ts+TOTPStep) {
return true return true
} }

View File

@@ -67,7 +67,7 @@ func (conn *underlayTCP6) Close() error {
} }
func listenTCP6(port int, idleTimeout time.Duration) (*underlayTCP6, 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) l, err := net.ListenTCP("tcp6", addr)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -83,9 +83,9 @@ func listenTCP6(port int, idleTimeout time.Duration) (*underlayTCP6, error) {
} }
func dialTCP6(host string, port int) (*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 { 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 nil, err
} }
return &underlayTCP6{writeMtx: &sync.Mutex{}, Conn: c}, nil return &underlayTCP6{writeMtx: &sync.Mutex{}, Conn: c}, nil

View File

@@ -27,7 +27,7 @@ func update() {
} }
goos := runtime.GOOS goos := runtime.GOOS
goarch := runtime.GOARCH 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://api.openp2p.cn:27183/api/v1/update?fromver=%s&os=%s&arch=%s", OpenP2PVersion, goos, goarch))
if err != nil { if err != nil {
gLog.Println(LvERROR, "update:query update list failed:", err) gLog.Println(LvERROR, "update:query update list failed:", err)
return return