81 lines
2.7 KiB
Swift
81 lines
2.7 KiB
Swift
//
|
|
// DNSResolver.swift
|
|
// TunnelKit
|
|
//
|
|
// Created by Davide De Rosa on 12/15/17.
|
|
// Copyright © 2017 London Trust Media. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
/// :nodoc:
|
|
public class DNSResolver {
|
|
private static let queue = DispatchQueue(label: "DNSResolver")
|
|
|
|
public static func resolve(_ hostname: String, timeout: Int, queue: DispatchQueue, completionHandler: @escaping ([String]?, Error?) -> Void) {
|
|
var pendingHandler: (([String]?, Error?) -> Void)? = completionHandler
|
|
let host = CFHostCreateWithName(nil, hostname as CFString).takeRetainedValue()
|
|
DNSResolver.queue.async {
|
|
CFHostStartInfoResolution(host, .addresses, nil)
|
|
guard let handler = pendingHandler else {
|
|
return
|
|
}
|
|
DNSResolver.didResolve(host: host) { (addrs, error) in
|
|
queue.async {
|
|
handler(addrs, error)
|
|
pendingHandler = nil
|
|
}
|
|
}
|
|
}
|
|
queue.asyncAfter(deadline: .now() + .milliseconds(timeout)) {
|
|
guard let handler = pendingHandler else {
|
|
return
|
|
}
|
|
CFHostCancelInfoResolution(host, .addresses)
|
|
handler(nil, nil)
|
|
pendingHandler = nil
|
|
}
|
|
}
|
|
|
|
private static func didResolve(host: CFHost, completionHandler: @escaping ([String]?, Error?) -> Void) {
|
|
var success: DarwinBoolean = false
|
|
guard let rawAddresses = CFHostGetAddressing(host, &success)?.takeUnretainedValue() as Array? else {
|
|
completionHandler(nil, nil)
|
|
return
|
|
}
|
|
|
|
var ipAddresses: [String] = []
|
|
for case var rawAddress as Data in rawAddresses {
|
|
var ipAddress = [CChar](repeating: 0, count: Int(NI_MAXHOST))
|
|
let result = rawAddress.withUnsafeBytes { (addr: UnsafePointer<sockaddr>) in
|
|
return getnameinfo(
|
|
addr,
|
|
socklen_t(rawAddress.count),
|
|
&ipAddress,
|
|
socklen_t(ipAddress.count),
|
|
nil,
|
|
0,
|
|
NI_NUMERICHOST
|
|
)
|
|
}
|
|
guard result == 0 else {
|
|
continue
|
|
}
|
|
ipAddresses.append(String(cString: ipAddress))
|
|
}
|
|
completionHandler(ipAddresses, nil)
|
|
}
|
|
|
|
public static func string(fromIPv4 ipv4: UInt32) -> String {
|
|
let a = UInt8(ipv4 & UInt32(0xff))
|
|
let b = UInt8((ipv4 >> 8) & UInt32(0xff))
|
|
let c = UInt8((ipv4 >> 16) & UInt32(0xff))
|
|
let d = UInt8((ipv4 >> 24) & UInt32(0xff))
|
|
|
|
return "\(a).\(b).\(c).\(d)"
|
|
}
|
|
|
|
private init() {
|
|
}
|
|
}
|