Files
elmprodvpn/selective-vpn-api/app/transport_iface_orchestrator_mapping.go

118 lines
3.7 KiB
Go

package app
import (
"fmt"
"strings"
"time"
)
type transportIfaceBinding struct {
IfaceID string
Mode TransportInterfaceMode
RuntimeIface string
NetnsName string
RoutingTable string
}
func syncTransportInterfacesWithClientsLocked(clients []TransportClient) (transportInterfacesState, error) {
ifaces := loadTransportInterfacesState()
norm, changed := normalizeTransportInterfacesState(ifaces, clients)
if changed {
if err := saveTransportInterfacesState(norm); err != nil {
appendTraceLineRateLimited(
"transport",
fmt.Sprintf("interfaces sync warning: save failed: %v", err),
20*time.Second,
)
}
}
return norm, nil
}
func findTransportInterfaceByID(items []TransportInterface, ifaceID string) (TransportInterface, bool) {
id := normalizeTransportIfaceID(ifaceID)
for _, it := range items {
if normalizeTransportIfaceID(it.ID) == id {
return it, true
}
}
return TransportInterface{}, false
}
func resolveTransportIfaceBinding(client TransportClient, ifaces transportInterfacesState) transportIfaceBinding {
ifaceID := normalizeTransportIfaceID(client.IfaceID)
binding := transportIfaceBinding{
IfaceID: ifaceID,
Mode: normalizeTransportInterfaceMode("", ifaceID),
}
if iface, ok := findTransportInterfaceByID(ifaces.Items, ifaceID); ok {
binding.Mode = normalizeTransportInterfaceMode(iface.Mode, ifaceID)
binding.RuntimeIface = strings.TrimSpace(iface.RuntimeIface)
if strings.TrimSpace(iface.NetnsName) != "" {
binding.NetnsName = normalizeTransportNetnsName(strings.TrimSpace(iface.NetnsName), client.ID)
}
if hint := resolveTransportInterfaceRoutingTable(iface, ifaceID); strings.TrimSpace(hint) != "" {
binding.RoutingTable = hint
}
}
if strings.TrimSpace(binding.RuntimeIface) == "" {
binding.RuntimeIface = strings.TrimSpace(client.Iface)
}
if strings.TrimSpace(binding.RoutingTable) == "" {
if binding.IfaceID != transportDefaultIfaceID {
binding.RoutingTable = transportRoutingTableForIfaceID(binding.IfaceID)
} else {
binding.RoutingTable = normalizeTransportRoutingTable(client.RoutingTable, transportRoutingTableForID(client.ID))
}
}
if transportNetnsEnabled(client) {
explicit := strings.TrimSpace(transportConfigString(client.Config, "netns_name"))
if explicit != "" {
binding.NetnsName = transportNetnsName(client)
} else if strings.TrimSpace(binding.NetnsName) == "" {
if binding.IfaceID != transportDefaultIfaceID {
binding.NetnsName = normalizeTransportNetnsName("svpn-"+binding.IfaceID, client.ID)
} else {
binding.NetnsName = normalizeTransportNetnsName("svpn-"+sanitizeID(client.ID), client.ID)
}
}
}
return binding
}
func applyTransportIfaceBinding(client TransportClient, ifaces transportInterfacesState, now time.Time) (TransportClient, bool) {
updated := client
changed := false
binding := resolveTransportIfaceBinding(client, ifaces)
if updated.IfaceID != binding.IfaceID {
updated.IfaceID = binding.IfaceID
changed = true
}
if strings.TrimSpace(updated.Iface) == "" && strings.TrimSpace(binding.RuntimeIface) != "" {
updated.Iface = binding.RuntimeIface
changed = true
}
if strings.TrimSpace(binding.RoutingTable) != "" && strings.TrimSpace(updated.RoutingTable) != strings.TrimSpace(binding.RoutingTable) {
updated.RoutingTable = strings.TrimSpace(binding.RoutingTable)
changed = true
}
if transportNetnsEnabled(updated) && strings.TrimSpace(transportConfigString(updated.Config, "netns_name")) == "" && strings.TrimSpace(binding.NetnsName) != "" {
cfg := cloneMap(updated.Config)
if cfg == nil {
cfg = map[string]any{}
}
cfg["netns_name"] = binding.NetnsName
updated.Config = cfg
changed = true
}
if changed {
updated.UpdatedAt = now.Format(time.RFC3339)
}
return updated, changed
}