我想从Swift
的DNS查询中获取IP服装(如192.168.0.1或87.12.56.50)。我用100种不同的方法尝试了100次......没有什么帮助我,所以我不得不寻求帮助(我希望这里有很多人;))
到目前为止,这是我的代码:
let host = CFHostCreateWithName(nil,"subdomain.of.stackoverflow.com").takeUnretainedValue();
CFHostStartInfoResolution(host, .Addresses, nil);
var success: Boolean = 0;
let addresses = CFHostGetAddressing(host, &success).takeUnretainedValue() as NSArray;
if(addresses.count > 0){
let theAddress = addresses[0] as NSData;
println(theAddress);
}
好的......这些是我试图实现但未成功实现的代码的链接:
https://gist.github.com/mikeash/bca3a341db74221625f5
How to perform DNS query on iOS
Create an Array in Swift from an NSData Object
Does CFHostGetAddressing() support ipv6 DNS entries?
Do a simple DNS lookup in Swift
因此,如果我们对此问题进行无意义的否定投票,我们可以尝试找到解决方案并帮助其他人(像我一样)
答案 0 :(得分:29)
您的代码将地址检索为"套接字地址"结构体。
getnameinfo()
可用于将地址转换为数字IP字符串
(从https://stackoverflow.com/a/25627545/1187415回收的代码,
现已更新为 Swift 2 ):
let host = CFHostCreateWithName(nil,"www.google.com").takeRetainedValue()
CFHostStartInfoResolution(host, .Addresses, nil)
var success: DarwinBoolean = false
if let addresses = CFHostGetAddressing(host, &success)?.takeUnretainedValue() as NSArray?,
let theAddress = addresses.firstObject as? NSData {
var hostname = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
if getnameinfo(UnsafePointer(theAddress.bytes), socklen_t(theAddress.length),
&hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 {
if let numAddress = String.fromCString(hostname) {
print(numAddress)
}
}
}
输出(示例):173.194.112.147
还要注意第一行中takeRetainedValue()
的用法,因为
CFHostCreateWithName()
已经"创建"因此,在其名称中返回保留的(+1)
对象
更新Swift 3 / Xcode 8:
let host = CFHostCreateWithName(nil,"www.google.com" as CFString).takeRetainedValue()
CFHostStartInfoResolution(host, .addresses, nil)
var success: DarwinBoolean = false
if let addresses = CFHostGetAddressing(host, &success)?.takeUnretainedValue() as NSArray?,
let theAddress = addresses.firstObject as? NSData {
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
if getnameinfo(theAddress.bytes.assumingMemoryBound(to: sockaddr.self), socklen_t(theAddress.length),
&hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 {
let numAddress = String(cString: hostname)
print(numAddress)
}
}
或者,为主机获取所有 IP地址:
let host = CFHostCreateWithName(nil,"www.google.com" as CFString).takeRetainedValue()
CFHostStartInfoResolution(host, .addresses, nil)
var success: DarwinBoolean = false
if let addresses = CFHostGetAddressing(host, &success)?.takeUnretainedValue() as NSArray? {
for case let theAddress as NSData in addresses {
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
if getnameinfo(theAddress.bytes.assumingMemoryBound(to: sockaddr.self), socklen_t(theAddress.length),
&hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 {
let numAddress = String(cString: hostname)
print(numAddress)
}
}
}
答案 1 :(得分:0)
请参阅以下Swift代码以获取网站的DNS解析。一种方法使用CFHostStartInfoResolution
,而另一种方法使用gethostbyname
。
这两个API均支持全部/多个IP地址解析。
private func urlToIP_cfHostResolution(_ url: String) -> [String] {
var ipList: [String] = []
let host = CFHostCreateWithName(nil,url as CFString).takeRetainedValue()
CFHostStartInfoResolution(host, .addresses, nil)
var success: DarwinBoolean = false
if let addresses = CFHostGetAddressing(host, &success)?.takeUnretainedValue() as NSArray? {
for case let theAddress as NSData in addresses {
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
if getnameinfo(theAddress.bytes.assumingMemoryBound(to: sockaddr.self), socklen_t(theAddress.length),
&hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 {
ipList.append(String(cString: hostname))
}
}
}
return ipList
}
此方法为["151.101.129.69", "151.101.1.69", "151.101.193.69", "151.101.65.69"]
返回www.stackoverflow.com
private func urlToIP_gethostbyname(_ url: URL) -> [String] {
var ipList: [String] = []
guard let hostname = url.host else {
return ipList
}
guard let host = hostname.withCString({gethostbyname($0)}) else {
return ipList
}
guard host.pointee.h_length > 0 else {
return ipList
}
var index = 0
while host.pointee.h_addr_list[index] != nil {
var addr: in_addr = in_addr()
memcpy(&addr.s_addr, host.pointee.h_addr_list[index], Int(host.pointee.h_length))
guard let remoteIPAsC = inet_ntoa(addr) else {
return ipList
}
ipList.append(String.init(cString: remoteIPAsC))
index += 1
}
return ipList
}
此方法还会为["151.101.129.69", "151.101.1.69", "151.101.193.69", "151.101.65.69"]
返回www.stackoverflow.com
希望这会有所帮助。
答案 2 :(得分:0)
许多答案正在使用不赞成使用的bytes
来检索sockaddr
,以提供给getnameinfo
。我们现在将使用address.withUnsafeBytes
。例如,在Swift 5中:
/// Returns the string representation of the supplied address.
///
/// - parameter address: Contains a `(struct sockaddr)` with the address to render.
///
/// - returns: A string representation of that address.
func stringRepresentation(forAddress address: Data) -> String? {
address.withUnsafeBytes { pointer in
var hostStr = [Int8](repeating: 0, count: Int(NI_MAXHOST))
let result = getnameinfo(
pointer.baseAddress?.assumingMemoryBound(to: sockaddr.self),
socklen_t(address.count),
&hostStr,
socklen_t(hostStr.count),
nil,
0,
NI_NUMERICHOST
)
guard result == 0 else { return nil }
return String(cString: hostStr)
}
}