127

I would like to obtain my iPad's IP address programmatically. How can I query the networking subsystem to find out what my IPv4 (and IPv6) addresses are?

PS: Can I disable IPv6 somehow?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Wilbur
  • 1,333
  • 3
  • 10
  • 5
  • 15
    In regards to your 'PS' above, please do not programmatically disable IPv6 on somebody's device. It's just plain rude. – Jeremy Visser Aug 16 '11 at 13:15
  • You can't disable IPv6. [It is mandatory.](https://developer.apple.com/library/mac/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html) In fact, your iOS app must support IPv6. – Michael Hampton Aug 24 '16 at 02:02

10 Answers10

134

The following code finds all IPv4 and IPv6 addresses on an iOS or OSX device. The first getIPAddress method acts more or less as the older code in this answer: you can prefer either one or the other type address, and it always prefers WIFI over cellular (obviously you could change this).

More interestingly it can return a dictionary of all addresses found, skipping addresses for not up interfaces, or addresses associated with loopback. The previous code as well as other solutions on this topic will not properly decode IPv6 (inet_ntoa cannot deal with them). This was pointed out to me by Jens Alfke on an Apple forum - the proper function to use is inet_ntop (look at the man page, and or refer to this inet_ntop article also provided by Jens.

The dictionary keys have the form "interface" "/" "ipv4 or ipv6".

#include <ifaddrs.h>
#include <arpa/inet.h>
#include <net/if.h>

#define IOS_CELLULAR    @"pdp_ip0"
#define IOS_WIFI        @"en0"
//#define IOS_VPN       @"utun0"
#define IP_ADDR_IPv4    @"ipv4"
#define IP_ADDR_IPv6    @"ipv6"

- (NSString *)getIPAddress:(BOOL)preferIPv4
{
    NSArray *searchArray = preferIPv4 ?
                            @[ /*IOS_VPN @"/" IP_ADDR_IPv4, IOS_VPN @"/" IP_ADDR_IPv6,*/ IOS_WIFI @"/" IP_ADDR_IPv4, IOS_WIFI @"/" IP_ADDR_IPv6, IOS_CELLULAR @"/" IP_ADDR_IPv4, IOS_CELLULAR @"/" IP_ADDR_IPv6 ] :
                            @[ /*IOS_VPN @"/" IP_ADDR_IPv6, IOS_VPN @"/" IP_ADDR_IPv4,*/ IOS_WIFI @"/" IP_ADDR_IPv6, IOS_WIFI @"/" IP_ADDR_IPv4, IOS_CELLULAR @"/" IP_ADDR_IPv6, IOS_CELLULAR @"/" IP_ADDR_IPv4 ] ;

    NSDictionary *addresses = [self getIPAddresses];
    NSLog(@"addresses: %@", addresses);

    __block NSString *address;
    [searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop)
        {
            address = addresses[key];
            if(address) *stop = YES;
        } ];
    return address ? address : @"0.0.0.0";
}

- (NSDictionary *)getIPAddresses
{
    NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:8];

    // retrieve the current interfaces - returns 0 on success
    struct ifaddrs *interfaces;
    if(!getifaddrs(&interfaces)) {
        // Loop through linked list of interfaces
        struct ifaddrs *interface;
        for(interface=interfaces; interface; interface=interface->ifa_next) {
            if(!(interface->ifa_flags & IFF_UP) /* || (interface->ifa_flags & IFF_LOOPBACK) */ ) {
                continue; // deeply nested code harder to read
            }
            const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr;
            char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ];
            if(addr && (addr->sin_family==AF_INET || addr->sin_family==AF_INET6)) {
                NSString *name = [NSString stringWithUTF8String:interface->ifa_name];
                NSString *type;
                if(addr->sin_family == AF_INET) {
                    if(inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN)) {
                        type = IP_ADDR_IPv4;
                    }
                } else {
                    const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)interface->ifa_addr;
                    if(inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, INET6_ADDRSTRLEN)) {
                        type = IP_ADDR_IPv6;
                    }
                }
                if(type) {
                    NSString *key = [NSString stringWithFormat:@"%@/%@", name, type];
                    addresses[key] = [NSString stringWithUTF8String:addrBuf];
                }
            }
        }
        // Free memory
        freeifaddrs(interfaces);
    }
    return [addresses count] ? addresses : nil;
}

EDIT1: Code updated on May 16, 2014 (bug pointed out by lhunath, see comments). Loopback addresses now returned, but its easy for you to uncomment the test to exclude them yourself.

