How to get your IP Address

  • warning: include(/tmp/fortune.txt): failed to open stream: No such file or directory in /home/mohawksoft/org/www/htdocs/includes/common.inc(1696) : eval()'d code on line 1.
  • warning: include(): Failed opening '/tmp/fortune.txt' for inclusion (include_path='.:/usr/share/php:/usr/share/pear') in /home/mohawksoft/org/www/htdocs/includes/common.inc(1696) : eval()'d code on line 1.

Many times application software needs to obtain its local IP address. This is not as simple to do as it seems it should be. It is likely that devices like laptops and tablets have more than one networking interface and the resource to which you are connecting may only be available via a specific interface.

Many texts suggest enumerating the devices and applying various tests on them depending on the operating systems you are using.

There is a simple methodology that works fairly reliably.

#include "stdio.h"
#include "string.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/socket.h"
#include "arpa/inet.h"
#include "errno.h"

typedef int sock_t;

bool find_ip(char *resource, char *result, int cbresult)
{
    bool found = false;
    sockaddr_in saddr;
    sock_t sock = socket(AF_INET, SOCK_DGRAM, 0);

    memset(&saddr,0, sizeof(saddr));
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(80);
    if(sock == -1) // Could not create socket
        return false;

    unsigned long ipaddr = inet_addr(resource);
    memcpy((char *)&saddr.sin_addr, (char *)&ipaddr, 4);

    if(!connect(sock, (sockaddr *) &saddr, sizeof(saddr)))
    {
        socklen_t len = sizeof(saddr);
        int n = getsockname(sock, (sockaddr *) &saddr, &len);
        if(n==0)
        {
            inet_ntop(AF_INET, &saddr.sin_addr, result, cbresult);
            found = true;
        }
    }
    if(sock != -1)
        close(sock);
    return found;
}

void main(int argc, char **argv)
{
    char buffer[256];
    if(find_ip(argv[1], buffer, sizeof(buffer)))
            printf("My IP Address: %s\n", buffer);
}

How it works is pretty interesting and while it would work with a stream socket (tcp), the connect(...) call would try to make a connection. That would cause the routing to block for network I/O. Worse yet, if the server to which you are trying to connect is not available, it could take a considerable amount of time to fail. With a datagram socket (udp), the connect call does not make a network connection. It merely references the internal routing tables and fills in the socket information for when you wish to send the information.

The best part of this technique is that it is fairly portable and works in most cases.