|
// retoor <retoor@molodetz.nl>
|
|
|
|
import Foundation
|
|
|
|
enum DnsResolver {
|
|
struct DnsResult {
|
|
let hostname: String
|
|
let addresses: [String]
|
|
let error: String?
|
|
}
|
|
|
|
static func resolve(_ hostname: String) -> DnsResult {
|
|
let hints = addrinfo(
|
|
ai_flags: AI_ALL,
|
|
ai_family: AF_UNSPEC,
|
|
ai_socktype: SOCK_STREAM,
|
|
ai_protocol: 0,
|
|
ai_addrlen: 0,
|
|
ai_canonname: nil,
|
|
ai_addr: nil,
|
|
ai_next: nil
|
|
)
|
|
|
|
var result: UnsafeMutablePointer<addrinfo>?
|
|
let errorCode = getaddrinfo(hostname, nil, &hints, &result)
|
|
|
|
if errorCode != 0 {
|
|
let errorStr = String(cString: gai_strerror(errorCode))
|
|
return DnsResult(hostname: hostname, addresses: [], error: errorStr)
|
|
}
|
|
|
|
var addresses: [String] = []
|
|
var current = result
|
|
while let addr = current {
|
|
var hostBuffer = [CChar](repeating: 0, count: Int(NI_MAXHOST))
|
|
let sa_len: socklen_t
|
|
let sa: UnsafePointer<sockaddr>
|
|
|
|
if addr.pointee.ai_family == AF_INET {
|
|
sa_len = socklen_t(MemoryLayout<sockaddr_in>.size)
|
|
sa = UnsafeRawPointer(addr.pointee.ai_addr).assumingMemoryBound(to: sockaddr.self)
|
|
} else if addr.pointee.ai_family == AF_INET6 {
|
|
sa_len = socklen_t(MemoryLayout<sockaddr_in6>.size)
|
|
sa = UnsafeRawPointer(addr.pointee.ai_addr).assumingMemoryBound(to: sockaddr.self)
|
|
} else {
|
|
current = addr.pointee.ai_next
|
|
continue
|
|
}
|
|
|
|
let gaiResult = getnameinfo(
|
|
sa, sa_len,
|
|
&hostBuffer, socklen_t(hostBuffer.count),
|
|
nil, 0,
|
|
NI_NUMERICHOST
|
|
)
|
|
if gaiResult == 0 {
|
|
addresses.append(String(cString: hostBuffer))
|
|
}
|
|
current = addr.pointee.ai_next
|
|
}
|
|
|
|
freeaddrinfo(result)
|
|
return DnsResult(hostname: hostname, addresses: addresses, error: nil)
|
|
}
|
|
}
|