Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions apple/ClashClient/Sources/AppArchitecture/ProxyImportBridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@ struct ProxyImportResult {
let identities: [String]
let shape: ProxyPayloadShape?

/// Split-DNS routing tables lifted from a mihomo configuration payload
/// (`dns.nameserver-policy` / `dns.proxy-server-nameserver-policy`). They let the airport's
/// DNS routing policy be append-merged into the user's main configuration instead of being
/// discarded when only nodes are extracted. `nil` when the payload carries no DNS policy.
var dnsNameServerPolicy: [String: Any]? = nil
var dnsProxyServerNameserverPolicy: [String: Any]? = nil

var issues: [ProxyImportIssue] {
skipped
}
Expand Down Expand Up @@ -344,10 +351,19 @@ enum ProxyImportBridge {
+ issues(root["recognizedUnsupported"]),
notHonoured: issues(root["notHonoured"]),
identities: root["identities"] as? [String] ?? [],
shape: shape(root["payloadShape"])
shape: shape(root["payloadShape"]),
dnsNameServerPolicy: dnsPolicy(root["dnsNameServerPolicy"]),
dnsProxyServerNameserverPolicy: dnsPolicy(root["dnsProxyServerNameserverPolicy"])
)
}

/// Normalises one split-DNS table from the kernel report into a JSON-safe dictionary.
/// Returns `nil` for missing or empty tables so callers can fall back to their own policy.
private static func dnsPolicy(_ raw: Any?) -> [String: Any]? {
guard let table = raw as? [String: Any], !table.isEmpty else { return nil }
return table
}




Expand Down Expand Up @@ -527,7 +543,18 @@ enum ProxyImportBridge {
}
log(skipped: result.issues, keeping: result.proxies.count)
log(notHonoured: result.notHonoured)
let data = try JSONSerialization.data(withJSONObject: ["proxies": result.proxies])
var document: [String: Any] = ["proxies": result.proxies]
// Carry the airport's split-DNS routing tables into the node document so they reach the
// main configuration instead of being dropped by node extraction. `mergeOverride` unions
// maps, and the user's own patch is the winning side, so conflicting domains stay under
// the user's control while the airport's remaining domains are still honoured.
var dns: [String: Any] = [:]
if let policy = result.dnsNameServerPolicy { dns["nameserver-policy"] = policy }
if let policy = result.dnsProxyServerNameserverPolicy {
dns["proxy-server-nameserver-policy"] = policy
}
if !dns.isEmpty { document["dns"] = dns }
let data = try JSONSerialization.data(withJSONObject: document)
let yaml = try ConfigTransforms.jsonToYAML(String(decoding: data, as: UTF8.self))
return (yaml, result.proxies.count, result.issues)
}
Expand Down