EDIT2: (by some unknown person): Improved further March 13, 2015: In case the user uses a VPN (regardless over WiFi or Cellular), the previous code would have failed. Now, it works even with VPN connections. VPN connections are given precedence over WiFi and Cell because that's how the device handles it. This should even work for Macs as the VPN connection on a Mac is also using IF utun0 but not tested.

EDIT3: (9/8/2016) Given the problems experienced by @Qiulang (see comments) with the VPN code (which someone else added), I've commented it out. If anyone knows definitively how to specify a user VPN please chime in with a comment.

Community
  • 1
  • 1
David H
  • 40,852
  • 12
  • 92
  • 138
  • how often `addr` gets NULL? my users occasionally get NULL. do you know whats possible reasons? – HelmiB Nov 06 '12 at 02:43
  • I'm using only `AF_INET` to check. could be this? – HelmiB Nov 06 '12 at 02:57
  • 1
    I don't know, but it is for sure possible your users could be on an IPV6 network. – David H Nov 06 '12 at 14:38
  • 2
    This should be the "right" answer as it is complete with 3G. Thanks for the update. – palme Sep 20 '13 at 11:59
  • 1
    I don't think this works correctly with IPv6. The inet_ntoa function takes an IPv4 address, so in the case where sa_type == AF_INET6, you're taking the IPv6 address and type-casting it to IPv4 and turning that to a string (basically from the high 32 bits of the 128-bit address.) – Jens Alfke Oct 09 '13 at 21:16
  • In which scenario the function will return 0.0.0.0? – jailani Oct 22 '13 at 09:26
  • If you use getIPAddress, and there is no current IPv4 or IPv6 address for either WIFI or cellular, then it returns 0.0.0.0. Really, it could return nil, its just historically the routine posted here returned that value instead. – David H Oct 22 '13 at 11:54
  • This shows the address of the iPad in a local network. Any ideas on how we can retrieve the WAN address? – Anton Unt Nov 05 '13 at 14:10
  • Did you print out (i.e. NSLog) the whole dictionary? The "helper" method simply selects one of the addresses, and the algorithm may be flawed. Never tested it on an iPad. – David H Nov 05 '13 at 14:20
  • No need to use inet_ntop() and deal with IPv4 / IPv6, just use getnameinfo() which will do the right thing – Pol Mar 30 '14 at 02:29
  • note that for INET6, the address is in sin6_addr, which has a different length and is at a different offset in the struct than sin_addr. That makes the above code broken for IPv6. – lhunath May 08 '14 at 16:30
  • @lhunath, please look at revised code and let me know if you believe its now correct. Printing out all addresses before and after the change showed that the offsets are in fact different. – David H May 08 '14 at 20:00
  • @DavidH It looks fine now, but messy. I ended up reworking it using `getnameinfo` instead, see my answer on this question: http://stackoverflow.com/a/23568406/58803 – lhunath May 09 '14 at 15:27
  • Also note that you don't always have en0 on the simulator – Jakob C Sep 03 '14 at 14:11
  • My function getIPAddress does not get called, I am just checking if I get the IP so that I can use it in one of my apps. I am using a single view application and tried implementing it in both app delegate and viewcontroller file. Please help. – Som Apr 15 '15 at 07:24
  • @Som you make no sense. Your code needs to call this method at some point. Add some log messages. It's possible that getiffaddrs fails - if so log the error. – David H Apr 15 '15 at 11:47
  • @DavidH You could have rejected the edit. You can still roll it back if you want. – rmaddy Oct 30 '15 at 17:45
  • I'm only getting a local address (10.10.100.85) I need the remote – chiliNUT Mar 02 '16 at 16:30
  • @chiliNUT - right, this gives you your local address. So you need to do the equivalent of a traceroute I'll guess. Or, there are web sites that you can connect to that tell you your IP address - perhaps you can find one that offers this as a service, or you can web scrape. Please add a comment if you figure this out. – David H Mar 02 '16 at 17:56
  • The code works fine till I got this IP result: { "lo0/ipv4" = "127.0.0.1"; "lo0/ipv6" = "fe80::1"; "pdp_ip0/ipv4" = "10.132.76.168"; "utun0/ipv6" = "fe80::72c3:e25e:da85:b730"; }. Can't make my words clear with comments. I will add my answer later – Qiulang Sep 01 '16 at 14:03
  • @Qiulang Well I doubt I can clarify WHY you get these results - the code just retrieves the info that Apple provides. – David H Sep 01 '16 at 16:34
  • @David H I know and thanks for the answer. But check my updated answer. I really have to to drop vpn check for the time being :( – Qiulang Sep 02 '16 at 02:46
  • @Qiulang Interestingly enough, my original code did not have VPN. Someone edited the answer and just added it without even contacting me. I had left a warning about that for a long time - maybe 2 years - and no one ever complained about it so I took the warning out. If you do use a VPN then the check must look for it first. – David H Sep 02 '16 at 03:16
  • Yes I read you words carefully and I noticed you said someone added that. The interesting part is that the real vpn is utun1 NOT utun0. – Qiulang Sep 02 '16 at 03:19
  • Another problem I face right now is how to check whether I really have a vpn or not :( – Qiulang Sep 02 '16 at 03:46
  • I raised a bug to apple and got their response "Not all utun interfaces are for VPN. There are other OS features that use utun interfaces... Is this IPv6 address on utun0 causing some sort of problem?" – Qiulang Sep 09 '16 at 00:02
  • @Qiulang Any guidance on how to know which are doing what? – David H Sep 09 '16 at 18:19
  • The bug id is 28131847. But I was rather disappointed with their answer. I asked how to get a valid vpn ip address then. Out of my surprise they said "You can go into Settings -> VPN and look at your VPN configuration to see if the VPN is active. In some cases you can see the assigned IP address there as well. We are now closing this bug report." – Qiulang Sep 10 '16 at 00:07
  • @Qiulang Sigh. The new Apple... I liked them better when they thought MS was going to bury them... – David H Sep 10 '16 at 03:58
  • @DavidH I hit this problem again! I needed to further modify your code to make it work. Check my answer below. :( – Qiulang Nov 04 '16 at 03:02
  • @Qiulang Looking at your success example, it makes me believe a heuristic of finding "utun0/ipv6" along with "utun1/ipv4" might work - that is, a real VPN will offer both IPV4 and IPV6 access, and perhaps exactly the same interfaces as you found. Or perhaps look for all combinations of utun[01] with ipv[46]. – David H Nov 08 '16 at 14:17
  • See what I got today. I totally gave up getting a real VPN,{ ... "pdp_ip0/ipv4" = "10.49.90.182"; "utun0/ipv6" = "fe80::549:8b76:b0d0:92de"; "utun1/ipv6" = "fe80::9f7a:1a07:da28:5aa6"; "utun2/ipv6" = "fe80::d41b:2392:e936:335d"; "utun3/ipv6" = "fe80::f010:4d4f:753a:ed7f"; "utun4/ipv6" = "fe80::2b1b:bc3:2651:aec4"; "utun5/ipv6" = "fe80::6e18:d409:967:2a9b"; "utun6/ipv6" = "fe80::3936:4240:19d1:3e9f"; } – Qiulang Dec 09 '16 at 09:14
  • This will fail with the result of "awdl0/ip6" being added to the top of the address list, resulting in the first return value being an ipv6 address, not an ipv4. A better filter and search approach needs to be created between ipv6 and ipv4 addresses than the one in this approach which assumes a predictable return order of interfaces. The address list needs to be filtered into an ipv4 and an ipv6 array and the desired address picked from the appropriate filtered array. – Alex Zavatone Nov 04 '18 at 14:08
  • Is it possible to get the host IP address using this? The context is that my ios device is connected to a ad hoc network where its only the host and my ios device present, no other devices in the network. – AdeleGoldberg Mar 05 '20 at 13:34
89

In your implementation file .m ,

#import <ifaddrs.h>
#import <arpa/inet.h>



// Get IP Address
- (NSString *)getIPAddress {    
    NSString *address = @"error";
    struct ifaddrs *interfaces = NULL;
    struct ifaddrs *temp_addr = NULL;
    int success = 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 != NULL) {
            if(temp_addr->ifa_addr->sa_family == AF_INET) {
                // Check if interface is en0 which is the wifi connection on the iPhone
                if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) {
                    // Get NSString from C String
                    address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];               
                }
            }
            temp_addr = temp_addr->ifa_next;
        }
    }
    // Free memory
    freeifaddrs(interfaces);
    return address;

} 
Raptor
  • 53,206
  • 45
  • 230
  • 366
  • 1
    No en0 interface appears in the interfaces list, so just returns error. Not sure if something has changed but definitely not working for me on iOS 5.x – wuf810 Mar 25 '12 at 18:36
  • May I ask which device are you working on? The codes run well on iPhone 3GS , iPhone 4, iPad 2 with iOS5.0 to iOS5.1 . – Raptor Mar 26 '12 at 03:29
  • The above code only works for devices. Is it possible to extend it to the iPad simulator? – user1120008 Apr 16 '12 at 19:18
  • um... actually the IP of iOS Simulator is the same as your Mac. – Raptor Apr 17 '12 at 01:48
  • The above code returns "error" and not the IPAddress of my mac when I use it on the simulator. – user1120008 Apr 18 '12 at 00:33
  • I mean why do you want to know the IP in iOS Simulator? the IP is exactly the same with your Mac. Also, the codes return error as the network interface name of simulator is not `en0`. – Raptor Apr 18 '12 at 01:53
  • 11
    If you look below you will find some slightly modified code that returns the cell (3G) address if WIFI is off. – David H May 29 '12 at 17:03
  • 1
    The following code gives the IPv4 address of en0 only. What about IPv6? Can someone give a code sample on how to retrieve it? – Oded Regev Jun 27 '12 at 11:52
  • 2
    This one doesn't find ip address when device is not connected to wifi, but to cellluar network – Mapedd Jan 08 '14 at 16:13
  • Is there a way to find the external ip? – Bagusflyer Nov 07 '14 at 13:46
  • No. External IP is usually "NAT" by routers / switches. Your phone is rarely connecting to public IP directly. – Raptor Nov 10 '14 at 02:04
  • 1
    Modify the if condition below if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) To if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"] || [[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"pdp_ip0"]) to get the IP when device not connected to WIFI.. – Raju Feb 06 '15 at 12:33
  • 1
    @cirronimbo thanks for your comment. This answer is 5 years old, which probably does not work for IPv6. I will add IPv6 stuff if I have time. – Raptor Mar 22 '16 at 11:26
  • 1
    well, after some researches, Apple returns IPv6 address by `getaddrinfo()` since iOS 9.2 : https://forums.developer.apple.com/thread/29066 – Raptor Mar 22 '16 at 11:36
  • @Raptor Thanks for pointing that out! But AFAIK getaddrinfo() needs a hostname as an arguments for which it returns the address... But the use case we're talking here is when the method simply returns the IPv6 address of the iOS device. How can that be achieved through getaddrinfo() ? – cirronimbo Mar 22 '16 at 20:12
  • Is it possible to get the host IP address using this? The context is that my ios device is connected to a ad hoc network where its only the host and my ios device present, no other devices in the network. – AdeleGoldberg Mar 05 '20 at 13:33
