1

In my application I need to get a NSString object value equal to the value of a users public/internet ip address. I have tried to ways of going about this but both return the local ip address NOT public. Below are my two methods. One is more precise and always returns the correct item in the array. The other does not. (Because one just picks a random index)...

- (NSString *)getPublicIP {   
    NSHost *publicIP = [[[NSHost currentHost] addresses] objectAtIndex:0];
    return publicIP;  
}

Other more precise:(but does not get Public IP)

 //start get ip
- (NSString *)getIPWithNSHost { 

NSArray *addresses = [[NSHost currentHost] addresses];
NSString *stringAddress;
for (NSString *anAddress in addresses) {
    if (![anAddress hasPrefix:@"127"] && [[anAddress componentsSeparatedByString:@"."] count] == 4) {
    stringAddress = anAddress;
    break;
    }
    else {
    stringAddress = @"IPv4 address not available" ;

}
    //NSLog(stringAddress);
}
NSLog (@"getIPWithNSHost: stringAddress = %@ ",stringAddress); 
stringAddress = (@"getIPWithNSHost: stringAddress = %@ ",stringAddress);

return  stringAddress;

}

Either way I just need a way to get the external/public/internet ip address. (Just to clarify external/public/internet ip is one that can be retrieved from whatsmyip.org)

Andrew Sheridan
  • 19
  • 1
  • 10

6 Answers6

5

Here is an iOS friendly version of joshbillions answer:

+(void)getPublicIP:(void(^)(NSString *))block {
    NSURL *url = [NSURL URLWithString:@"http://checkip.dyndns.org"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [[[NSURLSession sharedSession]dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (error) {
            // consider handling error
        } else {
            NSString *html = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
            NSCharacterSet *numbers = [NSCharacterSet characterSetWithCharactersInString:@"0123456789."];
            NSString *ipAddr = [[html componentsSeparatedByCharactersInSet:numbers.invertedSet]componentsJoinedByString:@""];
            if (block) {
                block(ipAddr);
            }
        }
    }]resume];
}
Justin Moser
  • 2,005
  • 3
  • 22
  • 28
4

Due to NAT you can't count on your machine having its external IP available on any of its interfaces.
The only semi-reliable way of getting your external IP is to ask a machine on the Internet (like whatsmyip.org that you mention) that sees your IP traffic after passing through any local router/firewall.

A somewhat standard way of asking for this information used in for example IP telephony is to use the STUN protocol.

Joachim Isaksson
  • 176,943
  • 25
  • 281
  • 294
4

It's ugly as sin, but this works for me:

NSTask *task = [[[NSTask alloc] init] autorelease];
[task setLaunchPath:@"/usr/bin/curl"];
[task setArguments:[NSArray arrayWithObjects:@"-s",@"http://checkip.dyndns.org", nil]];
NSPipe *outputPipe = [NSPipe pipe];
[task setStandardOutput:outputPipe];
[task launch];
NSData *curlData = [[outputPipe fileHandleForReading] readDataToEndOfFile];
NSString *curlString = [[NSString alloc] initWithData:curlData encoding:NSASCIIStringEncoding];
NSMutableString *strippedString = [NSMutableString
                                   stringWithCapacity:curlString.length];

NSScanner *scanner = [NSScanner scannerWithString:curlString];
NSCharacterSet *numbers = [NSCharacterSet
                           characterSetWithCharactersInString:@"0123456789."];

while ([scanner isAtEnd] == NO) {
    NSString *buffer;
    if ([scanner scanCharactersFromSet:numbers intoString:&buffer]) {
        [strippedString appendString:buffer];

    } else {
        [scanner setScanLocation:([scanner scanLocation] + 1)];
    }
}
NSLog(@"IP Address: %@", strippedString);
joshbillions
  • 1,048
  • 8
  • 19
3

STUN protocol is a good solution to get your public IP and port - check out STUN protocol implementation for iOS https://github.com/soulfly/STUN-iOS

Rubycon
  • 18,156
  • 10
  • 49
  • 70
1
  • methods should never be prefixed with get unless you are passing arguments by reference...

But that doesn't answer your question.

Answering that requires a question; what are you trying to do?

In all but the most limited circumstances, your device's IP address is quite likely meaningless.

  • if on a cellular network, it probably isn't routable

  • if on any kind of consumer internet connection, it is probably behind a NAT router of some kind

  • even in the rare case of being given a routable address, your device is likely behind a firewall

In all but the rarest of [generally very administrative intensive cases], you should use Bonjour to do non-IP centric service discovery or something like Game Center to do person to person matching (or other, domain specific, matching proxy).

bbum
  • 162,346
  • 23
  • 271
  • 359
  • I have an info pain of system information like updating cpu usage and ram. I wanted to display local ip and public ip there. – Andrew Sheridan Apr 28 '12 at 06:27
  • Best off, then, to display *all* the possible IPs, including the NAT'd address. You'll have to ping the external service -- like "whatsmyip" to grab the *true* external IP. – bbum Apr 28 '12 at 07:00
0

I use ifconfig.me, a great site to get your public IP address and another information, using multiple output formats (including JSON).

- (void)myPublicIPAddressWithCompletitionBlock:(void (^)(NSString *))completitionBlock {
    NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
    [sessionConfiguration setHTTPAdditionalHeaders:@{@"Content-Type": @"application/json"}];

    NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];

    NSURL *url = [NSURL URLWithString:@"https://ifconfig.me/all.json"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (!error) {
            NSError *jsonError = nil;
            NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&jsonError];
            if (!jsonError) {
                if (jsonResponse[@"ip_addr"]) {
                    if (completitionBlock) {
                        dispatch_async(dispatch_get_main_queue(), ^{
                            completitionBlock(jsonResponse[@"ip_addr"]);
                        });
                    }

                    return ;
                }
            }
        }

        if (completitionBlock) {
            dispatch_async(dispatch_get_main_queue(), ^{
                completitionBlock(@"none");
            });
        }
    }];

    [task resume];
}
Carlos Guzman
  • 363
  • 5
  • 11