Files
knotchy/Tests/KnotchyCoreTests/NetworkRouteTests.swift
T
2026-09-28 18:28:32 +05:30

146 lines
7.3 KiB
Swift

import Foundation
import Testing
@testable import KnotchyCore
@Suite struct NetworkRouteTests {
static let key = Data(repeating: 7, count: 32).base64EncodedString()
static let otherKey = Data(repeating: 9, count: 32).base64EncodedString()
static let mullvadStyle = """
[Interface]
# Device: Quick Fox
PrivateKey = \(key)
Address = 10.64.12.34/32,fc00:bbbb:bbbb:bb01::1:c21/128
DNS = 10.64.0.1
[Peer]
PublicKey = \(otherKey)
AllowedIPs = 0.0.0.0/0,::0/0
Endpoint = se-got-wg-001.relays.mullvad.net:51820
"""
@Test func parsesAProviderConfig() throws {
let config = try WireGuardConfig.parse(Self.mullvadStyle)
#expect(config.privateKey == Self.key)
#expect(config.addresses == ["10.64.12.34/32"])
#expect(config.dns == ["10.64.0.1"])
#expect(config.peerPublicKey == Self.otherKey)
#expect(config.endpointHost == "se-got-wg-001.relays.mullvad.net")
#expect(config.endpointPort == 51820)
#expect(config.mtu == nil)
#expect(config.persistentKeepalive == nil)
}
@Test func keysAreCaseInsensitiveAndRepeatsJoin() throws {
let text = """
[interface]
privatekey=\(Self.key)
Address = 10.2.0.2
Address = 10.2.0.3/32
DNS = 10.2.0.1, 1.1.1.1, example.search.domain
MTU = 1380
[PEER]
publickey = \(Self.otherKey)
PresharedKey = \(Self.key)
endpoint = 203.0.113.9:443
PersistentKeepalive = 15
"""
let config = try WireGuardConfig.parse(text)
#expect(config.addresses == ["10.2.0.2/32", "10.2.0.3/32"])
#expect(config.dns == ["10.2.0.1", "1.1.1.1"])
#expect(config.mtu == 1380)
#expect(config.presharedKey == Self.key)
#expect(config.persistentKeepalive == 15)
}
@Test func rejectsWhatTheVMCannotUse() {
func parse(_ text: String) -> WireGuardConfig.ParseError? {
do { _ = try WireGuardConfig.parse(text); return nil } catch { return error }
}
let peer = "[Peer]\nPublicKey = \(Self.otherKey)\nEndpoint = 1.2.3.4:51820\n"
#expect(parse("[Interface]\nAddress = 10.0.0.2/32\n" + peer) == .missing("PrivateKey"))
#expect(parse("[Interface]\nPrivateKey = nope\nAddress = 10.0.0.2/32\n" + peer) == .invalid("PrivateKey"))
#expect(parse("[Interface]\nPrivateKey = \(Self.key)\nAddress = fd00::2/128\n" + peer) == .missing("an IPv4 Address"))
#expect(parse("[Interface]\nPrivateKey = \(Self.key)\nAddress = 10.0.0.2/32\n") == .missing("[Peer]"))
#expect(parse("[Interface]\nPrivateKey = \(Self.key)\nAddress = 10.0.0.2/32\n" + peer + peer) == .multiplePeers)
let v6Endpoint = "[Peer]\nPublicKey = \(Self.otherKey)\nEndpoint = [2001:db8::1]:51820\n"
#expect(parse("[Interface]\nPrivateKey = \(Self.key)\nAddress = 10.0.0.2/32\n" + v6Endpoint) != nil)
let shellEndpoint = "[Peer]\nPublicKey = \(Self.otherKey)\nEndpoint = $(reboot):51820\n"
#expect(parse("[Interface]\nPrivateKey = \(Self.key)\nAddress = 10.0.0.2/32\n" + shellEndpoint) == .invalid("Endpoint"))
#expect(parse("[Interface]\nPrivateKey = \(Self.key)\nAddress = 10.0.0.2/32\nPostUp = rm -rf /\n" + peer) == nil)
}
@Test func setconfForcesAFullTunnelAndAKeepalive() throws {
let config = try WireGuardConfig.parse(Self.mullvadStyle)
let setconf = config.setconf(endpointAddress: "185.213.154.66")
#expect(setconf == """
[Interface]
PrivateKey = \(Self.key)
[Peer]
PublicKey = \(Self.otherKey)
Endpoint = 185.213.154.66:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
""")
}
@Test func proxyURLsEncodeCredentialsAndUseTheAddress() {
let proxy = ProxySettings(kind: .socks5, host: "proxy.example", port: 1080, username: "me@home", password: "p:w/d@!")
#expect(proxy.url(address: "203.0.113.7") == "socks5://me%40home:p%3Aw%2Fd%40%21@203.0.113.7:1080")
#expect(ProxySettings(kind: .http, host: "h", port: 8080).url(address: "10.0.0.5") == "http://10.0.0.5:8080")
#expect(ProxySettings(kind: .http, host: "h", port: 8080, username: "u").url(address: "10.0.0.5") == "http://u@10.0.0.5:8080")
}
@Test func launchKeepsSecretsOutOfTheEnvironment() throws {
var asked: [String] = []
let resolve = { (host: String) -> String in asked.append(host); return "198.51.100.4" }
#expect(try NetworkRoute.direct.launch(resolve: resolve) == RouteLaunch(environment: ["KNOTCHY_ROUTE=direct"], secrets: []))
let proxy = NetworkRoute.proxy(ProxySettings(kind: .http, host: "proxy.corp", port: 3128, username: "u", password: "p"))
#expect(try proxy.launch(resolve: resolve) == RouteLaunch(
environment: ["KNOTCHY_ROUTE=proxy", "KNOTCHY_PROXY_ADDR=198.51.100.4:3128"],
secrets: ["KNOTCHY_PROXY_URL=http://u:p@198.51.100.4:3128"]
))
let wireGuard = try NetworkRoute.wireGuard(WireGuardConfig.parse(Self.mullvadStyle)).launch(resolve: resolve)
#expect(asked == ["proxy.corp", "se-got-wg-001.relays.mullvad.net"])
#expect(wireGuard.environment == [
"KNOTCHY_ROUTE=wireguard", "KNOTCHY_WG_ENDPOINT=198.51.100.4:51820", "KNOTCHY_WG_ADDRESS=10.64.12.34/32",
"KNOTCHY_WG_DNS=10.64.0.1", "KNOTCHY_WG_MTU=1420",
])
#expect(wireGuard.environment.allSatisfy { !$0.contains(Self.key) })
#expect(wireGuard.secrets.count == 1 && wireGuard.secrets[0].hasPrefix("KNOTCHY_WG_SETCONF="))
#expect((wireGuard.environment + wireGuard.secrets).allSatisfy { !$0.contains("\n") })
#expect(throws: VMBackendError.failed("no")) { try NetworkRoute.unusable(reason: "no").launch(resolve: resolve) }
}
@Test func routeLabels() throws {
#expect(NetworkRoute.direct.label == nil)
#expect(NetworkRoute.proxy(ProxySettings(kind: .socks5, host: "h", port: 1)).label == "SOCKS5 proxy")
var config = try WireGuardConfig.parse(Self.mullvadStyle)
#expect(NetworkRoute.wireGuard(config).label == "VPN")
config.name = "sg-sin-wg-001"
#expect(NetworkRoute.wireGuard(config).label == "sg-sin-wg-001")
}
@Test func proxiesOnTheMacOrItsNetworkAreRefused() throws {
for local in ["10.1.2.3", "127.0.0.1", "169.254.169.254", "172.20.0.1", "192.168.64.1", "100.100.1.1", "0.0.0.0"] {
#expect(ProxySettings.isLocal(local, hostNetworks: []), "\(local)")
}
#expect(ProxySettings.isLocal("203.0.113.9", hostNetworks: ["203.0.113.0/24"]))
#expect(!ProxySettings.isLocal("203.0.113.9", hostNetworks: ["198.51.100.0/24"]))
#expect(!ProxySettings.isLocal("8.8.8.8", hostNetworks: []))
#expect(!ProxySettings.isLocal("172.32.0.1", hostNetworks: []))
let proxy = NetworkRoute.proxy(ProxySettings(kind: .http, host: "proxy.lan", port: 3128))
#expect(throws: VMBackendError.self) { try proxy.launch(resolve: { _ in "192.168.1.10" }) }
#expect(try proxy.launch(resolve: { _ in "192.168.1.10" }, allowLocalProxy: true).environment.count == 2)
// A local WireGuard server is fine: only wireguard-go can reach it.
let wireGuard = NetworkRoute.wireGuard(try WireGuardConfig.parse(Self.mullvadStyle))
#expect(try wireGuard.launch(resolve: { _ in "192.168.1.1" }).environment.contains("KNOTCHY_WG_ENDPOINT=192.168.1.1:51820"))
}
}