Wire gated QUIC fabric listener
This commit is contained in:
@@ -2,9 +2,15 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"crypto/x509/pkix"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"math/big"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@@ -364,6 +370,9 @@ type syntheticMeshState struct {
|
|||||||
ListenerRuntimeConfig config.Config
|
ListenerRuntimeConfig config.Config
|
||||||
ListenerHandler *dynamicHTTPHandler
|
ListenerHandler *dynamicHTTPHandler
|
||||||
StopListener func()
|
StopListener func()
|
||||||
|
QUICFabricServer *mesh.QUICFabricServer
|
||||||
|
QUICFabricListenAddr string
|
||||||
|
QUICFabricError string
|
||||||
ConfigLoadError string
|
ConfigLoadError string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -778,6 +787,7 @@ func startSyntheticMeshEndpoint(ctx context.Context, _ context.CancelFunc, cfg c
|
|||||||
listenerCfg := meshListenerRuntimeConfig(cfg, loadedConfig.MeshListener)
|
listenerCfg := meshListenerRuntimeConfig(cfg, loadedConfig.MeshListener)
|
||||||
listenerReport, stopListener := startSyntheticMeshHTTPServer(ctx, listenerCfg, identity, dynamicListenerHandler, len(peerEndpoints), len(routes), gateEnabled, runtimeEnabled)
|
listenerReport, stopListener := startSyntheticMeshHTTPServer(ctx, listenerCfg, identity, dynamicListenerHandler, len(peerEndpoints), len(routes), gateEnabled, runtimeEnabled)
|
||||||
vpnFabricSessionPeers := mesh.NewFabricSessionPeerManager()
|
vpnFabricSessionPeers := mesh.NewFabricSessionPeerManager()
|
||||||
|
quicFabricServer, quicFabricAddr, quicFabricErr := startQUICFabricEndpoint(ctx, cfg, identity)
|
||||||
return &syntheticMeshState{
|
return &syntheticMeshState{
|
||||||
Runtime: runtime,
|
Runtime: runtime,
|
||||||
Routes: routes,
|
Routes: routes,
|
||||||
@@ -813,6 +823,9 @@ func startSyntheticMeshEndpoint(ctx context.Context, _ context.CancelFunc, cfg c
|
|||||||
ListenerRuntimeConfig: listenerCfg,
|
ListenerRuntimeConfig: listenerCfg,
|
||||||
ListenerHandler: dynamicListenerHandler,
|
ListenerHandler: dynamicListenerHandler,
|
||||||
StopListener: stopListener,
|
StopListener: stopListener,
|
||||||
|
QUICFabricServer: quicFabricServer,
|
||||||
|
QUICFabricListenAddr: quicFabricAddr,
|
||||||
|
QUICFabricError: errorString(quicFabricErr),
|
||||||
ConfigLoadError: errorString(err),
|
ConfigLoadError: errorString(err),
|
||||||
}, stopListener, nil
|
}, stopListener, nil
|
||||||
}
|
}
|
||||||
@@ -1124,6 +1137,8 @@ func meshListenerConfigKey(cfg config.Config) string {
|
|||||||
strings.TrimSpace(cfg.MeshRegion),
|
strings.TrimSpace(cfg.MeshRegion),
|
||||||
fmt.Sprintf("%t", cfg.MeshProductionForwardingEnabled),
|
fmt.Sprintf("%t", cfg.MeshProductionForwardingEnabled),
|
||||||
fmt.Sprintf("%t", cfg.VPNFabricSessionTransportEnabled),
|
fmt.Sprintf("%t", cfg.VPNFabricSessionTransportEnabled),
|
||||||
|
fmt.Sprintf("%t", cfg.MeshQUICFabricEnabled),
|
||||||
|
strings.TrimSpace(cfg.MeshQUICFabricListenAddr),
|
||||||
}, "|")
|
}, "|")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1149,6 +1164,68 @@ func bindSyntheticMeshListener(cfg config.Config) (net.Listener, string, bool, e
|
|||||||
return nil, "", false, err
|
return nil, "", false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func startQUICFabricEndpoint(ctx context.Context, cfg config.Config, identity state.Identity) (*mesh.QUICFabricServer, string, error) {
|
||||||
|
if !cfg.MeshQUICFabricEnabled {
|
||||||
|
return nil, "", nil
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(cfg.MeshQUICFabricListenAddr) == "" {
|
||||||
|
return nil, "", fmt.Errorf("quic fabric enabled but listen addr is empty")
|
||||||
|
}
|
||||||
|
tlsConfig, err := quicFabricTLSConfig(identity)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
server, err := mesh.StartQUICFabricServer(ctx, mesh.QUICFabricServerConfig{
|
||||||
|
ListenAddr: cfg.MeshQUICFabricListenAddr,
|
||||||
|
TLSConfig: tlsConfig,
|
||||||
|
Logger: func(entry mesh.FabricSessionEventLogEntry) {
|
||||||
|
payload, err := json.Marshal(entry)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("fabric quic event marshal failed: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("fabric_quic_event=%s", string(payload))
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
addr := ""
|
||||||
|
if server.Addr() != nil {
|
||||||
|
addr = server.Addr().String()
|
||||||
|
}
|
||||||
|
log.Printf("quic fabric endpoint enabled: listen_addr=%s effective_addr=%s node_id=%s cluster_id=%s", cfg.MeshQUICFabricListenAddr, addr, identity.NodeID, identity.ClusterID)
|
||||||
|
return server, addr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func quicFabricTLSConfig(identity state.Identity) (*tls.Config, error) {
|
||||||
|
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
commonName := firstNonEmpty(identity.NodeID, "rap-fabric-node")
|
||||||
|
template := x509.Certificate{
|
||||||
|
SerialNumber: big.NewInt(time.Now().UnixNano()),
|
||||||
|
Subject: pkix.Name{CommonName: commonName},
|
||||||
|
NotBefore: time.Now().Add(-time.Minute),
|
||||||
|
NotAfter: time.Now().Add(24 * time.Hour),
|
||||||
|
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||||
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||||
|
DNSNames: []string{commonName, "localhost"},
|
||||||
|
}
|
||||||
|
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &tls.Config{
|
||||||
|
Certificates: []tls.Certificate{{
|
||||||
|
Certificate: [][]byte{certDER},
|
||||||
|
PrivateKey: key,
|
||||||
|
}},
|
||||||
|
NextProtos: []string{"rap-fabric-data-session-v1"},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func isAddressInUse(err error) bool {
|
func isAddressInUse(err error) bool {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return false
|
return false
|
||||||
@@ -1689,6 +1766,7 @@ func applyRefreshedSyntheticMeshConfig(ctx context.Context, cfg config.Config, i
|
|||||||
} else {
|
} else {
|
||||||
meshState.ListenerHandler.Update(nextListenerHandler)
|
meshState.ListenerHandler.Update(nextListenerHandler)
|
||||||
}
|
}
|
||||||
|
applyQUICFabricConfigIfChanged(ctx, cfg, identity, meshState)
|
||||||
applyMeshListenerConfigIfChanged(ctx, cfg, identity, meshState, loadedConfig, observedAt)
|
applyMeshListenerConfigIfChanged(ctx, cfg, identity, meshState, loadedConfig, observedAt)
|
||||||
meshState.Routes = loadedConfig.Routes
|
meshState.Routes = loadedConfig.Routes
|
||||||
meshState.RouteHealthRoutes = routeHealthRoutes
|
meshState.RouteHealthRoutes = routeHealthRoutes
|
||||||
@@ -1735,6 +1813,32 @@ func applyMeshListenerConfigIfChanged(ctx context.Context, base config.Config, i
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func applyQUICFabricConfigIfChanged(ctx context.Context, cfg config.Config, identity state.Identity, meshState *syntheticMeshState) {
|
||||||
|
if meshState == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
desiredAddr := strings.TrimSpace(cfg.MeshQUICFabricListenAddr)
|
||||||
|
if meshState.QUICFabricServer != nil && (!cfg.MeshQUICFabricEnabled || meshState.QUICFabricListenAddr != desiredAddr) {
|
||||||
|
_ = meshState.QUICFabricServer.Close()
|
||||||
|
meshState.QUICFabricServer = nil
|
||||||
|
meshState.QUICFabricListenAddr = ""
|
||||||
|
}
|
||||||
|
if !cfg.MeshQUICFabricEnabled {
|
||||||
|
meshState.QUICFabricError = ""
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if meshState.QUICFabricServer != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
server, addr, err := startQUICFabricEndpoint(ctx, cfg, identity)
|
||||||
|
meshState.QUICFabricServer = server
|
||||||
|
meshState.QUICFabricListenAddr = addr
|
||||||
|
meshState.QUICFabricError = errorString(err)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("quic fabric endpoint unavailable: listen_addr=%s node_id=%s cluster_id=%s err=%v", cfg.MeshQUICFabricListenAddr, identity.NodeID, identity.ClusterID, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func meshRendezvousLeasePostureForState(meshState *syntheticMeshState, identity state.Identity, observedAt time.Time) meshRendezvousLeasePosture {
|
func meshRendezvousLeasePostureForState(meshState *syntheticMeshState, identity state.Identity, observedAt time.Time) meshRendezvousLeasePosture {
|
||||||
posture := meshRendezvousLeasePosture{}
|
posture := meshRendezvousLeasePosture{}
|
||||||
if meshState == nil {
|
if meshState == nil {
|
||||||
@@ -2487,7 +2591,7 @@ func heartbeatPayload(cfg config.Config, identity state.Identity, meshState *syn
|
|||||||
payload.Capabilities["mesh_production_forwarding"] = true
|
payload.Capabilities["mesh_production_forwarding"] = true
|
||||||
}
|
}
|
||||||
if cfg.MeshFabricSessionEnabled {
|
if cfg.MeshFabricSessionEnabled {
|
||||||
payload.Metadata["fabric_session_endpoint_report"] = map[string]any{
|
report := map[string]any{
|
||||||
"schema_version": "rap.fabric_session_endpoint_report.v1",
|
"schema_version": "rap.fabric_session_endpoint_report.v1",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"transport": "websocket_binary_frames",
|
"transport": "websocket_binary_frames",
|
||||||
@@ -2498,8 +2602,20 @@ func heartbeatPayload(cfg config.Config, identity state.Identity, meshState *syn
|
|||||||
"traffic_isolation": "logical_streams",
|
"traffic_isolation": "logical_streams",
|
||||||
"observed_at": observedAt.UTC().Format(time.RFC3339Nano),
|
"observed_at": observedAt.UTC().Format(time.RFC3339Nano),
|
||||||
}
|
}
|
||||||
|
if meshState != nil && cfg.MeshQUICFabricEnabled {
|
||||||
|
report["quic"] = map[string]any{
|
||||||
|
"enabled": meshState.QUICFabricServer != nil,
|
||||||
|
"listen_addr": cfg.MeshQUICFabricListenAddr,
|
||||||
|
"effective_listen_addr": meshState.QUICFabricListenAddr,
|
||||||
|
"error": meshState.QUICFabricError,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
payload.Metadata["fabric_session_endpoint_report"] = report
|
||||||
payload.Capabilities["fabric_session_websocket_endpoint"] = true
|
payload.Capabilities["fabric_session_websocket_endpoint"] = true
|
||||||
payload.Capabilities["fabric_data_session_v1"] = true
|
payload.Capabilities["fabric_data_session_v1"] = true
|
||||||
|
if cfg.MeshQUICFabricEnabled {
|
||||||
|
payload.Capabilities["fabric_quic_endpoint"] = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if cfg.VPNFabricSessionTransportEnabled {
|
if cfg.VPNFabricSessionTransportEnabled {
|
||||||
report := map[string]any{
|
report := map[string]any{
|
||||||
|
|||||||
@@ -706,11 +706,14 @@ func TestHeartbeatPayloadIncludesMeshEndpointReport(t *testing.T) {
|
|||||||
MeshProductionForwardingEnabled: true,
|
MeshProductionForwardingEnabled: true,
|
||||||
MeshFabricSessionEnabled: true,
|
MeshFabricSessionEnabled: true,
|
||||||
VPNFabricSessionTransportEnabled: true,
|
VPNFabricSessionTransportEnabled: true,
|
||||||
|
MeshQUICFabricEnabled: true,
|
||||||
|
MeshQUICFabricListenAddr: ":19443",
|
||||||
}, state.Identity{
|
}, state.Identity{
|
||||||
ClusterID: "cluster-1",
|
ClusterID: "cluster-1",
|
||||||
NodeID: "node-a",
|
NodeID: "node-a",
|
||||||
}, &syntheticMeshState{
|
}, &syntheticMeshState{
|
||||||
VPNFabricSessionPeers: mesh.NewFabricSessionPeerManager(),
|
VPNFabricSessionPeers: mesh.NewFabricSessionPeerManager(),
|
||||||
|
QUICFabricListenAddr: "127.0.0.1:19443",
|
||||||
}, time.Date(2026, 4, 28, 12, 0, 0, 0, time.UTC))
|
}, time.Date(2026, 4, 28, 12, 0, 0, 0, time.UTC))
|
||||||
|
|
||||||
report, ok := payload.Metadata["mesh_endpoint_report"].(map[string]any)
|
report, ok := payload.Metadata["mesh_endpoint_report"].(map[string]any)
|
||||||
@@ -731,6 +734,11 @@ func TestHeartbeatPayloadIncludesMeshEndpointReport(t *testing.T) {
|
|||||||
}
|
}
|
||||||
if report, ok := payload.Metadata["fabric_session_endpoint_report"].(map[string]any); !ok || report["path"] != "/mesh/v1/fabric/session/ws" {
|
if report, ok := payload.Metadata["fabric_session_endpoint_report"].(map[string]any); !ok || report["path"] != "/mesh/v1/fabric/session/ws" {
|
||||||
t.Fatalf("fabric session endpoint report missing: %+v", payload.Metadata)
|
t.Fatalf("fabric session endpoint report missing: %+v", payload.Metadata)
|
||||||
|
} else if quic, ok := report["quic"].(map[string]any); !ok || quic["listen_addr"] != ":19443" || quic["effective_listen_addr"] != "127.0.0.1:19443" {
|
||||||
|
t.Fatalf("fabric quic endpoint report missing: %+v", report)
|
||||||
|
}
|
||||||
|
if payload.Capabilities["fabric_quic_endpoint"] != true {
|
||||||
|
t.Fatalf("fabric quic capability missing: %+v", payload.Capabilities)
|
||||||
}
|
}
|
||||||
if payload.Capabilities["vpn_fabric_session_transport"] != true || payload.Capabilities["vpn_packet_batch_binary_frames"] != true {
|
if payload.Capabilities["vpn_fabric_session_transport"] != true || payload.Capabilities["vpn_packet_batch_binary_frames"] != true {
|
||||||
t.Fatalf("vpn fabric session capabilities missing: %+v", payload.Capabilities)
|
t.Fatalf("vpn fabric session capabilities missing: %+v", payload.Capabilities)
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ type Config struct {
|
|||||||
MeshProductionForwardingEnabled bool
|
MeshProductionForwardingEnabled bool
|
||||||
MeshFabricSessionEnabled bool
|
MeshFabricSessionEnabled bool
|
||||||
VPNFabricSessionTransportEnabled bool
|
VPNFabricSessionTransportEnabled bool
|
||||||
|
MeshQUICFabricEnabled bool
|
||||||
|
MeshQUICFabricListenAddr string
|
||||||
MeshProductionObservationSinkCapacity int
|
MeshProductionObservationSinkCapacity int
|
||||||
MeshListenAddr string
|
MeshListenAddr string
|
||||||
MeshListenPortMode string
|
MeshListenPortMode string
|
||||||
@@ -67,6 +69,8 @@ func Load(args []string, env map[string]string) (Config, error) {
|
|||||||
fs.BoolVar(&cfg.MeshProductionForwardingEnabled, "mesh-production-forwarding-enabled", getEnvBool(env, "RAP_MESH_PRODUCTION_FORWARDING_ENABLED", false), "Enable production fabric-control direct next-hop forwarding gate. Disabled by default.")
|
fs.BoolVar(&cfg.MeshProductionForwardingEnabled, "mesh-production-forwarding-enabled", getEnvBool(env, "RAP_MESH_PRODUCTION_FORWARDING_ENABLED", false), "Enable production fabric-control direct next-hop forwarding gate. Disabled by default.")
|
||||||
fs.BoolVar(&cfg.MeshFabricSessionEnabled, "mesh-fabric-session-enabled", getEnvBool(env, "RAP_MESH_FABRIC_SESSION_ENABLED", false), "Enable authenticated fabric session WebSocket endpoint. Disabled by default.")
|
fs.BoolVar(&cfg.MeshFabricSessionEnabled, "mesh-fabric-session-enabled", getEnvBool(env, "RAP_MESH_FABRIC_SESSION_ENABLED", false), "Enable authenticated fabric session WebSocket endpoint. Disabled by default.")
|
||||||
fs.BoolVar(&cfg.VPNFabricSessionTransportEnabled, "vpn-fabric-session-transport-enabled", getEnvBool(env, "RAP_VPN_FABRIC_SESSION_TRANSPORT_ENABLED", false), "Route VPN packet transport over persistent fabric session when explicitly enabled. Disabled by default.")
|
fs.BoolVar(&cfg.VPNFabricSessionTransportEnabled, "vpn-fabric-session-transport-enabled", getEnvBool(env, "RAP_VPN_FABRIC_SESSION_TRANSPORT_ENABLED", false), "Route VPN packet transport over persistent fabric session when explicitly enabled. Disabled by default.")
|
||||||
|
fs.BoolVar(&cfg.MeshQUICFabricEnabled, "mesh-quic-fabric-enabled", getEnvBool(env, "RAP_MESH_QUIC_FABRIC_ENABLED", false), "Enable QUIC/UDP fabric listener. Disabled by default.")
|
||||||
|
fs.StringVar(&cfg.MeshQUICFabricListenAddr, "mesh-quic-fabric-listen-addr", getEnv(env, "RAP_MESH_QUIC_FABRIC_LISTEN_ADDR", ""), "Listen address for QUIC/UDP fabric endpoint, for example :19443.")
|
||||||
fs.IntVar(&cfg.MeshProductionObservationSinkCapacity, "mesh-production-observation-sink-capacity", getEnvSignedInt(env, "RAP_MESH_PRODUCTION_OBSERVATION_SINK_CAPACITY", 0), "Bounded local metadata-only production envelope observation sink capacity. Disabled when 0.")
|
fs.IntVar(&cfg.MeshProductionObservationSinkCapacity, "mesh-production-observation-sink-capacity", getEnvSignedInt(env, "RAP_MESH_PRODUCTION_OBSERVATION_SINK_CAPACITY", 0), "Bounded local metadata-only production envelope observation sink capacity. Disabled when 0.")
|
||||||
fs.StringVar(&cfg.MeshListenAddr, "mesh-listen-addr", getEnv(env, "RAP_MESH_LISTEN_ADDR", ""), "Listen address for disabled-by-default C17E synthetic mesh HTTP endpoint.")
|
fs.StringVar(&cfg.MeshListenAddr, "mesh-listen-addr", getEnv(env, "RAP_MESH_LISTEN_ADDR", ""), "Listen address for disabled-by-default C17E synthetic mesh HTTP endpoint.")
|
||||||
fs.StringVar(&cfg.MeshListenPortMode, "mesh-listen-port-mode", getEnv(env, "RAP_MESH_LISTEN_PORT_MODE", "manual"), "Mesh listen port behavior: manual, auto, or disabled.")
|
fs.StringVar(&cfg.MeshListenPortMode, "mesh-listen-port-mode", getEnv(env, "RAP_MESH_LISTEN_PORT_MODE", "manual"), "Mesh listen port behavior: manual, auto, or disabled.")
|
||||||
@@ -102,6 +106,7 @@ func Load(args []string, env map[string]string) (Config, error) {
|
|||||||
cfg.NodeName = strings.TrimSpace(cfg.NodeName)
|
cfg.NodeName = strings.TrimSpace(cfg.NodeName)
|
||||||
cfg.StateDir = strings.TrimSpace(cfg.StateDir)
|
cfg.StateDir = strings.TrimSpace(cfg.StateDir)
|
||||||
cfg.MeshListenAddr = strings.TrimSpace(cfg.MeshListenAddr)
|
cfg.MeshListenAddr = strings.TrimSpace(cfg.MeshListenAddr)
|
||||||
|
cfg.MeshQUICFabricListenAddr = strings.TrimSpace(cfg.MeshQUICFabricListenAddr)
|
||||||
cfg.MeshListenPortMode = strings.ToLower(strings.TrimSpace(cfg.MeshListenPortMode))
|
cfg.MeshListenPortMode = strings.ToLower(strings.TrimSpace(cfg.MeshListenPortMode))
|
||||||
cfg.MeshAdvertiseEndpoint = strings.TrimRight(strings.TrimSpace(cfg.MeshAdvertiseEndpoint), "/")
|
cfg.MeshAdvertiseEndpoint = strings.TrimRight(strings.TrimSpace(cfg.MeshAdvertiseEndpoint), "/")
|
||||||
cfg.MeshAdvertiseEndpointsJSON = strings.TrimSpace(cfg.MeshAdvertiseEndpointsJSON)
|
cfg.MeshAdvertiseEndpointsJSON = strings.TrimSpace(cfg.MeshAdvertiseEndpointsJSON)
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ func TestLoadConfigFromEnvAndArgs(t *testing.T) {
|
|||||||
"RAP_MESH_PRODUCTION_FORWARDING_ENABLED": "true",
|
"RAP_MESH_PRODUCTION_FORWARDING_ENABLED": "true",
|
||||||
"RAP_MESH_FABRIC_SESSION_ENABLED": "true",
|
"RAP_MESH_FABRIC_SESSION_ENABLED": "true",
|
||||||
"RAP_VPN_FABRIC_SESSION_TRANSPORT_ENABLED": "true",
|
"RAP_VPN_FABRIC_SESSION_TRANSPORT_ENABLED": "true",
|
||||||
|
"RAP_MESH_QUIC_FABRIC_ENABLED": "true",
|
||||||
|
"RAP_MESH_QUIC_FABRIC_LISTEN_ADDR": ":19443",
|
||||||
"RAP_MESH_PRODUCTION_OBSERVATION_SINK_CAPACITY": "5",
|
"RAP_MESH_PRODUCTION_OBSERVATION_SINK_CAPACITY": "5",
|
||||||
"RAP_MESH_LISTEN_ADDR": "127.0.0.1:19001",
|
"RAP_MESH_LISTEN_ADDR": "127.0.0.1:19001",
|
||||||
"RAP_MESH_LISTEN_PORT_MODE": "auto",
|
"RAP_MESH_LISTEN_PORT_MODE": "auto",
|
||||||
@@ -74,6 +76,9 @@ func TestLoadConfigFromEnvAndArgs(t *testing.T) {
|
|||||||
if !cfg.VPNFabricSessionTransportEnabled {
|
if !cfg.VPNFabricSessionTransportEnabled {
|
||||||
t.Fatal("VPNFabricSessionTransportEnabled = false, want true")
|
t.Fatal("VPNFabricSessionTransportEnabled = false, want true")
|
||||||
}
|
}
|
||||||
|
if !cfg.MeshQUICFabricEnabled || cfg.MeshQUICFabricListenAddr != ":19443" {
|
||||||
|
t.Fatalf("unexpected QUIC fabric config: %+v", cfg)
|
||||||
|
}
|
||||||
if cfg.MeshProductionObservationSinkCapacity != 5 {
|
if cfg.MeshProductionObservationSinkCapacity != 5 {
|
||||||
t.Fatalf("MeshProductionObservationSinkCapacity = %d, want 5", cfg.MeshProductionObservationSinkCapacity)
|
t.Fatalf("MeshProductionObservationSinkCapacity = %d, want 5", cfg.MeshProductionObservationSinkCapacity)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ type RuntimeConfig struct {
|
|||||||
MeshProductionForwardingEnabled bool
|
MeshProductionForwardingEnabled bool
|
||||||
MeshFabricSessionEnabled bool
|
MeshFabricSessionEnabled bool
|
||||||
VPNFabricSessionTransportEnabled bool
|
VPNFabricSessionTransportEnabled bool
|
||||||
|
MeshQUICFabricEnabled bool
|
||||||
|
MeshQUICFabricListenAddr string
|
||||||
MeshListenAddr string
|
MeshListenAddr string
|
||||||
MeshListenPortMode string
|
MeshListenPortMode string
|
||||||
MeshListenAutoPortStart int
|
MeshListenAutoPortStart int
|
||||||
@@ -63,6 +65,7 @@ func (cfg RuntimeConfig) Normalize() RuntimeConfig {
|
|||||||
cfg.Network = firstNonEmpty(cfg.Network, DefaultNetwork)
|
cfg.Network = firstNonEmpty(cfg.Network, DefaultNetwork)
|
||||||
cfg.RestartPolicy = firstNonEmpty(cfg.RestartPolicy, "unless-stopped")
|
cfg.RestartPolicy = firstNonEmpty(cfg.RestartPolicy, "unless-stopped")
|
||||||
cfg.MeshListenAddr = strings.TrimSpace(cfg.MeshListenAddr)
|
cfg.MeshListenAddr = strings.TrimSpace(cfg.MeshListenAddr)
|
||||||
|
cfg.MeshQUICFabricListenAddr = strings.TrimSpace(cfg.MeshQUICFabricListenAddr)
|
||||||
cfg.MeshListenPortMode = strings.ToLower(strings.TrimSpace(cfg.MeshListenPortMode))
|
cfg.MeshListenPortMode = strings.ToLower(strings.TrimSpace(cfg.MeshListenPortMode))
|
||||||
cfg.MeshAdvertiseEndpoint = strings.TrimRight(strings.TrimSpace(cfg.MeshAdvertiseEndpoint), "/")
|
cfg.MeshAdvertiseEndpoint = strings.TrimRight(strings.TrimSpace(cfg.MeshAdvertiseEndpoint), "/")
|
||||||
cfg.MeshAdvertiseEndpointsJSON = strings.TrimSpace(cfg.MeshAdvertiseEndpointsJSON)
|
cfg.MeshAdvertiseEndpointsJSON = strings.TrimSpace(cfg.MeshAdvertiseEndpointsJSON)
|
||||||
|
|||||||
@@ -266,6 +266,7 @@ func NodeAgentEnvWithStateDir(cfg RuntimeConfig, stateDir string) []string {
|
|||||||
"RAP_MESH_PRODUCTION_FORWARDING_ENABLED=" + boolString(cfg.MeshProductionForwardingEnabled),
|
"RAP_MESH_PRODUCTION_FORWARDING_ENABLED=" + boolString(cfg.MeshProductionForwardingEnabled),
|
||||||
"RAP_MESH_FABRIC_SESSION_ENABLED=" + boolString(cfg.MeshFabricSessionEnabled),
|
"RAP_MESH_FABRIC_SESSION_ENABLED=" + boolString(cfg.MeshFabricSessionEnabled),
|
||||||
"RAP_VPN_FABRIC_SESSION_TRANSPORT_ENABLED=" + boolString(cfg.VPNFabricSessionTransportEnabled),
|
"RAP_VPN_FABRIC_SESSION_TRANSPORT_ENABLED=" + boolString(cfg.VPNFabricSessionTransportEnabled),
|
||||||
|
"RAP_MESH_QUIC_FABRIC_ENABLED=" + boolString(cfg.MeshQUICFabricEnabled),
|
||||||
}
|
}
|
||||||
if cfg.JoinToken != "" {
|
if cfg.JoinToken != "" {
|
||||||
env = append(env, "RAP_JOIN_TOKEN="+cfg.JoinToken)
|
env = append(env, "RAP_JOIN_TOKEN="+cfg.JoinToken)
|
||||||
@@ -273,6 +274,9 @@ func NodeAgentEnvWithStateDir(cfg RuntimeConfig, stateDir string) []string {
|
|||||||
if cfg.MeshListenAddr != "" {
|
if cfg.MeshListenAddr != "" {
|
||||||
env = append(env, "RAP_MESH_LISTEN_ADDR="+cfg.MeshListenAddr)
|
env = append(env, "RAP_MESH_LISTEN_ADDR="+cfg.MeshListenAddr)
|
||||||
}
|
}
|
||||||
|
if cfg.MeshQUICFabricListenAddr != "" {
|
||||||
|
env = append(env, "RAP_MESH_QUIC_FABRIC_LISTEN_ADDR="+cfg.MeshQUICFabricListenAddr)
|
||||||
|
}
|
||||||
if cfg.MeshListenPortMode != "" {
|
if cfg.MeshListenPortMode != "" {
|
||||||
env = append(env, "RAP_MESH_LISTEN_PORT_MODE="+cfg.MeshListenPortMode)
|
env = append(env, "RAP_MESH_LISTEN_PORT_MODE="+cfg.MeshListenPortMode)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,6 +74,8 @@ func LinuxInstallConfigFromProfile(profile LinuxInstallProfile) LinuxInstallConf
|
|||||||
MeshProductionForwardingEnabled: profile.MeshProductionForwardingEnabled,
|
MeshProductionForwardingEnabled: profile.MeshProductionForwardingEnabled,
|
||||||
MeshFabricSessionEnabled: profile.MeshFabricSessionEnabled,
|
MeshFabricSessionEnabled: profile.MeshFabricSessionEnabled,
|
||||||
VPNFabricSessionTransportEnabled: profile.VPNFabricSessionTransportEnabled,
|
VPNFabricSessionTransportEnabled: profile.VPNFabricSessionTransportEnabled,
|
||||||
|
MeshQUICFabricEnabled: profile.MeshQUICFabricEnabled,
|
||||||
|
MeshQUICFabricListenAddr: profile.MeshQUICFabricListenAddr,
|
||||||
MeshListenAddr: profile.MeshListenAddr,
|
MeshListenAddr: profile.MeshListenAddr,
|
||||||
MeshListenPortMode: profile.MeshListenPortMode,
|
MeshListenPortMode: profile.MeshListenPortMode,
|
||||||
MeshListenAutoPortStart: profile.MeshListenAutoPortStart,
|
MeshListenAutoPortStart: profile.MeshListenAutoPortStart,
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ type DockerInstallProfile struct {
|
|||||||
MeshProductionForwardingEnabled bool `json:"mesh_production_forwarding_enabled"`
|
MeshProductionForwardingEnabled bool `json:"mesh_production_forwarding_enabled"`
|
||||||
MeshFabricSessionEnabled bool `json:"mesh_fabric_session_enabled"`
|
MeshFabricSessionEnabled bool `json:"mesh_fabric_session_enabled"`
|
||||||
VPNFabricSessionTransportEnabled bool `json:"vpn_fabric_session_transport_enabled"`
|
VPNFabricSessionTransportEnabled bool `json:"vpn_fabric_session_transport_enabled"`
|
||||||
|
MeshQUICFabricEnabled bool `json:"mesh_quic_fabric_enabled"`
|
||||||
|
MeshQUICFabricListenAddr string `json:"mesh_quic_fabric_listen_addr"`
|
||||||
MeshListenAddr string `json:"mesh_listen_addr"`
|
MeshListenAddr string `json:"mesh_listen_addr"`
|
||||||
MeshListenPortMode string `json:"mesh_listen_port_mode"`
|
MeshListenPortMode string `json:"mesh_listen_port_mode"`
|
||||||
MeshListenAutoPortStart int `json:"mesh_listen_auto_port_start"`
|
MeshListenAutoPortStart int `json:"mesh_listen_auto_port_start"`
|
||||||
@@ -76,6 +78,8 @@ type WindowsInstallProfile struct {
|
|||||||
MeshProductionForwardingEnabled bool `json:"mesh_production_forwarding_enabled"`
|
MeshProductionForwardingEnabled bool `json:"mesh_production_forwarding_enabled"`
|
||||||
MeshFabricSessionEnabled bool `json:"mesh_fabric_session_enabled"`
|
MeshFabricSessionEnabled bool `json:"mesh_fabric_session_enabled"`
|
||||||
VPNFabricSessionTransportEnabled bool `json:"vpn_fabric_session_transport_enabled"`
|
VPNFabricSessionTransportEnabled bool `json:"vpn_fabric_session_transport_enabled"`
|
||||||
|
MeshQUICFabricEnabled bool `json:"mesh_quic_fabric_enabled"`
|
||||||
|
MeshQUICFabricListenAddr string `json:"mesh_quic_fabric_listen_addr"`
|
||||||
MeshListenAddr string `json:"mesh_listen_addr"`
|
MeshListenAddr string `json:"mesh_listen_addr"`
|
||||||
MeshListenPortMode string `json:"mesh_listen_port_mode"`
|
MeshListenPortMode string `json:"mesh_listen_port_mode"`
|
||||||
MeshListenAutoPortStart int `json:"mesh_listen_auto_port_start"`
|
MeshListenAutoPortStart int `json:"mesh_listen_auto_port_start"`
|
||||||
@@ -110,6 +114,8 @@ type LinuxInstallProfile struct {
|
|||||||
MeshProductionForwardingEnabled bool `json:"mesh_production_forwarding_enabled"`
|
MeshProductionForwardingEnabled bool `json:"mesh_production_forwarding_enabled"`
|
||||||
MeshFabricSessionEnabled bool `json:"mesh_fabric_session_enabled"`
|
MeshFabricSessionEnabled bool `json:"mesh_fabric_session_enabled"`
|
||||||
VPNFabricSessionTransportEnabled bool `json:"vpn_fabric_session_transport_enabled"`
|
VPNFabricSessionTransportEnabled bool `json:"vpn_fabric_session_transport_enabled"`
|
||||||
|
MeshQUICFabricEnabled bool `json:"mesh_quic_fabric_enabled"`
|
||||||
|
MeshQUICFabricListenAddr string `json:"mesh_quic_fabric_listen_addr"`
|
||||||
MeshListenAddr string `json:"mesh_listen_addr"`
|
MeshListenAddr string `json:"mesh_listen_addr"`
|
||||||
MeshListenPortMode string `json:"mesh_listen_port_mode"`
|
MeshListenPortMode string `json:"mesh_listen_port_mode"`
|
||||||
MeshListenAutoPortStart int `json:"mesh_listen_auto_port_start"`
|
MeshListenAutoPortStart int `json:"mesh_listen_auto_port_start"`
|
||||||
@@ -289,6 +295,8 @@ func RuntimeConfigFromProfile(profile DockerInstallProfile) RuntimeConfig {
|
|||||||
MeshProductionForwardingEnabled: profile.MeshProductionForwardingEnabled,
|
MeshProductionForwardingEnabled: profile.MeshProductionForwardingEnabled,
|
||||||
MeshFabricSessionEnabled: profile.MeshFabricSessionEnabled,
|
MeshFabricSessionEnabled: profile.MeshFabricSessionEnabled,
|
||||||
VPNFabricSessionTransportEnabled: profile.VPNFabricSessionTransportEnabled,
|
VPNFabricSessionTransportEnabled: profile.VPNFabricSessionTransportEnabled,
|
||||||
|
MeshQUICFabricEnabled: profile.MeshQUICFabricEnabled,
|
||||||
|
MeshQUICFabricListenAddr: profile.MeshQUICFabricListenAddr,
|
||||||
MeshListenAddr: profile.MeshListenAddr,
|
MeshListenAddr: profile.MeshListenAddr,
|
||||||
MeshListenPortMode: profile.MeshListenPortMode,
|
MeshListenPortMode: profile.MeshListenPortMode,
|
||||||
MeshListenAutoPortStart: profile.MeshListenAutoPortStart,
|
MeshListenAutoPortStart: profile.MeshListenAutoPortStart,
|
||||||
|
|||||||
@@ -596,6 +596,8 @@ func (m DockerManager) runtimeConfigFromContainer(ctx context.Context, runner Co
|
|||||||
MeshProductionForwardingEnabled: parseBool(env["RAP_MESH_PRODUCTION_FORWARDING_ENABLED"]),
|
MeshProductionForwardingEnabled: parseBool(env["RAP_MESH_PRODUCTION_FORWARDING_ENABLED"]),
|
||||||
MeshFabricSessionEnabled: parseBool(env["RAP_MESH_FABRIC_SESSION_ENABLED"]),
|
MeshFabricSessionEnabled: parseBool(env["RAP_MESH_FABRIC_SESSION_ENABLED"]),
|
||||||
VPNFabricSessionTransportEnabled: parseBool(env["RAP_VPN_FABRIC_SESSION_TRANSPORT_ENABLED"]),
|
VPNFabricSessionTransportEnabled: parseBool(env["RAP_VPN_FABRIC_SESSION_TRANSPORT_ENABLED"]),
|
||||||
|
MeshQUICFabricEnabled: parseBool(env["RAP_MESH_QUIC_FABRIC_ENABLED"]),
|
||||||
|
MeshQUICFabricListenAddr: env["RAP_MESH_QUIC_FABRIC_LISTEN_ADDR"],
|
||||||
MeshListenAddr: env["RAP_MESH_LISTEN_ADDR"],
|
MeshListenAddr: env["RAP_MESH_LISTEN_ADDR"],
|
||||||
MeshListenPortMode: env["RAP_MESH_LISTEN_PORT_MODE"],
|
MeshListenPortMode: env["RAP_MESH_LISTEN_PORT_MODE"],
|
||||||
MeshListenAutoPortStart: parseInt(env["RAP_MESH_LISTEN_AUTO_PORT_START"]),
|
MeshListenAutoPortStart: parseInt(env["RAP_MESH_LISTEN_AUTO_PORT_START"]),
|
||||||
|
|||||||
@@ -68,6 +68,8 @@ func WindowsInstallConfigFromProfile(profile WindowsInstallProfile) WindowsInsta
|
|||||||
MeshProductionForwardingEnabled: profile.MeshProductionForwardingEnabled,
|
MeshProductionForwardingEnabled: profile.MeshProductionForwardingEnabled,
|
||||||
MeshFabricSessionEnabled: profile.MeshFabricSessionEnabled,
|
MeshFabricSessionEnabled: profile.MeshFabricSessionEnabled,
|
||||||
VPNFabricSessionTransportEnabled: profile.VPNFabricSessionTransportEnabled,
|
VPNFabricSessionTransportEnabled: profile.VPNFabricSessionTransportEnabled,
|
||||||
|
MeshQUICFabricEnabled: profile.MeshQUICFabricEnabled,
|
||||||
|
MeshQUICFabricListenAddr: profile.MeshQUICFabricListenAddr,
|
||||||
MeshListenAddr: profile.MeshListenAddr,
|
MeshListenAddr: profile.MeshListenAddr,
|
||||||
MeshListenPortMode: profile.MeshListenPortMode,
|
MeshListenPortMode: profile.MeshListenPortMode,
|
||||||
MeshListenAutoPortStart: profile.MeshListenAutoPortStart,
|
MeshListenAutoPortStart: profile.MeshListenAutoPortStart,
|
||||||
|
|||||||
@@ -301,6 +301,10 @@ Carrier selection understands QUIC transport labels and `quic://host:port`
|
|||||||
endpoints while preserving WebSocket as the default fallback.
|
endpoints while preserving WebSocket as the default fallback.
|
||||||
`QUICFabricServer` provides the matching node-side QUIC listener for accepting
|
`QUICFabricServer` provides the matching node-side QUIC listener for accepting
|
||||||
fabric streams and running the same session frame handler as other carriers.
|
fabric streams and running the same session frame handler as other carriers.
|
||||||
|
Node-agent can now gate the QUIC listener with
|
||||||
|
`RAP_MESH_QUIC_FABRIC_ENABLED` / `RAP_MESH_QUIC_FABRIC_LISTEN_ADDR`, report it
|
||||||
|
in heartbeat metadata, and pass the setting through host-agent install/update
|
||||||
|
profiles.
|
||||||
|
|
||||||
Deliverables:
|
Deliverables:
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user