This commit is contained in:
TenderIronh
2024-10-20 11:33:07 +08:00
parent c68094cc12
commit df1e16e708
14 changed files with 188 additions and 49 deletions

View File

@@ -1,6 +1,7 @@
package openp2p
import (
"fmt"
"log"
"testing"
)
@@ -114,3 +115,15 @@ func TestIsIPv6(t *testing.T) {
}
}
}
func TestNodeID(t *testing.T) {
node1 := "n1-stable"
node2 := "tony-stable"
nodeID1 := NodeNameToID(node1)
nodeID2 := NodeNameToID(node2)
if nodeID1 < nodeID2 {
fmt.Printf("%s < %s\n", node1, node2)
} else {
fmt.Printf("%s >= %s\n", node1, node2)
}
}

View File

@@ -78,12 +78,13 @@ type Config struct {
Apps []*AppConfig `json:"apps"`
LogLevel int
MaxLogSize int
daemonMode bool
mtx sync.Mutex
sdwanMtx sync.Mutex
sdwan SDWANInfo
delNodes []SDWANNode
addNodes []SDWANNode
delNodes []*SDWANNode
addNodes []*SDWANNode
}
func (c *Config) getSDWAN() SDWANInfo {
@@ -92,23 +93,30 @@ func (c *Config) getSDWAN() SDWANInfo {
return c.sdwan
}
func (c *Config) getDelNodes() []SDWANNode {
func (c *Config) getDelNodes() []*SDWANNode {
c.sdwanMtx.Lock()
defer c.sdwanMtx.Unlock()
return c.delNodes
}
func (c *Config) getAddNodes() []SDWANNode {
func (c *Config) getAddNodes() []*SDWANNode {
c.sdwanMtx.Lock()
defer c.sdwanMtx.Unlock()
return c.addNodes
}
func (c *Config) resetSDWAN() {
c.sdwanMtx.Lock()
defer c.sdwanMtx.Unlock()
c.delNodes = []*SDWANNode{}
c.addNodes = []*SDWANNode{}
c.sdwan = SDWANInfo{}
}
func (c *Config) setSDWAN(s SDWANInfo) {
c.sdwanMtx.Lock()
defer c.sdwanMtx.Unlock()
// get old-new
c.delNodes = []SDWANNode{}
c.delNodes = []*SDWANNode{}
for _, oldNode := range c.sdwan.Nodes {
isDeleted := true
for _, newNode := range s.Nodes {
@@ -122,7 +130,7 @@ func (c *Config) setSDWAN(s SDWANInfo) {
}
}
// get new-old
c.addNodes = []SDWANNode{}
c.addNodes = []*SDWANNode{}
for _, newNode := range s.Nodes {
isNew := true
for _, oldNode := range c.sdwan.Nodes {
@@ -230,17 +238,8 @@ func (c *Config) delete(app AppConfig) {
defer c.mtx.Unlock()
defer c.save()
for i := 0; i < len(c.Apps); i++ {
got := false
if app.SrcPort != 0 { // normal p2papp
if c.Apps[i].Protocol == app.Protocol && c.Apps[i].SrcPort == app.SrcPort {
got = true
}
} else { // memapp
if c.Apps[i].PeerNode == app.PeerNode {
got = true
}
}
if got {
if (app.SrcPort != 0 && c.Apps[i].Protocol == app.Protocol && c.Apps[i].SrcPort == app.SrcPort) || // normal app
(app.SrcPort == 0 && c.Apps[i].PeerNode == app.PeerNode) { // memapp
if i == len(c.Apps)-1 {
c.Apps = c.Apps[:i]
} else {
@@ -249,7 +248,6 @@ func (c *Config) delete(app AppConfig) {
return
}
}
}
func (c *Config) save() {
@@ -280,6 +278,7 @@ func (c *Config) saveCache() {
func init() {
gConf.LogLevel = int(LvINFO)
gConf.MaxLogSize = 1024 * 1024
gConf.Network.ShareBandwidth = 10
gConf.Network.ServerHost = "api.openp2p.cn"
gConf.Network.ServerPort = WsPort
@@ -463,6 +462,9 @@ func parseParams(subCommand string, cmd string) {
if f.Name == "loglevel" {
gConf.LogLevel = *logLevel
}
if f.Name == "maxlogsize" {
gConf.MaxLogSize = *maxLogSize
}
if f.Name == "tcpport" {
gConf.Network.TCPPort = *tcpPort
}

View File

@@ -52,7 +52,7 @@ func addRoute(dst, gw, ifname string) error {
}
func delRoute(dst, gw string) error {
err := exec.Command("route", "delete", dst, gw).Run()
err := exec.Command("route", "delete", dst, "-gateway", gw).Run()
return err
}
func delRoutesByGateway(gateway string) error {
@@ -68,13 +68,14 @@ func delRoutesByGateway(gateway string) error {
continue
}
fields := strings.Fields(line)
if len(fields) >= 7 && fields[0] == "default" && fields[len(fields)-1] == gateway {
delCmd := exec.Command("route", "delete", "default", gateway)
err := delCmd.Run()
if len(fields) >= 2 {
cmd := exec.Command("route", "delete", fields[0], gateway)
err := cmd.Run()
if err != nil {
return err
gLog.Printf(LvERROR, "Delete route %s error:%s", fields[0], err)
continue
}
fmt.Printf("Delete route ok: %s %s\n", "default", gateway)
gLog.Printf(LvINFO, "Delete route ok: %s %s\n", fields[0], gateway)
}
}
return nil

View File

@@ -124,9 +124,10 @@ func delRoutesByGateway(gateway string) error {
delCmd := exec.Command("route", "del", "-net", fields[0], "gw", gateway)
err := delCmd.Run()
if err != nil {
return err
gLog.Printf(LvERROR, "Delete route %s error:%s", fields[0], err)
continue
}
fmt.Printf("Delete route ok: %s %s %s\n", fields[0], fields[1], gateway)
gLog.Printf(LvINFO, "Delete route ok: %s %s %s\n", fields[0], fields[1], gateway)
}
}
return nil

View File

@@ -133,9 +133,10 @@ func delRoutesByGateway(gateway string) error {
cmd := exec.Command("route", "delete", fields[0], "mask", fields[1], gateway)
err := cmd.Run()
if err != nil {
fmt.Println("Delete route error:", err)
gLog.Printf(LvERROR, "Delete route %s error:%s", fields[0], err)
continue
}
fmt.Printf("Delete route ok: %s %s %s\n", fields[0], fields[1], gateway)
gLog.Printf(LvINFO, "Delete route ok: %s %s %s\n", fields[0], fields[1], gateway)
}
}
return nil

View File

@@ -115,6 +115,7 @@ func (pn *P2PNetwork) run() {
pn.write(MsgHeartbeat, 0, "")
case <-pn.restartCh:
gLog.Printf(LvDEBUG, "got restart channel")
GNetwork.sdwan.reset()
pn.online = false
pn.wgReconnect.Wait() // wait read/autorunapp goroutine end
delay := ClientAPITimeout + time.Duration(rand.Int()%pn.loginMaxDelaySeconds)*time.Second
@@ -124,6 +125,7 @@ func (pn *P2PNetwork) run() {
gLog.Println(LvERROR, "P2PNetwork init error:", err)
}
gConf.retryAllApp()
case t := <-pn.tunnelCloseCh:
gLog.Printf(LvDEBUG, "got tunnelCloseCh %s", t.config.LogPeerNode())
pn.apps.Range(func(id, i interface{}) bool {

View File

@@ -426,7 +426,7 @@ func (t *P2PTunnel) connectUnderlayTCPSymmetric() (c underlay, err error) {
}
_, buff, err := ul.ReadBuffer()
if err != nil {
gLog.Printf(LvERROR, "utcp.ReadBuffer error:", err)
gLog.Println(LvDEBUG, "c2s ul.ReadBuffer error:", err)
return
}
req := P2PHandshakeReq{}
@@ -455,7 +455,7 @@ func (t *P2PTunnel) connectUnderlayTCPSymmetric() (c underlay, err error) {
_, buff, err := ul.ReadBuffer()
if err != nil {
gLog.Printf(LvERROR, "utcp.ReadBuffer error:", err)
gLog.Println(LvDEBUG, "s2c ul.ReadBuffer error:", err)
return
}
req := P2PHandshakeReq{}
@@ -512,14 +512,14 @@ func (t *P2PTunnel) connectUnderlayTCP6() (c underlay, err error) {
t.pn.read(t.config.PeerNode, MsgPush, MsgPushUnderlayConnect, ReadMsgTimeout)
gLog.Println(LvDEBUG, "TCP6 dial to ", t.config.peerIPv6)
ul, err = dialTCP6(t.config.peerIPv6, t.config.peerConeNatPort)
if err != nil {
if err != nil || ul == nil {
return nil, fmt.Errorf("TCP6 dial to %s:%d error:%s", t.config.peerIPv6, t.config.peerConeNatPort, err)
}
handshakeBegin := time.Now()
ul.WriteBytes(MsgP2P, MsgTunnelHandshake, []byte("OpenP2P,hello"))
_, buff, err := ul.ReadBuffer()
if err != nil {
return nil, fmt.Errorf("read MsgTunnelHandshake error:%s", err)
_, buff, errR := ul.ReadBuffer()
if errR != nil {
return nil, fmt.Errorf("read MsgTunnelHandshake error:%s", errR)
}
if buff != nil {
gLog.Println(LvDEBUG, string(buff))

87
core/ping.go Normal file
View File

@@ -0,0 +1,87 @@
package openp2p
import (
"fmt"
"net"
"os"
"time"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
)
// 定义ICMP回显请求和应答的结构
type ICMPMessage struct {
Type uint8
Code uint8
Checksum uint16
Ident uint16
Seq uint16
Data []byte
}
// Ping sends an ICMP Echo request to the specified host and returns the response time.
func Ping(host string) (time.Duration, error) {
// Resolve the IP address of the host
ipAddr, err := net.ResolveIPAddr("ip4", host)
if err != nil {
return 0, fmt.Errorf("failed to resolve host: %v", err)
}
// Create an ICMP listener
conn, err := net.ListenPacket("ip4:icmp", "0.0.0.0")
if err != nil {
return 0, fmt.Errorf("failed to create ICMP connection: %v", err)
}
defer conn.Close()
// Create an ICMP Echo request message
message := icmp.Message{
Type: ipv4.ICMPTypeEcho,
Code: 0,
Body: &icmp.Echo{
ID: os.Getpid() & 0xffff,
Seq: 1,
Data: []byte("HELLO-R-U-THERE"),
},
}
// Marshal the message into binary form
messageBytes, err := message.Marshal(nil)
if err != nil {
return 0, fmt.Errorf("failed to marshal ICMP message: %v", err)
}
// Send the ICMP Echo request
start := time.Now()
if _, err := conn.WriteTo(messageBytes, ipAddr); err != nil {
return 0, fmt.Errorf("failed to send ICMP request: %v", err)
}
// Set a deadline for the response
err = conn.SetReadDeadline(time.Now().Add(3 * time.Second))
if err != nil {
return 0, fmt.Errorf("failed to set read deadline: %v", err)
}
// Read the ICMP response
response := make([]byte, 1500)
n, _, err := conn.ReadFrom(response)
if err != nil {
return 0, fmt.Errorf("failed to read ICMP response: %v", err)
}
// Parse the ICMP response message
parsedMessage, err := icmp.ParseMessage(ipv4.ICMPTypeEchoReply.Protocol(), response[:n])
if err != nil {
return 0, fmt.Errorf("failed to parse ICMP response: %v", err)
}
// Check if the response is an Echo reply
if parsedMessage.Type == ipv4.ICMPTypeEchoReply {
duration := time.Since(start)
return duration, nil
} else {
return 0, fmt.Errorf("unexpected ICMP message: %+v", parsedMessage)
}
}

View File

@@ -10,7 +10,7 @@ import (
"time"
)
const OpenP2PVersion = "3.19.0"
const OpenP2PVersion = "3.21.8"
const ProductName string = "openp2p"
const LeastSupportVersion = "3.0.0"
const SyncServerTimeVersion = "3.9.0"
@@ -495,7 +495,7 @@ type SDWANInfo struct {
ForceRelay int32 `json:"forceRelay,omitempty"`
PunchPriority int32 `json:"punchPriority,omitempty"`
Enable int32 `json:"enable,omitempty"`
Nodes []SDWANNode
Nodes []*SDWANNode
}
const (

View File

@@ -52,18 +52,36 @@ type p2pSDWAN struct {
internalRoute *IPTree
}
func (s *p2pSDWAN) reset() {
gLog.Println(LvINFO, "reset sdwan when network disconnected")
// clear sysroute
delRoutesByGateway(s.gateway.String())
// clear internel route
s.internalRoute = NewIPTree("")
// clear p2papp
for _, node := range gConf.getAddNodes() {
gConf.delete(AppConfig{SrcPort: 0, PeerNode: node.Name})
}
gConf.resetSDWAN()
}
func (s *p2pSDWAN) init(name string) error {
if gConf.getSDWAN().Gateway == "" {
gLog.Println(LvDEBUG, "not in sdwan clear all ")
gLog.Println(LvDEBUG, "sdwan init: not in sdwan clear all ")
}
if s.internalRoute == nil {
s.internalRoute = NewIPTree("")
}
s.nodeName = name
s.gateway, s.subnet, _ = net.ParseCIDR(gConf.getSDWAN().Gateway)
if gw, sn, err := net.ParseCIDR(gConf.getSDWAN().Gateway); err == nil { // preserve old gateway
s.gateway = gw
s.subnet = sn
}
for _, node := range gConf.getDelNodes() {
gLog.Println(LvDEBUG, "deal deleted node: ", node.Name)
gLog.Println(LvDEBUG, "sdwan init: deal deleted node: ", node.Name)
gLog.Printf(LvDEBUG, "sdwan init: delRoute: %s, %s ", node.IP, s.gateway.String())
delRoute(node.IP, s.gateway.String())
s.internalRoute.Del(node.IP, node.IP)
ipNum, _ := inetAtoN(node.IP)
@@ -88,24 +106,26 @@ func (s *p2pSDWAN) init(name string) error {
}
s.internalRoute.Del(minIP.String(), maxIP.String())
delRoute(ipnet.String(), s.gateway.String())
gLog.Printf(LvDEBUG, "sdwan init: resource delRoute: %s, %s ", ipnet.String(), s.gateway.String())
}
}
for _, node := range gConf.getAddNodes() {
gLog.Println(LvDEBUG, "deal add node: ", node.Name)
gLog.Println(LvDEBUG, "sdwan init: deal add node: ", node.Name)
ipNet := &net.IPNet{
IP: net.ParseIP(node.IP),
Mask: s.subnet.Mask,
}
if node.Name == s.nodeName {
s.virtualIP = ipNet
gLog.Println(LvINFO, "start tun ", ipNet.String())
gLog.Println(LvINFO, "sdwan init: start tun ", ipNet.String())
err := s.StartTun()
if err != nil {
gLog.Println(LvERROR, "start tun error:", err)
gLog.Println(LvERROR, "sdwan init: start tun error:", err)
return err
}
gLog.Println(LvINFO, "start tun ok")
gLog.Println(LvINFO, "sdwan init: start tun ok")
allowTunForward()
gLog.Printf(LvDEBUG, "sdwan init: addRoute %s %s %s", s.subnet.String(), s.gateway.String(), s.tun.tunName)
addRoute(s.subnet.String(), s.gateway.String(), s.tun.tunName)
// addRoute("255.255.255.255/32", s.gateway.String(), s.tun.tunName) // for broadcast
// addRoute("224.0.0.0/4", s.gateway.String(), s.tun.tunName) // for multicast
@@ -124,18 +144,28 @@ func (s *p2pSDWAN) init(name string) error {
continue
}
if len(node.Resource) > 0 {
gLog.Printf(LvINFO, "deal add node: %s resource: %s", node.Name, node.Resource)
gLog.Printf(LvINFO, "sdwan init: deal add node: %s resource: %s", node.Name, node.Resource)
arr := strings.Split(node.Resource, ",")
for _, r := range arr {
// add internal route
_, ipnet, err := net.ParseCIDR(r)
if err != nil {
fmt.Println("Error parsing CIDR:", err)
fmt.Println("sdwan init: Error parsing CIDR:", err)
continue
}
if ipnet.Contains(net.ParseIP(gConf.Network.localIP)) { // local ip and resource in the same lan
gLog.Printf(LvDEBUG, "sdwan init: local ip %s in this resource %s, ignore", gConf.Network.localIP, ipnet.IP.String())
continue
}
// local net could access this single ip
if ipnet.Mask[0] == 255 && ipnet.Mask[1] == 255 && ipnet.Mask[2] == 255 && ipnet.Mask[3] == 255 {
gLog.Printf(LvDEBUG, "sdwan init: ping %s start", ipnet.IP.String())
if _, err := Ping(ipnet.IP.String()); err == nil {
gLog.Printf(LvDEBUG, "sdwan init: ping %s ok, ignore this resource", ipnet.IP.String())
continue
}
gLog.Printf(LvDEBUG, "sdwan init: ping %s failed", ipnet.IP.String())
}
minIP := ipnet.IP
maxIP := make(net.IP, len(minIP))
copy(maxIP, minIP)
@@ -144,6 +174,7 @@ func (s *p2pSDWAN) init(name string) error {
}
s.internalRoute.Add(minIP.String(), maxIP.String(), &sdwanNode{name: node.Name, id: NodeNameToID(node.Name)})
// add sys route
gLog.Printf(LvDEBUG, "sdwan init: addRoute %s %s %s", ipnet.String(), s.gateway.String(), s.tun.tunName)
addRoute(ipnet.String(), s.gateway.String(), s.tun.tunName)
}
}

View File

@@ -47,7 +47,7 @@ func (vl *v4Listener) handleConnection(c net.Conn) {
utcp.SetReadDeadline(time.Now().Add(UnderlayTCPConnectTimeout))
_, buff, err := utcp.ReadBuffer()
if err != nil {
gLog.Printf(LvERROR, "utcp.ReadBuffer error:", err)
gLog.Println(LvERROR, "utcp.ReadBuffer error:", err)
}
utcp.WriteBytes(MsgP2P, MsgTunnelHandshakeAck, buff)
var tid uint64