views:

528

answers:

7

How can I programmatically get the Internet IP address?

1) If the computer is directly connected to the Internet using a USB modem.

2) If the computer is connected to the internet via another computer or a modem/router.

I there a way to do both?

P.S. This link gives exactly the Internet IP, but how can I use it in my program?

+5  A: 

You need to talk to an external server. Issuing HTTP requests to sites like http://checkip.dyndns.org or http://www.whatismyip.com will do the trick.

To do the HTTP request, you can for example use libcurl.

Krumelur
Do I have to use libcurl? Can't I do it using sockets?
Levo
You can, but it will be a lot more work. Raw sockets is a pain, if you ask me. If you are strictly linux and in a controlled environment, you may also get away with piping a command like curl or wget.
Krumelur
No, I use linux and cygwin. But I want my application to be as much standalone as possible. And I don't want to include a whole library for a simple task.
Levo
HTTP is a seemingly simple protocol, but it is actually quite complicated to implement. I really advice against going and reinventing the wheel. Not to mention that BSD sockets in themselves require a fair share of support code.If you want something other than curl, may I suggest that you look at the alternatives: http://curl.haxx.se/libcurl/competitors.html
Krumelur
I have used libcurl in the past, and it is simple and easy to use. Unless I find a way to what I want with sockets, I'll use libcurl.
Levo
A: 

Generally speaking, there is no correct answer. A computer might have no Internet IP adddress, can have one, but can also have multiple external IPs. For the case when it has one, you still can't get it locally, only by contacting an external service, which will tell you where you've connected from. Your link is an example of a service like that.

unbeli
+2  A: 

If you want to access a web page via c++, go for CurlPP. Use it to download the whatismyip-page you already found and you're done.

Malte Clasen
+1  A: 
  1. You can write socket code to send an http request to that link.

  2. Under unix/linux/cygwin you can use system("wget http://www.whatismyip.com/automation/n09230945.asp"); then open the file "n09230945.asp" and read its contents.

Here is an example of how to make the request using sockets (I modified an online example for this specific purpose). NOTE: It is an example and a real implementation would need to handle the errors better:

#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

#define RCVBUFSIZE 1024

int main(int argc, char *argv[])
{
    int sock;                        // Socket descriptor
    struct sockaddr_in servAddr;     // server address
    unsigned short servPort;         // server port
    char const *servIP;              // Server IP address (dotted quad)
    char const *request;             // String to send to server
    char recvBuffer[RCVBUFSIZE];     // Buffer for response string
    unsigned int requestLen;         // Length of string to send
    int bytesRcvd;                   // Bytes read in single recv()
    bool status = true;

    // Initialize port
    servIP = "72.233.89.199";
    servPort = 80;
    request = "GET /automation/n09230945.asp HTTP/1.1\r\nHost: www.whatismyip.com\r\n\r\n";

    std::cout << request << std::endl;

    /* Create a reliable, stream socket using TCP */
    if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
    {
        status = false;
    }

    if (status)
    {
        // Convert dotted decimal into binary server address.
        memset(&servAddr, 0, sizeof(servAddr));
        servAddr.sin_family      = AF_INET;
        servAddr.sin_addr.s_addr = inet_addr(servIP);
        servAddr.sin_port        = htons(servPort);

        // Connect to the server.
        if (connect(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
        {
            status = false;
        }
    }

    if (status)
    {
        // Calculate request length.
        requestLen = strlen(request);

        // Send the request to the server.
        if (send(sock, request, requestLen, 0) != requestLen)
        {
            status = false;
        }
    }

    if (status)
    {
        std::cout << "My IP Address: ";

        if ((bytesRcvd = recv(sock, recvBuffer, RCVBUFSIZE - 1, 0)) <= 0)
        {
            status = false;
        }

        if (status && (bytesRcvd >0) && (bytesRcvd < (RCVBUFSIZE-1)))
        {
            recvBuffer[bytesRcvd] = '\0';
            std::cout << recvBuffer << std::endl;
        }
    }

    close(sock);

    return 0;
}
Amardeep
Can you suggest an example for 1?
Levo
@Levo: I'll put an example together and post it in the reply.
Amardeep
Okay, there's a working example. I tested it under cygwin --- YMMV.
Amardeep
@Amardeep: Perfect! Thank you very much.
Levo
A: 

It shouldn't be too difficult to implement url.h to request the link you gave http://www.gnutelephony.org/doxy/bayonne2/a00242.html. I remember once using a C++ wrapper for wget called URLStream.h that used the extraction operator which would make this task really easy but I can't seem to find it.

puddingfox
+1  A: 

For C/C++, you're looking for functions in the gethostbyname() family (see man gethostbyname) and inet_ntoa. The gethostbyname() query DNS and return a list of IP addresses for the host name, which you could then print with inet_ntoa.

Here's an example program that will lookup the IP addresses of the specified host name and print them out. Note: I've not put in any error checking, so be careful!

#include <stdio.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char** argv)
{
   struct hostent* host = gethostbyname(argv[1]);
   int count = 0; 
   char** current_addr = host->h_addr_list;
   while (*current_addr != NULL) 
   { 
       struct in_addr* addr = (struct in_addr*)(*current_addr); 
       printf("address[%d]: %s\n", count, inet_ntoa(*addr));
       ++current_addr;
       ++count;
   }
}

An example from my Kubuntu 10.04 machine:

[email protected]:~/sandbox/c$ ./gethostbyaddr_ex www.yahoo.com
address[0]: 69.147.125.65
address[1]: 67.195.160.76
Matt McClellan
-1, how is this supposed to help him to find an external IP of his own machine?
unbeli
A: 

Depending on the context in which the program you are writing needs to run you might want to solve this by asking NetworkManager over DBus (see http://projects.gnome.org/NetworkManager/developers/)

This really only applies to desktop systems (and not even all of them... but most distros use NM now)

Also this doesn't help with #2, however you could use a STUN server see Wikipedia

Spudd86