en2
interface.
Add:
[[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en2"]
to the first solution in
iPhone/iPad/OSX: How to get my IP address programmatically? to also get the device's IP address through wired connection.
UPDATE: Just expanding on @Raptor's solution linked above; this will return both wired and wireless IP Address, if both or either is present. Then just check the return dictionary's values' lengths to see what you're working with.
#import <ifaddrs.h>
#import <arpa/inet.h>
+ (NSDictionary *)getBothIPAddresses {
const NSString *WIFI_IF = @"en0";
NSArray *KNOWN_WIRED_IFS = @[@"en1",@"en2",@"en3",@"en4"];
NSArray *KNOWN_CELL_IFS = @[@"pdp_ip0",@"pdp_ip1",@"pdp_ip2",@"pdp_ip3"];
const NSString *UNKNOWN_IP_ADDRESS = @"";
NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithDictionary:@{@"wireless":UNKNOWN_IP_ADDRESS,
@"wired":UNKNOWN_IP_ADDRESS,
@"cell":UNKNOWN_IP_ADDRESS}];
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 == NULL) {
temp_addr = temp_addr->ifa_next;
continue;
}
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:WIFI_IF]) {
// Get NSString from C String
[addresses setObject:[NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)] forKey:@"wireless"];
}
// Check if interface is a wired connection
if([KNOWN_WIRED_IFS containsObject:[NSString stringWithUTF8String:temp_addr->ifa_name]]) {
[addresses setObject:[NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)] forKey:@"wired"];
}
// Check if interface is a cellular connection
if([KNOWN_CELL_IFS containsObject:[NSString stringWithUTF8String:temp_addr->ifa_name]]) {
[addresses setObject:[NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)] forKey:@"cell"];
}
}
temp_addr = temp_addr->ifa_next;
}
}
// Free memory
freeifaddrs(interfaces);
return addresses;
}
UPDATE:
en3
interface, another possibility; seems to depend on the type of adapter. Makes me think there could be more interfaces that I'm still missing based on hardware being used, so please comment if anyone discovers more.
UPDATE:
en4
as well; doesn't necessarily depend on adapter like I originally thought, because a Mini with all the same hardware at one point decided to switch from one interface to this new one. Also, I'm starting to think it may be easier to just compare the ifa_name to any string with a format of en[2..n]
, so long as it's in the AF_INET
family (for example, en1
is NOT and doesn't return an address we're looking for); it's likely premature to implement something like that for Prod without more proof, so for now I manage with a list of 'known' wired interfaces.
UPDATE:
Considers cellular AF_INET
interfaces too, mentioned in What exactly means iOS networking interface name? what's pdp_ip ? what's ap?
UPDATE:
Ethernet IP addresses have begun showing up on the en1
interface lately on certain new iPads, so it should also be considered when it's a member of the AF_INET
family. No distinguishable rhyme or reason, it happens with varying iPad models and iOS versions.