// 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)
}
}