4

Many existing solutions only consider wireless interfaces, which won't work for wired connections via an Ethernet adapter (ie. no Wifi or 3G); see this more recent solution which considers IP addresses obtained through wired interfaces as well.

iPad: How to get IP address programmatically WIRED (not via wireless)

Community
  • 1
  • 1
lundhjem
  • 608
  • 6
  • 12
  • Excellent! I'm going to add this to my code above soon. What is en1 - do you know? – David H Sep 02 '16 at 14:25
  • 1
    I don't, but I did notice it's not AF_INET family like the other en interfaces – lundhjem Oct 04 '16 at 18:56
  • 1
    @DavidH recently the ethernet IP has been showing up on en1 on certain iPads, so it appears that it is also a member of the AF_INET family in certain scenarios. You should check that interface as well. – lundhjem May 20 '19 at 20:54
3

Get IP address using Swift 3:

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
}
Pang
  • 9,564
  • 146
  • 81
  • 122
BHAVIK
  • 890
  • 7
  • 35
2

@DavidH's answer works fine till I got this result from some 4G cellular network:

{
    "lo0/ipv4" = "127.0.0.1";
    "lo0/ipv6" = "fe80::1";
    "pdp_ip0/ipv4" = "10.132.76.168";
    "utun0/ipv6" = "fe80::72c3:e25e:da85:b730";
}

