feat: audit api, sdwan persist, relay fallback updates
This commit is contained in:
@@ -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