package fabricvpn import ( "os" "testing" ) func TestFabricRuntimeEndpointsPreferRouteBundle(t *testing.T) { cfg := runtimeConfig{ Endpoints: []endpointConfig{{EndpointID: "legacy", Address: "quic://legacy.example:19131"}}, RouteBundle: routeBundleConfig{ EndpointCandidates: []endpointConfig{{EndpointID: "bundle", Address: "quic://bundle.example:19131"}}, }, } got := fabricRuntimeEndpoints(cfg) if len(got) != 1 || got[0].EndpointID != "bundle" { t.Fatalf("endpoints = %+v, want route bundle endpoint", got) } } func TestFabricRuntimeEndpointsPreferRouteLease(t *testing.T) { cfg := runtimeConfig{ Endpoints: []endpointConfig{{EndpointID: "legacy", Address: "quic://legacy.example:19131"}}, RouteBundle: routeBundleConfig{ EndpointCandidates: []endpointConfig{{EndpointID: "bundle", Address: "quic://bundle.example:19131"}}, RouteLease: routeLeaseConfig{ SelectedTargetNode: "exit-1", PrimaryPath: routeLeasePath{ TargetNodeID: "exit-1", EndpointCandidates: []endpointConfig{{EndpointID: "lease-primary", Address: "quic://lease.example:19131"}}, }, }, }, } got := fabricRuntimeEndpoints(cfg) if len(got) != 1 || got[0].EndpointID != "lease-primary" { t.Fatalf("endpoints = %+v, want route lease primary endpoint", got) } if target := fabricRuntimeTargetNodeID(cfg); target != "exit-1" { t.Fatalf("target = %q, want exit-1", target) } } func TestFabricRuntimeEndpointsFallbackToLegacyEndpoints(t *testing.T) { cfg := runtimeConfig{ Endpoints: []endpointConfig{{EndpointID: "legacy", Address: "quic://legacy.example:19131"}}, } got := fabricRuntimeEndpoints(cfg) if len(got) != 1 || got[0].EndpointID != "legacy" { t.Fatalf("endpoints = %+v, want legacy endpoint fallback", got) } } func TestLiveFabricVPNRuntimeStartsFromRouteLease(t *testing.T) { raw := os.Getenv("RAP_LIVE_FABRICVPN_CONFIG") if raw == "" { t.Skip("RAP_LIVE_FABRICVPN_CONFIG is not set") } manager := NewManager() if err := manager.Start(raw); err != nil { t.Fatalf("start live fabric vpn runtime: %v", err) } defer manager.Stop() if snapshot := manager.SnapshotJSON(); snapshot == "" { t.Fatal("empty live fabric vpn snapshot") } if os.Getenv("RAP_LIVE_FABRICVPN_PACKET_PROBE") == "" { return } if err := manager.SendPacket(testDNSIPv4Packet()); err != nil { t.Fatalf("send live dns packet: %v", err) } for i := 0; i < 20; i++ { packet, err := manager.ReceivePacket(500) if err != nil { t.Fatalf("receive live dns packet: %v", err) } if len(packet) > 0 { if packet[9] != 17 || packet[12] != 1 || packet[13] != 1 || packet[14] != 1 || packet[15] != 1 { t.Fatalf("unexpected response packet header: %v", packet[:min(20, len(packet))]) } return } } t.Fatal("timed out waiting for live dns response through fabric vpn") } func testDNSIPv4Packet() []byte { dns := []byte{ 0x12, 0x34, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm', 0x00, 0x00, 0x01, 0x00, 0x01, } udpLen := 8 + len(dns) totalLen := 20 + udpLen packet := make([]byte, totalLen) packet[0] = 0x45 packet[2] = byte(totalLen >> 8) packet[3] = byte(totalLen) packet[8] = 64 packet[9] = 17 copy(packet[12:16], []byte{10, 77, 0, 2}) copy(packet[16:20], []byte{1, 1, 1, 1}) packet[20] = 0xcf packet[21] = 0x08 packet[22] = 0x00 packet[23] = 0x35 packet[24] = byte(udpLen >> 8) packet[25] = byte(udpLen) copy(packet[28:], dns) sum := ipv4HeaderChecksum(packet[:20]) packet[10] = byte(sum >> 8) packet[11] = byte(sum) return packet } func ipv4HeaderChecksum(header []byte) uint16 { var sum uint32 for i := 0; i+1 < len(header); i += 2 { if i == 10 { continue } sum += uint32(header[i])<<8 | uint32(header[i+1]) } for sum > 0xffff { sum = (sum & 0xffff) + (sum >> 16) } return ^uint16(sum) } func min(a, b int) int { if a < b { return a } return b }