How to use inet_ntop to detect a VPN?

I support an answer on StackOverflow on how to get active IP addresses on iOS devices (code below). Someone updated it to detect if the device is on a VPN by testing for 'utun0' and/or 'utun1', but the heuristic failed as it seems those are used for other purposes. Is there a way to detect a primary VPN connection?


#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];
    struct ifaddrs *interfaces;
    if(!getifaddrs(&interfaces)) {
        struct ifaddrs *interface;
        for(interface   interfaces; interface; interface    interface->ifa_next) {
            if(!(interface->ifa_flags & IFF_UP) / || (interface->ifa_flags & IFF_LOOPBACK) */ ) {
                continue; /
            }
            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];
                }
            }
        }
        freeifaddrs(interfaces);
    }
    return [addresses count] ? addresses : nil;
}

Is there a way to detect a primary VPN connection?

OK, this is a “What are you really trying to do?” moment. The code you posted is not going to work reliably because there’s no documented mapping between iOS interface names and their user-level functionality. There are approaches you could take but it’s hard to suggest something concrete without more info about your high-level goals.

Share and Enjoy
—
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Somehow I got pulled into a thread on Stack Overflow - I cannot recall why or how: stackoverflow.com / a / 10803584 / 1633251


I just cannot remember why I posted this answer. Note that Jens Alfke jumped in at one point and helped me refine IPv6 addresses.


At some point someone modified the code to detect VPNs (the utun comment), which later on caused people grief so I commented it out. One commenter (with a separate answer), Qiulang, was trying to get "VPN to work". There is a related rdar on this mentioned in this answer: 28131847


I was able to get into contactd with Qiulang to relay your question ("Why?") - but that person is on longer working on iOS. A coworker is and may jump back into this thread.


Other than VPN people seem pretty happy about the code - but I have no idea what its being used for.