feat: SDWAN data plane + UDP punch port fix + TUN reader
SDWAN: - protocol: add SDWANConfig/SDWANPeer/SDWANPacket structs, MsgTunnel type - server: sdwan.go (JSON file store), sdwan_api.go (Get/Set/broadcast/route) - server: push SDWAN config on login, announce peer online/offline events - server: RouteSDWANPacket routes TUN packets between nodes via signaling - client: TUN device setup (optun), tunReadLoop reads IP packets - client: handle SDWANConfig/SDWANPeer/SDWANDel push messages - client: apply routes (per-node /32 + broad CIDR fallback) UDP punch fix: - nat/detect: capture LocalPort from STUN UDP socket for punch binding - client: pass publicPort + localPort through login and punch config - coordinator: include PublicPort in PunchParams for both sides - protocol: add PublicPort to LoginReq and ReportBasic Other: - server: use client-reported PublicIP instead of raw r.RemoteAddr - server: update PublicIP/Port from ReportBasic if provided - client: config file loading with zero-value defaults backfill - .gitignore: exclude run/, *.pid, *.log, sdwan.json - go.mod: add golang.org/x/sys for TUN ioctl
This commit is contained in:
147
internal/server/sdwan_api.go
Normal file
147
internal/server/sdwan_api.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
|
||||
"github.com/openp2p-cn/inp2p/pkg/protocol"
|
||||
)
|
||||
|
||||
func (s *Server) GetSDWAN() protocol.SDWANConfig {
|
||||
return s.sdwan.get()
|
||||
}
|
||||
|
||||
func (s *Server) SetSDWAN(cfg protocol.SDWANConfig) error {
|
||||
if err := s.sdwan.save(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
s.broadcastSDWAN(s.sdwan.get())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) broadcastSDWAN(cfg protocol.SDWANConfig) {
|
||||
if !cfg.Enabled || cfg.GatewayCIDR == "" {
|
||||
return
|
||||
}
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
for _, n := range s.nodes {
|
||||
if !n.IsOnline() {
|
||||
continue
|
||||
}
|
||||
_ = n.Conn.Write(protocol.MsgPush, protocol.SubPushSDWANConfig, cfg)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) pushSDWANPeer(to *NodeInfo, peer protocol.SDWANPeer) {
|
||||
if to == nil || !to.IsOnline() {
|
||||
return
|
||||
}
|
||||
_ = to.Conn.Write(protocol.MsgPush, protocol.SubPushSDWANPeer, peer)
|
||||
}
|
||||
|
||||
func (s *Server) pushSDWANDel(to *NodeInfo, peer protocol.SDWANPeer) {
|
||||
if to == nil || !to.IsOnline() {
|
||||
return
|
||||
}
|
||||
_ = to.Conn.Write(protocol.MsgPush, protocol.SubPushSDWANDel, peer)
|
||||
}
|
||||
|
||||
func (s *Server) announceSDWANNodeOnline(nodeName string) {
|
||||
cfg := s.sdwan.get()
|
||||
if cfg.GatewayCIDR == "" {
|
||||
return
|
||||
}
|
||||
selfIP := ""
|
||||
for _, n := range cfg.Nodes {
|
||||
if n.Node == nodeName {
|
||||
selfIP = n.IP
|
||||
break
|
||||
}
|
||||
}
|
||||
if selfIP == "" {
|
||||
return
|
||||
}
|
||||
|
||||
s.mu.RLock()
|
||||
newNode := s.nodes[nodeName]
|
||||
if newNode == nil || !newNode.IsOnline() {
|
||||
s.mu.RUnlock()
|
||||
return
|
||||
}
|
||||
for _, n := range cfg.Nodes {
|
||||
if n.Node == nodeName {
|
||||
continue
|
||||
}
|
||||
other := s.nodes[n.Node]
|
||||
if other == nil || !other.IsOnline() {
|
||||
continue
|
||||
}
|
||||
// existing -> new
|
||||
s.pushSDWANPeer(newNode, protocol.SDWANPeer{Node: n.Node, IP: n.IP, Online: true})
|
||||
// new -> existing
|
||||
s.pushSDWANPeer(other, protocol.SDWANPeer{Node: nodeName, IP: selfIP, Online: true})
|
||||
}
|
||||
s.mu.RUnlock()
|
||||
}
|
||||
|
||||
func (s *Server) announceSDWANNodeOffline(nodeName string) {
|
||||
cfg := s.sdwan.get()
|
||||
if cfg.GatewayCIDR == "" {
|
||||
return
|
||||
}
|
||||
selfIP := ""
|
||||
for _, n := range cfg.Nodes {
|
||||
if n.Node == nodeName {
|
||||
selfIP = n.IP
|
||||
break
|
||||
}
|
||||
}
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
for _, n := range s.nodes {
|
||||
if n.Name == nodeName || !n.IsOnline() {
|
||||
continue
|
||||
}
|
||||
s.pushSDWANDel(n, protocol.SDWANPeer{Node: nodeName, IP: selfIP, Online: false})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RouteSDWANPacket(from *NodeInfo, pkt protocol.SDWANPacket) {
|
||||
if from == nil {
|
||||
return
|
||||
}
|
||||
cfg := s.sdwan.get()
|
||||
if cfg.GatewayCIDR == "" || pkt.DstIP == "" || len(pkt.Payload) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
dst, err := netip.ParseAddr(pkt.DstIP)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
toNode := ""
|
||||
for _, n := range cfg.Nodes {
|
||||
if n.IP == pkt.DstIP {
|
||||
toNode = n.Node
|
||||
break
|
||||
}
|
||||
if p, err := netip.ParseAddr(n.IP); err == nil && p == dst {
|
||||
toNode = n.Node
|
||||
break
|
||||
}
|
||||
}
|
||||
if toNode == "" || toNode == from.Name {
|
||||
return
|
||||
}
|
||||
|
||||
s.mu.RLock()
|
||||
to := s.nodes[toNode]
|
||||
s.mu.RUnlock()
|
||||
if to == nil || !to.IsOnline() {
|
||||
return
|
||||
}
|
||||
|
||||
pkt.FromNode = from.Name
|
||||
pkt.ToNode = toNode
|
||||
_ = to.Conn.Write(protocol.MsgTunnel, protocol.SubTunnelSDWANData, pkt)
|
||||
}
|
||||
Reference in New Issue
Block a user