By BlaM


2008-10-17 15:00:45 8 Comments

This Question is almost the same as the previously asked Get the IP Address of local computer-Question. However I need to find the IP address(es) of a Linux Machine.

So: How do I - programmatically in C++ - detect the IP addresses of the linux server my application is running on. The servers will have at least two IP addresses and I need a specific one (the one in a given network (the public one)).

I'm sure there is a simple function to do that - but where?


To make things a bit clearer:

  • The server will obviously have the "localhost": 127.0.0.1
  • The server will have an internal (management) IP address: 172.16.x.x
  • The server will have an external (public) IP address: 80.190.x.x

I need to find the external IP address to bind my application to it. Obviously I can also bind to INADDR_ANY (and actually that's what I do at the moment). I would prefer to detect the public address, though.

12 comments

@Erik Aronesty 2011-05-18 13:23:50

This has the advantage of working on many flavors of unix ...and you can modify it trivially to work on any o/s. All of the solutions above give me compiler errors depending on the phase of the moon. The moment there's a good POSIX way to do it... don't use this (at the time this was written, that wasn't the case).

// ifconfig | perl -ne 'print "$1\n" if /inet addr:([\d.]+)/'

#include <stdlib.h>

int main() {
        setenv("LANG","C",1);
        FILE * fp = popen("ifconfig", "r");
        if (fp) {
                char *p=NULL, *e; size_t n;
                while ((getline(&p, &n, fp) > 0) && p) {
                   if (p = strstr(p, "inet ")) {
                        p+=5;
                        if (p = strchr(p, ':')) {
                            ++p;
                            if (e = strchr(p, ' ')) {
                                 *e='\0';
                                 printf("%s\n", p);
                            }
                        }
                   }
              }
        }
        pclose(fp);
        return 0;
}

@zitroneneis 2012-04-09 15:43:46

thank you for this solution, works great for me and comes very handy in many situations when you just want to get some data from cl-programs

@Zaur Nasibov 2012-06-12 11:52:52

Although ifconfig outputs the required data, I would strongly discourage using any program this way. It's much better to actually get into ifconfig's source and get the functionality than run it and parse its output.

@Erik Aronesty 2012-11-05 16:06:26

@zitroneneis : c programmers sometimes forget to think like perl programmers.... and vice versa.

@Martin Meeser 2013-11-18 11:29:36

This does not work on non-English linuxs, e.g. in German debian output of "inet addr" is "inet Adresse" instead.

@Martin Meeser 2013-11-18 11:34:12

One of my linux colleagues just gave me this: /sbin/ifconfig eth1 | grep \"inet addr\" | cut -d':' -f2 | cut -d' ' -f1. Of course this just moves the "parsing" to the console and language problem still exists.

@Erik Aronesty 2014-01-22 16:09:26

@MartinMeeser : made it language neutral, by looking for "inet " then ":" separately.

@Anders 2014-09-12 23:03:43

Then you have other languages which isn't even Latin based character set. The sollution is to not use command tools, as they get deprecated like ifconfig. You should use ip now. The proper way of generate language neutral output is to set LANG environment variable to C, like: LANG=C ls -l

@gsamaras 2015-08-05 16:11:40

sh: 1: ifconfig: not found on Debian.

@Erik Aronesty 2016-09-13 12:55:36

Change it to the "ip" command then, not that hard. System internals change faster than command lines.

@fcm 2017-08-28 03:09:17

A new version or mix versions on your environment will disrupt parse scripts. Never a good advise to parse the text response: always for humans. So many rewrites finally teach me the hard way.

@Erik Aronesty 2017-10-05 13:05:20

New system library versions will also disrupt stuff. I agree... go ahead and use a library call if a good cross-platform POSIX one exists. But damned if that isnt the case for lots of things you may need.

@Tino 2015-11-23 13:28:50

I do not think there is a definitive right answer to your question. Instead there is a big bundle of ways how to get close to what you wish. Hence I will provide some hints how to get it done.

If a machine has more than 2 interfaces (lo counts as one) you will have problems to autodetect the right interface easily. Here are some recipes on how to do it.

The problem, for example, is if hosts are in a DMZ behind a NAT firewall which changes the public IP into some private IP and forwards the requests. Your machine may have 10 interfaces, but only one corresponds to the public one.

Even autodetection does not work in case you are on double-NAT, where your firewall even translates the source-IP into something completely different. So you cannot even be sure, that the default route leads to your interface with a public interface.

Detect it via the default route

This is my recommended way to autodetect things

Something like ip r get 1.1.1.1 usually tells you the interface which has the default route.

If you want to recreate this in your favourite scripting/programming language, use strace ip r get 1.1.1.1 and follow the yellow brick road.

Set it with /etc/hosts

This is my recommendation if you want to stay in control

You can create an entry in /etc/hosts like

80.190.1.3 publicinterfaceip

Then you can use this alias publicinterfaceip to refer to your public interface.

Sadly haproxy does not grok this trick with IPv6

Use the environment

This is a good workaround for /etc/hosts in case you are not root

Same as /etc/hosts. but use the environment for this. You can try /etc/profile or ~/.profile for this.

Hence if your program needs a variable MYPUBLICIP then you can include code like (this is C, feel free to create C++ from it):

#define MYPUBLICIPENVVAR "MYPUBLICIP"

const char *mypublicip = getenv(MYPUBLICIPENVVAR);

if (!mypublicip) { fprintf(stderr, "please set environment variable %s\n", MYPUBLICIPENVVAR); exit(3); }

So you can call your script/program /path/to/your/script like this

MYPUBLICIP=80.190.1.3 /path/to/your/script

this even works in crontab.

Enumerate all interfaces and eliminate those you do not want

The desperate way if you cannot use ip

If you do know what you do not want, you can enumerate all interfaces and ignore all the false ones.

Here already seems to be an answer https://stackoverflow.com/a/265978/490291 for this approach.

Do it like DLNA

The way of the drunken man who tries to drown himself in alcohol

You can try to enumerate all the UPnP gateways on your network and this way find out a proper route for some "external" thing. This even might be on a route where your default route does not point to.

For more on this perhaps see https://en.wikipedia.org/wiki/Internet_Gateway_Device_Protocol

This gives you a good impression which one is your real public interface, even if your default route points elsewhere.

There are even more

Where the mountain meets the prophet

IPv6 routers advertise themselves to give you the right IPv6 prefix. Looking at the prefix gives you a hint about if it has some internal IP or a global one.

You can listen for IGMP or IBGP frames to find out some suitable gateway.

There are less than 2^32 IP addresses. Hence it does not take long on a LAN to just ping them all. This gives you a statistical hint on where the majority of the Internet is located from your point of view. However you should be a bit more sensible than the famous https://de.wikipedia.org/wiki/SQL_Slammer

ICMP and even ARP are good sources for network sideband information. It might help you out as well.

You can use Ethernet Broadcast address to contact to all your network infrastructure devices which often will help out, like DHCP (even DHCPv6) and so on.

This additional list is probably endless and always incomplete, because every manufacturer of network devices is busily inventing new security holes on how to auto-detect their own devices. Which often helps a lot on how to detect some public interface where there shouln't be one.

'Nuff said. Out.

@Steve Baker 2008-10-17 15:38:32

  1. Create a socket.
  2. Perform ioctl(<socketfd>, SIOCGIFCONF, (struct ifconf)&buffer);

Read /usr/include/linux/if.h for information on the ifconf and ifreq structures. This should give you the IP address of each interface on the system. Also read /usr/include/linux/sockios.h for additional ioctls.

@Matt Joiner 2011-03-12 07:06:58

I was under the impression it will only give you the address of the interface it binds to.

@Stéphane 2017-03-26 00:44:53

@MattJoiner No, take a look at the man page, SIOCGIFCONF returns info on all interfaces. Part of the man page quoted here: "Return a list of interface (transport layer) addresses. This currently means only addresses of the AF_INET (IPv4) family for compatibility. The user passes a ifconf structure as argument to the ioctl. It contains a pointer to an array of ifreq structures in ifc_req and its length in bytes in ifc_len. The kernel fills the ifreqs with all current L3 interface addresses that are running"

@Twelve47 2008-11-05 17:34:43

I found the ioctl solution problematic on os x (which is POSIX compliant so should be similiar to linux). However getifaddress() will let you do the same thing easily, it works fine for me on os x 10.5 and should be the same below.

I've done a quick example below which will print all of the machine's IPv4 address, (you should also check the getifaddrs was successful ie returns 0).

I've updated it show IPv6 addresses too.

#include <stdio.h>      
#include <sys/types.h>
#include <ifaddrs.h>
#include <netinet/in.h> 
#include <string.h> 
#include <arpa/inet.h>

int main (int argc, const char * argv[]) {
    struct ifaddrs * ifAddrStruct=NULL;
    struct ifaddrs * ifa=NULL;
    void * tmpAddrPtr=NULL;

    getifaddrs(&ifAddrStruct);

    for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
        if (!ifa->ifa_addr) {
            continue;
        }
        if (ifa->ifa_addr->sa_family == AF_INET) { // check it is IP4
            // is a valid IP4 Address
            tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
            char addressBuffer[INET_ADDRSTRLEN];
            inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
            printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); 
        } else if (ifa->ifa_addr->sa_family == AF_INET6) { // check it is IP6
            // is a valid IP6 Address
            tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
            char addressBuffer[INET6_ADDRSTRLEN];
            inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
            printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); 
        } 
    }
    if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct);
    return 0;
}

@Andrey 2011-10-14 10:04:43

+1 and thanks for bringing this nice approach instead of those boring ioctl's! However, your handling of IP6 is still incorrect - you should cast to sockaddr_in6, i.e. something like tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;

@Twelve47 2011-10-17 11:14:17

@Andrey, thanks. I've updated my answer (haven't had a chance to test it though)

@Sudip Bhattarai 2016-02-27 07:14:44

gives lo and wlan0 interfaces in my case. What I require is wlan0 or eth0 which has internet connection.So, Should I use strcmp or thre's a better way?

@Kristian Evensen 2013-06-27 22:00:28

As the question specifies Linux, my favourite technique for discovering the IP-addresses of a machine is to use netlink. By creating a netlink socket of the protocol NETLINK_ROUTE, and sending an RTM_GETADDR, your application will received a message(s) containing all available IP addresses. An example is provided here.

In order to simply parts of the message handling, libmnl is convenient. If you are curios in figuring out more about the different options of NETLINK_ROUTE (and how they are parsed), the best source is the source code of iproute2 (especially the monitor application) as well as the receive functions in the kernel. The man page of rtnetlink also contains useful information.

@Dave Sieving 2012-09-29 02:26:47

An elegant scripted solution for Linux can be found at: http://www.damnsmalllinux.org/f/topic-3-23-17031-0.html

