Skip to content

Instantly share code, notes, and snippets.

@justMaku
Last active January 7, 2020 13:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save justMaku/723f14cc03ed154478a5b5efebf28035 to your computer and use it in GitHub Desktop.
Save justMaku/723f14cc03ed154478a5b5efebf28035 to your computer and use it in GitHub Desktop.
import Foundation
import SystemConfiguration
enum Error: Swift.Error {
case pppInterfaceNotFound
case failedToWriteToConfigurationStore
}
let dynamicStore = SCDynamicStoreCreate(nil, "setVPNDNS" as CFString, nil, nil)
func cast<T>(_ input: CFArray?) -> Array<T> {
guard
let asAnyObject = input as? [AnyObject],
let asTypedObject = asAnyObject as? [T]
else {
return []
}
return asTypedObject
}
func query<T>(_ filter: String) -> [T] {
return cast((SCDynamicStoreCopyKeyList(dynamicStore, filter as CFString)))
}
func get<T>(_ path: String) -> T {
return SCDynamicStoreCopyValue(dynamicStore, path as CFString) as! T
}
func set(path: String, value: NSDictionary) -> Bool {
return SCDynamicStoreSetValue(dynamicStore, path as CFString, value)
}
func getServiceUUID(for desiredInterfaceName: String) throws -> String {
let serviceKeys: [NSString] = query("State:/Network/Service/(.+)/PPP")
for serviceKey in serviceKeys {
let dictionary: [String: AnyObject] = get(serviceKey as String)
let interfaceName = dictionary[kSCPropInterfaceName as String] as? String
if (interfaceName == desiredInterfaceName) {
return serviceKey
.replacingOccurrences(of: "State:/Network/Service/", with: "")
.replacingOccurrences(of: "/PPP", with: "") // Quite a naive approach, might explode.
}
}
throw Error.pppInterfaceNotFound
}
func overridePrimary(for serviceUIID: String) {
let path = "State:/Network/Service/\(serviceUIID)/IPv4"
var current: [CFString: AnyObject] = get(path)
current[kSCPropNetOverridePrimary] = 1 as NSNumber
current[kSCPropInterfaceName] = "en0" as CFString // TODO: Hardcoded for my setup.
current[kSCPropNetIPv4Router] = "192.168.1.1" as CFString // TODO: Hardcoded for my setup.
set(path: path, value: current as NSDictionary)
}
func injectDNSServers(for serviceUUID: String, dnsServers: [String]) {
let path = "State:/Network/Service/\(serviceUUID)/DNS"
let dictionary = [
kSCPropNetDNSServerAddresses: dnsServers,
kSCPropNetDNSSupplementalMatchOrders: [100000 as NSNumber],
kSCPropNetDNSSupplementalMatchDomains: []
] as [CFString : Any]
set(path: path, value: dictionary as NSDictionary)
}
func makePrimaryService(uuid: String) {
let globalIPv4Path = "State:/Network/Global/IPv4"
var current: [CFString: AnyObject] = get(globalIPv4Path)
current[kSCDynamicStorePropNetPrimaryService] = uuid as CFString
set(path: globalIPv4Path, value: current as NSDictionary)
}
let interface = "ppp0"
let dnsServers = [
"10.11.3.241", // VPN DNS
"10.11.3.242", // VPN DNS
"83.169.184.33",
"83.169.184.97"
]
let uuid = try getServiceUUID(for: interface)
injectDNSServers(for: uuid, dnsServers: dnsServers)
overridePrimary(for: uuid)
makePrimaryService(uuid: uuid)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment