获取网络(非设备)IP地址iOS swift



我已经制作了一些代码来获取Wi-Fi当前SSID和设备当前IP,但我需要获取网络IP地址,所以如果我的设备的IP是192.168.4.3,我知道它连接到192.168.4.1网络,但我不需要在代码中做这个假设。。。

获取SSID:

private func fetchSSIDInfo() -> String? {
var ssid: String?
if let interfaces = CNCopySupportedInterfaces() as NSArray? {
for interface in interfaces {

if let interfaceInfo = CNCopyCurrentNetworkInfo(interface as! CFString) as NSDictionary? {
ssid = interfaceInfo[kCNNetworkInfoKeySSID as String] as? String
break
}
}
}
return ssid
} 

获取设备的IP

static func getIPAddress()->String?{
var address : String?
// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs>?
guard getifaddrs(&ifaddr) == 0 else { return nil }
guard let firstAddr = ifaddr else { return nil }
// For each interface ...
for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
let interface = ifptr.pointee
// Check for IPv4 or IPv6 interface:
let addrFamily = interface.ifa_addr.pointee.sa_family
if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {
// Check interface name:
let name = String(cString: interface.ifa_name)
if  name == "en0" {
// Convert interface address to a human readable string:
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
getnameinfo(interface.ifa_addr, socklen_t(interface.ifa_addr.pointee.sa_len),
&hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST)
address = String(cString: hostname)
}
}
}
freeifaddrs(ifaddr)
return address
}

??网络IP地址??

**编辑**如果我调用ifa_netmask,它将返回网络掩码,对于192.168.4.2/24 IP ,它为255.255.255.0

您似乎在寻找外部IP,而本地IP是192.168.4.1。如果没有一些外部服务的帮助,这是不可能的。。。

更新有关详细信息,请参阅rfc1533 rfc2131,请在游乐场中尝试:-(

import Foundation
func pack<T:FixedWidthInteger>(_ fi: T)->Data {
var nfi = fi
if 1 == 1.littleEndian {
nfi = fi.bigEndian
}
return withUnsafeBytes(of: nfi) { un -> Data in
var data = Data()
un.forEach({ (byte) in
data.append(byte)
})
return data
}
}
enum StringPack {
case ipv4, ipv6, mac
}
func pack(_ txt: String, type: StringPack)->Data {
var data = Data()
switch type {
case .ipv4:
txt.split(separator: ".", omittingEmptySubsequences: false).forEach { s in
data.append(UInt8(s) ?? 0)
}
while data.count < 4 { // padding with 0
data.append(0)
}
case .ipv6:
txt.split(separator: ":", omittingEmptySubsequences: false).forEach { (s) in
data.append(pack(UInt16(s, radix: 16) ?? 0))
}
while data.count < 8 { // padding with 0
data.append(0)
}
case .mac:
txt.split(separator: ":", omittingEmptySubsequences: false).forEach { s in
s
UInt8(s, radix:16)
data.append(UInt8(s, radix:16) ?? 0)
}
while data.count < 16 { // padding with 0
data.append(0)
}
}
return data
}
func dhcp_packet(
// all parameters have default value (https://www.ietf.org/rfc/rfc2131.txt) for client using wifi interface
op: UInt8 = 1, htype: UInt8 = 1, hlen: UInt8 = 6, hops: UInt8 = 0,
xid: UInt32 = UInt32.random(in: UInt32.min...UInt32.max),
secs: UInt16 = 0, flags: UInt16 = 0,
ciaddr: String = "...",
yiaddr: String = "...",
siaddr: String = "...",
giaddr: String = "...",
chaddr: String = ":::::",
sname: String = "",
file: String = ""
)->Data {
// data represents dhcp_packet
var data = Data()
// sd tuple represents predefined fixed size data
var sd:(Data, Int)
data.append(op)
data.append(htype)
data.append(hlen)
data.append(hops)
data.append(pack(xid))
data.append(pack(secs))
data.append(pack(flags))
data.append(pack(ciaddr, type: .ipv4))
data.append(pack(yiaddr, type: .ipv4))
data.append(pack(siaddr, type: .ipv4))
data.append(pack(giaddr, type: .ipv4))
data.append(pack(chaddr, type: .mac))
sd = (Data(count: 64), min(sname.utf8.count, 64))
sd.0.replaceSubrange(0..<sd.1, with: Data(sname.utf8)[0..<sd.1])
data.append(sd.0)
sd = (Data(count: 128), min(file.utf8.count, 128))
sd.0.replaceSubrange(0..<sd.1, with: Data(sname.utf8)[0..<sd.1])
data.append(sd.0)
return data
}

import Darwin
func getWiFiAddress() -> (ip4: String, mac: String, addr: sockaddr_in) {
var address : String = "..."
var mac: String = ":::::"
var success: Bool
var addr_in = sockaddr_in()
var ifaddr : UnsafeMutablePointer<ifaddrs>?
success = getifaddrs(&ifaddr) == 0
assert(success)
assert(ifaddr != nil)
let firstAddr = ifaddr!
for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
let interface = ifptr.pointee
let addrFamily = interface.ifa_addr.pointee.sa_family
let name = String(cString: interface.ifa_name)
if  name == "en0" {
if addrFamily == UInt8(AF_INET) {
var addr = interface.ifa_addr.pointee
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
success = getnameinfo(&addr, socklen_t(interface.ifa_addr.pointee.sa_len),
&hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST) == 0
assert(success)
addr_in = withUnsafePointer(to: &addr) {
$0.withMemoryRebound(to: sockaddr_in.self, capacity: 1) {
$0.pointee
}
}
address = String(cString: hostname)
}
if addrFamily == UInt8(AF_LINK) {
interface.ifa_addr.withMemoryRebound(to: sockaddr_dl.self, capacity: 1) { (sdl) -> Void in
var hw = sdl.pointee.sdl_data
withUnsafeBytes(of: &hw, { (p) -> Void in
mac = p[Int(sdl.pointee.sdl_nlen)..<Int(sdl.pointee.sdl_alen + sdl.pointee.sdl_nlen)].map({ (u) -> String in
var s = String(u, radix:16)
if s.count < 2 {
s.append("0")
s = String(s.reversed())
}
return s
}).joined(separator: ":")
})
}
}
}
}
freeifaddrs(ifaddr)

return (address, mac, addr_in)
}
func sendBroadcast(data: Data, toPort: UInt16, waitForReplayOn: sockaddr_in)->Data {
var wifiInterface: UInt32
var fd: Int32
var success: Bool
var destAddr = sockaddr_in()
var response = Data()
wifiInterface = if_nametoindex("en0")
assert(wifiInterface != 0)
fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
assert(fd >= 0)
var kOne = 1
success = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &kOne, socklen_t(MemoryLayout.size(ofValue: kOne))) == 0
assert(success)
success = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &kOne, socklen_t(MemoryLayout.size(ofValue: kOne))) == 0
assert(success)
success = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &kOne, socklen_t(MemoryLayout.size(ofValue: kOne))) == 0
assert(success)
var wait = timeval(tv_sec: 0, tv_usec: 64000)
success = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &wait, socklen_t(MemoryLayout.size(ofValue: wait))) == 0
assert(success)
success = setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &wifiInterface, socklen_t(MemoryLayout.size(ofValue: wifiInterface))) == 0
assert(success)
var addr_in = waitForReplayOn
success = bindresvport(fd, &addr_in) == 0
assert(success)
destAddr.sin_family = sa_family_t(AF_INET)
destAddr.sin_len = __uint8_t(MemoryLayout.size(ofValue: destAddr))
destAddr.sin_addr.s_addr = INADDR_BROADCAST
destAddr.sin_port = in_port_t(toPort.bigEndian)
let bytesSent = data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Int in
let destAddrSize = socklen_t(MemoryLayout.size(ofValue: destAddr))
return withUnsafePointer(to: &destAddr) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
sendto(fd, bytes, data.count, 0, $0, destAddrSize)
}
}
}
if (bytesSent >= 0) {
print("DHCP packet with (bytesSent) bytes broadcasted to UDP port (toPort)")
var receiveBuffer = [UInt8](repeating: 0, count: 1024)
let bytes = recv(fd, &receiveBuffer, receiveBuffer.count, 0)
response.append(contentsOf: receiveBuffer[0..<bytes])
} else {
print("error", errno)
}
success = close(fd) == 0
assert(success)
return response
}

