简体   繁体   English

获取网络(不是设备)的IP地址iOS Swift

[英]Get Network (Not device) IP address iOS swift

I have made some code for getting the Wi-Fi current SSID and device current IP but i need to get the Network IP Address so if my device's IP is 192.168.4.3 i Know it is connected to 192.168.4.1 Network but I need not to make this assumption in the code ... 我已经编写了一些代码来获取Wi-Fi当前的SSID和设备的当前IP,但是我需要获取网络IP地址,因此,如果我的设备的IP为192.168.4.3,我知道它已连接至192.168.4.1网络,但是我不需要在代码中做这个假设...

Get SSID: 获取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

} 

Get Device's IP 获取设备的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

}

¿¿Network IP address?? ??网络IP地址?

** Edit ** if I call ifa_netmask it returns the netmask which it 255.255.255.0 for a 192.168.4.2/24 IP **编辑**如果我调用ifa_netmask它将返回255.255.255.0的192.168.4.2/24 IP地址的网络掩码

It seems that you are looking for your external IP, while your local IP is 192.168.4.1. 似乎您在寻找外部IP,而本地IP为192.168.4.1。 Without the help of some external service, it is impossible ... 没有一些外部服务的帮助,这是不可能的...

UPDATE see rfc1533 rfc2131 for details, try in Playground :-) 更新请参见rfc1533 rfc2131了解详细信息,请在Playground中尝试:-)

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

On my environment it prints 在我的环境中打印

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]]

where: 哪里:

option 3 represents a list of the routers 选项3代表路由器列表

option 6 represents a list of DNS servers 选项6代表DNS服务器列表

option 53 means DHCP Message Type DHCPACK 选项53表示DHCP消息类型DHCPACK

option 54 means DHCP Server Identifier (where is this particular response from) 选项54表示DHCP服务器标识符(此特定响应来自何处)

option 1 represents Subnet Mask 选项1代表子网掩码

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM