How to get its own IP address with a socket address?

24,142

Solution 1

When you bind() a socket to 0.0.0.0, that is the only IP the socket has available when calling getsockname(). It means the socket is bound to all local interfaces. In order to get a specific IP from a socket, it has to be bound to a specific IP.

Using the socket API to get the machine's local IP(s) is the wrong approach anyway. A common mistake is to use gethostname() with gethostbyname() or getaddrinfo() to get the local IP list. Usually that works, but it has some hidden gotchas that can cause false information, but people tend to ignore that fact, or don't even know about it in the first place (I didn't know about it for years, but then I learned better).

Instead, you really should use platform-specific APIs for enumerating the local networking interfaces. That will provide more reliable information. Windows has GetAdaptersInfo() and GetAdaptersAddresses(). Other platforms have getifaddrs(). Those will tell you what local IPs are available. You can then bind() a socket to 0.0.0.0 in order to accept clients on any of those IPs, or bind() to a specific IP to accept clients only on that IP.

Solution 2

The sockets API allows you to enumerate the IP addresses assigned to your network interfaces, but it will not tell you what you "real IP" is if you are connecting to the Internet from behind a router.

The only way to know it is by asking someone outside. Thats how servers like FileZilla FTP Server do that. They instruct you to configure the URL to a "ip.php" script like this one in the server's settings so it can ask the Internet whats its public IP address, to use in Passive Mode.

You can also consider using STUN, a protocol widely used in VoIP to discover public IP.

Solution 3

You could call ioctl(sock, SIOCGIFADDR, adr)

see netdevice(7)

Share:
24,142
Julien Fouilhé
Author by

Julien Fouilhé

Updated on December 24, 2020

Comments

  • Julien Fouilhé
    Julien Fouilhé over 3 years

    I want to get the IP address of the computer my program is launched on, to be able then to send it to a client, but I always get 0.0.0.1 instead of the real IP address (like 127.0.0.1 for instance).

    I'm currently able to get the port, but not the IP address.

    How can I get it?

    The best solution would be to be able to get it with a sockaddr_in. Here's what I'm currently doing:

    int open_connection(char* ip, int* port)
    {
      int                   sock;
      struct sockaddr_in    sin;
      socklen_t             len;
      int                   i;
    
      i = 0;
      len = sizeof(sin);
      if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
        return (-1);
      bzero(&sin, sizeof(struct sockaddr_in));
      sin.sin_family = AF_INET;
      if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0)
        perror("Error on bind");
      if (getsockname(sock, (struct sockaddr *)&sin, &len) != 0)
        perror("Error on getsockname");
      strcpy(ip, inet_ntoa(sin.sin_addr)); // IP = 0.0.0.0
      *port = sin.sin_port;
      return (sock);
    }
    

    EDIT: I understand I was going on the wrong way with my way of thinking. So my question is: What's the best way to get your own IP address?

  • jweyrich
    jweyrich about 11 years
    +1. In case OP wants more options, I personally like ifconfig.me, and canhazip.com.
  • Julien Fouilhé
    Julien Fouilhé about 11 years
    Thanks,that's not adapted for my current needs (it's a school project, and it is not meant to work from the internet). I'll see if I have time to implement it.
  • alk
    alk about 11 years
    Could you elaborate on the "... hidden gotchas ..." in getaddrinfo(), please?
  • Remy Lebeau
    Remy Lebeau about 11 years
    gethostbyname() and getaddrinfo() are designed to use DNS lookups to resolve hostnames to IPs. They are not meant to retrieve info about localhost. It is possible for a) a user to alter/corrupt the OS's DNS cache (hosts file, etc), and b) a PC's hostname to be configured to not have an IP at all or to map to multiple IPs which may not all belong to the PC (think load balancing, etc). Those functions are not 100% guaranteed to return valid local IPs when passed a local hostname in all setups. Functions like GetAdaptersInfo() and getifsaddrs() are designed for that purpose instead.
  • alk
    alk about 11 years
    Oh yes, the external DNS involved is what you are basically referring to. I do agree on this. Thanks for clarifing.
  • Julien Fouilhé
    Julien Fouilhé about 11 years
    That works perfectly (getifaddrs()), and it is easy to implement this, thanks !
  • bebbo
    bebbo over 9 years
    on Windows this code does not result into a DNS query and returns all local IP addresses: gethostname(hostname, 255); for (getaddrinfo(hostname, 0, 0, &ai); ai; ai = ai->ai_next) { if (ai->ai_family != AF_INET) continue; // now use ai->ai_addr
  • Remy Lebeau
    Remy Lebeau over 9 years
    gethostbyname() and getaddrinfo() on Windows are subject to the same pitfalls I mentioned earlier. Just because you usually do not see them happen does not mean they cannot happen at all (and I have seen reports of them happening, even on Windows). The correct way to get local IPs on Windows is to use GetAdaptersInfo() or GetAdaptersAddresses().
  • aardvarkk
    aardvarkk almost 8 years
    This was super helpful for me. I was using RakNet in C++ for networking and their code internally called gethostbyname(). On certain networks, the call was taking a very long time (~30s) just to get the local IP address. It seems like one of your "gotchas". Changing their internal code to use getifaddrs() instead appeared to fix the problem. Thanks so much for posting this answer!