This commit is contained in:
TenderIronh
2026-04-01 15:33:30 +08:00
parent ef4bc1e1e3
commit 12393f00c5
23 changed files with 1047 additions and 383 deletions
+1
View File
@@ -25,3 +25,4 @@ openp2p
lib/openp2p.dll lib/openp2p.dll
cmd/config.json0 cmd/config.json0
test/docker/Dockerfile test/docker/Dockerfile
test/docker/get-client.sh
+20
View File
@@ -1,5 +1,25 @@
ChangeLog ChangeLog
v3.25.8更新 (2026.3.13)
Feature
1. web控制台可以修改公网监听端口
1. 可以修改虚拟网络网段
1. 回滚至go1.20因为需要支持老版本的macos和windows
Issue
1. 修复客户端重装后强制v6连接失效bug
v3.25.4更新 (2026.2.9)
Feature
1. 优化websocket读数据卡死问题
1. 优化睡眠唤醒客户端恢复慢问题
Issue
1. 修复获取ifconfig异常
1. 修复数据同步异常导致设备间连接失败
1. 修复底层连接潜在发送数据不完整问题
v3.24.33更新 (2025.12.10) v3.24.33更新 (2025.12.10)
Feature Feature
1. 安装和升级下载文件到临时目录 1. 安装和升级下载文件到临时目录
+14 -2
View File
@@ -138,8 +138,8 @@ func netInfo() *NetInfo {
defer r.Body.Close() defer r.Body.Close()
buf := make([]byte, 1024*64) buf := make([]byte, 1024*64)
n, err := r.Body.Read(buf) n, err := r.Body.Read(buf)
if err != nil { if err != nil && err != io.EOF {
gLog.d("netInfo error:%s", err) gLog.d("error reading response body: %s", err)
continue continue
} }
rsp := NetInfo{} rsp := NetInfo{}
@@ -391,3 +391,15 @@ func lookupWithCustomDNS(ctx context.Context, domain string) ([]string, error) {
return resolver.LookupHost(ctx, domain) return resolver.LookupHost(ctx, domain)
} }
func writeFull(w io.Writer, data []byte) error {
totalWritten := 0
for totalWritten < len(data) {
n, err := w.Write(data[totalWritten:])
if err != nil {
return fmt.Errorf("write failed after %d bytes: %w", totalWritten, err)
}
totalWritten += n
}
return nil
}
+10
View File
@@ -199,6 +199,11 @@ func (c *Config) retryAllMemApp() {
if app.config.SrcPort != 0 { if app.config.SrcPort != 0 {
return true return true
} }
if app.tunnelNum != int(gConf.sdwan.TunnelNum) {
gLog.d("memapp %s tunnelNum changed from %d to %d, delete it and not retry", app.config.LogPeerNode(), app.tunnelNum, gConf.sdwan.TunnelNum)
GNetwork.DeleteApp(app.config)
return true
}
app.Retry(true) app.Retry(true)
return true return true
}) })
@@ -333,6 +338,11 @@ func (c *Config) setNode(node string) {
c.Network.Node = node c.Network.Node = node
c.Network.nodeID = NodeNameToID(c.Network.Node) c.Network.nodeID = NodeNameToID(c.Network.Node)
} }
func (c *Config) setForcev6(force bool) {
c.mtx.Lock()
defer c.mtx.Unlock()
c.Forcev6 = force
}
func (c *Config) nodeID() uint64 { func (c *Config) nodeID() uint64 {
c.mtx.Lock() c.mtx.Lock()
defer c.mtx.Unlock() defer c.mtx.Unlock()
+20 -15
View File
@@ -51,7 +51,7 @@ func handlePush(subType uint16, msg []byte) error {
config.PunchPriority = req.PunchPriority config.PunchPriority = req.PunchPriority
config.UnderlayProtocol = req.UnderlayProtocol config.UnderlayProtocol = req.UnderlayProtocol
go func(r AddRelayTunnelReq) { go func(r AddRelayTunnelReq) {
t, errDt := GNetwork.addDirectTunnel(config, 0) t, errDt := GNetwork.addDirectTunnel(config, 0, nil)
if errDt == nil && t != nil { if errDt == nil && t != nil {
// notify peer relay ready // notify peer relay ready
msg := TunnelMsg{ID: t.id} msg := TunnelMsg{ID: t.id}
@@ -90,18 +90,24 @@ func handlePush(subType uint16, msg []byte) error {
appIdx = req.AppID appIdx = req.AppID
} }
existApp, appok := GNetwork.apps.Load(appIdx) existApp, appok := GNetwork.apps.Load(appIdx)
var app *p2pApp
if appok { if appok {
app := existApp.(*p2pApp) app = existApp.(*p2pApp)
if app.tunnelNum != int(req.TunnelNum) {
gLog.d("memapp tunnelNum changed from %d to %d", app.tunnelNum, req.TunnelNum)
GNetwork.DeleteApp(app.config)
app = nil
}
}
if app != nil {
app.config.AppName = fmt.Sprintf("%d", peerID) app.config.AppName = fmt.Sprintf("%d", peerID)
app.id = req.AppID app.id = req.AppID
app.key = req.AppKey app.key = req.AppKey
app.PreCalcKeyBytes() app.PreCalcKeyBytes()
app.relayMode[req.RelayIndex] = req.RelayMode app.relayMode[req.RelayIndex] = req.RelayMode
app.hbTime[req.RelayIndex] = time.Now() app.hbTime[req.RelayIndex] = time.Now()
if req.RelayTunnelID == 0 { app.SetTunnel(existTunnel, int(req.RelayIndex))
app.SetTunnel(existTunnel, 0) if req.RelayTunnelID != 0 {
} else {
app.SetTunnel(existTunnel, int(req.RelayIndex)) // TODO: merge two func
app.SetRelayTunnelID(req.RelayTunnelID, int(req.RelayIndex)) // direct tunnel rtid=0, no need set rtid app.SetRelayTunnelID(req.RelayTunnelID, int(req.RelayIndex)) // direct tunnel rtid=0, no need set rtid
} }
gLog.d("found existing memapp, update it") gLog.d("found existing memapp, update it")
@@ -111,7 +117,7 @@ func handlePush(subType uint16, msg []byte) error {
appConfig.Protocol = "" appConfig.Protocol = ""
appConfig.AppName = fmt.Sprintf("%d", peerID) appConfig.AppName = fmt.Sprintf("%d", peerID)
appConfig.PeerNode = req.From appConfig.PeerNode = req.From
app := p2pApp{ app = &p2pApp{
id: req.AppID, id: req.AppID,
config: appConfig, config: appConfig,
running: true, running: true,
@@ -126,17 +132,13 @@ func handlePush(subType uint16, msg []byte) error {
app.Init(tunnelNum) app.Init(tunnelNum)
app.relayMode[req.RelayIndex] = req.RelayMode app.relayMode[req.RelayIndex] = req.RelayMode
app.hbTime[req.RelayIndex] = time.Now() app.hbTime[req.RelayIndex] = time.Now()
if req.RelayTunnelID == 0 { app.SetTunnel(existTunnel, int(req.RelayIndex))
app.SetTunnel(existTunnel, 0)
} else {
app.SetTunnel(existTunnel, int(req.RelayIndex))
app.SetRelayTunnelID(req.RelayTunnelID, int(req.RelayIndex))
}
if req.RelayTunnelID != 0 { if req.RelayTunnelID != 0 {
app.SetRelayTunnelID(req.RelayTunnelID, int(req.RelayIndex))
app.relayNode[req.RelayIndex] = req.Node app.relayNode[req.RelayIndex] = req.Node
} }
app.Start(false) app.Start(false)
GNetwork.apps.Store(appIdx, &app) GNetwork.apps.Store(appIdx, app)
gLog.d("store memapp %d %d", appIdx, req.SrcPort) gLog.d("store memapp %d %d", appIdx, req.SrcPort)
} }
@@ -175,6 +177,9 @@ func handlePush(subType uint16, msg []byte) error {
} }
gConf.setNode(req.NewName) gConf.setNode(req.NewName)
gConf.setShareBandwidth(req.Bandwidth) gConf.setShareBandwidth(req.Bandwidth)
if req.PublicIPPort != 0 {
gConf.Network.PublicIPPort = req.PublicIPPort
}
gConf.Forcev6 = (req.Forcev6 != 0) gConf.Forcev6 = (req.Forcev6 != 0)
gLog.i("set forcev6 to %v", gConf.Forcev6) gLog.i("set forcev6 to %v", gConf.Forcev6)
gConf.save() gConf.save()
@@ -341,7 +346,7 @@ func handleConnectReq(msg []byte) (err error) {
} }
// go GNetwork.AddTunnel(config, req.ID) // go GNetwork.AddTunnel(config, req.ID)
go func() { go func() {
GNetwork.addDirectTunnel(config, req.ID) GNetwork.addDirectTunnel(config, req.ID, nil)
}() }()
return nil return nil
} }
+8 -6
View File
@@ -9,6 +9,8 @@ import (
"strings" "strings"
"time" "time"
upnp "openp2p/pkg/upnp"
reuse "github.com/openp2p-cn/go-reuseport" reuse "github.com/openp2p-cn/go-reuseport"
) )
@@ -190,23 +192,23 @@ func publicIPTest(publicIP string, echoPort int) (hasPublicIP int, hasUPNPorNATP
} }
func setUPNP(echoPort int) { func setUPNP(echoPort int) {
nat, err := Discover() nat := upnp.Any() // Initialize the NAT interface
if err != nil || nat == nil { if nat == nil {
gLog.d("could not perform UPNP discover:%s", err) gLog.d("NAT interface is not available")
return return
} }
ext, err := nat.GetExternalAddress() ext, err := nat.ExternalIP()
if err != nil { if err != nil {
gLog.d("could not perform UPNP external address:%s", err) gLog.d("could not perform UPNP external address:%s", err)
return return
} }
gLog.i("PublicIP:%v", ext) gLog.i("PublicIP:%v", ext)
externalPort, err := nat.AddPortMapping("udp", echoPort, echoPort, "openp2p", 604800) externalPort, err := nat.AddMapping("udp", echoPort, echoPort, "openp2p", 604800)
if err != nil { if err != nil {
gLog.d("could not add udp UPNP port mapping %d", externalPort) gLog.d("could not add udp UPNP port mapping %d", externalPort)
return return
} else { } else {
nat.AddPortMapping("tcp", echoPort, echoPort, "openp2p", 604800) nat.AddMapping("tcp", echoPort, echoPort, "openp2p", 604800)
} }
} }
+13 -17
View File
@@ -8,8 +8,6 @@ import (
"fmt" "fmt"
"net" "net"
"os" "os"
"os/exec"
"strings"
"github.com/openp2p-cn/wireguard-go/tun" "github.com/openp2p-cn/wireguard-go/tun"
"github.com/vishvananda/netlink" "github.com/vishvananda/netlink"
@@ -116,26 +114,24 @@ func delRoute(dst, gw string) error {
} }
func delRoutesByGateway(gateway string) error { func delRoutesByGateway(gateway string) error {
cmd := exec.Command("route", "-n") ipGW := net.ParseIP(gateway)
output, err := cmd.Output() if ipGW == nil {
if err != nil { return fmt.Errorf("invalid gateway IP: %s", gateway)
return err
} }
lines := strings.Split(string(output), "\n") routes, err := netlink.RouteList(nil, netlink.FAMILY_V4)
for _, line := range lines { if err != nil {
if !strings.Contains(line, gateway) { return fmt.Errorf("failed to list routes: %v", err)
continue }
}
fields := strings.Fields(line) for _, route := range routes {
if len(fields) >= 8 && fields[1] == "0.0.0.0" && fields[7] == gateway { if route.Gw != nil && route.Gw.Equal(ipGW) || (route.Dst != nil && route.Dst.IP.Equal(ipGW)) {
delCmd := exec.Command("route", "del", "-net", fields[0], "gw", gateway) err := netlink.RouteDel(&route)
err := delCmd.Run()
if err != nil { if err != nil {
gLog.e("Delete route %s error:%s", fields[0], err) gLog.e("Failed to delete route: %v, error: %v", route, err)
continue continue
} }
gLog.i("Delete route ok: %s %s %s\n", fields[0], fields[1], gateway) gLog.i("Deleted route: %v", route)
} }
} }
return nil return nil
+2 -1
View File
@@ -141,7 +141,8 @@ func (oConn *overlayConn) Write(buff []byte) (n int, err error) {
return return
} }
if oConn.connTCP != nil { if oConn.connTCP != nil {
n, err = oConn.connTCP.Write(buff) err = writeFull(oConn.connTCP, buff)
n = len(buff)
} }
if err != nil { if err != nil {
+99 -68
View File
@@ -42,6 +42,7 @@ type p2pApp struct {
msgChan chan appMsgCtx msgChan chan appMsgCtx
once sync.Once once sync.Once
tunnelNum int tunnelNum int
relayIdxStart int
allTunnels []*P2PTunnel allTunnels []*P2PTunnel
retryNum []int retryNum []int
retryTime []time.Time retryTime []time.Time
@@ -106,7 +107,7 @@ func (app *p2pApp) RetryTime() time.Time {
if app.allTunnels[0] != nil { if app.allTunnels[0] != nil {
return app.config.retryTime return app.config.retryTime
} }
return app.retryTime[1] return app.retryTime[app.relayIdxStart]
} }
func (app *p2pApp) Init(tunnelNum int) { func (app *p2pApp) Init(tunnelNum int) {
@@ -133,6 +134,10 @@ func (app *p2pApp) Init(tunnelNum int) {
for i := 0; i < tunnelNum; i++ { for i := 0; i < tunnelNum; i++ {
app.hbTime[i] = time.Now() app.hbTime[i] = time.Now()
} }
app.relayIdxStart = app.tunnelNum - 2
if app.relayIdxStart == 0 {
app.relayIdxStart = 1 // at least one direct tunnel
}
// app.unAckSeqStart.Store(0) // app.unAckSeqStart.Store(0)
// app.mergeAckTs.Store(0) // app.mergeAckTs.Store(0)
// for i := 0; i < relayNum; i++ { // for i := 0; i < relayNum; i++ {
@@ -152,64 +157,72 @@ func (app *p2pApp) Start(isClient bool) {
func (app *p2pApp) daemonP2PTunnel() error { func (app *p2pApp) daemonP2PTunnel() error {
for app.running { for app.running {
app.daemonDirectTunnel()
if app.config.peerIP == gConf.Network.publicIP {
time.Sleep(time.Second * 10) // if peerIP is local IP, delay relay tunnel
}
for i := 1; i < app.tunnelNum; i++ {
app.daemonRelayTunnel(i)
}
for i := 0; i < app.relayIdxStart; i++ {
app.daemonDirectTunnel(i)
time.Sleep(time.Second)
}
for i := app.relayIdxStart; i < app.tunnelNum; i++ {
if i > app.relayIdxStart {
app.nextRetryTime[i] = time.Now().Add(time.Second * 180) // the second relay tunnel wait 3 mins
}
app.daemonRelayTunnel(i)
time.Sleep(time.Second)
}
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
} }
return nil return nil
} }
func (app *p2pApp) daemonDirectTunnel() error { func (app *p2pApp) daemonDirectTunnel(idx int) error {
if !GNetwork.online { if !GNetwork.online {
return nil return nil
} }
if app.config.ForceRelay == 1 && app.config.RelayNode != app.config.PeerNode { if app.config.ForceRelay == 1 && app.config.RelayNode != app.config.PeerNode {
return nil return nil
} }
if app.Tunnel(0) != nil && app.Tunnel(0).isActive() { // TODO: multi direct tunnel support symmetric NAT traversal later
if idx > 0 && gConf.Network.hasIPv4 == 0 && gConf.Network.hasUPNPorNATPMP == 0 && app.config.hasIPv4 == 0 && app.config.hasUPNPorNATPMP == 0 && (gConf.Network.natType == NATSymmetric || app.config.peerNatType == NATSymmetric) {
return nil
}
if app.Tunnel(idx) != nil && app.Tunnel(idx).isActive() {
return nil return nil
} }
if app.config.nextRetryTime.After(time.Now()) || app.config.Enabled == 0 { if app.config.nextRetryTime.After(time.Now()) || app.config.Enabled == 0 {
return nil return nil
} }
if time.Now().Add(-time.Minute * 15).After(app.config.retryTime) { // run normally 15min, reset retrynum if time.Now().Add(-time.Minute * 15).After(app.config.retryTime) { // run normally 15min, reset retrynum
app.config.retryNum = 1 app.retryNum[idx] = 1
} }
if app.config.retryNum > 0 { // first time not show reconnect log if app.retryNum[idx] > 0 { // first time not show reconnect log
gLog.i("appid:%d checkDirectTunnel detect peer %s disconnect, reconnecting the %d times...", app.id, app.config.LogPeerNode(), app.config.retryNum) gLog.i("appid:%d checkDirectTunnel detect peer %s disconnect, reconnecting the %d times...", app.id, app.config.LogPeerNode(), app.retryNum[idx])
} }
app.config.retryNum++ app.retryNum[idx]++
app.config.retryTime = time.Now() app.config.retryTime = time.Now()
app.config.connectTime = time.Now() app.config.connectTime = time.Now()
err := app.buildDirectTunnel() err := app.buildDirectTunnel(idx)
if err != nil { if err != nil {
app.config.errMsg = err.Error() app.config.errMsg = err.Error()
if err == ErrPeerOffline && app.config.retryNum > 2 { // stop retry, waiting for online if err == ErrPeerOffline && app.retryNum[idx] > 2 { // stop retry, waiting for online
app.config.retryNum = retryLimit app.retryNum[idx] = retryLimit
gLog.i("appid:%d checkDirectTunnel %s offline, it will auto reconnect when peer node online", app.id, app.config.LogPeerNode()) gLog.i("appid:%d checkDirectTunnel %s offline, it will auto reconnect when peer node online", app.id, app.config.LogPeerNode())
} }
if err == ErrBuildTunnelBusy { if err == ErrBuildTunnelBusy {
app.config.retryNum-- app.retryNum[idx]--
} }
} }
interval := calcRetryTimeRelay(float64(app.config.retryNum)) interval := calcRetryTimeRelay(float64(app.retryNum[idx]))
if app.preDirectSuccessIP == app.config.peerIP { if app.preDirectSuccessIP == app.config.peerIP {
interval = math.Min(interval, 1800) // if peerIP has been direct link succeed, retry 30min max interval = math.Min(interval, 1800) // if peerIP has been direct link succeed, retry 30min max
} }
app.config.nextRetryTime = time.Now().Add(time.Duration(interval) * time.Second) app.config.nextRetryTime = time.Now().Add(time.Duration(interval) * time.Second)
if app.Tunnel(0) != nil { if app.Tunnel(idx) != nil {
app.preDirectSuccessIP = app.config.peerIP app.preDirectSuccessIP = app.config.peerIP
app.once.Do(func() { app.once.Do(func() {
go app.listen() go app.listen()
// memapp also need // memapp also need
for i := 1; i < app.tunnelNum; i++ { for i := app.relayIdxStart; i < app.tunnelNum; i++ {
go app.relayHeartbeatLoop(i) go app.relayHeartbeatLoop(i)
} }
@@ -217,7 +230,7 @@ func (app *p2pApp) daemonDirectTunnel() error {
} }
return nil return nil
} }
func (app *p2pApp) buildDirectTunnel() error { func (app *p2pApp) buildDirectTunnel(idx int) error {
relayNode := "" relayNode := ""
peerNatType := NATUnknown peerNatType := NATUnknown
peerIP := "" peerIP := ""
@@ -225,12 +238,13 @@ func (app *p2pApp) buildDirectTunnel() error {
var t *P2PTunnel var t *P2PTunnel
var err error var err error
pn := GNetwork pn := GNetwork
// TODO: optimize requestPeerInfo call frequency
initErr := pn.requestPeerInfo(&app.config) initErr := pn.requestPeerInfo(&app.config)
if initErr != nil { if initErr != nil {
gLog.w("appid:%d buildDirectTunnel %s requestPeerInfo error:%s", app.id, app.config.LogPeerNode(), initErr) gLog.w("appid:%d buildDirectTunnel %s requestPeerInfo error:%s", app.id, app.config.LogPeerNode(), initErr)
return initErr return initErr
} }
t, err = pn.addDirectTunnel(app.config, 0) t, err = pn.addDirectTunnel(app.config, 0, app.Tunnel(idx^1))
if t != nil { if t != nil {
peerNatType = t.config.peerNatType peerNatType = t.config.peerNatType
peerIP = t.config.peerIP peerIP = t.config.peerIP
@@ -267,11 +281,11 @@ func (app *p2pApp) buildDirectTunnel() error {
} }
gLog.d("appid:%d buildDirectTunnel sync appkey to %s", app.id, app.config.LogPeerNode()) gLog.d("appid:%d buildDirectTunnel sync appkey to %s", app.id, app.config.LogPeerNode())
pn.push(app.config.PeerNode, MsgPushAPPKey, &syncKeyReq) pn.push(app.config.PeerNode, MsgPushAPPKey, &syncKeyReq)
app.SetTunnel(t, 0) app.SetTunnel(t, idx)
// if memapp notify peer addmemapp // if memapp notify peer addmemapp
// if app.config.SrcPort == 0 { // if app.config.SrcPort == 0 {
req2 := ServerSideSaveMemApp{From: gConf.Network.Node, Node: gConf.Network.Node, TunnelID: t.id, RelayTunnelID: 0, TunnelNum: uint32(app.tunnelNum), AppID: app.id, AppKey: app.key, SrcPort: uint32(app.config.SrcPort)} req2 := ServerSideSaveMemApp{From: gConf.Network.Node, Node: gConf.Network.Node, TunnelID: t.id, RelayTunnelID: 0, RelayIndex: uint32(idx), TunnelNum: uint32(app.tunnelNum), AppID: app.id, AppKey: app.key, SrcPort: uint32(app.config.SrcPort)}
pn.push(app.config.PeerNode, MsgPushServerSideSaveMemApp, &req2) pn.push(app.config.PeerNode, MsgPushServerSideSaveMemApp, &req2)
gLog.d("appid:%d buildDirectTunnel push %s ServerSideSaveMemApp: %s", app.id, app.config.LogPeerNode(), prettyJson(req2)) gLog.d("appid:%d buildDirectTunnel push %s ServerSideSaveMemApp: %s", app.id, app.config.LogPeerNode(), prettyJson(req2))
@@ -284,14 +298,15 @@ func (app *p2pApp) daemonRelayTunnel(idx int) error {
if !GNetwork.online { if !GNetwork.online {
return nil return nil
} }
if app.Tunnel(0) != nil && app.Tunnel(0).linkModeWeb == LinkModeIntranet { // in the same Lan, no relay
if app.Tunnel(0) != nil && app.relayIdxStart >= 2 { // multi direct tunnel no relay
return nil return nil
} }
// if app.config.ForceRelay == 1 && (gConf.sdwan.CentralNode == app.config.PeerNode && compareVersion(app.config.peerVersion, SupportDualTunnelVersion) < 0) { // if app.config.ForceRelay == 1 && (gConf.sdwan.CentralNode == app.config.PeerNode && compareVersion(app.config.peerVersion, SupportDualTunnelVersion) < 0) {
if app.config.SrcPort == 0 && (gConf.sdwan.CentralNode == app.config.PeerNode || gConf.sdwan.CentralNode == gConf.Network.Node) { // memapp central node not build relay tunnel if app.config.SrcPort == 0 && (gConf.sdwan.CentralNode == app.config.PeerNode || gConf.sdwan.CentralNode == gConf.Network.Node) { // memapp central node not build relay tunnel
return nil return nil
} }
if gConf.sdwan.CentralNode != "" && idx > 1 { // if central node exist only need one relayTunnel if gConf.sdwan.CentralNode != "" && idx != app.relayIdxStart { // if central node exist only need one relayTunnel
return nil return nil
} }
app.hbMtx.Lock() app.hbMtx.Lock()
@@ -352,9 +367,12 @@ func (app *p2pApp) buildRelayTunnel(idx int) error {
return initErr return initErr
} }
ExcludeNodes := "" ExcludeNodes := ""
kk := 1 + ((idx - 1) ^ 1) theOtherTunnelIdx := app.relayIdxStart
if app.tunnelNum > 2 && app.allTunnels[kk] != nil { if idx == app.relayIdxStart {
ExcludeNodes = app.allTunnels[1+((idx-1)^1)].config.PeerNode theOtherTunnelIdx = app.relayIdxStart + 1
}
if app.tunnelNum > 2 && app.allTunnels[theOtherTunnelIdx] != nil {
ExcludeNodes = app.allTunnels[theOtherTunnelIdx].config.PeerNode
} }
t, rtid, relayMode, err = pn.addRelayTunnel(config, ExcludeNodes) t, rtid, relayMode, err = pn.addRelayTunnel(config, ExcludeNodes)
if t != nil { if t != nil {
@@ -364,24 +382,27 @@ func (app *p2pApp) buildRelayTunnel(idx int) error {
if err != nil { if err != nil {
errMsg = err.Error() errMsg = err.Error()
} }
req := ReportConnect{ if app.Tunnel(0) == nil {
Error: errMsg, req := ReportConnect{
Protocol: config.Protocol, Error: errMsg,
SrcPort: config.SrcPort, Protocol: config.Protocol,
NatType: gConf.Network.natType, SrcPort: config.SrcPort,
PeerNode: config.PeerNode, NatType: gConf.Network.natType,
DstPort: config.DstPort, PeerNode: config.PeerNode,
DstHost: config.DstHost, DstPort: config.DstPort,
PeerNatType: peerNatType, DstHost: config.DstHost,
PeerIP: peerIP, PeerNatType: peerNatType,
ShareBandwidth: gConf.Network.ShareBandwidth, PeerIP: peerIP,
RelayNode: relayNode, ShareBandwidth: gConf.Network.ShareBandwidth,
Version: OpenP2PVersion, RelayNode: relayNode,
Version: OpenP2PVersion,
}
pn.write(MsgReport, MsgReportConnect, &req)
} }
pn.write(MsgReport, MsgReportConnect, &req) if err != nil || t == nil {
if err != nil {
return err return err
} }
// if rtid != 0 || t.conn.Protocol() == "tcp" { // if rtid != 0 || t.conn.Protocol() == "tcp" {
// sync appkey // sync appkey
syncKeyReq := APPKeySync{ syncKeyReq := APPKeySync{
@@ -446,31 +467,40 @@ func (app *p2pApp) IsActive() bool {
return res return res
} }
// only for relay tunnel heartbeat update
func (app *p2pApp) UpdateHeartbeat(rtid uint64) { func (app *p2pApp) UpdateHeartbeat(rtid uint64) {
app.hbMtx.Lock() app.hbMtx.Lock()
defer app.hbMtx.Unlock() defer app.hbMtx.Unlock()
tidx := 1 for i := app.relayIdxStart; i < app.tunnelNum; i++ {
if app.tunnelNum > 2 && rtid == app.rtid[2] || (app.Tunnel(2) != nil && app.Tunnel(2).id == rtid) { // ack return rtid!= if rtid == app.rtid[i] || (app.Tunnel(i) != nil && app.Tunnel(i).id == rtid) {
tidx = 2 app.hbTime[i] = time.Now()
rtt := int32(time.Since(app.whbTime[i]) / time.Millisecond)
preRtt := app.rtt[i].Load()
if preRtt != DefaultRtt {
rtt = int32(float64(preRtt)*(1-ma20) + float64(rtt)*ma20)
}
app.rtt[i].Store(rtt)
gLog.dev("appid:%d relay heartbeat %d store rtt %d", app.id, i, rtt)
return
}
} }
app.hbTime[tidx] = time.Now()
rtt := int32(time.Since(app.whbTime[tidx]) / time.Millisecond)
preRtt := app.rtt[tidx].Load()
if preRtt != DefaultRtt {
rtt = int32(float64(preRtt)*(1-ma20) + float64(rtt)*ma20)
}
app.rtt[tidx].Store(rtt)
gLog.dev("appid:%d relay heartbeat %d store rtt %d", app.id, tidx, rtt)
} }
func (app *p2pApp) UpdateRelayHeartbeatTs(rtid uint64) { func (app *p2pApp) UpdateRelayHeartbeatTs(rtid uint64) {
app.hbMtx.Lock() app.hbMtx.Lock()
defer app.hbMtx.Unlock() defer app.hbMtx.Unlock()
relayIdx := 1 for i := app.relayIdxStart; i < app.tunnelNum; i++ {
if app.tunnelNum > 2 && rtid == app.rtid[2] || (app.Tunnel(2) != nil && app.Tunnel(2).id == rtid) { // ack return rtid!= if rtid == app.rtid[i] || (app.Tunnel(i) != nil && app.Tunnel(i).id == rtid) {
relayIdx = 2 app.whbTime[i] = time.Now()
return
}
} }
app.whbTime[relayIdx] = time.Now() // one side did not write relay hb, so write whbtime in this. // relayIdx := 1
// if app.tunnelNum > 2 && rtid == app.rtid[2] || (app.Tunnel(2) != nil && app.Tunnel(2).id == rtid) { // ack return rtid!=
// relayIdx = 2
// }
// app.whbTime[relayIdx] = time.Now() // one side did not write relay hb, so write whbtime in this.
} }
func (app *p2pApp) listenTCP() error { func (app *p2pApp) listenTCP() error {
@@ -714,7 +744,7 @@ func (app *p2pApp) WriteBytes(data []byte) error {
if t == nil { if t == nil {
return ErrAppWithoutTunnel return ErrAppWithoutTunnel
} }
if tidx == 0 { if tidx < app.relayIdxStart { // direct mode
return t.conn.WriteBytes(MsgP2P, MsgOverlayData, data) return t.conn.WriteBytes(MsgP2P, MsgOverlayData, data)
} }
all := append(app.relayHead[tidx].Bytes(), encodeHeader(MsgP2P, MsgOverlayData, uint32(len(data)))...) all := append(app.relayHead[tidx].Bytes(), encodeHeader(MsgP2P, MsgOverlayData, uint32(len(data)))...)
@@ -745,7 +775,7 @@ func (app *p2pApp) WriteNodeDataMP(IPPacket []byte) (err error) {
dataWithSeq.Write(IPPacket) dataWithSeq.Write(IPPacket)
// gLog.d("DEBUG writeTs=%d, unAckSeqStart=%d", wu.writeTs.UnixMilli(), app.unAckSeqStart[tidx].Load()) // gLog.d("DEBUG writeTs=%d, unAckSeqStart=%d", wu.writeTs.UnixMilli(), app.unAckSeqStart[tidx].Load())
if tidx == 0 { if tidx < app.relayIdxStart { // direct mode
t.asyncWriteNodeData(gConf.nodeID(), app.seqW, IPPacket, nil) t.asyncWriteNodeData(gConf.nodeID(), app.seqW, IPPacket, nil)
gLog.dev("appid:%d asyncWriteDirect IPPacket len=%d", app.id, len(IPPacket)) gLog.dev("appid:%d asyncWriteDirect IPPacket len=%d", app.id, len(IPPacket))
} else { } else {
@@ -782,12 +812,13 @@ func (app *p2pApp) fastestTunnel() (t *P2PTunnel, idx int) {
return app.Tunnel(gConf.Network.specTunnel), gConf.Network.specTunnel return app.Tunnel(gConf.Network.specTunnel), gConf.Network.specTunnel
} }
} }
t = app.Tunnel(0)
idx = 0
if app.Tunnel(1) != nil { for i := 0; i < app.tunnelNum; i++ {
t = app.Tunnel(1) if app.Tunnel(i) != nil {
idx = 1 t = app.Tunnel(i)
idx = i
break
}
} }
return return
} }
@@ -812,7 +843,7 @@ func (app *p2pApp) Retry(all bool) {
app.hbMtx.Lock() app.hbMtx.Lock()
app.hbTime[i] = time.Now().Add(-TunnelHeartbeatTime * 3) app.hbTime[i] = time.Now().Add(-TunnelHeartbeatTime * 3)
app.hbMtx.Unlock() app.hbMtx.Unlock()
app.config.retryNum = 0 // app.config.retryNum = 0
app.config.nextRetryTime = time.Now() app.config.nextRetryTime = time.Now()
app.ResetWindow() app.ResetWindow()
} }
+67 -39
View File
@@ -126,6 +126,7 @@ func P2PNetworkInstance() {
HasUPNPorNATPMP: gConf.Network.hasUPNPorNATPMP, HasUPNPorNATPMP: gConf.Network.hasUPNPorNATPMP,
Version: OpenP2PVersion, Version: OpenP2PVersion,
IPv6: newIPv6, IPv6: newIPv6,
PublicIPPort: gConf.Network.PublicIPPort,
} }
GNetwork.write(MsgReport, MsgReportBasic, &req) GNetwork.write(MsgReport, MsgReportBasic, &req)
} }
@@ -142,19 +143,9 @@ func P2PNetworkInstance() {
func (pn *P2PNetwork) keepAlive() { func (pn *P2PNetwork) keepAlive() {
gLog.i("P2PNetwork keepAlive start") gLog.i("P2PNetwork keepAlive start")
// !hbTime && !initTime = hang, exit worker
var lastCheckTime time.Time
for { for {
time.Sleep(time.Second * 10) time.Sleep(time.Second * 10)
// Skip check if we're waking from sleep/hibernation
now := time.Now()
if !lastCheckTime.IsZero() && now.Sub(lastCheckTime) > NetworkHeartbeatTime*3 {
gLog.i("Detected possible sleep/wake cycle, skipping this check")
lastCheckTime = now
continue
}
lastCheckTime = now
if pn.hbTime.Before(time.Now().Add(-NetworkHeartbeatTime * 3)) { if pn.hbTime.Before(time.Now().Add(-NetworkHeartbeatTime * 3)) {
if pn.initTime.After(time.Now().Add(-NetworkHeartbeatTime * 3)) { if pn.initTime.After(time.Now().Add(-NetworkHeartbeatTime * 3)) {
gLog.d("Init less than 3 mins, skipping this check") gLog.d("Init less than 3 mins, skipping this check")
@@ -285,8 +276,8 @@ func (pn *P2PNetwork) autorunApp() {
} }
func (pn *P2PNetwork) addRelayTunnel(config AppConfig, excludeNodes string) (*P2PTunnel, uint64, string, error) { func (pn *P2PNetwork) addRelayTunnel(config AppConfig, excludeNodes string) (*P2PTunnel, uint64, string, error) {
gLog.i("addRelayTunnel to %s start", config.LogPeerNode()) gLog.d("addRelayTunnel to %s start", config.LogPeerNode())
defer gLog.i("addRelayTunnel to %s end", config.LogPeerNode()) defer gLog.d("addRelayTunnel to %s end", config.LogPeerNode())
var relayTunnel *P2PTunnel var relayTunnel *P2PTunnel
relayConfig := AppConfig{ relayConfig := AppConfig{
peerToken: config.peerToken, peerToken: config.peerToken,
@@ -342,7 +333,7 @@ func (pn *P2PNetwork) addRelayTunnel(config AppConfig, excludeNodes string) (*P2
/// ///
if relayTunnel == nil { if relayTunnel == nil {
var err error var err error
relayTunnel, err = pn.addDirectTunnel(relayConfig, 0) relayTunnel, err = pn.addDirectTunnel(relayConfig, 0, nil)
if err != nil || relayTunnel == nil { if err != nil || relayTunnel == nil {
gLog.w("direct connect error:%s", err) gLog.w("direct connect error:%s", err)
if err != nil && config.RelayNode != "" { if err != nil && config.RelayNode != "" {
@@ -392,8 +383,15 @@ func (pn *P2PNetwork) AddApp(config AppConfig) error {
pn.msgMap.Store(NodeNameToID(config.PeerNode), make(chan msgCtx, MsgQueueSize)) pn.msgMap.Store(NodeNameToID(config.PeerNode), make(chan msgCtx, MsgQueueSize))
} }
// check if app already exist? // check if app already exist?
if pn.findApp(&config) != nil { existApp := pn.findApp(&config)
return errors.New("P2PApp already exist") if existApp != nil {
if existApp.tunnelNum == int(gConf.sdwan.TunnelNum) {
return errors.New("P2PApp already exist")
} else {
gLog.d("app %s exist but tunnelNum changed from %d to %d, delete it and recreate", existApp.config.AppName, existApp.tunnelNum, gConf.sdwan.TunnelNum)
pn.DeleteApp(config)
}
} }
app := p2pApp{ app := p2pApp{
@@ -459,13 +457,13 @@ func (pn *P2PNetwork) DeleteApp(config AppConfig) {
} }
func (pn *P2PNetwork) findTunnel(peerNode string) (t *P2PTunnel) { func (pn *P2PNetwork) findTunnel(peerNode string, ignoredTunnel *P2PTunnel) (t *P2PTunnel) {
t = nil t = nil
// find existing tunnel to peer // find existing tunnel to peer
pn.allTunnels.Range(func(id, i interface{}) bool { pn.allTunnels.Range(func(id, i interface{}) bool {
tmpt := i.(*P2PTunnel) tmpt := i.(*P2PTunnel)
if tmpt.config.PeerNode == peerNode { if tmpt.config.PeerNode == peerNode && tmpt != ignoredTunnel {
gLog.i("tunnel already exist %s", tmpt.config.LogPeerNode()) gLog.d("tunnel already exist %s", tmpt.config.LogPeerNode())
isActive := tmpt.checkActive() isActive := tmpt.checkActive()
// inactive, close it // inactive, close it
if !isActive { if !isActive {
@@ -481,7 +479,7 @@ func (pn *P2PNetwork) findTunnel(peerNode string) (t *P2PTunnel) {
return t return t
} }
func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (t *P2PTunnel, err error) { func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64, ignoredTunnel *P2PTunnel) (t *P2PTunnel, err error) {
gLog.d("addDirectTunnel %s%d to %s:%s:%d tid:%d start", config.Protocol, config.SrcPort, config.LogPeerNode(), config.DstHost, config.DstPort, tid) gLog.d("addDirectTunnel %s%d to %s:%s:%d tid:%d start", config.Protocol, config.SrcPort, config.LogPeerNode(), config.DstHost, config.DstPort, tid)
defer gLog.d("addDirectTunnel %s%d to %s:%s:%d tid:%d end", config.Protocol, config.SrcPort, config.LogPeerNode(), config.DstHost, config.DstPort, tid) defer gLog.d("addDirectTunnel %s%d to %s:%s:%d tid:%d end", config.Protocol, config.SrcPort, config.LogPeerNode(), config.DstHost, config.DstPort, tid)
@@ -502,14 +500,14 @@ func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (t *P2PTunne
} }
if isClient { // only client side find existing tunnel, server side should force build tunnel if isClient { // only client side find existing tunnel, server side should force build tunnel
if existTunnel := pn.findTunnel(config.PeerNode); existTunnel != nil { if existTunnel := pn.findTunnel(config.PeerNode, ignoredTunnel); existTunnel != nil {
return existTunnel, nil return existTunnel, nil
} }
} }
// server side // server side
if !isClient { if !isClient {
t, err = pn.newTunnel(config, tid, isClient) t, err = pn.newTunnel(config, tid, isClient, ignoredTunnel)
return t, err // always return return t, err // always return
} }
@@ -521,15 +519,15 @@ func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (t *P2PTunne
return nil, initErr return nil, initErr
} }
gLog.d("config.peerNode=%s,config.peerVersion=%s,config.peerIP=%s,config.peerLanIP=%s,gConf.Network.publicIP=%s,config.peerIPv6=%s,config.hasIPv4=%d,config.hasUPNPorNATPMP=%d,gConf.Network.hasIPv4=%d,gConf.Network.hasUPNPorNATPMP=%d,config.peerNatType=%d,gConf.Network.natType=%d,", gLog.d("config.peerNode=%s,config.peerVersion=%s,config.peerIP=%s,config.peerLanIP=%s,gConf.Network.publicIP=%s,config.peerIPv6=%s,config.hasIPv4=%d,config.hasUPNPorNATPMP=%d,gConf.Network.hasIPv4=%d,gConf.Network.hasUPNPorNATPMP=%d,config.peerNatType=%d,gConf.Network.natType=%d,config.PunchPriority=%d,IPv6=%s",
config.LogPeerNode(), config.peerVersion, config.peerIP, config.peerLanIP, gConf.Network.publicIP, config.peerIPv6, config.hasIPv4, config.hasUPNPorNATPMP, gConf.Network.hasIPv4, gConf.Network.hasUPNPorNATPMP, config.peerNatType, gConf.Network.natType) config.LogPeerNode(), config.peerVersion, config.peerIP, config.peerLanIP, gConf.Network.publicIP, config.peerIPv6, config.hasIPv4, config.hasUPNPorNATPMP, gConf.Network.hasIPv4, gConf.Network.hasUPNPorNATPMP, config.peerNatType, gConf.Network.natType, config.PunchPriority, gConf.IPv6())
// try Intranet // try Intranet
if config.peerIP == gConf.Network.publicIP && compareVersion(config.peerVersion, SupportIntranetVersion) >= 0 { // old version client has no peerLanIP if config.peerIP == gConf.Network.publicIP && compareVersion(config.peerVersion, SupportIntranetVersion) >= 0 { // old version client has no peerLanIP
gLog.i("try Intranet") gLog.i("try Intranet")
config.linkMode = LinkModeIntranet config.linkMode = LinkModeIntranet
config.isUnderlayServer = 0 config.isUnderlayServer = 0
if t, err = pn.newTunnel(config, tid, isClient); err == nil { if t, err = pn.newTunnel(config, tid, isClient, ignoredTunnel); err == nil {
return t, nil return t, nil
} }
} }
@@ -542,7 +540,7 @@ func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (t *P2PTunne
if gConf.Forcev6 { if gConf.Forcev6 {
thisTunnelForcev6 = true thisTunnelForcev6 = true
} }
if t, err = pn.newTunnel(config, tid, isClient); err == nil { if t, err = pn.newTunnel(config, tid, isClient, ignoredTunnel); err == nil {
return t, nil return t, nil
} }
} }
@@ -564,7 +562,7 @@ func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (t *P2PTunne
} else { } else {
config.isUnderlayServer = 0 config.isUnderlayServer = 0
} }
if t, err = pn.newTunnel(config, tid, isClient); err == nil { if t, err = pn.newTunnel(config, tid, isClient, ignoredTunnel); err == nil {
return t, nil return t, nil
} }
} }
@@ -581,7 +579,7 @@ func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (t *P2PTunne
gLog.i("try UDP4 Punch") gLog.i("try UDP4 Punch")
config.linkMode = LinkModeUDPPunch config.linkMode = LinkModeUDPPunch
config.isUnderlayServer = 0 config.isUnderlayServer = 0
if t, err = pn.newTunnel(config, tid, isClient); err == nil { if t, err = pn.newTunnel(config, tid, isClient, ignoredTunnel); err == nil {
return t, nil return t, nil
} }
} }
@@ -601,7 +599,7 @@ func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (t *P2PTunne
gLog.i("try TCP4 Punch") gLog.i("try TCP4 Punch")
config.linkMode = LinkModeTCPPunch config.linkMode = LinkModeTCPPunch
config.isUnderlayServer = 0 config.isUnderlayServer = 0
if t, err = pn.newTunnel(config, tid, isClient); err == nil { if t, err = pn.newTunnel(config, tid, isClient, ignoredTunnel); err == nil {
gLog.i("TCP4 Punch ok") gLog.i("TCP4 Punch ok")
return t, nil return t, nil
} }
@@ -613,8 +611,8 @@ func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (t *P2PTunne
primaryPunchFunc = funcTCP primaryPunchFunc = funcTCP
secondaryPunchFunc = funcUDP secondaryPunchFunc = funcUDP
} else { } else {
primaryPunchFunc = funcTCP primaryPunchFunc = funcUDP
secondaryPunchFunc = funcUDP secondaryPunchFunc = funcTCP
} }
if t, err = primaryPunchFunc(); t != nil && err == nil { if t, err = primaryPunchFunc(); t != nil && err == nil {
return t, err return t, err
@@ -627,9 +625,9 @@ func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (t *P2PTunne
return nil, err return nil, err
} }
func (pn *P2PNetwork) newTunnel(config AppConfig, tid uint64, isClient bool) (t *P2PTunnel, err error) { func (pn *P2PNetwork) newTunnel(config AppConfig, tid uint64, isClient bool, ignoredTunnel *P2PTunnel) (t *P2PTunnel, err error) {
if isClient { // only client side find existing tunnel, server side should force build tunnel if isClient { // only client side find existing tunnel, server side should force build tunnel
if existTunnel := pn.findTunnel(config.PeerNode); existTunnel != nil { if existTunnel := pn.findTunnel(config.PeerNode, ignoredTunnel); existTunnel != nil {
return existTunnel, nil return existTunnel, nil
} }
} }
@@ -665,8 +663,9 @@ func (pn *P2PNetwork) init() error {
pn.wgReconnect.Add(1) pn.wgReconnect.Add(1)
defer pn.wgReconnect.Done() defer pn.wgReconnect.Done()
var err error var err error
initOK := false
defer func() { defer func() {
if err != nil { if !initOK {
// init failed, retry // init failed, retry
pn.close(true) pn.close(true)
gLog.e("P2PNetwork init error:%s", err) gLog.e("P2PNetwork init error:%s", err)
@@ -760,6 +759,14 @@ func (pn *P2PNetwork) init() error {
ws, _, err := d.Dial(u.String(), nil) ws, _, err := d.Dial(u.String(), nil)
if err != nil { if err != nil {
gLog.e("Dial error:%s", err) gLog.e("Dial error:%s", err)
switch gConf.Network.ServerPort {
case WsPort:
gConf.Network.ServerPort = WsPort2
gLog.i("try alternative port %d", WsPort2)
case WsPort2:
gConf.Network.ServerPort = WsPort
gLog.i("try alternative port %d", WsPort)
}
break break
} }
pn.running = true pn.running = true
@@ -769,7 +776,7 @@ func (pn *P2PNetwork) init() error {
if len(localAddr) == 2 { if len(localAddr) == 2 {
gConf.Network.localIP = localAddr[0] gConf.Network.localIP = localAddr[0]
} else { } else {
err = errors.New("get local ip failed") gLog.e("get local ip failed:%s", ws.LocalAddr().String())
break break
} }
go pn.readLoop() go pn.readLoop()
@@ -781,6 +788,7 @@ func (pn *P2PNetwork) init() error {
LanIP: gConf.Network.localIP, LanIP: gConf.Network.localIP,
OS: gConf.Network.os, OS: gConf.Network.os,
HasIPv4: gConf.Network.hasIPv4, HasIPv4: gConf.Network.hasIPv4,
PublicIPPort: gConf.Network.PublicIPPort,
HasUPNPorNATPMP: gConf.Network.hasUPNPorNATPMP, HasUPNPorNATPMP: gConf.Network.hasUPNPorNATPMP,
Version: OpenP2PVersion, Version: OpenP2PVersion,
} }
@@ -795,10 +803,22 @@ func (pn *P2PNetwork) init() error {
pn.refreshIPv6() pn.refreshIPv6()
} }
req.IPv6 = gConf.IPv6() req.IPv6 = gConf.IPv6()
pn.write(MsgReport, MsgReportBasic, &req) pn.write(MsgReport, MsgReportBasic, &req) // TODO: if report failed, many logic problems, loss lanip os version...
head, _ := pn.read("", MsgReport, MsgReportBasicRsp, ClientAPITimeout)
if head == nil {
gLog.e("read MsgReportBasic rsp error, retry")
pn.write(MsgReport, MsgReportBasic, &req) // TODO: if report failed, many logic problems, loss lanip os version...
head, _ := pn.read("", MsgReport, MsgReportBasicRsp, ClientAPITimeout)
if head == nil {
gLog.e("read MsgReportBasic rsp error again, exit")
os.Exit(9)
}
return
}
}() }()
go pn.autorunApp() go pn.autorunApp()
pn.write(MsgSDWAN, MsgSDWANInfoReq, nil) pn.write(MsgSDWAN, MsgSDWANInfoReq, nil)
initOK = true
gLog.d("P2PNetwork init ok") gLog.d("P2PNetwork init ok")
break break
} }
@@ -828,6 +848,10 @@ func (pn *P2PNetwork) handleMessage(msg []byte) {
} else { } else {
gConf.setToken(rsp.Token) gConf.setToken(rsp.Token)
gConf.setUser(rsp.User) gConf.setUser(rsp.User)
gConf.setForcev6(rsp.Forcev6 != 0)
if rsp.PublicIPPort != 0 {
gConf.Network.PublicIPPort = rsp.PublicIPPort
}
if len(rsp.Node) >= MinNodeNameLen { if len(rsp.Node) >= MinNodeNameLen {
gConf.setNode(rsp.Node) gConf.setNode(rsp.Node)
} }
@@ -1039,7 +1063,7 @@ func (pn *P2PNetwork) read(node string, mainType uint16, subType uint16, timeout
if head.MainType != mainType || head.SubType != subType { if head.MainType != mainType || head.SubType != subType {
// gLog.d("read msg error type %d:%d expect %d:%d, requeue it", head.MainType, head.SubType, mainType, subType) // gLog.d("read msg error type %d:%d expect %d:%d, requeue it", head.MainType, head.SubType, mainType, subType)
ch <- msg ch <- msg
time.Sleep(time.Second) time.Sleep(time.Millisecond * 50)
continue continue
} }
if mainType == MsgPush { if mainType == MsgPush {
@@ -1069,9 +1093,14 @@ func (pn *P2PNetwork) updateAppHeartbeat(appID uint64, rtid uint64, updateRelayT
// ipv6 will expired need to refresh. // ipv6 will expired need to refresh.
func (pn *P2PNetwork) refreshIPv6() { func (pn *P2PNetwork) refreshIPv6() {
for i := 0; i < 2; i++ { for i := 0; i < 2; i++ {
url := "http://ipv6.ddnspod.com/"
if i == 1 {
url = "ipv6.icanhazip.com"
}
client := &http.Client{Timeout: time.Second * 10} client := &http.Client{Timeout: time.Second * 10}
r, err := client.Get("http://ipv6.ddnspod.com/") r, err := client.Get(url)
if err != nil { if err != nil {
gLog.d("refreshIPv6 error:%s", err) gLog.d("refreshIPv6 error:%s", err)
continue continue
@@ -1221,4 +1250,3 @@ func (pn *P2PNetwork) ReadNode(tm time.Duration) []byte {
} }
return nil return nil
} }
+10 -5
View File
@@ -293,7 +293,7 @@ func (t *P2PTunnel) connectUnderlayUDP() (c underlay, err error) {
gLog.d("UDP4 connection ok") gLog.d("UDP4 connection ok")
} else { } else {
if t.config.UnderlayProtocol == "kcp" { if t.config.UnderlayProtocol == "kcp" {
ul, err = listenKCP(t.localHoleAddr.String(), TunnelIdleTimeout) // ul, err = listenKCP(t.localHoleAddr.String(), TunnelIdleTimeout)
} else { } else {
ul, err = listenQuic(t.localHoleAddr.String(), TunnelIdleTimeout) ul, err = listenQuic(t.localHoleAddr.String(), TunnelIdleTimeout)
} }
@@ -337,7 +337,7 @@ func (t *P2PTunnel) connectUnderlayUDP() (c underlay, err error) {
GNetwork.read(t.config.PeerNode, MsgPush, MsgPushUnderlayConnect, ReadMsgTimeout) GNetwork.read(t.config.PeerNode, MsgPush, MsgPushUnderlayConnect, ReadMsgTimeout)
gLog.d("%s dial to %s", underlayProtocol, t.remoteHoleAddr.String()) gLog.d("%s dial to %s", underlayProtocol, t.remoteHoleAddr.String())
if t.config.UnderlayProtocol == "kcp" { if t.config.UnderlayProtocol == "kcp" {
ul, errL = dialKCP(conn, t.remoteHoleAddr, UnderlayConnectTimeout) // ul, errL = dialKCP(conn, t.remoteHoleAddr, UnderlayConnectTimeout)
} else { } else {
ul, errL = dialQuic(conn, t.remoteHoleAddr, UnderlayConnectTimeout) ul, errL = dialQuic(conn, t.remoteHoleAddr, UnderlayConnectTimeout)
} }
@@ -602,7 +602,7 @@ func (t *P2PTunnel) readLoop() {
head, body, err := t.conn.ReadBuffer() head, body, err := t.conn.ReadBuffer()
if err != nil || head == nil { if err != nil || head == nil {
if t.isRuning() { if t.isRuning() {
gLog.w("%d tunnel read error:%s", t.id, err) gLog.d("%d tunnel read error:%s", t.id, err)
} }
break break
} }
@@ -630,7 +630,12 @@ func (t *P2PTunnel) readLoop() {
existApp, appok := GNetwork.apps.Load(memAppPeerID) existApp, appok := GNetwork.apps.Load(memAppPeerID)
if appok { if appok {
app := existApp.(*p2pApp) app := existApp.(*p2pApp)
app.rtt[0].Store(int32(time.Since(t.whbTime) / time.Millisecond)) for i := 0; i < app.relayIdxStart; i++ {
if app.Tunnel(i) == t {
app.rtt[i].Store(int32(time.Since(t.whbTime) / time.Millisecond))
break
}
}
} }
} }
@@ -806,7 +811,7 @@ func (t *P2PTunnel) writeLoop() {
t.whbTime = time.Now() t.whbTime = time.Now()
err := t.conn.WriteBytes(MsgP2P, MsgTunnelHeartbeat, nil) err := t.conn.WriteBytes(MsgP2P, MsgTunnelHeartbeat, nil)
if err != nil { if err != nil {
gLog.w("%d write tunnel heartbeat error %s", t.id, err) gLog.d("%d write tunnel heartbeat error %s", t.id, err)
t.close() t.close()
return return
} }
+44 -37
View File
@@ -10,7 +10,7 @@ import (
"time" "time"
) )
const OpenP2PVersion = "3.24.33" const OpenP2PVersion = "3.25.8"
const ProductName string = "openp2p" const ProductName string = "openp2p"
const LeastSupportVersion = "3.0.0" const LeastSupportVersion = "3.0.0"
const SyncServerTimeVersion = "3.9.0" const SyncServerTimeVersion = "3.9.0"
@@ -20,10 +20,12 @@ const SupportIntranetVersion = "3.14.5"
const SupportDualTunnelVersion = "3.15.5" const SupportDualTunnelVersion = "3.15.5"
const IPv6PunchVersion = "3.24.9" const IPv6PunchVersion = "3.24.9"
const SupportUDP4DirectVersion = "3.24.16" const SupportUDP4DirectVersion = "3.24.16"
const SupportMultiDirectVersion = "3.25.1"
const ( const (
NATDetectPort1 = 27180 NATDetectPort1 = 27180
NATDetectPort2 = 27181 NATDetectPort2 = 27181
WsPort = 27183 WsPort = 27183
WsPort2 = 465
UDPPort1 = 27182 UDPPort1 = 27182
UDPPort2 = 27183 UDPPort2 = 27183
) )
@@ -124,41 +126,42 @@ const (
// MsgP2P sub type message // MsgP2P sub type message
const ( const (
MsgPunchHandshake = iota MsgPunchHandshake = 0
MsgPunchHandshakeAck MsgPunchHandshakeAck = 1
MsgTunnelHandshake MsgTunnelHandshake = 2
MsgTunnelHandshakeAck MsgTunnelHandshakeAck = 3
MsgTunnelHeartbeat MsgTunnelHeartbeat = 4
MsgTunnelHeartbeatAck MsgTunnelHeartbeatAck = 5
MsgOverlayConnectReq MsgOverlayConnectReq = 6
MsgOverlayConnectRsp MsgOverlayConnectRsp = 7
MsgOverlayDisconnectReq MsgOverlayDisconnectReq = 8
MsgOverlayData MsgOverlayData = 9
MsgRelayData MsgRelayData = 10
MsgRelayHeartbeat MsgRelayHeartbeat = 11
MsgRelayHeartbeatAck MsgRelayHeartbeatAck = 12
MsgNodeData MsgNodeData = 13
MsgRelayNodeData MsgRelayNodeData = 14
MsgNodeDataMP MsgNodeDataMP = 15
MsgNodeDataMPAck MsgNodeDataMPAck = 16
MsgRelayHeartbeatAck2 MsgRelayHeartbeatAck2 = 17
) )
// MsgRelay sub type message // MsgRelay sub type message
const ( const (
MsgRelayNodeReq = iota MsgRelayNodeReq = 0
MsgRelayNodeRsp MsgRelayNodeRsp = 1
) )
// MsgReport sub type message // MsgReport sub type message
const ( const (
MsgReportBasic = iota MsgReportBasic = 0
MsgReportQuery MsgReportQuery = 1
MsgReportConnect MsgReportConnect = 2
MsgReportApps MsgReportApps = 3
MsgReportLog MsgReportLog = 4
MsgReportMemApps MsgReportMemApps = 5
MsgReportResponse MsgReportResponse = 6
MsgReportBasicRsp = 7
) )
const ( const (
@@ -218,19 +221,19 @@ const (
) )
const ( const (
MsgQueryPeerInfoReq = iota MsgQueryPeerInfoReq = 0
MsgQueryPeerInfoRsp MsgQueryPeerInfoRsp = 1
) )
const ( const (
MsgSDWANInfoReq = iota MsgSDWANInfoReq = 0
MsgSDWANInfoRsp MsgSDWANInfoRsp = 1
) )
// MsgNATDetect // MsgNATDetect
const ( const (
MsgNAT = iota MsgNAT = 0
MsgPublicIP MsgPublicIP = 1
) )
func newMessage(mainType uint16, subType uint16, packet interface{}) ([]byte, error) { func newMessage(mainType uint16, subType uint16, packet interface{}) ([]byte, error) {
@@ -320,6 +323,8 @@ type LoginRsp struct {
Token uint64 `json:"token,omitempty"` Token uint64 `json:"token,omitempty"`
Ts int64 `json:"ts,omitempty"` Ts int64 `json:"ts,omitempty"`
LoginMaxDelay int `json:"loginMaxDelay,omitempty"` // seconds LoginMaxDelay int `json:"loginMaxDelay,omitempty"` // seconds
Forcev6 int `json:"forcev6,omitempty"`
PublicIPPort int `json:"publicIPPort,omitempty"`
} }
type NatDetectReq struct { type NatDetectReq struct {
@@ -394,6 +399,7 @@ type ReportBasic struct {
LanIP string `json:"lanIP,omitempty"` LanIP string `json:"lanIP,omitempty"`
HasIPv4 int `json:"hasIPv4,omitempty"` HasIPv4 int `json:"hasIPv4,omitempty"`
IPv6 string `json:"IPv6,omitempty"` IPv6 string `json:"IPv6,omitempty"`
PublicIPPort int `json:"publicIPPort,omitempty"`
HasUPNPorNATPMP int `json:"hasUPNPorNATPMP,omitempty"` HasUPNPorNATPMP int `json:"hasUPNPorNATPMP,omitempty"`
Version string `json:"version,omitempty"` Version string `json:"version,omitempty"`
NetInfo NetInfo `json:"netInfo,omitempty"` NetInfo NetInfo `json:"netInfo,omitempty"`
@@ -498,9 +504,10 @@ type ProfileInfo struct {
} }
type EditNode struct { type EditNode struct {
NewName string `json:"newName,omitempty"` NewName string `json:"newName,omitempty"`
Bandwidth int `json:"bandwidth,omitempty"` Bandwidth int `json:"bandwidth,omitempty"`
Forcev6 int `json:"forcev6,omitempty"` Forcev6 int `json:"forcev6,omitempty"`
PublicIPPort int `json:"publicIPPort,omitempty"`
} }
type QueryPeerInfoReq struct { type QueryPeerInfoReq struct {
+15 -1
View File
@@ -57,6 +57,10 @@ func (s *p2pSDWAN) reset() {
gLog.i("reset sdwan when network disconnected") gLog.i("reset sdwan when network disconnected")
// clear sysroute // clear sysroute
delRoutesByGateway(s.gateway.String()) delRoutesByGateway(s.gateway.String())
s.sysRoute.Range(func(key, value interface{}) bool {
s.sysRoute.Delete(key)
return true
})
// clear internel route // clear internel route
s.internalRoute = NewIPTree("") s.internalRoute = NewIPTree("")
// clear p2papp // clear p2papp
@@ -67,6 +71,7 @@ func (s *p2pSDWAN) reset() {
gConf.resetSDWAN() gConf.resetSDWAN()
} }
func (s *p2pSDWAN) init() error { func (s *p2pSDWAN) init() error {
gConf.Network.previousIP = gConf.Network.publicIP gConf.Network.previousIP = gConf.Network.publicIP
if gConf.getSDWAN().Gateway == "" { if gConf.getSDWAN().Gateway == "" {
@@ -88,6 +93,15 @@ func (s *p2pSDWAN) init() error {
s.internalRoute.Del(node.IP, node.IP) s.internalRoute.Del(node.IP, node.IP)
ipNum, _ := inetAtoN(node.IP) ipNum, _ := inetAtoN(node.IP)
s.sysRoute.Delete(ipNum) s.sysRoute.Delete(ipNum)
// if node.Name == gConf.Network.Node {
// // this is local node, need rm all client-side apps
// GNetwork.apps.Range(func(id, i interface{}) bool {
// app := i.(*p2pApp)
// if app.config.is
// return true
// })
// continue
// }
gConf.delete(AppConfig{SrcPort: 0, PeerNode: node.Name}) gConf.delete(AppConfig{SrcPort: 0, PeerNode: node.Name})
GNetwork.DeleteApp(AppConfig{SrcPort: 0, PeerNode: node.Name}) GNetwork.DeleteApp(AppConfig{SrcPort: 0, PeerNode: node.Name})
arr := strings.Split(node.Resource, ",") arr := strings.Split(node.Resource, ",")
@@ -309,7 +323,7 @@ func handleSDWAN(subType uint16, msg []byte) error {
} }
gLog.i("sdwan init:%s", prettyJson(rsp)) gLog.i("sdwan init:%s", prettyJson(rsp))
// GNetwork.sdwan.detail = &rsp // GNetwork.sdwan.detail = &rsp
if gConf.Network.previousIP != gConf.Network.publicIP || gConf.getSDWAN().CentralNode != rsp.CentralNode { if gConf.Network.previousIP != gConf.Network.publicIP || gConf.getSDWAN().CentralNode != rsp.CentralNode || gConf.getSDWAN().Gateway != rsp.Gateway {
GNetwork.sdwan.reset() GNetwork.sdwan.reset()
preAndroidSDWANConfig = "" // let androind app reset vpnservice preAndroidSDWANConfig = "" // let androind app reset vpnservice
} }
+3 -3
View File
@@ -42,7 +42,7 @@ func DefaultWriteBytes(ul underlay, mainType, subType uint16, data []byte) error
writeBytes := append(encodeHeader(mainType, subType, uint32(len(data))), data...) writeBytes := append(encodeHeader(mainType, subType, uint32(len(data))), data...)
ul.SetWriteDeadline(time.Now().Add(TunnelHeartbeatTime / 2)) ul.SetWriteDeadline(time.Now().Add(TunnelHeartbeatTime / 2))
ul.WLock() ul.WLock()
_, err := ul.Write(writeBytes) err := writeFull(ul, writeBytes)
ul.WUnlock() ul.WUnlock()
return err return err
} }
@@ -50,7 +50,7 @@ func DefaultWriteBytes(ul underlay, mainType, subType uint16, data []byte) error
func DefaultWriteBuffer(ul underlay, data []byte) error { func DefaultWriteBuffer(ul underlay, data []byte) error {
ul.SetWriteDeadline(time.Now().Add(TunnelHeartbeatTime / 2)) ul.SetWriteDeadline(time.Now().Add(TunnelHeartbeatTime / 2))
ul.WLock() ul.WLock()
_, err := ul.Write(data) err := writeFull(ul, data)
ul.WUnlock() ul.WUnlock()
return err return err
} }
@@ -62,7 +62,7 @@ func DefaultWriteMessage(ul underlay, mainType uint16, subType uint16, packet in
} }
ul.SetWriteDeadline(time.Now().Add(TunnelHeartbeatTime / 2)) ul.SetWriteDeadline(time.Now().Add(TunnelHeartbeatTime / 2))
ul.WLock() ul.WLock()
_, err = ul.Write(writeBytes) err = writeFull(ul, writeBytes)
ul.WUnlock() ul.WUnlock()
return err return err
} }
+14 -25
View File
@@ -16,14 +16,14 @@ import (
"github.com/quic-go/quic-go" "github.com/quic-go/quic-go"
) )
// quic.Dial do not support version 44, disable it // quic.DialContext do not support version 44,disable it
var quicVersion []quic.Version var quicVersion []quic.VersionNumber
type underlayQUIC struct { type underlayQUIC struct {
listener *quic.Listener listener quic.Listener
writeMtx *sync.Mutex writeMtx *sync.Mutex
*quic.Stream quic.Stream
*quic.Conn quic.Connection
} }
func (conn *underlayQUIC) Protocol() string { func (conn *underlayQUIC) Protocol() string {
@@ -47,17 +47,8 @@ func (conn *underlayQUIC) WriteMessage(mainType uint16, subType uint16, packet i
} }
func (conn *underlayQUIC) Close() error { func (conn *underlayQUIC) Close() error {
// CancelRead expects a StreamErrorCode; using 1 as before (application-defined) conn.Stream.CancelRead(1)
if conn.Stream != nil { conn.Connection.CloseWithError(0, "")
conn.Stream.CancelRead(1)
// close send-side of stream
_ = conn.Stream.Close()
}
if conn.Conn != nil {
// CloseWithError expects an ApplicationErrorCode and a description.
// 0 is zero-value; keep behavior similar to old CloseWithError(0,"")
_ = conn.Conn.CloseWithError(0, "")
}
conn.CloseListener() conn.CloseListener()
return nil return nil
} }
@@ -69,7 +60,7 @@ func (conn *underlayQUIC) WUnlock() {
} }
func (conn *underlayQUIC) CloseListener() { func (conn *underlayQUIC) CloseListener() {
if conn.listener != nil { if conn.listener != nil {
_ = conn.listener.Close() conn.listener.Close()
} }
} }
@@ -85,7 +76,7 @@ func (conn *underlayQUIC) Accept() error {
return err return err
} }
conn.Stream = stream conn.Stream = stream
conn.Conn = sess conn.Connection = sess
return nil return nil
} }
@@ -105,25 +96,23 @@ func listenQuic(addr string, idleTimeout time.Duration) (*underlayQUIC, error) {
return ul, nil return ul, nil
} }
func dialQuic(pconn *net.UDPConn, remoteAddr *net.UDPAddr, timeout time.Duration) (*underlayQUIC, error) { func dialQuic(conn *net.UDPConn, remoteAddr *net.UDPAddr, timeout time.Duration) (*underlayQUIC, error) {
tlsConf := &tls.Config{ tlsConf := &tls.Config{
InsecureSkipVerify: true, InsecureSkipVerify: true,
NextProtos: []string{"openp2pv1"}, NextProtos: []string{"openp2pv1"},
} }
ctx, cancel := context.WithTimeout(context.Background(), timeout) ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel() defer cancel()
Connection, err := quic.DialContext(ctx, conn, remoteAddr, conn.LocalAddr().String(), tlsConf,
// New API: quic.Dial(ctx, packetConn, remoteAddr, tlsConf, quicConfig)
connection, err := quic.Dial(ctx, pconn, remoteAddr, tlsConf,
&quic.Config{Versions: quicVersion, MaxIdleTimeout: TunnelIdleTimeout, DisablePathMTUDiscovery: true}) &quic.Config{Versions: quicVersion, MaxIdleTimeout: TunnelIdleTimeout, DisablePathMTUDiscovery: true})
if err != nil { if err != nil {
return nil, fmt.Errorf("quic.Dial error:%s", err) return nil, fmt.Errorf("quic.DialContext error:%s", err)
} }
stream, err := connection.OpenStreamSync(context.Background()) stream, err := Connection.OpenStreamSync(context.Background())
if err != nil { if err != nil {
return nil, fmt.Errorf("OpenStreamSync error:%s", err) return nil, fmt.Errorf("OpenStreamSync error:%s", err)
} }
qConn := &underlayQUIC{nil, &sync.Mutex{}, stream, connection} qConn := &underlayQUIC{nil, &sync.Mutex{}, stream, Connection}
return qConn, nil return qConn, nil
} }
+3 -3
View File
@@ -9,7 +9,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
@@ -49,7 +48,7 @@ func update(host string, port int) error {
gLog.e("get update info error:%s", rsp.Status) gLog.e("get update info error:%s", rsp.Status)
return err return err
} }
rspBuf, err := ioutil.ReadAll(rsp.Body) rspBuf, err := io.ReadAll(rsp.Body)
if err != nil { if err != nil {
gLog.e("update:read update list failed:%s", err) gLog.e("update:read update list failed:%s", err)
return err return err
@@ -94,7 +93,8 @@ func downloadFile(url string, checksum string, dstFile string) error {
RootCAs: caCertPool, RootCAs: caCertPool,
InsecureSkipVerify: gConf.TLSInsecureSkipVerify}, InsecureSkipVerify: gConf.TLSInsecureSkipVerify},
} }
client := &http.Client{Transport: tr} client := &http.Client{Transport: tr,
Timeout: 60 * time.Second}
response, err := client.Get(url) response, err := client.Get(url)
if err != nil { if err != nil {
gLog.e("download url %s error:%s", url, err) gLog.e("download url %s error:%s", url, err)
+11 -29
View File
@@ -17,13 +17,13 @@ type v4Listener struct {
acceptCh chan bool acceptCh chan bool
running bool running bool
tcpListener *net.TCPListener tcpListener *net.TCPListener
udpListener *quic.Listener udpListener quic.Listener
wg sync.WaitGroup wg sync.WaitGroup
} }
func (vl *v4Listener) start() { func (vl *v4Listener) start() {
vl.running = true vl.running = true
vl.acceptCh = make(chan bool, 500) v4l.acceptCh = make(chan bool, 500)
vl.wg.Add(1) vl.wg.Add(1)
go func() { go func() {
defer vl.wg.Done() defer vl.wg.Done()
@@ -56,11 +56,11 @@ func (vl *v4Listener) stop() {
func (vl *v4Listener) listenTCP() error { func (vl *v4Listener) listenTCP() error {
gLog.d("v4Listener listenTCP %d start", vl.port) gLog.d("v4Listener listenTCP %d start", vl.port)
defer gLog.d("v4Listener listenTCP %d end", vl.port) defer gLog.d("v4Listener listenTCP %d end", vl.port)
addr, _ := net.ResolveTCPAddr("tcp", fmt.Sprintf("0.0.0.0:%d", vl.port)) addr, _ := net.ResolveTCPAddr("tcp", fmt.Sprintf("0.0.0.0:%d", vl.port)) // system will auto listen both v4 and v6
var err error var err error
vl.tcpListener, err = net.ListenTCP("tcp", addr) vl.tcpListener, err = net.ListenTCP("tcp", addr)
if err != nil { if err != nil {
gLog.e("v4Listener listen %d error:%s", vl.port, err) gLog.e("v4Listener listen %d error:", vl.port, err)
return err return err
} }
defer vl.tcpListener.Close() defer vl.tcpListener.Close()
@@ -69,11 +69,7 @@ func (vl *v4Listener) listenTCP() error {
if err != nil { if err != nil {
break break
} }
utcp := &underlayTCP{ utcp := &underlayTCP{writeMtx: &sync.Mutex{}, Conn: c, connectTime: time.Now()}
writeMtx: &sync.Mutex{},
Conn: c,
connectTime: time.Now(),
}
go vl.handleConnection(utcp) go vl.handleConnection(utcp)
} }
vl.tcpListener = nil vl.tcpListener = nil
@@ -84,15 +80,8 @@ func (vl *v4Listener) listenUDP() error {
gLog.d("v4Listener listenUDP %d start", vl.port) gLog.d("v4Listener listenUDP %d start", vl.port)
defer gLog.d("v4Listener listenUDP %d end", vl.port) defer gLog.d("v4Listener listenUDP %d end", vl.port)
var err error var err error
vl.udpListener, err = quic.ListenAddr( vl.udpListener, err = quic.ListenAddr(fmt.Sprintf("0.0.0.0:%d", vl.port), generateTLSConfig(),
fmt.Sprintf("0.0.0.0:%d", vl.port), &quic.Config{Versions: quicVersion, MaxIdleTimeout: TunnelIdleTimeout, DisablePathMTUDiscovery: true})
generateTLSConfig(),
&quic.Config{
Versions: quicVersion,
MaxIdleTimeout: TunnelIdleTimeout,
DisablePathMTUDiscovery: true,
},
)
if err != nil { if err != nil {
return err return err
} }
@@ -108,14 +97,7 @@ func (vl *v4Listener) listenUDP() error {
if err != nil { if err != nil {
break break
} }
ul := &underlayQUIC{writeMtx: &sync.Mutex{}, Stream: stream, Connection: sess}
ul := &underlayQUIC{
listener: nil,
writeMtx: &sync.Mutex{},
Stream: stream,
Conn: sess,
}
go vl.handleConnection(ul) go vl.handleConnection(ul)
} }
vl.udpListener = nil vl.udpListener = nil
@@ -128,14 +110,14 @@ func (vl *v4Listener) handleConnection(ul underlay) {
_, buff, err := ul.ReadBuffer() _, buff, err := ul.ReadBuffer()
if err != nil || buff == nil { if err != nil || buff == nil {
gLog.e("v4Listener read MsgTunnelHandshake error:%s", err) gLog.e("v4Listener read MsgTunnelHandshake error:%s", err)
return
} }
ul.WriteBytes(MsgP2P, MsgTunnelHandshakeAck, buff) ul.WriteBytes(MsgP2P, MsgTunnelHandshakeAck, buff)
var tid uint64 var tid uint64
if string(buff) == "OpenP2P,hello" { // old client if string(buff) == "OpenP2P,hello" { // old client
// save remoteIP as key
remoteAddr := ul.RemoteAddr().(*net.TCPAddr).IP remoteAddr := ul.RemoteAddr().(*net.TCPAddr).IP
ipBytes := remoteAddr.To4() ipBytes := remoteAddr.To4()
tid = uint64(binary.BigEndian.Uint32(ipBytes)) tid = uint64(binary.BigEndian.Uint32(ipBytes)) // bytes not enough for uint64
gLog.d("hello %s", string(buff)) gLog.d("hello %s", string(buff))
} else { } else {
if len(buff) < 8 { if len(buff) < 8 {
@@ -164,7 +146,7 @@ func (vl *v4Listener) handleConnection(ul underlay) {
func (vl *v4Listener) getUnderlay(tid uint64) underlay { func (vl *v4Listener) getUnderlay(tid uint64) underlay {
for i := 0; i < 100; i++ { for i := 0; i < 100; i++ {
select { select {
case <-time.After(50 * time.Millisecond): case <-time.After(time.Millisecond * 50):
case <-vl.acceptCh: case <-vl.acceptCh:
} }
if u, ok := vl.conns.LoadAndDelete(tid); ok { if u, ok := vl.conns.LoadAndDelete(tid); ok {
+17 -12
View File
@@ -1,32 +1,37 @@
module openp2p module openp2p
go 1.25 go 1.20
require ( require (
github.com/emirpasic/gods v1.18.1 github.com/emirpasic/gods v1.18.1
github.com/gorilla/websocket v1.5.3 github.com/gorilla/websocket v1.5.3
github.com/huin/goupnp v1.3.0
github.com/jackpal/go-nat-pmp v1.0.2
github.com/openp2p-cn/go-reuseport v0.3.2 github.com/openp2p-cn/go-reuseport v0.3.2
github.com/openp2p-cn/service v1.0.0 github.com/openp2p-cn/service v1.0.0
github.com/openp2p-cn/totp v0.0.0-20230421034602-0f3320ffb25e github.com/openp2p-cn/totp v0.0.0-20230421034602-0f3320ffb25e
github.com/openp2p-cn/wireguard-go v0.0.20241020 github.com/openp2p-cn/wireguard-go v0.0.20241020
github.com/quic-go/quic-go v0.57.1 github.com/quic-go/quic-go v0.34.0
github.com/vishvananda/netlink v1.1.1-0.20211118161826-650dca95af54 github.com/vishvananda/netlink v1.1.1-0.20211118161826-650dca95af54
github.com/xtaci/kcp-go/v5 v5.5.17 golang.org/x/net v0.30.0
golang.org/x/net v0.43.0 golang.org/x/sys v0.26.0
golang.org/x/sys v0.35.0
golang.zx2c4.com/wireguard/windows v0.5.3 golang.zx2c4.com/wireguard/windows v0.5.3
) )
require ( require (
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/golang/mock v1.7.0-rc.1 // indirect
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
github.com/kardianos/service v1.2.2 // indirect github.com/kardianos/service v1.2.2 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/onsi/ginkgo/v2 v2.2.0 // indirect
github.com/klauspost/reedsolomon v1.11.8 // indirect github.com/quic-go/qtls-go1-19 v0.3.2 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/quic-go/qtls-go1-20 v0.2.2 // indirect
github.com/templexxx/cpu v0.1.0 // indirect
github.com/templexxx/xorsimd v0.4.2 // indirect
github.com/tjfoc/gmsm v1.4.1 // indirect
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect
golang.org/x/crypto v0.41.0 // indirect golang.org/x/crypto v0.28.0 // indirect
golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 // indirect
golang.org/x/mod v0.21.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/tools v0.26.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
gvisor.dev/gvisor v0.0.0-20241128011400-745828301c93 // indirect gvisor.dev/gvisor v0.0.0-20241128011400-745828301c93 // indirect
+60 -120
View File
@@ -1,44 +1,32 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60= github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60=
github.com/kardianos/service v1.2.2/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= github.com/kardianos/service v1.2.2/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
github.com/klauspost/cpuid v1.2.4/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI=
github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4= github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/klauspost/reedsolomon v1.9.9/go.mod h1:O7yFFHiQwDR6b2t63KPUpccPtNdp5ADgh1gg4fd12wo=
github.com/klauspost/reedsolomon v1.11.8 h1:s8RpUW5TK4hjr+djiOpbZJB4ksx+TdYbRH7vHQpwPOY=
github.com/klauspost/reedsolomon v1.11.8/go.mod h1:4bXRN+cVzMdml6ti7qLouuYi32KHJ5MGv0Qd8a47h6A=
github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104/go.mod h1:wqKykBG2QzQDJEzvRkcS8x6MiSJkF52hXZsXcjaB3ls=
github.com/openp2p-cn/go-reuseport v0.3.2 h1:TO78WsyJ1F6g7rLp3hpTKOBxtZTU5Lz+Y4Mj+fVUfZc= github.com/openp2p-cn/go-reuseport v0.3.2 h1:TO78WsyJ1F6g7rLp3hpTKOBxtZTU5Lz+Y4Mj+fVUfZc=
github.com/openp2p-cn/go-reuseport v0.3.2/go.mod h1:+EwCusXz50jaYkPNZcCrK4cLoA9tr2jEiJC+bjzpWc8= github.com/openp2p-cn/go-reuseport v0.3.2/go.mod h1:+EwCusXz50jaYkPNZcCrK4cLoA9tr2jEiJC+bjzpWc8=
github.com/openp2p-cn/service v1.0.0 h1:1++FroLvW4Mc/PStFIAF0mzudVW6E8EAeqWyIESTGZA= github.com/openp2p-cn/service v1.0.0 h1:1++FroLvW4Mc/PStFIAF0mzudVW6E8EAeqWyIESTGZA=
@@ -47,98 +35,65 @@ github.com/openp2p-cn/totp v0.0.0-20230421034602-0f3320ffb25e h1:QqP3Va/nPj45wq0
github.com/openp2p-cn/totp v0.0.0-20230421034602-0f3320ffb25e/go.mod h1:RYVP3CTIvHD9IwQe2M3zy5iLKNjusRVDz/4gQuKcc/o= github.com/openp2p-cn/totp v0.0.0-20230421034602-0f3320ffb25e/go.mod h1:RYVP3CTIvHD9IwQe2M3zy5iLKNjusRVDz/4gQuKcc/o=
github.com/openp2p-cn/wireguard-go v0.0.20241020 h1:cNgG8o2ctYT9YanqalfMQo+jVju7MrdJFI6WLZZRr7M= github.com/openp2p-cn/wireguard-go v0.0.20241020 h1:cNgG8o2ctYT9YanqalfMQo+jVju7MrdJFI6WLZZRr7M=
github.com/openp2p-cn/wireguard-go v0.0.20241020/go.mod h1:ka26SCScyLEd+uFrnq6w4n65Sxq1W/xIJfXEXLLvJEc= github.com/openp2p-cn/wireguard-go v0.0.20241020/go.mod h1:ka26SCScyLEd+uFrnq6w4n65Sxq1W/xIJfXEXLLvJEc=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U=
github.com/quic-go/quic-go v0.57.1 h1:25KAAR9QR8KZrCZRThWMKVAwGoiHIrNbT72ULHTuI10= github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
github.com/quic-go/quic-go v0.57.1/go.mod h1:ly4QBAjHA2VhdnxhojRsCUOeJwKYg+taDlos92xb1+s= github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/quic-go/quic-go v0.34.0 h1:OvOJ9LFjTySgwOTYUZmNoq0FzVicP8YujpV0kB7m2lU=
github.com/templexxx/cpu v0.0.1/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk= github.com/quic-go/quic-go v0.34.0/go.mod h1:+4CVgVppm0FNjpG3UcX8Joi/frKOH7/ciD5yGcwOO1g=
github.com/templexxx/cpu v0.0.7/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/templexxx/cpu v0.1.0 h1:wVM+WIJP2nYaxVxqgHPD4wGA2aJ9rvrQRV8CvFzNb40= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/templexxx/cpu v0.1.0/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/templexxx/xorsimd v0.4.1/go.mod h1:W+ffZz8jJMH2SXwuKu9WhygqBMbFnp14G2fqEr8qaNo=
github.com/templexxx/xorsimd v0.4.2 h1:ocZZ+Nvu65LGHmCLZ7OoCtg8Fx8jnHKK37SjvngUoVI=
github.com/templexxx/xorsimd v0.4.2/go.mod h1:HgwaPoDREdi6OnULpSfxhzaiiSUY4Fi3JPn1wpt28NI=
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
github.com/vishvananda/netlink v1.1.1-0.20211118161826-650dca95af54 h1:8mhqcHPqTMhSPoslhGYihEgSfc77+7La1P6kiB6+9So= github.com/vishvananda/netlink v1.1.1-0.20211118161826-650dca95af54 h1:8mhqcHPqTMhSPoslhGYihEgSfc77+7La1P6kiB6+9So=
github.com/vishvananda/netlink v1.1.1-0.20211118161826-650dca95af54/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netlink v1.1.1-0.20211118161826-650dca95af54/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA=
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/xtaci/kcp-go/v5 v5.5.17 h1:bkdaqtER0PMlP05BBHfu6W+71kt/NwbAk93KH7F78Ck= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/xtaci/kcp-go/v5 v5.5.17/go.mod h1:pVx3jb4LT5edTmPayc77tIU9nRsjGck8wep5ZV/RBO0=
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM=
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
golang.org/x/arch v0.0.0-20190909030613-46d78d1859ac/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 h1:Di6/M8l0O2lCLc6VVRWhgCiApHV8MnQurBnFSHsQtNY=
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20230725093048-515e97ebf090/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200425043458-8463f397d07c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.0.0-20200808161706-5bf02b21f123/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
@@ -146,24 +101,9 @@ golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uI
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA= golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE= golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE=
golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gvisor.dev/gvisor v0.0.0-20241128011400-745828301c93 h1:QyA/pFgC67EZ5+0oRfiNFhfEGd3NqZM1A2HQEuPKC3c= gvisor.dev/gvisor v0.0.0-20241128011400-745828301c93 h1:QyA/pFgC67EZ5+0oRfiNFhfEGd3NqZM1A2HQEuPKC3c=
gvisor.dev/gvisor v0.0.0-20241128011400-745828301c93/go.mod h1:5DMfjtclAbTIjbXqO1qCe2K5GKKxWz2JHvCChuTcJEM= gvisor.dev/gvisor v0.0.0-20241128011400-745828301c93/go.mod h1:5DMfjtclAbTIjbXqO1qCe2K5GKKxWz2JHvCChuTcJEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
+239
View File
@@ -0,0 +1,239 @@
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// Package nat provides access to common network port mapping protocols.
package openp2p
import (
"errors"
"fmt"
"net"
"strings"
"sync"
"time"
natpmp "github.com/jackpal/go-nat-pmp"
)
// Interface An implementation of nat.Interface can map local ports to ports
// accessible from the Internet.
type Interface interface {
// These methods manage a mapping between a port on the local
// machine to a port that can be connected to from the internet.
//
// protocol is "UDP" or "TCP". Some implementations allow setting
// a display name for the mapping. The mapping may be removed by
// the gateway when its lifetime ends.
AddMapping(protocol string, extport, intport int, name string, lifetime time.Duration) (uint16, error)
DeleteMapping(protocol string, extport, intport int) error
// ExternalIP should return the external (Internet-facing)
// address of the gateway device.
ExternalIP() (net.IP, error)
// String should return name of the method. This is used for logging.
String() string
}
// Parse parses a NAT interface description.
// The following formats are currently accepted.
// Note that mechanism names are not case-sensitive.
//
// "" or "none" return nil
// "extip:77.12.33.4" will assume the local machine is reachable on the given IP
// "any" uses the first auto-detected mechanism
// "upnp" uses the Universal Plug and Play protocol
// "pmp" uses NAT-PMP with an auto-detected gateway address
// "pmp:192.168.0.1" uses NAT-PMP with the given gateway address
func Parse(spec string) (Interface, error) {
var (
before, after, found = strings.Cut(spec, ":")
mech = strings.ToLower(before)
ip net.IP
)
if found {
ip = net.ParseIP(after)
if ip == nil {
return nil, errors.New("invalid IP address")
}
}
switch mech {
case "", "none", "off":
return nil, nil
case "any", "auto", "on":
return Any(), nil
case "extip", "ip":
if ip == nil {
return nil, errors.New("missing IP address")
}
return ExtIP(ip), nil
case "upnp":
return UPnP(), nil
case "pmp", "natpmp", "nat-pmp":
return PMP(ip), nil
default:
return nil, fmt.Errorf("unknown mechanism %q", before)
}
}
const (
DefaultMapTimeout = 10 * time.Minute
)
// Map adds a port mapping on m and keeps it alive until c is closed.
// This function is typically invoked in its own goroutine.
//
// Note that Map does not handle the situation where the NAT interface assigns a different
// external port than the requested one.
func Map(m Interface, c <-chan struct{}, protocol string, extport, intport int, name string) {
// log := log.New("proto", protocol, "extport", extport, "intport", intport, "interface", m)
refresh := time.NewTimer(DefaultMapTimeout)
defer func() {
refresh.Stop()
// log.Debug("Deleting port mapping")
m.DeleteMapping(protocol, extport, intport)
}()
if _, err := m.AddMapping(protocol, extport, intport, name, DefaultMapTimeout); err != nil {
// log.Debug("Couldn't add port mapping", "err", err)
} else {
// log.Info("Mapped network port")
}
for {
select {
case _, ok := <-c:
if !ok {
return
}
case <-refresh.C:
// log.Trace("Refreshing port mapping")
if _, err := m.AddMapping(protocol, extport, intport, name, DefaultMapTimeout); err != nil {
// log.Debug("Couldn't add port mapping", "err", err)
}
refresh.Reset(DefaultMapTimeout)
}
}
}
// ExtIP assumes that the local machine is reachable on the given
// external IP address, and that any required ports were mapped manually.
// Mapping operations will not return an error but won't actually do anything.
type ExtIP net.IP
func (n ExtIP) ExternalIP() (net.IP, error) { return net.IP(n), nil }
func (n ExtIP) String() string { return fmt.Sprintf("ExtIP(%v)", net.IP(n)) }
// These do nothing.
func (ExtIP) AddMapping(string, int, int, string, time.Duration) (uint16, error) { return 0, nil }
func (ExtIP) DeleteMapping(string, int, int) error { return nil }
// Any returns a port mapper that tries to discover any supported
// mechanism on the local network.
func Any() Interface {
// TODO: attempt to discover whether the local machine has an
// Internet-class address. Return ExtIP in this case.
return startautodisc("UPnP or NAT-PMP", func() Interface {
found := make(chan Interface, 2)
go func() { found <- discoverUPnP() }()
go func() { found <- discoverPMP() }()
for i := 0; i < cap(found); i++ {
if c := <-found; c != nil {
return c
}
}
return nil
})
}
// UPnP returns a port mapper that uses UPnP. It will attempt to
// discover the address of your router using UDP broadcasts.
func UPnP() Interface {
return startautodisc("UPnP", discoverUPnP)
}
// PMP returns a port mapper that uses NAT-PMP. The provided gateway
// address should be the IP of your router. If the given gateway
// address is nil, PMP will attempt to auto-discover the router.
func PMP(gateway net.IP) Interface {
if gateway != nil {
return &pmp{gw: gateway, c: natpmp.NewClient(gateway)}
}
return startautodisc("NAT-PMP", discoverPMP)
}
// autodisc represents a port mapping mechanism that is still being
// auto-discovered. Calls to the Interface methods on this type will
// wait until the discovery is done and then call the method on the
// discovered mechanism.
//
// This type is useful because discovery can take a while but we
// want return an Interface value from UPnP, PMP and Auto immediately.
type autodisc struct {
what string // type of interface being autodiscovered
once sync.Once
doit func() Interface
mu sync.Mutex
found Interface
}
func startautodisc(what string, doit func() Interface) Interface {
// TODO: monitor network configuration and rerun doit when it changes.
return &autodisc{what: what, doit: doit}
}
func (n *autodisc) AddMapping(protocol string, extport, intport int, name string, lifetime time.Duration) (uint16, error) {
if err := n.wait(); err != nil {
return 0, err
}
return n.found.AddMapping(protocol, extport, intport, name, lifetime)
}
func (n *autodisc) DeleteMapping(protocol string, extport, intport int) error {
if err := n.wait(); err != nil {
return err
}
return n.found.DeleteMapping(protocol, extport, intport)
}
func (n *autodisc) ExternalIP() (net.IP, error) {
if err := n.wait(); err != nil {
return nil, err
}
return n.found.ExternalIP()
}
func (n *autodisc) String() string {
n.mu.Lock()
defer n.mu.Unlock()
if n.found == nil {
return n.what
}
return n.found.String()
}
// wait blocks until auto-discovery has been performed.
func (n *autodisc) wait() error {
n.once.Do(func() {
n.mu.Lock()
n.found = n.doit()
n.mu.Unlock()
})
if n.found == nil {
return fmt.Errorf("no %s router discovered", n.what)
}
return nil
}
+130
View File
@@ -0,0 +1,130 @@
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package openp2p
import (
"fmt"
"net"
"strings"
"time"
natpmp "github.com/jackpal/go-nat-pmp"
)
// natPMPClient adapts the NAT-PMP protocol implementation so it conforms to
// the common interface.
type pmp struct {
gw net.IP
c *natpmp.Client
}
func (n *pmp) String() string {
return fmt.Sprintf("NAT-PMP(%v)", n.gw)
}
func (n *pmp) ExternalIP() (net.IP, error) {
response, err := n.c.GetExternalAddress()
if err != nil {
return nil, err
}
return response.ExternalIPAddress[:], nil
}
func (n *pmp) AddMapping(protocol string, extport, intport int, name string, lifetime time.Duration) (uint16, error) {
if lifetime <= 0 {
return 0, fmt.Errorf("lifetime must not be <= 0")
}
// Note order of port arguments is switched between our
// AddMapping and the client's AddPortMapping.
res, err := n.c.AddPortMapping(strings.ToLower(protocol), intport, extport, int(lifetime/time.Second))
if err != nil {
return 0, err
}
// NAT-PMP maps an alternative available port number if the requested port
// is already mapped to another address and returns success. Handling of
// alternate port numbers is done by the caller.
return res.MappedExternalPort, nil
}
func (n *pmp) DeleteMapping(protocol string, extport, intport int) (err error) {
// To destroy a mapping, send an add-port with an internalPort of
// the internal port to destroy, an external port of zero and a
// time of zero.
_, err = n.c.AddPortMapping(strings.ToLower(protocol), intport, 0, 0)
return err
}
func discoverPMP() Interface {
// run external address lookups on all potential gateways
gws := potentialGateways()
found := make(chan *pmp, len(gws))
for i := range gws {
gw := gws[i]
go func() {
c := natpmp.NewClient(gw)
if _, err := c.GetExternalAddress(); err != nil {
found <- nil
} else {
found <- &pmp{gw, c}
}
}()
}
// return the one that responds first.
// discovery needs to be quick, so we stop caring about
// any responses after a very short timeout.
timeout := time.NewTimer(1 * time.Second)
defer timeout.Stop()
for range gws {
select {
case c := <-found:
if c != nil {
return c
}
case <-timeout.C:
return nil
}
}
return nil
}
// TODO: improve this. We currently assume that (on most networks)
// the router is X.X.X.1 in a local LAN range.
func potentialGateways() (gws []net.IP) {
ifaces, err := net.Interfaces()
if err != nil {
return nil
}
for _, iface := range ifaces {
ifaddrs, err := iface.Addrs()
if err != nil {
return gws
}
for _, addr := range ifaddrs {
if x, ok := addr.(*net.IPNet); ok {
if x.IP.IsPrivate() {
ip := x.IP.Mask(x.Mask).To4()
if ip != nil {
ip[3] = ip[3] | 0x01
gws = append(gws, ip)
}
}
}
}
}
return gws
}
+247
View File
@@ -0,0 +1,247 @@
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package openp2p
import (
"errors"
"fmt"
"math"
"math/rand"
"net"
"strings"
"sync"
"time"
"github.com/huin/goupnp"
"github.com/huin/goupnp/dcps/internetgateway1"
"github.com/huin/goupnp/dcps/internetgateway2"
)
const (
soapRequestTimeout = 3 * time.Second
rateLimit = 200 * time.Millisecond
)
type upnp struct {
dev *goupnp.RootDevice
service string
client upnpClient
mu sync.Mutex
lastReqTime time.Time
rand *rand.Rand
}
type upnpClient interface {
GetExternalIPAddress() (string, error)
AddPortMapping(string, uint16, string, uint16, string, bool, string, uint32) error
DeletePortMapping(string, uint16, string) error
GetNATRSIPStatus() (sip bool, nat bool, err error)
}
func (n *upnp) natEnabled() bool {
var ok bool
var err error
n.withRateLimit(func() error {
_, ok, err = n.client.GetNATRSIPStatus()
return err
})
return err == nil && ok
}
func (n *upnp) ExternalIP() (addr net.IP, err error) {
var ipString string
n.withRateLimit(func() error {
ipString, err = n.client.GetExternalIPAddress()
return err
})
if err != nil {
return nil, err
}
ip := net.ParseIP(ipString)
if ip == nil {
return nil, errors.New("bad IP in response")
}
return ip, nil
}
func (n *upnp) AddMapping(protocol string, extport, intport int, desc string, lifetime time.Duration) (uint16, error) {
ip, err := n.internalAddress()
if err != nil {
return 0, nil // TODO: Shouldn't we return the error?
}
protocol = strings.ToUpper(protocol)
lifetimeS := uint32(lifetime / time.Second)
n.DeleteMapping(protocol, extport, intport)
err = n.withRateLimit(func() error {
return n.client.AddPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS)
})
if err == nil {
return uint16(extport), nil
}
return uint16(extport), n.withRateLimit(func() error {
p, err := n.addAnyPortMapping(protocol, extport, intport, ip, desc, lifetimeS)
if err == nil {
extport = int(p)
}
return err
})
}
func (n *upnp) addAnyPortMapping(protocol string, extport, intport int, ip net.IP, desc string, lifetimeS uint32) (uint16, error) {
if client, ok := n.client.(*internetgateway2.WANIPConnection2); ok {
return client.AddAnyPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS)
}
// It will retry with a random port number if the client does
// not support AddAnyPortMapping.
extport = n.randomPort()
err := n.client.AddPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS)
if err != nil {
return 0, err
}
return uint16(extport), nil
}
func (n *upnp) randomPort() int {
if n.rand == nil {
n.rand = rand.New(rand.NewSource(time.Now().UnixNano()))
}
return n.rand.Intn(math.MaxUint16-10000) + 10000
}
func (n *upnp) internalAddress() (net.IP, error) {
devaddr, err := net.ResolveUDPAddr("udp4", n.dev.URLBase.Host)
if err != nil {
return nil, err
}
ifaces, err := net.Interfaces()
if err != nil {
return nil, err
}
for _, iface := range ifaces {
addrs, err := iface.Addrs()
if err != nil {
return nil, err
}
for _, addr := range addrs {
if x, ok := addr.(*net.IPNet); ok && x.Contains(devaddr.IP) {
return x.IP, nil
}
}
}
return nil, fmt.Errorf("could not find local address in same net as %v", devaddr)
}
func (n *upnp) DeleteMapping(protocol string, extport, intport int) error {
return n.withRateLimit(func() error {
return n.client.DeletePortMapping("", uint16(extport), strings.ToUpper(protocol))
})
}
func (n *upnp) String() string {
return "UPNP " + n.service
}
func (n *upnp) withRateLimit(fn func() error) error {
n.mu.Lock()
defer n.mu.Unlock()
lastreq := time.Since(n.lastReqTime)
if lastreq < rateLimit {
time.Sleep(rateLimit - lastreq)
}
err := fn()
n.lastReqTime = time.Now()
return err
}
// discoverUPnP searches for Internet Gateway Devices
// and returns the first one it can find on the local network.
func discoverUPnP() Interface {
found := make(chan *upnp, 2)
// IGDv1
go discover(found, internetgateway1.URN_WANConnectionDevice_1, func(sc goupnp.ServiceClient) *upnp {
switch sc.Service.ServiceType {
case internetgateway1.URN_WANIPConnection_1:
return &upnp{service: "IGDv1-IP1", client: &internetgateway1.WANIPConnection1{ServiceClient: sc}}
case internetgateway1.URN_WANPPPConnection_1:
return &upnp{service: "IGDv1-PPP1", client: &internetgateway1.WANPPPConnection1{ServiceClient: sc}}
}
return nil
})
// IGDv2
go discover(found, internetgateway2.URN_WANConnectionDevice_2, func(sc goupnp.ServiceClient) *upnp {
switch sc.Service.ServiceType {
case internetgateway2.URN_WANIPConnection_1:
return &upnp{service: "IGDv2-IP1", client: &internetgateway2.WANIPConnection1{ServiceClient: sc}}
case internetgateway2.URN_WANIPConnection_2:
return &upnp{service: "IGDv2-IP2", client: &internetgateway2.WANIPConnection2{ServiceClient: sc}}
case internetgateway2.URN_WANPPPConnection_1:
return &upnp{service: "IGDv2-PPP1", client: &internetgateway2.WANPPPConnection1{ServiceClient: sc}}
}
return nil
})
for i := 0; i < cap(found); i++ {
if c := <-found; c != nil {
return c
}
}
return nil
}
// finds devices matching the given target and calls matcher for all
// advertised services of each device. The first non-nil service found
// is sent into out. If no service matched, nil is sent.
func discover(out chan<- *upnp, target string, matcher func(goupnp.ServiceClient) *upnp) {
devs, err := goupnp.DiscoverDevices(target)
if err != nil {
out <- nil
return
}
found := false
for i := 0; i < len(devs) && !found; i++ {
if devs[i].Root == nil {
continue
}
devs[i].Root.Device.VisitServices(func(service *goupnp.Service) {
if found {
return
}
// check for a matching IGD service
sc := goupnp.ServiceClient{
SOAPClient: service.NewSOAPClient(),
RootDevice: devs[i].Root,
Location: devs[i].Location,
Service: service,
}
sc.SOAPClient.HTTPClient.Timeout = soapRequestTimeout
upnp := matcher(sc)
if upnp == nil {
return
}
upnp.dev = devs[i].Root
out <- upnp
found = true
})
}
if !found {
out <- nil
}
}