I need to get IP Address of iOS device in Swift. This is not a duplicate of other questions about this! I need to get only WiFi IP address, if there is no wifi ip address - I need to handle it. There are a few questions about it on Stack Overflow, but there are only functions that return ip addresses. For example (from How to get Ip address in swift):
func getIFAddresses() -> [String] {
var addresses = [String]()
// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs> = nil
if getifaddrs(&ifaddr) == 0 {
// For each interface ...
for (var ptr = ifaddr; ptr != nil; ptr = ptr.memory.ifa_next) {
let flags = Int32(ptr.memory.ifa_flags)
var addr = ptr.memory.ifa_addr.memory
// Check for running IPv4, IPv6 interfaces. Skip the loopback interface.
if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) {
if addr.sa_family == UInt8(AF_INET) || addr.sa_family == UInt8(AF_INET6) {
// Convert interface address to a human readable string:
var hostname = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
if (getnameinfo(&addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST) == 0) {
if let address = String.fromCString(hostname) {
addresses.append(address)
}
}
}
}
}
freeifaddrs(ifaddr)
}
return addresses
}
Here I get 2 values - address from mobile internet(I think) and WiFi address I need. Is there any other way to get ONLY 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 generalized
sequence() 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 }
To get IPAddress for wifi , wired, and cellular - swift 5
func getIPAddress() -> String {
var address: String?
var ifaddr: UnsafeMutablePointer<ifaddrs>? = nil
if getifaddrs(&ifaddr) == 0 {
var ptr = ifaddr
while ptr != nil {
defer { ptr = ptr?.pointee.ifa_next }
guard let interface = ptr?.pointee else { return "" }
let addrFamily = interface.ifa_addr.pointee.sa_family
if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {
// wifi = ["en0"]
// wired = ["en2", "en3", "en4"]
// cellular = ["pdp_ip0","pdp_ip1","pdp_ip2","pdp_ip3"]
let name: String = String(cString: (interface.ifa_name))
if name == "en0" || name == "en2" || name == "en3" || name == "en4" || name == "pdp_ip0" || name == "pdp_ip1" || name == "pdp_ip2" || name == "pdp_ip3" {
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 ?? ""
}
How to use
let strIPAddress : String = self.getIPAddress()
print("IPAddress :: \(strIPAddress)")
Note : Add this below in your project's Bridging-Header file
#include<ifaddrs.h>
Create bridging header and Include #include <ifaddrs.h> in it.
then write this method
func getIFAddresses() -> [String] {
var addresses = [String]()
// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs> = nil
if getifaddrs(&ifaddr) == 0 {
// For each interface ...
for (var ptr = ifaddr; ptr != nil; ptr = ptr.memory.ifa_next) {
let flags = Int32(ptr.memory.ifa_flags)
var addr = ptr.memory.ifa_addr.memory
// Check for running IPv4, IPv6 interfaces. Skip the loopback interface.
if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) {
if addr.sa_family == UInt8(AF_INET) || addr.sa_family == UInt8(AF_INET6) {
// Convert interface address to a human readable string:
var hostname = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
if (getnameinfo(&addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST) == 0) {
if let address = String.fromCString(hostname) {
addresses.append(address)
}
}
}
}
}
freeifaddrs(ifaddr)
}
return addresses
}
when I call this method in my viewController like var arr : NSArray = self.getIFAddresses() I get perfect response in my console like
IP :(
"10.0.0.94"
)
from this array you can access it where ever u want.
Hope it helps
Swift 4.2 UIDevice extension that avoids force unwraps and supports cellular and wired ip addresses:
import UIKit
extension UIDevice {
private struct InterfaceNames {
static let wifi = ["en0"]
static let wired = ["en2", "en3", "en4"]
static let cellular = ["pdp_ip0","pdp_ip1","pdp_ip2","pdp_ip3"]
static let supported = wifi + wired + cellular
}
func ipAddress() -> String? {
var ipAddress: String?
var ifaddr: UnsafeMutablePointer<ifaddrs>?
if getifaddrs(&ifaddr) == 0 {
var pointer = ifaddr
while pointer != nil {
defer { pointer = pointer?.pointee.ifa_next }
guard
let interface = pointer?.pointee,
interface.ifa_addr.pointee.sa_family == UInt8(AF_INET) || interface.ifa_addr.pointee.sa_family == UInt8(AF_INET6),
let interfaceName = interface.ifa_name,
let interfaceNameFormatted = String(cString: interfaceName, encoding: .utf8),
InterfaceNames.supported.contains(interfaceNameFormatted)
else { continue }
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)
guard
let formattedIpAddress = String(cString: hostname, encoding: .utf8),
!formattedIpAddress.isEmpty
else { continue }
ipAddress = formattedIpAddress
break
}
freeifaddrs(ifaddr)
}
return ipAddress
}
}
Usage:
UIDevice.current.ipAddress()
Swift 4 - Get device's IP Address:
Add #include<ifaddrs.h> in your bridging header.
This is the framework needed to get IP address.
class func getIPAddress() -> String? {
var address: String?
var ifaddr: UnsafeMutablePointer<ifaddrs>? = nil
if getifaddrs(&ifaddr) == 0 {
var ptr = ifaddr
while ptr != nil {
defer { ptr = ptr?.pointee.ifa_next }
let interface = ptr?.pointee
let addrFamily = interface?.ifa_addr.pointee.sa_family
if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {
if let name: String = String(cString: (interface?.ifa_name)!), name == "en0" {
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
}
Another solution thats a bit of a different approach is using Ipify, which is a free lightweight service that you can ping to get your IP
Heres their Swift example:
let url = URL(string: "https://api.ipify.org")
do {
if let url = url {
let ipAddress = try String(contentsOf: url)
print("My public IP address is: " + ipAddress)
}
} catch let error {
print(error)
}
You can fetch IP address using the code below:
Note : I've used reachability so that it captures new IP address in case WiFi is changed to another.
In Podfile file
pod 'ReachabilitySwift' and then install pod
In AppDelegate.swift file import ReachabilitySwift
Note : If it prompts an error that Could not find ReachabilitySwift module then simply copy and paste this. It works!
didFinishLaunchingOptions function
NotificationCenter.default.addObserver(self, selector: #selector(self.reachabilityChanged), name: ReachabilityChangedNotification, object: reachability)
do{
try reachability.startNotifier()
}
catch {
print("could not start reachability notifier")
}
Then copy paste below code in AppDelegate file
func reachabilityChanged(note: NSNotification) {
let reachability = note.object as! Reachability
if reachability.isReachable {
if reachability.isReachableViaWiFi {
print("Reachable via WiFi")
} else {
print("Reachable via Cellular")
}
setIPAddress()
} else {
ipAddress = "" // No IP captures
print("Network not reachable")
}
}
func setIPAddress() {
if let addr = self.getWiFiAddress() {
print("ipAddress : \(addr)")
ipAddress = addr
} else {
ipAddress = "" // No IP captures
print("No WiFi address")
}
}
// 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 addr = interface.ifa_addr.pointee
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
getnameinfo(&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
}
Add this in Bridging-Header file #include<ifaddrs.h>
In case you don't have this file then you can create it Check this link
6.
func applicationWillEnterForeground(_ application: UIApplication) {
// Post notification
NotificationCenter.default.post(name: ReachabilityChangedNotification, object: reachability)
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
If you want to remove observer, then:
reachability.stopNotifier()
NSNotificationCenter.defaultCenter().removeObserver(self,name: ReachabilityChangedNotification,object: reachability)
Swift 5 Cleanup
I updated an answer above to eliminate any force unwrapping and some SwiftLint cleanup.
class func getIPAddress() -> String? {
var address: String?
var ifaddr: UnsafeMutablePointer<ifaddrs>?
if getifaddrs(&ifaddr) == 0 {
var ptr = ifaddr
while ptr != nil {
defer { ptr = ptr?.pointee.ifa_next }
let interface = ptr?.pointee
let addrFamily = interface?.ifa_addr.pointee.sa_family
if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6),
let cString = interface?.ifa_name,
String(cString: cString) == "en0",
let saLen = (interface?.ifa_addr.pointee.sa_len) {
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
let ifaAddr = interface?.ifa_addr
getnameinfo(ifaAddr,
socklen_t(saLen),
&hostname,
socklen_t(hostname.count),
nil,
socklen_t(0),
NI_NUMERICHOST)
address = String(cString: hostname)
}
}
freeifaddrs(ifaddr)
}
return address
}
An extension for NWInterface.InterfaceType based on some of the above answers:
import Network
extension NWInterface.InterfaceType {
var names : [String]? {
switch self {
case .wifi: return ["en0"]
case .wiredEthernet: return ["en2", "en3", "en4"]
case .cellular: return ["pdp_ip0","pdp_ip1","pdp_ip2","pdp_ip3"]
default: return nil
}
}
func address(family: Int32) -> String?
{
guard let names = names else { return nil }
var address : String?
for name in names {
guard let nameAddress = self.address(family: family, name: name) else { continue }
address = nameAddress
break
}
return address
}
func address(family: Int32, name: String) -> String? {
var address: String?
// Get list of all interfaces on the local machine:
var ifaddr: UnsafeMutablePointer<ifaddrs>?
guard getifaddrs(&ifaddr) == 0, let firstAddr = ifaddr else { return nil }
// For each interface ...
for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
let interface = ifptr.pointee
let addrFamily = interface.ifa_addr.pointee.sa_family
if addrFamily == UInt8(family)
{
// Check interface name:
if name == String(cString: interface.ifa_name) {
// 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
}
var ipv4 : String? { self.address(family: AF_INET) }
var ipv6 : String? { self.address(family: AF_INET6) }
}
Usage:
For ipv4 of cellular: NWInterface.InterfaceType.cellular.ipv4
func getIPAddress() -> String {
var address: String = "error"
var interfaces: ifaddrs? = nil
var temp_addr: ifaddrs? = nil
var success: Int = 0
// retrieve the current interfaces - returns 0 on success
success = getifaddrs(interfaces)
if success == 0 {
// Loop through linked list of interfaces
temp_addr = interfaces
while temp_addr != nil {
if temp_addr?.ifa_addr?.sa_family == AF_INET {
// Check if interface is en0 which is the wifi connection on the iPhone
if (String(utf8String: temp_addr?.ifa_name) == "en0") {
// Get NSString from C String
address = String(utf8String: inet_ntoa((temp_addr?.ifa_addr as? sockaddr_in)?.sin_addr))
}
}
temp_addr = temp_addr?.ifa_next
}
}
// Free memory
freeifaddrs(interfaces)
return address
}
All the answers here gives only ip address for wifi and not wired or cellular. Following snippet can be used for wifi/wired/cellular case:
func getIPAddressForCellOrWireless()-> String? {
let WIFI_IF : [String] = ["en0"]
let KNOWN_WIRED_IFS : [String] = ["en2", "en3", "en4"]
let KNOWN_CELL_IFS : [String] = ["pdp_ip0","pdp_ip1","pdp_ip2","pdp_ip3"]
var addresses : [String : String] = ["wireless":"",
"wired":"",
"cell":""]
var address: String?
var ifaddr: UnsafeMutablePointer<ifaddrs>? = nil
if getifaddrs(&ifaddr) == 0 {
var ptr = ifaddr
while ptr != nil {
defer { ptr = ptr?.pointee.ifa_next } // memory has been renamed to pointee in swift 3 so changed memory to pointee
let interface = ptr?.pointee
let addrFamily = interface?.ifa_addr.pointee.sa_family
if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {
if let name: String = String(cString: (interface?.ifa_name)!), (WIFI_IF.contains(name) || KNOWN_WIRED_IFS.contains(name) || KNOWN_CELL_IFS.contains(name)) {
// String.fromCString() is deprecated in Swift 3. So use the following code inorder to get the exact IP Address.
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)
if WIFI_IF.contains(name){
addresses["wireless"] = address
}else if KNOWN_WIRED_IFS.contains(name){
addresses["wired"] = address
}else if KNOWN_CELL_IFS.contains(name){
addresses["cell"] = address
}
}
}
}
}
freeifaddrs(ifaddr)
var ipAddressString : String?
let wirelessString = addresses["wireless"]
let wiredString = addresses["wired"]
let cellString = addresses["cell"]
if let wirelessString = wirelessString, wirelessString.count > 0{
ipAddressString = wirelessString
}else if let wiredString = wiredString, wiredString.count > 0{
ipAddressString = wiredString
}else if let cellString = cellString, cellString.count > 0{
ipAddressString = cellString
}
return ipAddressString
}
This class monitors the device interfaces with NWPathMonitor. You can set an updatehandler that informs you about interface state changes. Choose if you want to track ipv4 or ipv6 and check for status.interfaceType == .wifi to see, if your active interface is wifi
Usage:
let monitor = IPMonitor(ipType: .ipv4)
monitor.pathUpdateHandler = { status in
print("\(status.debugDescription)")
}
Class:
import Foundation
import Network
class IPMonitor {
enum InterfaceType: String {
case cellular = "cellular"
case wifi = "wifi"
case wired = "wired"
case loopback = "loopback"
case other = "other"
case notFound = "not found"
}
enum IPType: String {
case ipv4 = "IPv4"
case ipv6 = "ipV6"
case unknown = "unknown"
}
struct Status {
var name = "unknown"
var interfaceType: InterfaceType = InterfaceType.notFound
var ip: [String] = []
var ipType: IPType = IPType.unknown
var debugDescription: String {
let result = "Interface: \(name)/\(interfaceType.rawValue), \(ipType.rawValue)\(ip.debugDescription)"
return result
}
}
private let monitor = NWPathMonitor()
private let queue = DispatchQueue(label: "ip_monitor_queue")
final var pathUpdateHandler: ((Status) -> Void)?
init(ipType: IPType) {
monitor.pathUpdateHandler = { path in
let name = self.getInterfaceName(path: path)
let type = self.getInterfaceType(path: path)
let ip = self.getIPAddresses(interfaceName: name, ipType: ipType)
let status = Status(name: name, interfaceType: type, ip: ip, ipType: ipType)
//print("\(status)")
self.pathUpdateHandler?(status)
}
monitor.start(queue: queue)
}
private func getInterfaceName(path: NWPath) -> String {
if let name = path.availableInterfaces.first?.name {
return name
}
return "unknown"
}
private func getInterfaceType(path: NWPath) -> InterfaceType {
if let type = path.availableInterfaces.first?.type {
switch type {
case NWInterface.InterfaceType.cellular:
return InterfaceType.cellular
case NWInterface.InterfaceType.wifi:
return InterfaceType.wifi
case NWInterface.InterfaceType.wiredEthernet:
return InterfaceType.wired
case NWInterface.InterfaceType.loopback:
return InterfaceType.loopback
default:
return InterfaceType.other
}
}
return InterfaceType.notFound
}
private func getIPAddresses(interfaceName: String, ipType: IPType)-> [String]{
var addresses: [String] = []
var ifaddr: UnsafeMutablePointer<ifaddrs>? = nil
if getifaddrs(&ifaddr) == 0 {
var ptr = ifaddr
while ptr != nil {
defer { ptr = ptr?.pointee.ifa_next }
let interface = ptr?.pointee
let addrFamily = interface?.ifa_addr.pointee.sa_family
if (addrFamily == UInt8(AF_INET) && ipType == .ipv4)
|| (addrFamily == UInt8(AF_INET6) && ipType == .ipv6) {
let name = String(cString: (interface?.ifa_name)!)
if name == interfaceName {
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)
addresses.append(String(cString: hostname))
}
}
}
}
freeifaddrs(ifaddr)
return addresses
}
}
If you want only IPv4 response as output just modify the solution by Martin R.
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) { // **ipv6 committed
if addrFamily == UInt8(AF_INET){
// 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
}
Usage:
if let addr = getWiFiAddress() {
print(addr)
} else {
print("No WiFi address")
}
SUPPORT FOR IPV4 & IPV6
Make it an extension of UIDevice and call using UIDevice.current.getIPAdress()
private struct Interfaces {
// INTERFACCIE SUPPORT
static let wifi = ["en0"]
static let cellular = ["pdp_ip0","pdp_ip1","pdp_ip2","pdp_ip3"]
static let supported = wifi + cellular
}
func getIPAdress() -> (String?,String?)? {
var ip4Adress: String?
var ip6Adress: String?
var hasAdress: UnsafeMutablePointer<ifaddrs>?
if getifaddrs(&hasAdress) == 0 {
var pointer = hasAdress
while pointer != nil {
defer { pointer = pointer?.pointee.ifa_next}
guard let interface = pointer?.pointee else {continue}
// SEARCH FOR IPV4 OR IPV6 IN THE INTERFACE OF THE NODE
// HERE I'M ALREADY LOOSING MY MIND
// PRIORITY FOR IPV4 THAN IPV6
if interface.ifa_addr.pointee.sa_family == UInt8(AF_INET) {
guard let ip4 = processInterface(interface: interface) else {
continue
}
ip4Adress = ip4
}
if interface.ifa_addr.pointee.sa_family == UInt8(AF_INET6) {
guard let ip6 = processInterface(interface: interface) else {
continue
}
ip6Adress = ip6
}
}
freeifaddrs(hasAdress)
}
return (ip4Adress, ip6Adress)
}
func processInterface(interface: ifaddrs) -> String? {
var ipAdress: String = ""
guard
let interfaceName = interface.ifa_name else {return nil}
guard
let interfaceNameFormatted = String(cString: interfaceName, encoding: .utf8) else {return nil}
guard Interfaces.supported.contains(interfaceNameFormatted) else {return nil}
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
print(interfaceNameFormatted)
// CONVERT THE SOCKET ADRESS TO A CORRESPONDING HOST AND SERVICE
getnameinfo(interface.ifa_addr,
socklen_t(interface.ifa_addr.pointee.sa_len),
&hostname, socklen_t(hostname.count),
nil,
socklen_t(0),
NI_NUMERICHOST)
guard let formattedIpAdress = String(cString: hostname, encoding: .utf8) else {return nil}
if !formattedIpAdress.isEmpty {
ipAdress = formattedIpAdress
}
return ipAdress
}
enum Network: String {
case wifi = "en0"
case cellular = "pdp_ip0"
// case en1 = "en1"
// case lo = "lo0"
}
// get ipv4 or ipv6 address
extension UIDevice {
func address(family: Int32, for network: Network) -> String? {
var address: String?
// Get list of all interfaces on the local machine:
var ifaddr: UnsafeMutablePointer<ifaddrs>?
guard getifaddrs(&ifaddr) == 0, let firstAddr = ifaddr else { return nil }
// For each interface ...
for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
let interface = ifptr.pointee
let addrFamily = interface.ifa_addr.pointee.sa_family
if addrFamily == UInt8(family) {
// 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
}
func ipv4(for network: Network) -> String? {
self.address(family: AF_INET, for: network)
}
func ipv6(for network: Network) -> String? {
self.address(family: AF_INET6, for: network)
}
// get all addresses
func getIFAddresses() -> [String] {
var addresses = [String]()
// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs>?
guard getifaddrs(&ifaddr) == 0 else { return [] }
guard let firstAddr = ifaddr else { return [] }
// For each interface ...
for ptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
let flags = Int32(ptr.pointee.ifa_flags)
let addr = ptr.pointee.ifa_addr.pointee
// Check for running IPv4, IPv6 interfaces. Skip the loopback interface.
if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) {
if addr.sa_family == UInt8(AF_INET) || addr.sa_family == UInt8(AF_INET6) {
// Convert interface address to a human readable string:
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
if (getnameinfo(ptr.pointee.ifa_addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST) == 0) {
let address = String(cString: hostname)
addresses.append(address)
}
}
}
}
freeifaddrs(ifaddr)
return addresses
}
}
How to use
// for wifi
let wifi = UIDevice.current.ipv4(for: .wifi) # ipv4
let wifi6 = UIDevice.current.ipv6(for: .wifi) # ipv6
// for cellular
let cellular = UIDevice.current.ipv4(for: .cellular) # ipv4
let cellular6 = UIDevice.current.ipv6(for: .cellular) # ipv6
For Swift on Mac - Swift 4 :
This way you can also find out the ip from the Wifi (not only Ethernet)
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)
} else if name == "en1" {
// 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(1), NI_NUMERICHOST)
address = String(cString: hostname)
}
}
}
freeifaddrs(ifaddr)
return address
}
Given you already have the socket's file descriptor this is a solution for Swift 5.2.
// Depending on your case get the socket's file descriptor
// the way you want
let socketFd = foo()
// Get the remote address for that file descriptor
var addr: sockaddr_storage = sockaddr_storage()
var addr_len: socklen_t = socklen_t(MemoryLayout.size(ofValue: addr))
var hostBuffer = [CChar](repeating: 0, count: Int(NI_MAXHOST))
// Make local copy to avoid: "Overlapping accesses to 'addr',
// but modification requires exclusive access; consider copying
// to a local variable"
let addrLen = addr.ss_len
withUnsafeMutablePointer(to: &addr) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
if getpeername(socketFd, $0, &addr_len) != 0 { return }
getnameinfo($0, socklen_t(addrLen), &hostBuffer, socklen_t(hostBuffer.count), nil, 0, NI_NUMERICHOST)
}
}
let connectedHost = String(cString: hostBuffer, encoding: .utf8)
enum Network: String {
case wifi = "en0"
case cellular = "pdp_ip0"
case hotspot = "bridge100"
}
if use hotspot get ip
Related
I checked the below code to get ipv6 address and this code returned global unicast address like '2001:x:x...'.
But I want to get link local address like 'fe80:...'.
How can I get link local address by using the below code?
static var ipAddress: String? {
var ipv6 : String?
var ifaddr : UnsafeMutablePointer<ifaddrs>?
guard getifaddrs(&ifaddr) == 0 else { return (nil, nil) }
guard let firstAddr = ifaddr else { return (nil, nil) }
for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
let interface = ifptr.pointee
let addrFamily = interface.ifa_addr.pointee.sa_family
if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {
let name = String(cString: interface.ifa_name)
if name == "en0" {
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)
ipv6 = String(cString: hostname)
}
}
}
freeifaddrs(ifaddr)
return ipv6
}
The system include file netinet6/in6.h defines a macro
#define IN6_IS_ADDR_LINKLOCAL(a) \
(((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0x80))
That macro is not imported into Swift, but shows how we have to proceed.
The following modification of the loop (from Swift - Get device's WIFI IP Address) finds all IPv6 link-local addresses:
for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
let interface = ifptr.pointee
let addrFamily = interface.ifa_addr.pointee.sa_family
if addrFamily == UInt8(AF_INET6) {
// Get the sin6_addr part of the sockaddr as UInt8 "array":
let s6_addr = interface.ifa_addr.withMemoryRebound(to: sockaddr_in6.self, capacity: 1) {
$0.pointee.sin6_addr.__u6_addr.__u6_addr8
}
// Check for link-local address:
if s6_addr.0 == 0xfe && (s6_addr.1 & 0xc0) == 0x80 {
let name = String(cString: interface.ifa_name)
// ...
}
}
}
I am not able to get IP address using mobile data but if I use WiFi then it works fine.
My code:
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
}
The function always returns nil, if i print interface name there is no name "en0". i need to get the local ipaddress of the device, how can i do it??
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
}
You didn't set any value to ifaddr.
instead of en0 i changed it to en1 and it gets my local ip address....the reason is en0 is for wired or ethernet, for wireless we need to use en1.
You need to use
lo0
for local address
func getWiFiAddress() -> 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 == "lo0" {
// 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)
freeifaddrs(ifaddr)
return String(cString: hostname)
}
}
}
return nil
}
The IPv6 addresses returned in the code below don't match the IPv6 addresses found in Settings. The first half of the IP's matches, but the second half is always different. Is this expected? Am I doing something wrong in the code below?
IP address in Settings: "2601:483:4500:4d92:1cc9:84c9:7a3a:5101"
IP address in app: "2601:483:4500:4d92:f014:24c0:100::"
static 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 addr = interface.ifa_addr.pointee
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
getnameinfo(&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
}
Thanks in advance!
I'm migrating my Swift code from version 2 to 3 and there is this issue:
Argument labels '(count:, repeatedValue:)' do not match any available overloads
My code
static func getWiFiAddress() -> String? {
var address: String?
var ifaddr: UnsafeMutablePointer<ifaddrs>? = nil
if getifaddrs(&ifaddr) == 0 {
var ptr = ifaddr
while ptr != nil {
defer { ptr = ptr?.pointee.ifa_next }
let interface = ptr?.pointee
let addrFamily = interface?.ifa_addr.pointee.sa_family
if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {
let name = String(cString: (interface?.ifa_name)!)
var addr = interface?.ifa_addr.pointee
// issue while assigning to hostname variable
var hostname = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
getnameinfo(&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)
}
if address == nil {
address = ""
}
return address
}
In Swift 3 they changed the function for no good reason. You should have
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
Note that, not only are the arguments reversed but repeatedValue: -> repeating: