Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get Ip address in swift

How do i get my local IpAddress?

I tried to use this Obj C example: how to get ip address of iphone programmatically

When i get to the function getifaddrs() i can't get any further. i can't use the function.

Is there an alternative way to do this, or am I approaching this the wrong way?

like image 409
Mads Gadeberg Avatar asked Sep 02 '14 14:09

Mads Gadeberg


People also ask

How do I find my IP address in Swift?

Swift 4 - Get device's IP Address:h> in your bridging header. This is the framework needed to get IP address. Getting a "Non-optional expression of type 'String' used in a check for optionals" warning.

How do I find the IP address of my iOS device?

Find your IP address on an iOS deviceOn the Home screen, tap Settings. Tap Wi-Fi. Tap the information icon (blue i, in a circle) to the right of the network name (eduroam). Tap DHCP and the IP Address will be listed as the first line item below the heading.

Can app developers see your IP address?

Your IP is public, so unless you use a Proxy server anyone can see it. It indeed entirely depends on the app developer.

Can apps access IP?

The websites you visit, apps you use, and even your ISP collect your IP address along with other personal information. However, individual users can also easily trace your IP address.


2 Answers

As it turned out in the discussion, OP needs the interface address on a Mac and not on an iOS device as I thought initially. The code referenced in the question checks for the interface name "en0", which is the WiFi interface on the iPhone. On a Mac it makes more sense to check for any "up-and-running" interface instead. Therefore I have rewritten the answer. It is now a Swift translation of the code in Detect any connected network.


getifaddrs() is defined in <ifaddrs.h>, which is not included by default. Therefore you have to create a bridging header and add

#include <ifaddrs.h> 

The following function returns an array with the names of all local "up-and-running" network interfaces.

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 ...         var ptr = ifaddr         while ptr != nil {             defer { ptr = ptr.memory.ifa_next }               let flags = Int32(ptr.memory.ifa_flags)             let 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(ptr.memory.ifa_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 } 

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:

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 } 
like image 69
Martin R Avatar answered Sep 23 '22 10:09

Martin R


Answering to Is there an alternative way to getifaddrs() for getting the ip-address?

Yes, there is an alternative way. You can also get the ip address by utilizing ioctl(). The cleanest way would be doing it in C and then wrapping it up in Swift. So consider this:

Create a C Source File (Xcode should create it together with a .h) and remember adding the header into your project's bridging header, or into umbrella-header if you have a cocoa touch framework.

Add the following into your .c source and method's declaration into .h:

#include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <netinet/in.h> #include <net/if.h>  int _interfaceAddressForName(char* interfaceName, struct sockaddr* interfaceAddress) {      struct ifreq ifr;     int fd = socket(AF_INET, SOCK_DGRAM, 0);     ifr.ifr_addr.sa_family = AF_INET;      strncpy(ifr.ifr_name, interfaceName, IFNAMSIZ-1);      int ioctl_res;     if ( (ioctl_res = ioctl(fd, SIOCGIFADDR, &ifr)) < 0){         return ioctl_res;     }      close(fd);     memcpy(interfaceAddress, &ifr.ifr_addr, sizeof(struct sockaddr));     return 0; } 

Your Swift wrapper might look something like:

public enum Error:ErrorType {     case IOCTLFailed(Int32)     case StringIsNotAnASCIIString }  public func interfaceAddress(forInterfaceWithName interfaceName: String) throws -> sockaddr_in {      guard let cString = interfaceName.cStringUsingEncoding(NSASCIIStringEncoding) else {         throw Error.StringIsNotAnASCIIString     }      let addressPtr = UnsafeMutablePointer<sockaddr>.alloc(1)     let ioctl_res = _interfaceAddressForName(strdup(cString), addressPtr)     let address = addressPtr.move()     addressPtr.dealloc(1)      if ioctl_res < 0 {         throw Error.IOCTLFailed(errno)     } else {         return unsafeBitCast(address, sockaddr_in.self)     } } 

Then you can use it in your code like:

let interfaceName = "en0" do {     let wlanInterfaceAddress = try interfaceAddress(forInterfaceWithName: interfaceName)     print(String.fromCString(inet_ntoa(wlanInterfaceAddress.sin_addr))!) } catch {     if case Error.IOCTLFailed(let errno) = error where errno == ENXIO {         print("interface(\(interfaceName)) is not available")     } else {         print(error)     } } 

en0 typically is the interface you need, which stands for WLAN

If you also need to know available interface names you can utilize if_indextoname():

public func interfaceNames() -> [String] {      let MAX_INTERFACES = 128;      var interfaceNames = [String]()     let interfaceNamePtr = UnsafeMutablePointer<Int8>.alloc(Int(IF_NAMESIZE))     for interfaceIndex in 1...MAX_INTERFACES {         if (if_indextoname(UInt32(interfaceIndex), interfaceNamePtr) != nil){             if let interfaceName = String.fromCString(interfaceNamePtr) {                 interfaceNames.append(interfaceName)             }         } else {             break         }     }      interfaceNamePtr.dealloc(Int(IF_NAMESIZE))     return interfaceNames } 
like image 23
ambientlight Avatar answered Sep 21 '22 10:09

ambientlight