2010-11-09 32 views

Répondre

19

Utilisez simplement getifaddrs(). Voici un exemple:

#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; 
} 

Et voici la sortie que je reçois sur ma machine:

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

Pourquoi avez-vous 2 eth0? btw, thnks pour votre réponse – gvalero87

+0

@ gvalero87 Le premier eth0 indique à la carte réseau de communiquer sur Internet. Ce second eth0 communique via une connexion privée (ligne optique) à un tiers. C'est un paramètre dans la table de routage que l'administrateur réseau a mis ensemble. – chrisaycock

0

Vérifiez la (Windows spécifique) IP Helper API - heureusement, vous n'avez pas besoin ioctl pour cela sur Windows.

0

Vous pouvez essayer quelque chose comme ça:

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

Notez que ce code échouera sur BSD où la taille de la structure ifreq est variable. Vous ne pouvez pas supposer que 'ifc.ifc_len/sizeof (struct ifreq)' vous donnera le nombre d'interfaces. Au lieu de cela, vous devez parcourir les éléments de la liste comme suit: 'struct ifreq * ifr_iterator = ifc.ireq; size_t len; while (i ifr_addr.sa_len; ifr_iterator = (struct ifreq *) ((char *) ifr_iterator + len); i + = len; } ' – Joakim

+0

@Joakim ce qui signifie que' '#define ifc_req ifc_ifcu.ifcu_req/* tableau de structures ret'd * /' 'techniquement n'est pas un tableau parce que la taille varie? Il semble que 5,9 ait ajouté plus de choses. Le code ifconfig.c ne semble pas avoir SIOCGIFCONF – GorillaApe

+0

@GorillaApe Sur un système, il peut s'agir d'un tableau, sur un autre non. Il y a différentes implémentations est mon point. Sous Linux, il s'agit d'un tableau dont chaque élément est de taille fixe, mais sur BSD, la taille de chaque élément peut varier, donc la manière correcte de le faire est de toujours utiliser le champ de longueur. Si vous voulez du code portable c'est. – Joakim

5

Voici quelques exemple de code Linux qui pourraient vous aider.

#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

Merci pour votre choix d'ioctl. Cependant, je ne sais jamais, quand je devrais utiliser 'ioctl' et quand' getifaddrs'. – Youda008

+0

Je crois que «ioctl» peut être un peu plus portable même s'il n'est pas conforme à une norme unique.Il est pris en charge sur la plupart des systèmes Unix et Unix et l'appel de la fonction 'ioctl' est apparu pour la première fois dans la version 7 AT & T UNIX. Je crois que 'getifaddrs' est supporté par BSD et Linux et est apparu pour la première fois dans la glibc 2.3. – jschmier

+0

Cela fonctionne également sur Android qui n'a pas la chose 'ifaddrs' pour une raison quelconque, mais ne fonctionne pas sur OS X. [Voici un exemple] (https://gist.github.com/OrangeTide/909204) qui fonctionne sur tous les deux. – Grishka

2

La solution à l'aide getifaddrs() est grande. Je suggérerais seulement un améliorer:

--- 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); 

Juste parce que j'ai moi-même eu une erreur de segmentation.

+0

J'ai une erreur de segmentation. Ce code le corrige. –