feat: audit api, sdwan persist, relay fallback updates
This commit is contained in:
@@ -36,17 +36,17 @@ const (
|
||||
|
||||
// ServerConfig holds inp2ps configuration.
|
||||
type ServerConfig struct {
|
||||
WSPort int `json:"wsPort"`
|
||||
STUNUDP1 int `json:"stunUDP1"`
|
||||
STUNUDP2 int `json:"stunUDP2"`
|
||||
STUNTCP1 int `json:"stunTCP1"`
|
||||
STUNTCP2 int `json:"stunTCP2"`
|
||||
WebPort int `json:"webPort"`
|
||||
APIPort int `json:"apiPort"`
|
||||
DBPath string `json:"dbPath"`
|
||||
CertFile string `json:"certFile"`
|
||||
KeyFile string `json:"keyFile"`
|
||||
LogLevel int `json:"logLevel"` // 0=debug, 1=info, 2=warn, 3=error
|
||||
WSPort int `json:"wsPort"`
|
||||
STUNUDP1 int `json:"stunUDP1"`
|
||||
STUNUDP2 int `json:"stunUDP2"`
|
||||
STUNTCP1 int `json:"stunTCP1"`
|
||||
STUNTCP2 int `json:"stunTCP2"`
|
||||
WebPort int `json:"webPort"`
|
||||
APIPort int `json:"apiPort"`
|
||||
DBPath string `json:"dbPath"`
|
||||
CertFile string `json:"certFile"`
|
||||
KeyFile string `json:"keyFile"`
|
||||
LogLevel int `json:"logLevel"` // 0=debug, 1=info, 2=warn, 3=error
|
||||
Token uint64 `json:"token"` // master token for auth
|
||||
Tokens []uint64 `json:"tokens"` // additional tenant tokens
|
||||
JWTKey string `json:"jwtKey"` // auto-generated if empty
|
||||
@@ -132,10 +132,11 @@ type ClientConfig struct {
|
||||
STUNTCP1 int `json:"stunTCP1,omitempty"`
|
||||
STUNTCP2 int `json:"stunTCP2,omitempty"`
|
||||
|
||||
RelayEnabled bool `json:"relayEnabled"` // --relay
|
||||
SuperRelay bool `json:"superRelay"` // --super
|
||||
RelayPort int `json:"relayPort"`
|
||||
MaxRelayLoad int `json:"maxRelayLoad"`
|
||||
RelayEnabled bool `json:"relayEnabled"` // --relay
|
||||
SuperRelay bool `json:"superRelay"` // --super
|
||||
RelayOfficial bool `json:"relayOfficial"` // official relay tag
|
||||
RelayPort int `json:"relayPort"`
|
||||
MaxRelayLoad int `json:"maxRelayLoad"`
|
||||
|
||||
ShareBandwidth int `json:"shareBandwidth"` // Mbps
|
||||
LogLevel int `json:"logLevel"`
|
||||
@@ -163,6 +164,8 @@ func DefaultClientConfig() ClientConfig {
|
||||
ShareBandwidth: 10,
|
||||
RelayPort: DefaultRelayPort,
|
||||
MaxRelayLoad: DefaultMaxRelayLoad,
|
||||
RelayEnabled: true,
|
||||
RelayOfficial: false,
|
||||
LogLevel: 1,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,8 +197,9 @@ type LoginReq struct {
|
||||
Version string `json:"version"`
|
||||
NATType NATType `json:"natType"`
|
||||
ShareBandwidth int `json:"shareBandwidth"`
|
||||
RelayEnabled bool `json:"relayEnabled"` // --relay flag
|
||||
SuperRelay bool `json:"superRelay"` // --super flag
|
||||
RelayEnabled bool `json:"relayEnabled"` // --relay flag
|
||||
SuperRelay bool `json:"superRelay"` // --super flag
|
||||
RelayOfficial bool `json:"relayOfficial"` // official relay tag
|
||||
PublicIP string `json:"publicIP,omitempty"`
|
||||
PublicPort int `json:"publicPort,omitempty"`
|
||||
}
|
||||
@@ -264,6 +265,7 @@ type ConnectRsp struct {
|
||||
// RelayNodeReq asks the server for a relay node.
|
||||
type RelayNodeReq struct {
|
||||
PeerNode string `json:"peerNode"`
|
||||
Mode string `json:"mode,omitempty"` // "tenant" | "official"
|
||||
}
|
||||
|
||||
type RelayNodeRsp struct {
|
||||
@@ -292,17 +294,24 @@ type SDWANNode struct {
|
||||
IP string `json:"ip"`
|
||||
}
|
||||
|
||||
type SubnetProxy struct {
|
||||
Node string `json:"node"`
|
||||
LocalCIDR string `json:"localCIDR"`
|
||||
VirtualCIDR string `json:"virtualCIDR"`
|
||||
}
|
||||
|
||||
type SDWANConfig struct {
|
||||
Enabled bool `json:"enabled,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
GatewayCIDR string `json:"gatewayCIDR"`
|
||||
Mode string `json:"mode,omitempty"` // hub | mesh | fullmesh
|
||||
HubNode string `json:"hubNode,omitempty"`
|
||||
IP string `json:"ip,omitempty"` // node self IP if pushed per-node
|
||||
MTU int `json:"mtu,omitempty"`
|
||||
Routes []string `json:"routes,omitempty"`
|
||||
Nodes []SDWANNode `json:"nodes"`
|
||||
UpdatedAt int64 `json:"updatedAt,omitempty"`
|
||||
Enabled bool `json:"enabled,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
GatewayCIDR string `json:"gatewayCIDR"`
|
||||
Mode string `json:"mode,omitempty"` // hub | mesh | fullmesh
|
||||
HubNode string `json:"hubNode,omitempty"`
|
||||
IP string `json:"ip,omitempty"` // node self IP if pushed per-node
|
||||
MTU int `json:"mtu,omitempty"`
|
||||
Routes []string `json:"routes,omitempty"`
|
||||
Nodes []SDWANNode `json:"nodes"`
|
||||
SubnetProxies []SubnetProxy `json:"subnetProxies,omitempty"`
|
||||
UpdatedAt int64 `json:"updatedAt,omitempty"`
|
||||
}
|
||||
|
||||
type SDWANPeer struct {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
// Package relay implements relay/super-relay node capabilities.
|
||||
//
|
||||
// Relay flow:
|
||||
// 1. Client A asks server for relay (RelayNodeReq)
|
||||
// 2. Server finds relay R, generates TOTP/token, responds to A (RelayNodeRsp)
|
||||
// 3. Server pushes RelayOffer to R with session info
|
||||
// 4. A connects to R:relayPort, sends RelayHandshake{SessionID, Role="from", Token}
|
||||
// 5. B connects to R:relayPort, sends RelayHandshake{SessionID, Role="to", Token}
|
||||
// (B gets the session info via server push)
|
||||
// 6. R verifies both tokens, bridges A↔B
|
||||
// 1. Client A asks server for relay (RelayNodeReq)
|
||||
// 2. Server finds relay R, generates TOTP/token, responds to A (RelayNodeRsp)
|
||||
// 3. Server pushes RelayOffer to R with session info
|
||||
// 4. A connects to R:relayPort, sends RelayHandshake{SessionID, Role="from", Token}
|
||||
// 5. B connects to R:relayPort, sends RelayHandshake{SessionID, Role="to", Token}
|
||||
// (B gets the session info via server push)
|
||||
// 6. R verifies both tokens, bridges A↔B
|
||||
package relay
|
||||
|
||||
import (
|
||||
@@ -68,6 +68,7 @@ type Manager struct {
|
||||
enabled bool
|
||||
superRelay bool
|
||||
maxLoad int
|
||||
maxMbps int
|
||||
token uint64 // this node's auth token
|
||||
port int
|
||||
listener net.Listener
|
||||
@@ -92,11 +93,12 @@ type Session struct {
|
||||
}
|
||||
|
||||
// NewManager creates a relay manager.
|
||||
func NewManager(port int, enabled, superRelay bool, maxLoad int, token uint64) *Manager {
|
||||
func NewManager(port int, enabled, superRelay bool, maxLoad int, token uint64, maxMbps int) *Manager {
|
||||
return &Manager{
|
||||
enabled: enabled,
|
||||
superRelay: superRelay,
|
||||
maxLoad: maxLoad,
|
||||
maxMbps: maxMbps,
|
||||
token: token,
|
||||
port: port,
|
||||
pending: make(map[string]*pendingSession),
|
||||
@@ -296,14 +298,47 @@ func (m *Manager) bridge(ps *pendingSession) {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
|
||||
copyWithLimit := func(dst, src net.Conn) int64 {
|
||||
if m.maxMbps <= 0 {
|
||||
n, _ := io.Copy(dst, src)
|
||||
return n
|
||||
}
|
||||
bytesPerSec := int64(m.maxMbps) * 1024 * 1024 / 8
|
||||
if bytesPerSec < 1 {
|
||||
bytesPerSec = 1
|
||||
}
|
||||
var total int64
|
||||
buf := make([]byte, 32*1024)
|
||||
ticker := time.NewTicker(100 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
var allowance = bytesPerSec / 10
|
||||
for {
|
||||
n, err := src.Read(buf)
|
||||
if n > 0 {
|
||||
// simple token bucket
|
||||
if allowance < int64(n) {
|
||||
<-ticker.C
|
||||
allowance = bytesPerSec / 10
|
||||
}
|
||||
allowance -= int64(n)
|
||||
w, _ := dst.Write(buf[:n])
|
||||
total += int64(w)
|
||||
}
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
n, _ := io.Copy(sess.ConnB, sess.ConnA)
|
||||
n := copyWithLimit(sess.ConnB, sess.ConnA)
|
||||
atomic.AddInt64(&sess.BytesFwd, n)
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
n, _ := io.Copy(sess.ConnA, sess.ConnB)
|
||||
n := copyWithLimit(sess.ConnA, sess.ConnB)
|
||||
atomic.AddInt64(&sess.BytesFwd, n)
|
||||
}()
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
func TestRelayBridge(t *testing.T) {
|
||||
token := auth.MakeToken("test", "pass")
|
||||
mgr := NewManager(29700, true, false, 10, token)
|
||||
mgr := NewManager(29700, true, false, 10, token, 10)
|
||||
if err := mgr.Start(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -94,7 +94,7 @@ func TestRelayBridge(t *testing.T) {
|
||||
|
||||
func TestRelayLargeData(t *testing.T) {
|
||||
token := auth.MakeToken("test", "pass")
|
||||
mgr := NewManager(29701, true, false, 10, token)
|
||||
mgr := NewManager(29701, true, false, 10, token, 10)
|
||||
if err := mgr.Start(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -173,7 +173,7 @@ func TestRelayLargeData(t *testing.T) {
|
||||
|
||||
func TestRelayAuthDenied(t *testing.T) {
|
||||
token := auth.MakeToken("real", "token")
|
||||
mgr := NewManager(29702, true, false, 10, token)
|
||||
mgr := NewManager(29702, true, false, 10, token, 10)
|
||||
if err := mgr.Start(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user