How can I get the IP Address of a local computer?

Viewed 222154

In C++, what's the easiest way to get the local computer's IP address and subnet mask?

I want to be able to detect the local machine's IP address in my local network. In my particular case, I have a network with a subnet mask of 255.255.255.0 and my computer's IP address is 192.168.0.5. I need to get these had two values programmatically in order to send a broadcast message to my network (in the form 192.168.0.255, for my particular case)

Edit: Many answers were not giving the results I expected because I had two different network IP's. Torial's code did the trick (it gave me both IP addresses).

Edit 2: Thanks to Brian R. Bondy for the info about the subnet mask.

13 Answers

You can use gethostname followed by gethostbyname to get your local interface internal IP.

This returned IP may be different from your external IP though. To get your external IP you would have to communicate with an external server that will tell you what your external IP is. Because the external IP is not yours but it is your routers.

//Example: b1 == 192, b2 == 168, b3 == 0, b4 == 100
struct IPv4
{
    unsigned char b1, b2, b3, b4;
};

bool getMyIP(IPv4 & myIP)
{
    char szBuffer[1024];

    #ifdef WIN32
    WSADATA wsaData;
    WORD wVersionRequested = MAKEWORD(2, 0);
    if(::WSAStartup(wVersionRequested, &wsaData) != 0)
        return false;
    #endif


    if(gethostname(szBuffer, sizeof(szBuffer)) == SOCKET_ERROR)
    {
      #ifdef WIN32
      WSACleanup();
      #endif
      return false;
    }

    struct hostent *host = gethostbyname(szBuffer);
    if(host == NULL)
    {
      #ifdef WIN32
      WSACleanup();
      #endif
      return false;
    }

    //Obtain the computer's IP
    myIP.b1 = ((struct in_addr *)(host->h_addr))->S_un.S_un_b.s_b1;
    myIP.b2 = ((struct in_addr *)(host->h_addr))->S_un.S_un_b.s_b2;
    myIP.b3 = ((struct in_addr *)(host->h_addr))->S_un.S_un_b.s_b3;
    myIP.b4 = ((struct in_addr *)(host->h_addr))->S_un.S_un_b.s_b4;

    #ifdef WIN32
    WSACleanup();
    #endif
    return true;
}

You can also always just use 127.0.0.1 which represents the local machine always.

Subnet mask in Windows:

You can get the subnet mask (and gateway and other info) by querying subkeys of this registry entry:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces

Look for the registry value SubnetMask.

Other methods to get interface information in Windows:

You could also retrieve the information you're looking for by using: WSAIoctl with this option: SIO_GET_INTERFACE_LIST

Winsock specific:

// Init WinSock
WSADATA wsa_Data;
int wsa_ReturnCode = WSAStartup(0x101,&wsa_Data);

// Get the local hostname
char szHostName[255];
gethostname(szHostName, 255);
struct hostent *host_entry;
host_entry=gethostbyname(szHostName);
char * szLocalIP;
szLocalIP = inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list);
WSACleanup();

Also, note that "the local IP" might not be a particularly unique thing. If you are on several physical networks (wired+wireless+bluetooth, for example, or a server with lots of Ethernet cards, etc.), or have TAP/TUN interfaces setup, your machine can easily have a whole host of interfaces.

from torial: If you use winsock, here's a way: http://tangentsoft.net/wskfaq/examples/ipaddr.html

As for the subnet portion of the question; there is not platform agnostic way to retrieve the subnet mask as the POSIX socket API (which all modern operating systems implement) does not specify this. So you will have to use whatever method is available on the platform you are using.

I suggest my code.

