3

I'm trying to retrieve the IP Address of the local machine in my program. The Operating System is Ubuntu 8.10. I tried using gethostname() and gethostbyname() to retrieve the IP Address. The answer I received is 127.0.1.1. I learned that it seems to be a Debian thing: The document linked here explained the idea.

The content of my /etc/hosts file is:

127.0.0.1 localhost
127.0.1.1 mymachine

In this case, is there any other way to programmatically (prefer C or C++) to get the IP Address without modifying the system file on the machine?

Deepu
  • 7,592
  • 4
  • 25
  • 47
gc .
  • 415
  • 4
  • 9
  • 18
  • You can have multiple local IPs on a single system. How do you know which one you want? – Paul Tomblin Mar 31 '09 at 13:42
  • Thanks for reminding me, eventually, I realize I need to know all. – gc . Mar 31 '09 at 15:26
  • gethostbyname is an old routine anyway, and IPv4 specific. You should use getaddrinfo (but do note the whole algorithm is flawed because nothing guarantees that the resolution of the name will give you the real IP address, the DNS and /etc/hosts can lie...) – bortzmeyer Mar 31 '09 at 21:32

6 Answers6

5

Here's some quick and dirty code that demonstrates SIOCGIFCONF :

#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main()
{
    int sock, i;
    struct ifreq ifreqs[20];
    struct ifconf ic;

    ic.ifc_len = sizeof ifreqs;
    ic.ifc_req = ifreqs;

    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0) {
        perror("socket");
        exit(1);
    }

    if (ioctl(sock, SIOCGIFCONF, &ic) < 0) {
        perror("SIOCGIFCONF");
        exit(1);
    }

    for (i = 0; i < ic.ifc_len/sizeof(struct ifreq); ++i)
        printf("%s: %s\n", ifreqs[i].ifr_name,
                inet_ntoa(((struct sockaddr_in*)&ifreqs[i].ifr_addr)->sin_addr));

    return 0;
}

I get the following output on my Linux machine.

lo: 127.0.0.1
br0: 192.168.0.42
dummy1: 10.0.0.2
mpromonet
  • 11,326
  • 43
  • 62
  • 91
sigjuice
  • 28,661
  • 12
  • 68
  • 93
3

So, as per Ken's point:

ip addr show scope global | grep inet | cut -d' ' -f6 | cut -d/ -f1

Shame that when the Debian gods made the "ip" command they didn't think to add a simple command to get just the ip address.

Martin Cleaver
  • 909
  • 8
  • 21
2

See "netdevice", through man netdevice or on the web.
SIOCGIFCONF can then be used to get an enumeration of all transport layer addresses.

Edit (on manpages): man is a very useful command on Linux (or other UNIX-like systems as well). It shows a brief description of most commands, library functions, programs, etc. Open a shell prompt and type man ls or man netdevice, and you'll see what I mean.

Edit (on general retrieving of IP): The easiest way, if you think the C way is too messy, is a simple shell script like (just from the top of my head):
ifconfig|grep 'inet addr'|awk '{print $2}'|sed 's/addr://g'

Edit (on the Brain solution): What he does is using the if_nameindex() function for finding all network device names, and then the SIOCFIFCONF ioctl on each of these names for finding their IP. As he says, it only lists one IP per device.

E Dominique
  • 1,535
  • 13
  • 17
  • Probably I should ask Brain, but that thread was dated back to last year, so I will ask here anyway, in what case a device can have multiple IP addresses? Can the program posted by sigjuice down here list all those IPs? I haven't seen device with multiple IPs, I guess I can't test it myself. – gc . Apr 01 '09 at 11:31
  • No, the sigjuice solution is just like the Brain solution. An interface can have multiple IPs (though some WLAN interfaces cannot, as an example). It is normally not used, I'd say. Would you need an example that can list them as well? Have you played around with the current examples? – E Dominique Apr 01 '09 at 15:13
  • Sorry for taking so long to response, got caught on some other things. Yes, I've tried the examples, and they work. If it won't take you too much time, could you give me an example that can list all? – gc . Apr 07 '09 at 07:52
  • Well, I seem to have been mistaken. The code (the sigjuice) lists all IPs on all machines I've tested it on, so with some polish you can use that one. – E Dominique Apr 07 '09 at 09:59
  • Ok, thanks again. I think I didn't see the difference while running the program because I don't have any device that has multiple IPs. – gc . Apr 07 '09 at 12:00
  • Binding multiple IPs to a device in Linux (they term it 'IP aliasing') has an interesting side-effect: the IPs are not "first class citizens", that is, the device's primary IP is what is operated on, and any IP address that matches the alias(es) simply "come along for the ride". – Avery Payne Apr 16 '09 at 16:59
  • That is why you're probably seeing just a single IP address per interface- I would gamble that it is the "true" IP address that is bound to the device, and not the "aliases". – Avery Payne Apr 16 '09 at 16:59
1

Thanks all for the shares!

For a bash solution, this what I ended up going with:

#!/bin/bash

/sbin/ifconfig|fgrep 'inet addr:'|fgrep -v '127'|cut -d: -f2|awk '{print $1}'|head -n1

The head ensures the primary ip is returned, as multi homed and/or logical interfaces will also be returned without the head.

So if the script was located at /sbin/get_primary_ip, you could do stuff like:

foo=$(get_primary_ip)
Kyle
  • 966
  • 7
  • 8
1

ifconfig is deprecated and old. iproute2 is the new stack, use the ip command:

ip addr, and parse from there.

ken
  • 11
  • 1
1

Take a look at the netdevice man page. Call SIOCGIFCONF to obtain a list of all the interfaces and their addresses.

sigjuice
  • 28,661
  • 12
  • 68
  • 93