I am not using vpn so I have no idea why I had a utun0/ipv6.

--- Updated ---

I further debug this issue and found that I can get an fake vpn address even in other 4G networks (is this iOS bug??),

{
    ""awdl0/ipv6"" = ""fe80::c018:9fff:feb2:988"";
    ""en0/ipv6"" = ""fe80::181a:2e43:f91b:db2b"";
    ""lo0/ipv4"" = ""127.0.0.1"";
    ""lo0/ipv6"" = ""fe80::1"";
    ""pdp_ip0/ipv4"" = ""10.48.10.210"";
    ""utun0/ipv4"" = ""192.168.99.2"";
}

If I did use vpn I will get this:

{
    "lo0/ipv4" = "127.0.0.1";
    "lo0/ipv6" = "fe80::1";
    "pdp_ip0/ipv4" = "10.49.187.23";
    "utun0/ipv6" = "fe80::5748:5b5d:2bf0:658d";
    "utun1/ipv4" = "192.168.99.2"; //the real one
}

So it is utun1 NOT utun0

Without figuring out why I will just have to drop vpn check :(

---- update ----

I raised a bug (28131847) to apple and replied with "Not all utun interfaces are for VPN. There are other OS features that use utun interfaces."

But when I asked how to get a valid vpn IP address then, their answer was rather disappointed, "You can go into Settings -> VPN and look at your VPN configuration to see if the VPN is active. In some cases you can see the assigned IP address there as well. We are now closing this bug report." :(

---- update 2016/11/04 ----

I hit the problem again and I need to further modify @DavidH's answer to fix it:

I was in 4G network and I got this address:

addresses: {
    "awdl0/ipv6" = "fe80::98fd:e6ff:fea9:3afd";
    "en0/ipv6" = "fe80::8dd:7d92:4159:170e";
    "lo0/ipv4" = "127.0.0.1";
    "lo0/ipv6" = "fe80::1";
    "pdp_ip0/ipv4" = "10.37.212.102";
    "utun0/ipv6" = "fe80::279c:ea56:a2ef:d128";
}

With his original answer I will get the wifi IP fe80::8dd:7d92:4159:170e, which was fake and connection failed.

So I modified the code to like,

[searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop)
 {
     if ((internetReach.isReachableViaWiFi && [key hasPrefix:IOS_WIFI]) ||
         (internetReach.isReachableViaWWAN && [key hasPrefix:IOS_CELLULAR])) {
         address = addresses[key];
         if(address) *stop = YES;
     }
 } ];
Qiulang
  • 10,295
  • 11
  • 80
  • 129
  • I posted on internal forums about the VPN problem, Apple engineer has offered to help. I need you to contact me offline dhoerl at mac dot com – David H Jun 29 '17 at 15:35
1

The current solution doesn't return the en0 device on OS X, the following code uses the System Configuration Framework to get the interfaces then uses standard C functions to get the IP address.

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <net/if.h>
#define IFT_ETHER 0x6

#include <SystemConfiguration/SCDynamicStore.h>

+(void)getInterfaces
{
    SCDynamicStoreRef storeRef = SCDynamicStoreCreate(NULL, (CFStringRef)@"FindCurrentInterfaceIpMac", NULL, NULL);
    CFPropertyListRef global = SCDynamicStoreCopyValue (storeRef,CFSTR("State:/Network/Interface"));
    id primaryInterface = [(__bridge NSDictionary *)global valueForKey:@"Interfaces"];

    for (NSString* item in primaryInterface)
    {
        if(get_iface_address([item UTF8String]))
        {
            NSString *ip = [NSString stringWithUTF8String:get_iface_address([item UTF8String])];
            NSLog(@"interface: %@ - %@",item,ip);
        } else
            NSLog(@"interface: %@",item);
    }
}

static char * get_iface_address (char *interface)
{
    int sock;
    uint32_t ip;
    struct ifreq ifr;
    char *val;

    if (!interface)
        return NULL;

    /* determine UDN according to MAC address */
    sock = socket (AF_INET, SOCK_STREAM, 0);
    if (sock < 0)
    {
        perror ("socket");
        return NULL;
    }

    strcpy (ifr.ifr_name, interface);
    ifr.ifr_addr.sa_family = AF_INET;

    if (ioctl (sock, SIOCGIFADDR, &ifr) < 0)
    {
        perror ("ioctl");
        close (sock);
        return NULL;
    }

    val = (char *) malloc (16 * sizeof (char));
    ip = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr;
    ip = ntohl (ip);
    sprintf (val, "%d.%d.%d.%d",
             (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF);

    close (sock);

    return val;
}
A.Badger
  • 4,279
  • 1
  • 26
  • 18
1

This answer was inspired by @DavidH's answer. I fixed some issues, replaced inet_ntop with getnameinfo which allows a cleaner approach. Note that this yields a dictionary that maps an interface name to an array of IP addresses (an interface can have multiple IPv4 and IPv6's associated with it, technically). It does not distinguish between IPv4 and IPv6:

  // Get all our interface addresses.
  struct ifaddrs *ifAddresses;
  if (getifaddrs( &ifAddresses ) != 0) {
    NSLog( @"Couldn't get interface addresses: %d", errno );
    return nil;
  }

  int error;
  char host[MAX( INET_ADDRSTRLEN, INET6_ADDRSTRLEN )];
  _ipAddressesByInterface = [NSMutableDictionary dictionaryWithCapacity:8];

  for (struct ifaddrs *ifAddress = ifAddresses; ifAddress; ifAddress = ifAddress->ifa_next) {
    if (!(ifAddress->ifa_flags & IFF_UP) || (ifAddress->ifa_flags & IFF_LOOPBACK))
      // Ignore interfaces that aren't up and loopback interfaces.
      continue;

    if (ifAddress->ifa_addr->sa_family != AF_INET && ifAddress->ifa_addr->sa_family != AF_INET6)
      // Ignore non-internet addresses.
      continue;

    if ((error = getnameinfo( ifAddress->ifa_addr, ifAddress->ifa_addr->sa_len, host, sizeof( host ), NULL, 0, NI_NUMERICHOST )) != noErr) {
      // Couldn't to format host name for this address.
      NSLog( @"Couldn't resolve host name for address: %s", gai_strerror( error ) );
      continue;
    }

    NSString *ifName = [NSString stringWithCString:ifAddress->ifa_name encoding: NSUTF8StringEncoding];
    NSMutableArray *ifIpAddresses = _ipAddressesByInterface[ifName];
    if (!ifIpAddresses)
      ifIpAddresses = _ipAddressesByInterface[ifName] = [NSMutableArray arrayWithCapacity:2];
    [ifIpAddresses addObject:[NSString stringWithCString:host encoding: NSUTF8StringEncoding]];
  }

  freeifaddrs( ifAddresses );
  return _ipAddressesByInterface;
lhunath
  • 120,288
  • 16
  • 68
  • 77
  • I have never seen `strf` - is that a helper function you have in your code? – David H May 09 '14 at 15:36
  • Yeah, sorry, there are a few helpers in the above code. `err` and `strf`. You can just replace `strf` with `-stringWithCString:encoding:`. `err` is an `NSLog` wrapper that outputs the file & line as well. https://github.com/Lyndir/Pearl/blob/master/Pearl/PearlStringUtils.m#L20 – lhunath May 10 '14 at 18:10
1

Great solution for swift in This file which serves all the details.

In One of my app I need to fetch wifi IP address. I have used answers above, in swift 3 like this:

let WIFI_IF = "en0"
let UNKNOWN_IP_ADDRESS = ""
var addresses: [AnyHashable: Any] = ["wireless": UNKNOWN_IP_ADDRESS, "wired": UNKNOWN_IP_ADDRESS, "cell": UNKNOWN_IP_ADDRESS]
var interfaces: UnsafeMutablePointer<ifaddrs>? = nil
var temp_addr: UnsafeMutablePointer<ifaddrs>? = nil
var success: Int = 0
success = Int(getifaddrs(&interfaces))
if success == 0 {
   temp_addr = interfaces
   while temp_addr != nil {
      if temp_addr?.pointee.ifa_addr == nil {
           continue
      }
      if temp_addr?.pointee.ifa_addr.pointee.sa_family == UInt8(AF_INET) {
         if (String(utf8String: (temp_addr?.pointee.ifa_name)!) == WIFI_IF) {
             addresses["wireless"] = String(utf8String: inet_ntoa(((temp_addr?.pointee.ifa_addr as? sockaddr_in)?.sin_addr)!))
         }
      }
      temp_addr = temp_addr?.pointee.ifa_next
   }
}

In this code, It crashes because I have to check for nil in each statement I have used as optional with ?. So it is better for me to use given linked file in my class. It becomes easy for me to check now like:

class func getWifiIPAddress() -> String {
    var wifiIp = ""

    let WIFI_IF = "en0"
    let allInterface = Interface.allInterfaces()

    for interf in allInterface {
        if interf.name == WIFI_IF {
            if let address = interf.address {

                if address.contains(".") {
                wifiIp = address
                break
                }
            }
        }
    }

    return wifiIp
}

I have parsed string for "." because Interface Class returns two interface in my iPhone for en0 address like "fb00::" and address like "101.10.1.1"

Max
  • 2,269
  • 4
  • 24
  • 49
  • 1
    A link to a potential solution is always welcome, but please [add context around the link](//meta.stackoverflow.com/a/8259) so your fellow users will have some idea what it is and why it’s there. **Always quote the most relevant part of an important link, in case the target site is unreachable or goes permanently offline.** Take into account that being _barely more than a link to an external site_ is a possible reason as to [Why and how are some answers deleted?](//stackoverflow.com/help/deleted-answers). – Paul Roub Jun 24 '17 at 16:56
  • 1
    Ok will update accordingly as it how helpful for me for better understanding – Max Jun 24 '17 at 17:39
1

I created a simple file for getting the ip address. I based this solution on @ lundhjem's, @DavidH's and @Ihunath's answers. It considers wired connections. I haven't included VPN in this solution though.

PCNetwork.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface PCNetwork : NSObject
+ (NSString *)getIPAddress; // Prefers IPv4
+ (NSString *)getIPAddress:(BOOL)preferIPv4;
+ (NSDictionary *)getIPAddresses;
@end

NS_ASSUME_NONNULL_END

PCNetwork.m

#import "PCNetwork.h"
#include <ifaddrs.h>
#include <arpa/inet.h>
#include <net/if.h>

#define IP_UNKNOWN          @"0.0.0.0"
#define IP_ADDR_IPv4        @"ipv4"
#define IP_ADDR_IPv6        @"ipv6"

@implementation PCNetwork
#pragma mark - IP
+ (NSString *)getIPAddress {
    return [self getIPAddress:YES];
}

+ (NSString *)getIPAddress:(BOOL)preferIPv4 {
    NSArray *searchArray = [self getAllIFSearchArray:preferIPv4];
    NSDictionary *addresses = [self getIPAddresses];
    DLog(@"addresses: %@", addresses);

    __block NSString *address = nil;
    [searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop) {
         address = addresses[key];
         if(address) *stop = YES;
     }];
    return address ?: IP_UNKNOWN;
}

+ (NSDictionary *)getIPAddresses {
    NSMutableDictionary *addresses = [NSMutableDictionary dictionary];
    struct ifaddrs *interfaces;
    BOOL success = !getifaddrs(&interfaces); // Retrieve the current interfaces : returns 0 on success
    if (success) {
        struct ifaddrs *temp_interface;
        for (temp_interface = interfaces; temp_interface; temp_interface = temp_interface->ifa_next) { // Loop through linked list of interfaces
            if (!(temp_interface->ifa_flags & IFF_UP) || (temp_interface->ifa_flags & IFF_LOOPBACK)) { // Ignore interfaces that aren't up and loopback interfaces.
                continue;
            }

            if (!temp_interface->ifa_addr) {
                continue;
            }

            const struct sockaddr_in *temp_addr = (const struct sockaddr_in*)temp_interface->ifa_addr;
            if (temp_addr->sin_family == AF_INET || temp_addr->sin_family == AF_INET6) {
                char addrBuf[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
                NSString *name = [NSString stringWithUTF8String:temp_interface->ifa_name];
                NSString *type = nil;
                if (temp_addr->sin_family == AF_INET) {
                    if (inet_ntop(AF_INET, &temp_addr->sin_addr, addrBuf, INET_ADDRSTRLEN)) {
                        type = IP_ADDR_IPv4;
                    }
                } else {
                    const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)temp_interface->ifa_addr; // AF_INET6
                    if (inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, INET6_ADDRSTRLEN)) {
                        type = IP_ADDR_IPv6;
                    }
                }

                if (type) {
                    NSString *key = [NSString stringWithFormat:@"%@/%@", name, type];
                    addresses[key] = [NSString stringWithUTF8String:addrBuf];
                }
            }
        }
        freeifaddrs(interfaces); // Free memory
    }
    return addresses.count ? addresses.copy : nil;
}

