Swift - Get device's WIFI IP Address
According to several SO threads (e.g. What exactly means iOS networking interface name? what's pdp_ip ? what's ap?), the WiFi interface on an iOS device always has then name "en0".
Your code (which seems to be what I answered at How to get Ip address in swift :) retrieves a list of the IP addresses of all running network interfaces. It can easily be modified to return only the IP address
of the "en0" interface, and actually that is what I originally had
answered at that thread (and this is just a Swift translation of the
answer to how to get ip address of iphone programmatically):
// Return IP address of WiFi interface (en0) as a String, or `nil`
func getWiFiAddress() -> String? {
var address : String?
// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs> = nil
if getifaddrs(&ifaddr) == 0 {
// For each interface ...
var ptr = ifaddr
while ptr != nil {
defer { ptr = ptr.memory.ifa_next }
let interface = ptr.memory
// Check for IPv4 or IPv6 interface:
let addrFamily = interface.ifa_addr.memory.sa_family
if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {
// Check interface name:
if let name = String.fromCString(interface.ifa_name) where name == "en0" {
// Convert interface address to a human readable string:
var hostname = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
getnameinfo(interface.ifa_addr, socklen_t(interface.ifa_addr.memory.sa_len),
&hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST)
address = String.fromCString(hostname)
}
}
}
freeifaddrs(ifaddr)
}
return address
}
Usage:
if let addr = getWiFiAddress() {
print(addr)
} else {
print("No WiFi address")
}
Update for Swift 3: In addition to adopting the code to the
many changes in Swift 3,
iterating over all interfaces can now use the new generalizedsequence()
function:
Do NOT forget to add #include <ifaddrs.h>
in your bridging header
// Return IP address of WiFi interface (en0) as a String, or `nil`
func getWiFiAddress() -> 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
}
For those of you who came looking for more than the WIFI IP you could modify this code a little
func getAddress(for network: Network) -> 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 == network.rawValue {
// 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
}
enum Network: String {
case wifi = "en0"
case cellular = "pdp_ip0"
//... case ipv4 = "ipv4"
//... case ipv6 = "ipv6"
}
Then we have access to the cellular IP as well.
guard let wifiIp = getAddress(for: .wifi) else { return }
&
guard let cellularIp = getAddress(for: .cellular) else { return }
Get IPAddress of iPhone or iPad device Using Swift 3
Add #include<ifaddrs.h>
in your bridging header.
This is the framework needed to get IP address.
Also you can refer the following link:
Swift - Get device's IP Address
Get Network (Not device) IP address iOS swift
It seems that you are looking for your external IP, while your local IP is 192.168.4.1. Without the help of some external service, it is impossible ...
UPDATE
see rfc1533 rfc2131 for details, try in 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
option 6 represents a list of DNS servers
option 53 means DHCP Message Type DHCPACK
option 54 means DHCP Server Identifier (where is this particular response from)
option 1 represents Subnet Mask
Related Topics
Redirect to Application If Installed, Otherwise to App Store
How to Get Height of Uitableview When Cells Are Dynamically Sized
Create Tap-Able "Links" in the Nsattributedstring of a Uilabel
Presenting Modal in iOS 13 Fullscreen
Detecting Which Uibutton Was Pressed in a Uitableview
Create Singleton Using Gcd'S Dispatch_Once in Objective-C
Assertion Failure in Dequeuereusablecellwithidentifier:Forindexpath:
Getting a Screenshot of a Uiscrollview, Including Offscreen Parts
The Best Way to Remove Duplicate Values from Nsmutablearray in Objective-C
How to Use Userdefaults in Swift
How to Save Picture to Iphone Photo Library
Iphone Keyboard Covers Uitextfield
Openurl Not Work in Action Extension
Xcode Error "Could Not Find Developer Disk Image"
Request Failed: Unacceptable Content-Type: Text/Html Using Afnetworking 2.0
Uiimageview - How to Get the File Name of the Image Assigned