2010-11-09 65 views
11

假設我正在運行一個名爲IpAddresses.c的程序。我希望該程序根據每個接口獲取此設備具有的所有IP地址。就像ifconfig。我怎樣才能做到這一點?如何才能知道C中接口的IP地址?

我對ioctl瞭解不多,但我讀過它可能對我有幫助。

+3

你的平臺是什麼? – 2010-11-09 22:39:22

回答

19

只需使用getifaddrs()。這裏有一個例子:

#include <arpa/inet.h> 
#include <sys/socket.h> 
#include <ifaddrs.h> 
#include <stdio.h> 

int main() 
{ 
    struct ifaddrs *ifap, *ifa; 
    struct sockaddr_in *sa; 
    char *addr; 

    getifaddrs (&ifap); 
    for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 
     if (ifa->ifa_addr->sa_family==AF_INET) { 
      sa = (struct sockaddr_in *) ifa->ifa_addr; 
      addr = inet_ntoa(sa->sin_addr); 
      printf("Interface: %s\tAddress: %s\n", ifa->ifa_name, addr); 
     } 
    } 

    freeifaddrs(ifap); 
    return 0; 
} 

而這裏的輸出我得到我的機器上:

Interface: lo Address: 127.0.0.1 
Interface: eth0 Address: 69.72.234.7 
Interface: eth0:1  Address: 10.207.9.3 
+0

爲什麼你有2個eth0?順便說一句,thk爲您的答案 – gvalero87 2010-11-10 00:32:52

+0

@ gvalero87第一eth0告訴網卡通過互聯網進行通信。第二個eth0通過專用連接(光線路)與第三方進行通信。這是網絡管理員放在一起的路由表中的一個設置。 – chrisaycock 2010-11-10 01:33:46

0

