Allow for updating destinations

This commit is contained in:
Owen
2025-07-28 22:41:11 -07:00
parent 78c768e497
commit 38483f4a26
2 changed files with 105 additions and 20 deletions

83
main.go
View File

@@ -82,6 +82,12 @@ type ProxyMappingUpdate struct {
NewDestination relay.PeerDestination `json:"newDestination"` NewDestination relay.PeerDestination `json:"newDestination"`
} }
type UpdateDestinationsRequest struct {
SourceIP string `json:"sourceIp"`
SourcePort int `json:"sourcePort"`
Destinations []relay.PeerDestination `json:"destinations"`
}
func parseLogLevel(level string) logger.LogLevel { func parseLogLevel(level string) logger.LogLevel {
switch strings.ToUpper(level) { switch strings.ToUpper(level) {
case "DEBUG": case "DEBUG":
@@ -252,7 +258,7 @@ func main() {
go periodicBandwidthCheck(remoteConfigURL + "/gerbil/receive-bandwidth") go periodicBandwidthCheck(remoteConfigURL + "/gerbil/receive-bandwidth")
// Start the UDP proxy server // Start the UDP proxy server
proxyServer = relay.NewUDPProxyServer(":21820", remoteConfigURL, key) proxyServer = relay.NewUDPProxyServer(":21820", remoteConfigURL, key, reachableAt)
err = proxyServer.Start() err = proxyServer.Start()
if err != nil { if err != nil {
logger.Fatal("Failed to start UDP proxy server: %v", err) logger.Fatal("Failed to start UDP proxy server: %v", err)
@@ -262,6 +268,7 @@ func main() {
// Set up HTTP server // Set up HTTP server
http.HandleFunc("/peer", handlePeer) http.HandleFunc("/peer", handlePeer)
http.HandleFunc("/update-proxy-mapping", handleUpdateProxyMapping) http.HandleFunc("/update-proxy-mapping", handleUpdateProxyMapping)
http.HandleFunc("/update-destinations", handleUpdateDestinations)
logger.Info("Starting HTTP server on %s", listenAddr) logger.Info("Starting HTTP server on %s", listenAddr)
// Run HTTP server in a goroutine // Run HTTP server in a goroutine
@@ -727,29 +734,34 @@ func removePeerInternal(publicKey string) error {
func handleUpdateProxyMapping(w http.ResponseWriter, r *http.Request) { func handleUpdateProxyMapping(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost { if r.Method != http.MethodPost {
logger.Error("Invalid method: %s", r.Method)
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return return
} }
var update ProxyMappingUpdate var update ProxyMappingUpdate
if err := json.NewDecoder(r.Body).Decode(&update); err != nil { if err := json.NewDecoder(r.Body).Decode(&update); err != nil {
logger.Error("Failed to decode request body: %v", err)
http.Error(w, fmt.Sprintf("Failed to decode request body: %v", err), http.StatusBadRequest) http.Error(w, fmt.Sprintf("Failed to decode request body: %v", err), http.StatusBadRequest)
return return
} }
// Validate the update request // Validate the update request
if update.OldDestination.DestinationIP == "" || update.NewDestination.DestinationIP == "" { if update.OldDestination.DestinationIP == "" || update.NewDestination.DestinationIP == "" {
logger.Error("Both old and new destination IP addresses are required")
http.Error(w, "Both old and new destination IP addresses are required", http.StatusBadRequest) http.Error(w, "Both old and new destination IP addresses are required", http.StatusBadRequest)
return return
} }
if update.OldDestination.DestinationPort <= 0 || update.NewDestination.DestinationPort <= 0 { if update.OldDestination.DestinationPort <= 0 || update.NewDestination.DestinationPort <= 0 {
logger.Error("Both old and new destination ports must be positive integers")
http.Error(w, "Both old and new destination ports must be positive integers", http.StatusBadRequest) http.Error(w, "Both old and new destination ports must be positive integers", http.StatusBadRequest)
return return
} }
// Update the proxy mappings in the relay server // Update the proxy mappings in the relay server
if proxyServer == nil { if proxyServer == nil {
logger.Error("Proxy server is not available")
http.Error(w, "Proxy server is not available", http.StatusInternalServerError) http.Error(w, "Proxy server is not available", http.StatusInternalServerError)
return return
} }
@@ -770,6 +782,75 @@ func handleUpdateProxyMapping(w http.ResponseWriter, r *http.Request) {
}) })
} }
func handleUpdateDestinations(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
logger.Error("Invalid method: %s", r.Method)
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
var request UpdateDestinationsRequest
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
logger.Error("Failed to decode request body: %v", err)
http.Error(w, fmt.Sprintf("Failed to decode request body: %v", err), http.StatusBadRequest)
return
}
// Validate the request
if request.SourceIP == "" {
logger.Error("Source IP address is required")
http.Error(w, "Source IP address is required", http.StatusBadRequest)
return
}
if request.SourcePort <= 0 {
logger.Error("Source port must be a positive integer")
http.Error(w, "Source port must be a positive integer", http.StatusBadRequest)
return
}
if len(request.Destinations) == 0 {
logger.Error("At least one destination is required")
http.Error(w, "At least one destination is required", http.StatusBadRequest)
return
}
// Validate each destination
for i, dest := range request.Destinations {
if dest.DestinationIP == "" {
logger.Error("Destination IP is required for destination %d", i)
http.Error(w, fmt.Sprintf("Destination IP is required for destination %d", i), http.StatusBadRequest)
return
}
if dest.DestinationPort <= 0 {
logger.Error("Destination port must be a positive integer for destination %d", i)
http.Error(w, fmt.Sprintf("Destination port must be a positive integer for destination %d", i), http.StatusBadRequest)
return
}
}
// Update the proxy mappings in the relay server
if proxyServer == nil {
logger.Error("Proxy server is not available")
http.Error(w, "Proxy server is not available", http.StatusInternalServerError)
return
}
proxyServer.UpdateProxyMapping(request.SourceIP, request.SourcePort, request.Destinations)
logger.Info("Updated proxy mapping for %s:%d with %d destinations",
request.SourceIP, request.SourcePort, len(request.Destinations))
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]interface{}{
"status": "Destinations updated successfully",
"sourceIP": request.SourceIP,
"sourcePort": request.SourcePort,
"destinationCount": len(request.Destinations),
"destinations": request.Destinations,
})
}
func periodicBandwidthCheck(endpoint string) { func periodicBandwidthCheck(endpoint string) {
ticker := time.NewTicker(10 * time.Second) ticker := time.NewTicker(10 * time.Second)
defer ticker.Stop() defer ticker.Stop()

View File

@@ -8,7 +8,6 @@ import (
"io" "io"
"net" "net"
"net/http" "net/http"
"strconv"
"sync" "sync"
"time" "time"
@@ -31,12 +30,13 @@ type HolePunchMessage struct {
} }
type ClientEndpoint struct { type ClientEndpoint struct {
OlmID string `json:"olmId"` OlmID string `json:"olmId"`
NewtID string `json:"newtId"` NewtID string `json:"newtId"`
Token string `json:"token"` Token string `json:"token"`
IP string `json:"ip"` IP string `json:"ip"`
Port int `json:"port"` Port int `json:"port"`
Timestamp int64 `json:"timestamp"` Timestamp int64 `json:"timestamp"`
ReachableAt string `json:"reachableAt"`
} }
// Updated to support multiple destination peers // Updated to support multiple destination peers
@@ -104,15 +104,18 @@ type UDPProxyServer struct {
// Session tracking for WireGuard peers // Session tracking for WireGuard peers
// Key format: "senderIndex:receiverIndex" // Key format: "senderIndex:receiverIndex"
wgSessions sync.Map wgSessions sync.Map
// ReachableAt is the URL where this server can be reached
ReachableAt string
} }
// NewUDPProxyServer initializes the server with a buffered packet channel. // NewUDPProxyServer initializes the server with a buffered packet channel.
func NewUDPProxyServer(addr, serverURL string, privateKey wgtypes.Key) *UDPProxyServer { func NewUDPProxyServer(addr, serverURL string, privateKey wgtypes.Key, reachableAt string) *UDPProxyServer {
return &UDPProxyServer{ return &UDPProxyServer{
addr: addr, addr: addr,
serverURL: serverURL, serverURL: serverURL,
privateKey: privateKey, privateKey: privateKey,
packetChan: make(chan Packet, 1000), packetChan: make(chan Packet, 1000),
ReachableAt: reachableAt,
} }
} }
@@ -215,12 +218,13 @@ func (s *UDPProxyServer) packetWorker() {
} }
endpoint := ClientEndpoint{ endpoint := ClientEndpoint{
NewtID: msg.NewtID, NewtID: msg.NewtID,
OlmID: msg.OlmID, OlmID: msg.OlmID,
Token: msg.Token, Token: msg.Token,
IP: packet.remoteAddr.IP.String(), IP: packet.remoteAddr.IP.String(),
Port: packet.remoteAddr.Port, Port: packet.remoteAddr.Port,
Timestamp: time.Now().Unix(), Timestamp: time.Now().Unix(),
ReachableAt: s.ReachableAt,
} }
logger.Debug("Created endpoint from packet remoteAddr %s: IP=%s, Port=%d", packet.remoteAddr.String(), endpoint.IP, endpoint.Port) logger.Debug("Created endpoint from packet remoteAddr %s: IP=%s, Port=%d", packet.remoteAddr.String(), endpoint.IP, endpoint.Port)
s.notifyServer(endpoint) s.notifyServer(endpoint)
@@ -644,7 +648,7 @@ func (s *UDPProxyServer) notifyServer(endpoint ClientEndpoint) {
// Updated to support multiple destinations // Updated to support multiple destinations
func (s *UDPProxyServer) UpdateProxyMapping(sourceIP string, sourcePort int, destinations []PeerDestination) { func (s *UDPProxyServer) UpdateProxyMapping(sourceIP string, sourcePort int, destinations []PeerDestination) {
key := net.JoinHostPort(sourceIP, strconv.Itoa(sourcePort)) key := fmt.Sprintf("%s:%d", sourceIP, sourcePort)
mapping := ProxyMapping{ mapping := ProxyMapping{
Destinations: destinations, Destinations: destinations,
LastUsed: time.Now(), LastUsed: time.Now(),