DllExport void get_local_ips(boost::container::vector<wstring>& ips)
{
   IP_ADAPTER_ADDRESSES*       adapters  = NULL;
   IP_ADAPTER_ADDRESSES*       adapter       = NULL;
   IP_ADAPTER_UNICAST_ADDRESS* adr           = NULL;
   ULONG                       adapter_size = 0;
   ULONG                       err           = 0;
   SOCKADDR_IN*                sockaddr  = NULL;

   err = ::GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME, NULL, NULL, &adapter_size);
   adapters = (IP_ADAPTER_ADDRESSES*)malloc(adapter_size);
   err = ::GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME, NULL, adapters, &adapter_size);

   for (adapter = adapters; NULL != adapter; adapter = adapter->Next)
   {
       if (adapter->IfType     == IF_TYPE_SOFTWARE_LOOPBACK) continue; // Skip Loopback
       if (adapter->OperStatus != IfOperStatusUp) continue;            // Live connection only  

       for (adr = adapter->FirstUnicastAddress;adr != NULL; adr = adr->Next)
       {
           sockaddr = (SOCKADDR_IN*)(adr->Address.lpSockaddr);
           char    ipstr [INET6_ADDRSTRLEN] = { 0 };
           wchar_t ipwstr[INET6_ADDRSTRLEN] = { 0 };
           inet_ntop(AF_INET, &(sockaddr->sin_addr), ipstr, INET_ADDRSTRLEN);
           mbstowcs(ipwstr, ipstr, INET6_ADDRSTRLEN);
           wstring wstr(ipwstr);
           if (wstr != "0.0.0.0") ips.push_back(wstr);                      
       }
   }

   free(adapters);
   adapters = NULL; }

A modified version of this answer.
Added headers and libs.

It's also based on these pages:
GetAdaptersAddresses
IP_ADAPTER_ADDRESSES_LH
IP_ADAPTER_UNICAST_ADDRESS_LH

In short, to get an IPv4 address, you call GetAdaptersAddresses() to get the adapters, then run through the IP_ADAPTER_UNICAST_ADDRESS structures starting with FirstUnicastAddress and get the Address field to then convert it to a readable format with inet_ntop().

Prints info in the format:

[ADAPTER]: Realtek PCIe
[NAME]:    Ethernet 3
[IP]:      123.123.123.123

Can be compiled with:

cl test.cpp

or, if you need to add libs dependencies in the command line:

cl test.cpp Iphlpapi.lib ws2_32.lib
#include <winsock2.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <ws2tcpip.h>

// Link with Iphlpapi.lib and ws2_32.lib
#pragma comment(lib, "Iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")

void ListIpAddresses() {
  IP_ADAPTER_ADDRESSES* adapter_addresses(NULL);
  IP_ADAPTER_ADDRESSES* adapter(NULL);
  
  DWORD adapter_addresses_buffer_size = 16 * 1024;
  
  // Get adapter addresses
  for (int attempts = 0; attempts != 3; ++attempts) {
    adapter_addresses = (IP_ADAPTER_ADDRESSES*) malloc(adapter_addresses_buffer_size);

    DWORD error = ::GetAdaptersAddresses(AF_UNSPEC, 
      GAA_FLAG_SKIP_ANYCAST | 
        GAA_FLAG_SKIP_MULTICAST | 
        GAA_FLAG_SKIP_DNS_SERVER | 
        GAA_FLAG_SKIP_FRIENDLY_NAME,
      NULL, 
      adapter_addresses,
      &adapter_addresses_buffer_size);
    
    if (ERROR_SUCCESS == error) {
      break;
    }
    else if (ERROR_BUFFER_OVERFLOW == error) {
      // Try again with the new size
      free(adapter_addresses);
      adapter_addresses = NULL;
      continue;
    }
    else {
      // Unexpected error code - log and throw
      free(adapter_addresses);
      adapter_addresses = NULL;
      return;
    }
  }

  // Iterate through all of the adapters
  for (adapter = adapter_addresses; NULL != adapter; adapter = adapter->Next) {
    // Skip loopback adapters
    if (IF_TYPE_SOFTWARE_LOOPBACK == adapter->IfType) continue;
    
    printf("[ADAPTER]: %S\n", adapter->Description);
    printf("[NAME]:    %S\n", adapter->FriendlyName);

    // Parse all IPv4 addresses
    for (IP_ADAPTER_UNICAST_ADDRESS* address = adapter->FirstUnicastAddress; NULL != address; address = address->Next) {
      auto family = address->Address.lpSockaddr->sa_family;
      if (AF_INET == family) {
        SOCKADDR_IN* ipv4 = reinterpret_cast<SOCKADDR_IN*>(address->Address.lpSockaddr);
        char str_buffer[16] = {0};
        inet_ntop(AF_INET, &(ipv4->sin_addr), str_buffer, 16);

        printf("[IP]:      %s\n", str_buffer);
      }
    }
    printf("\n");
  }

  free(adapter_addresses);
  adapter_addresses = NULL;
}

int main() {
  ListIpAddresses();
  return 0;
}
Related