檢查出(Windows特定IP Helper API - 幸運的是,您不需要ioctl這在Windows上。

0

你可以嘗試這樣的事情:

struct ifreq ifr[MAX_INTERFACES]; 
struct ifconf ifc; 
memset(ifr, 0, sizeof(ifr)); 
ifc.ifc_len = sizeof(ifr); 
ifc.ifc_req = ifr; 

// Get the list of interfaces 
if (ioctl(sock, SIOCGIFCONF, &ifc) == -1) { 
    fprintf(stderr, "ioctl SIOCGIFCONF failed: %d", errno); 
} 

for (int i=0; i < ifc.ifc_len/sizeof(struct ifreq); ++i) { 
    if (ifr[i].ifr_addr.sa_family != AF_INET) { 
     continue; 
    } 

    // Maybe some more filtering based on SIOCGIFFLAGS 

    // Your code 
} 
+3

請注意,此代碼將在BSD上失敗,其中ifreq結構的大小是可變的。你不能假設'ifc.ifc_len/sizeof(struct ifreq)'會給你接口的數量。相反,你需要像這樣迭代列表中的元素:struct ifreq * ifr_iterator = ifc.ireq; size_t len; while(i ifr_addr.sa_len; ifr_iterator =(struct ifreq *)((char *)ifr_iterator + len);我+ = len; }' – Joakim 2012-09-24 09:20:57

+0

@Joakim所以這意味着''#define ifc_req ifc_ifcu.ifcu_req/*結構數組ret'd * /''技術上不是一個數組,因爲大小不一樣?看來5.9增加了更多的東西。此外,ifconfig.c代碼似乎沒有SIOCGIFCONF – GorillaApe 2016-07-15 20:34:45

+0

@GorillaApe在一個系統上它可能是一個數組,另一個不是。我的觀點有不同的實現。在Linux上,這是一個數組,每個項目的大小都是固定的,但在BSD上,每個項目的大小可能會有所不同,因此正確的方法是始終使用長度字段。如果你想要的便攜式代碼。 – Joakim 2016-08-27 11:19:16

5

下面是一些Linux的示例代碼,可以幫助你。

#include <stdio.h> 
#include <net/if.h> 
#include <netinet/in.h> 
#include <sys/ioctl.h> 
#include <sys/types.h> 
#include <sys/socket.h> 

#define INT_TO_ADDR(_addr) \ 
(_addr & 0xFF), \ 
(_addr >> 8 & 0xFF), \ 
(_addr >> 16 & 0xFF), \ 
(_addr >> 24 & 0xFF) 

int main() 
{ 
    struct ifconf ifc; 
    struct ifreq ifr[10]; 
    int sd, ifc_num, addr, bcast, mask, network, i; 

    /* Create a socket so we can use ioctl on the file 
    * descriptor to retrieve the interface info. 
    */ 

    sd = socket(PF_INET, SOCK_DGRAM, 0); 
    if (sd > 0) 
    { 
     ifc.ifc_len = sizeof(ifr); 
     ifc.ifc_ifcu.ifcu_buf = (caddr_t)ifr; 

     if (ioctl(sd, SIOCGIFCONF, &ifc) == 0) 
     { 
      ifc_num = ifc.ifc_len/sizeof(struct ifreq); 
      printf("%d interfaces found\n", ifc_num); 

      for (i = 0; i < ifc_num; ++i) 
      { 
       if (ifr[i].ifr_addr.sa_family != AF_INET) 
       { 
        continue; 
       } 

       /* display the interface name */ 
       printf("%d) interface: %s\n", i+1, ifr[i].ifr_name); 

       /* Retrieve the IP address, broadcast address, and subnet mask. */ 
       if (ioctl(sd, SIOCGIFADDR, &ifr[i]) == 0) 
       { 
        addr = ((struct sockaddr_in *)(&ifr[i].ifr_addr))->sin_addr.s_addr; 
        printf("%d) address: %d.%d.%d.%d\n", i+1, INT_TO_ADDR(addr)); 
       } 
       if (ioctl(sd, SIOCGIFBRDADDR, &ifr[i]) == 0) 
       { 
        bcast = ((struct sockaddr_in *)(&ifr[i].ifr_broadaddr))->sin_addr.s_addr; 
        printf("%d) broadcast: %d.%d.%d.%d\n", i+1, INT_TO_ADDR(bcast)); 
       } 
       if (ioctl(sd, SIOCGIFNETMASK, &ifr[i]) == 0) 
       { 
        mask = ((struct sockaddr_in *)(&ifr[i].ifr_netmask))->sin_addr.s_addr; 
        printf("%d) netmask: %d.%d.%d.%d\n", i+1, INT_TO_ADDR(mask)); 
       }     

       /* Compute the current network value from the address and netmask. */ 
       network = addr & mask; 
       printf("%d) network: %d.%d.%d.%d\n", i+1, INT_TO_ADDR(network)); 
      }      
     } 

     close(sd); 
    } 

    return 0; 
} 

+0

感謝您的ioctl選擇。然而,我永遠不知道,當我應該使用'ioctl'和'getifaddrs'時。 – Youda008 2015-12-27 09:25:31

+0

我相信即使它不符合任何單一標準,'ioctl'也可能稍微更具可移植性。它在大多數Unix和類Unix系統上得到支持,並且'ioctl'函數調用首次出現在版本7 AT&T UNIX中。我相信'getifaddrs'在BSD和Linux中得到支持,並首次出現在glibc 2.3中。 – jschmier 2016-01-04 15:40:43

+0

這也適用於Android,因爲某些原因沒有'ifaddrs'的東西,但不在OS X上。[這是一個例子](https://gist.github.com/OrangeTide/909204)都。 – Grishka 2016-10-30 03:22:37

2

使用getifaddrs()解決方案是巨大的。我建議只有一個提高:

--- chrisaycock 
+++ normando 
@@ -11,7 +11,7 @@ 

    getifaddrs (&ifap); 
    for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 
-  if (ifa->ifa_addr->sa_family==AF_INET) { 
+  if (ifa->ifa_addr && ifa->ifa_addr->sa_family==AF_INET) { 
      sa = (struct sockaddr_in *) ifa->ifa_addr; 
      addr = inet_ntoa(sa->sin_addr); 
      printf("Interface: %s\tAddress: %s\n", ifa->ifa_name, addr); 

只因爲我自己得到了分割錯誤。

+0

我得到了分割錯誤。這段代碼修復了它。 – 2017-01-10 11:20:23

相關問題