#pragma mark - Inter Frame Spacing
+ (NSArray *)getAllIFSearchArray:(BOOL)preferIPv4 {
    NSArray *KNOWN_WIFI_IFS = @[@"en0"];
    NSArray *KNOWN_WIRED_IFS = @[@"en1",@"en2",@"en3",@"en4"];
    NSArray *KNOWN_CELL_IFS = @[@"pdp_ip0",@"pdp_ip1",@"pdp_ip2",@"pdp_ip3"];

    NSMutableArray *searchArray = [NSMutableArray array];

    // Add wifi
    [searchArray addObjectsFromArray:[self getIFSearchArrayWith:KNOWN_WIFI_IFS preferIPv4:preferIPv4]];

    // Add cell
    [searchArray addObjectsFromArray:[self getIFSearchArrayWith:KNOWN_CELL_IFS preferIPv4:preferIPv4]];

    // Add wired
    [searchArray addObjectsFromArray:[self getIFSearchArrayWith:KNOWN_WIRED_IFS preferIPv4:preferIPv4]];

    return searchArray.copy;
}

+ (NSArray *)getIFSearchArrayWith:(NSArray *)iFList preferIPv4:(BOOL)preferIPv4 {
    NSMutableArray *searchArray = [NSMutableArray array];
    for (NSString *iFType in iFList) {
        if (preferIPv4) {
            [searchArray addObject:[NSString stringWithFormat:@"%@/%@", iFType, IP_ADDR_IPv4]];
            [searchArray addObject:[NSString stringWithFormat:@"%@/%@", iFType, IP_ADDR_IPv6]];
        } else {
            [searchArray addObject:[NSString stringWithFormat:@"%@/%@", iFType, IP_ADDR_IPv6]];
            [searchArray addObject:[NSString stringWithFormat:@"%@/%@", iFType, IP_ADDR_IPv4]];
        }
    }
    return searchArray.copy;
}