@Chaza 2011-03-27 22:03:06

// Use a HTTP request to a well known server that echo's back the public IP address void GetPublicIP(CString & csIP) { // Initialize COM bool bInit = false; if (SUCCEEDED(CoInitialize(NULL))) { // COM was initialized bInit = true;

    // Create a HTTP request object
    MSXML2::IXMLHTTPRequestPtr HTTPRequest;
    HRESULT hr = HTTPRequest.CreateInstance("MSXML2.XMLHTTP");
    if (SUCCEEDED(hr))
    {
        // Build a request to a web site that returns the public IP address
        VARIANT Async;
        Async.vt = VT_BOOL;
        Async.boolVal = VARIANT_FALSE;
        CComBSTR ccbRequest = L"http://whatismyipaddress.com/";

        // Open the request
        if (SUCCEEDED(HTTPRequest->raw_open(L"GET",ccbRequest,Async)))
        {
            // Send the request
            if (SUCCEEDED(HTTPRequest->raw_send()))
            {
                // Get the response
                CString csRequest = HTTPRequest->GetresponseText();

                // Parse the IP address
                CString csMarker = "<!-- contact us before using a script to get your IP address -->";
                int iPos = csRequest.Find(csMarker);
                if (iPos == -1)
                    return;
                iPos += csMarker.GetLength();
                int iPos2 = csRequest.Find(csMarker,iPos);
                if (iPos2 == -1)
                    return;

                // Build the IP address
                int nCount = iPos2 - iPos;
                csIP = csRequest.Mid(iPos,nCount);
            }
        }
    }
}

// Unitialize COM
if (bInit)
    CoUninitialize();

}

@viraptor 2011-05-18 13:38:03

This is a heavy, windows-only (question about linux), badly formatted solution relying on services out of local control via fragile parsing of website content. Can't find any positive side of this "solution".

@notlesh 2015-04-01 18:23:44

Hah! The HTML parsing even looks for a comment that is a warning about exactly what is being done.

@Thanatos 2010-07-12 04:41:54