var en0info = getWiFiAddress()
var packet = dhcp_packet(/*ciaddr: en0info.ip4,*/ chaddr: en0info.mac)
let dhcp_MAGIC_COOKIE: [UInt8] = [0x63, 0x82, 0x53, 0x63]
// DHCP_OPTIONS  [code, length, value]
let dhcp_DHCPINFORM : [UInt8] = [53, 1, 8]
// we request router(s) address (it is standart report, but ... :-)
// see https://www.ietf.org/rfc/rfc1533.txt
let dhcp_PARAMETER_REQUEST_LIST: [UInt8] = [55, 1, 3]
let dhcp_OPTIONS_END: UInt8 = 0xFF
packet.append(contentsOf: dhcp_MAGIC_COOKIE)
packet.append(contentsOf: dhcp_DHCPINFORM)
packet.append(contentsOf: dhcp_PARAMETER_REQUEST_LIST)
packet.append(dhcp_OPTIONS_END)
en0info.addr.sin_len = __uint8_t(MemoryLayout.size(ofValue: sockaddr_in()))
en0info.addr.sin_port = in_port_t(UInt16(68).bigEndian)
en0info.addr.sin_addr.s_addr = INADDR_ANY
var success = false
var attempt = 5
var response = Data()
repeat {
response = sendBroadcast(data: packet, toPort: 67, waitForReplayOn: en0info.addr)
// if succes is false, response is not for us, or invalid
success = response[1..<240] == packet[1..<240]
attempt -= 1
} while success == false && attempt > 0
if success == true {
success = false
var index = 240
let maxIndex = response.count
var option = (code: UInt8, length: UInt8, value: [UInt8])(0,0,[])
var options = [UInt8: [UInt8]]()
repeat {
option.code = response[index]
index += 1
if option.code == 0 {
continue
}
if option.code == 255 {
success = true
break
}
option.length = response[index]
index += 1
let nexti = index + Int(option.length)
if nexti <= maxIndex {
option.value = Array(response[index..<nexti])
options[option.code] = option.value
}
index = nexti
} while index < maxIndex
print(options, success ? "OK" : "incoplete")
} else {
print("DHCPINFORM failed")
}

在我的环境中,它打印

DHCP packet with 244 bytes broadcasted to UDP port 67
[3: [192, 168, 8, 1], 6: [192, 168, 8, 1, 192, 168, 8, 1], 53: [5], 54: [192, 168, 8, 1], 1: [255, 255, 255, 0]]

其中:

选项3表示路由器列表

选项6表示DNS服务器的列表

选项53表示DHCP消息类型DHCPACK

选项54表示DHCP服务器标识符(该特定响应来自哪里(

选项1表示子网掩码

最新更新