@end
cessmestreet
  • 2,298
  • 3
  • 22
  • 42
0

in iOS 13.4.1 is not work for me . i use this fix it.

+ (NSString *)getIPAddress{
    NSArray *searchArray =
    @[ IOS_VPN @"/" IP_ADDR_IPv4, IOS_VPN @"/" IP_ADDR_IPv6, IOS_WIFI @"/" IP_ADDR_IPv4, IOS_WIFI @"/" IP_ADDR_IPv6, IOS_4_3G @"/" IP_ADDR_IPv4, IOS_4_3G @"/" IP_ADDR_IPv6, IOS_CELLULAR @"/" IP_ADDR_IPv4, IOS_CELLULAR @"/" IP_ADDR_IPv6];

    __block NSDictionary *addresses = [self getIPAddressArray];

    __block NSString *address;
    [searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop)
    {
         address = addresses[key];
         if ([key rangeOfString:@"ipv6"].length > 0  && ![[NSString stringWithFormat:@"%@",addresses[key]] hasPrefix:@"(null)"] ) {
             if ( ![addresses[key] hasPrefix:@"fe80"]) {
                 //     isIpv6 = YES;
                 *stop = YES;
              }
         }else{
             if([self isValidatIP:address]) {
                 *stop = YES;
             }
         }
     } ];
    return address ? address : @"error";
}
+ (NSString *)getIPType{
    NSString *ipAddress = [self getIPAddress];
    if ([self isValidatIP:ipAddress]) {
        return @"04";//ipv4
    }else{
        return @"06";//ipv6
    }
}
+ (NSDictionary *)getIPAddressArray{
    NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:8];
    // retrieve the current interfaces - returns 0 on success
    struct ifaddrs *interfaces;
    if(!getifaddrs(&interfaces)) {
        // Loop through linked list of interfaces
        struct ifaddrs *interface;
        for(interface=interfaces; interface; interface=interface->ifa_next) {
            if(!(interface->ifa_flags & IFF_UP) /* || (interface->ifa_flags & IFF_LOOPBACK) */ ) {
                continue; // deeply nested code harder to read
            }
            const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr;
            char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ];
            if(addr && (addr->sin_family==AF_INET || addr->sin_family==AF_INET6)) {
                NSString *name = [NSString stringWithUTF8String:interface->ifa_name];
                NSString *type;
                if(addr->sin_family == AF_INET) {
                    if(inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN)) {
                        type = IP_ADDR_IPv4;
                    }
                } else {
                    const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)interface->ifa_addr;
                    if(inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, INET6_ADDRSTRLEN)) {
                        type = IP_ADDR_IPv6;
                    }
                }
                if(type) {
                    NSString *key = [NSString stringWithFormat:@"%@/%@", name, type];
                    addresses[key] = [NSString stringWithUTF8String:addrBuf];
                }
            }
        }
        // Free memory
        freeifaddrs(interfaces);
    }
    return [addresses count] ? addresses : nil;
}
+ (BOOL)isValidatIP:(NSString *)ipAddress {
    if (ipAddress.length == 0) {
        return NO;
    }
    NSString *urlRegEx = @"^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
    "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
    "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
    "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";

    NSError *error;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:urlRegEx options:0 error:&error];

    if (regex != nil) {
        NSTextCheckingResult *firstMatch=[regex firstMatchInString:ipAddress options:0 range:NSMakeRange(0, [ipAddress length])];

        if (firstMatch) {
            NSRange resultRange = [firstMatch rangeAtIndex:0];
            NSString *result=[ipAddress substringWithRange:resultRange];
            //输出结果
            NSLog(@"%@",result);
            return YES;
        }
    }
    return NO;
}
yaoning
  • 121
  • 4