Don't hard code it: this is the sort of thing that can change. Many programs figure out what to bind to by reading in a config file, and doing whatever that says. This way, should your program sometime in the future need to bind to something that's not a public IP, it can do so.

@4dan 2010-06-25 18:15:55

I like jjvainio's answer. As Zan Lnyx says, it uses the local routing table to find the IP address of the ethernet interface that would be used for a connection to a specific external host. By using a connected UDP socket, you can get the information without actually sending any packets. The approach requires that you choose a specific external host. Most of the time, any well-known public IP should do the trick. I like Google's public DNS server address 8.8.8.8 for this purpose, but there may be times you'd want to choose a different external host IP. Here is some code that illustrates the full approach.

void GetPrimaryIp(char* buffer, size_t buflen) 
{
    assert(buflen >= 16);

    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    assert(sock != -1);

    const char* kGoogleDnsIp = "8.8.8.8";
    uint16_t kDnsPort = 53;
    struct sockaddr_in serv;
    memset(&serv, 0, sizeof(serv));
    serv.sin_family = AF_INET;
    serv.sin_addr.s_addr = inet_addr(kGoogleDnsIp);
    serv.sin_port = htons(kDnsPort);

    int err = connect(sock, (const sockaddr*) &serv, sizeof(serv));
    assert(err != -1);

    sockaddr_in name;
    socklen_t namelen = sizeof(name);
    err = getsockname(sock, (sockaddr*) &name, &namelen);
    assert(err != -1);

    const char* p = inet_ntop(AF_INET, &name.sin_addr, buffer, buflen);
    assert(p);

    close(sock);
}

@eugene 2011-04-07 10:42:44

this gives me priviate ip 127.*.*.* . maybe because i'm behind NAT?

@jjvainio 2008-10-18 17:51:42

As you have found out there is no such thing as a single "local IP address". Here's how to find out the local address that can be sent out to a specific host.

  1. Create a UDP socket
  2. Connect the socket to an outside address (the host that will eventually receive the local address)
  3. Use getsockname to get the local address

@Zan Lynx 2008-10-21 00:09:06

I've never done it this way but I like it. It uses the OS routing table automatically and is much easier than scanning the interface list.

@Christopher 2010-06-14 20:25:49

This assumes that you know what an outside address will be. This is often not the case in data centers.

@Joshua 2010-11-09 04:09:34

You could always try three that are assigned to different continents (IANA makes this easy) and accept best two out of three.

@camh 2008-10-18 09:24:50

Further to what Steve Baker has said, you can find a description of the SIOCGIFCONF ioctl in the netdevice(7) man page.

Once you have the list of all the IP addresses on the host, you will have to use application specific logic to filter out the addresses you do not want and hope you have one IP address left.

@Zeist 2008-10-17 18:13:55

You can do some integration with curl as something as easy as: curl www.whatismyip.org from the shell will get you your global ip. You're kind of reliant on some external server, but you will always be if you're behind a NAT.

@deft_code 2009-08-29 00:12:16

I never understand why more people don't use this site. They even have a machine readable page so you don't have to screen scrap the information.

@Jack 2010-07-12 05:38:37

You may not get correct IP if you are operating inside proxy.

@lukecyca 2011-03-16 20:42:24

icanhazip.com returns the IP and nothing more. Perfect for embedding in a bash script!

@Ben Dowling 2013-07-06 02:41:45

ipinfo.io/ip is another alternative. If you curl ipinfo.io it also returns the hostname, geolocation info and more in JSON format.

Related Questions

Sponsored Content

45 Answered Questions

[SOLVED] Finding local IP addresses using Python's stdlib

50 Answered Questions

[SOLVED] How to get client's IP address using JavaScript?

25 Answered Questions

[SOLVED] How to get IP address of the device from code?

  • 2011-05-19 20:29:48
  • Nilesh Tupe
  • 396921 View
  • 367 Score
  • 25 Answer
  • Tags:   android ip-address

19 Answered Questions

[SOLVED] How to get a user's client IP address in ASP.NET?

13 Answered Questions

26 Answered Questions

[SOLVED] How to get the IP address of the server on which my C# application is running on?

  • 2009-07-01 13:20:23
  • Nefzen
  • 361828 View
  • 363 Score
  • 26 Answer
  • Tags:   c# ip-address

24 Answered Questions

[SOLVED] Image Processing: Algorithm Improvement for 'Coca-Cola Can' Recognition

7 Answered Questions

Sponsored Content