Interogarea numelor interfețelor prin SIOCGIFCONF în Linux (Programare, C, Linux, Rețea)

Parker a intrebat.

Încerc să interoghez numele dispozitivelor de rețea. Am pus laolaltă acest lucru din diverse fragmente,

  1. http://unixhelp.ed.ac.uk/CGI/man-cgi?netdevice+7
  2. http://lists.apple.com/archives/Unix-porting/2002/Apr/msg00134.html
  3. http://ubuntuforums.org/showthread.php?t=1421487

Dar ieșirea mea este doar o harababură.

#include <stdio.h>
#include <stdlib.h>
#include <net/route.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>

#define BUFLEN 1024
#define SEQ 9999

int main (int argc, const char* argv[])
{
  // File descriptor for socket
  int socketfd;
  struct ifconf conf;
  struct ifreq req[10];
  struct ifreq *ifr;

  printf("Opening socket...");
  socketfd = socket(AF_ROUTE, SOCK_RAW, 0);
  if (socketfd >= 0) {
    printf(" OK
");
    conf.ifc_len = sizeof(req);
    conf.ifc_buf = (__caddr_t) req;
    ioctl(socketfd,SIOCGIFCONF,&conf);

    printf("Discovering interfaces...
");
    int i;
    for (i=0; i<conf.ifc_len/sizeof(req[0]); i++) {
      ifr = &conf.ifc_req[i];
      printf("%d. %s
", i+1, req[i].ifr_name);
    }
  }
  else {
    printf("Failed!
");
  }
  return 0;
}

Ieșire:

Opening socket... OK
Discovering interfaces...
?u???}??Gh???
2. p?9}?
3.
4. v?=?n??u?`?y??]g?<?~?v??
5.
6.
7.
8. ?v?T?
9. ?|?mw??j??v??h??|??v?T00~??v?$?|??|[email protected]
10. T00~??v?$?|??|[email protected]

Am încercat să scot fiecare caracter din array-ul ifr_name unul câte unul pentru a vedea dacă sunt terminate cu null, dar asta nu a schimbat prea multe. Fiecare iterație a programului meu produce ceva diferit, așa că asta mă face să cred că fac referire la ceva greșit. Poate cineva să-mi ofere o idee despre ce aș putea face greșit?

Comentarii

  • Nu verificați valoarea de retur din ioctl(). Probabil că este EOPNOTSUPP, de aceea valorile din buffer nu au niciun sens. –  > Por ldx.
3 răspunsuri
user562374

Vă rugăm să consultați http://git.netfilter.org/cgi-bin/gitweb.cgi?p=libmnl.git;a=blob;f=exemple/rtnl/rtnl-link-dump.c;hb=HEAD despre cum să obțineți lista de interfețe pe Linux. AF_ROUTE este o chestie BSD, iar utilizarea ioctl este descurajată pe Linux pentru limitările sale aparente (cum ar fi pentru a transmite mai multe adrese pe o singură interfață).

Comentarii

  • Vedeți, acesta este motivul pentru care nu mi-a plăcut niciodată ca oamenii să includă link-uri în răspunsul lor. Dacă nu știi că informațiile de pe pagina web la care îi îndrumi pe cititori să meargă NU vor fi niciodată eliminate sau șterse, atunci nu include un link în răspunsul tău. Acest utilizator ar fi trebuit să copieze codul rtnl-link-dump.c chiar în răspunsul său. –  > Por ThN.
  • tl;dr; linkul este mort 🙁 – –  > Por Niko.
  • Link-urile sunt bune atâta timp cât nu sunt necesare pentru a înțelege răspunsul. Din păcate, acum că are un link mort, acest răspuns nu mai este bun. –  > Por Wayne Conrad.
  • Link fixat (deocamdată): git.netfilter.org/libmnl/tree/examples/rtnl/rtnl-link-dump.c –  > Por xOneca.
Sam Lantinga

Iată un cod pe care l-am pus laolaltă pentru Mac OS X:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <netinet/in.h>

/* This is defined on Mac OS X */
#ifndef _SIZEOF_ADDR_IFREQ
#define _SIZEOF_ADDR_IFREQ sizeof
#endif

int main (int argc, const char* argv[])
{
  // File descriptor for socket
  int socketfd;
  struct ifconf conf;
  char data[4096];
  struct ifreq *ifr;
  char addrbuf[1024];
  int i;

  printf("Opening socket...");
  socketfd = socket(AF_INET, SOCK_DGRAM, 0);
  if (socketfd >= 0) {
    printf(" OK
");
    conf.ifc_len = sizeof(data);
    conf.ifc_buf = (caddr_t) data;
    if (ioctl(socketfd,SIOCGIFCONF,&conf) < 0) {
      perror("ioctl");
    }

    printf("Discovering interfaces...
");
    i = 0;
    ifr = (struct ifreq*)data;
    while ((char*)ifr < data+conf.ifc_len) {
      switch (ifr->ifr_addr.sa_family) {
        case AF_INET:
            ++i;
            printf("%d. %s : %s
", i, ifr->ifr_name, inet_ntop(ifr->ifr_addr.sa_family, &((struct sockaddr_in*)&ifr->ifr_addr)->sin_addr, addrbuf, sizeof(addrbuf)));
            break;
#if 0
        case AF_INET6:
            ++i;
            printf("%d. %s : %s
", i, ifr->ifr_name, inet_ntop(ifr->ifr_addr.sa_family, &((struct sockaddr_in6*)&ifr->ifr_addr)->sin6_addr, addrbuf, sizeof(addrbuf)));
            break;
#endif
      }
      ifr = (struct ifreq*)((char*)ifr +_SIZEOF_ADDR_IFREQ(*ifr));
    }
    close(socketfd);
  }
  else {
    printf(" Failed!
");
  }
  return 0;
}

Comentarii

  • +1 Frumos exemplu, deși aș dori să remarc că i nu va reprezenta ifindexul real al dispozitivului, deoarece nu toate vor fi returnate dacă sunt dezactivate. Tampoanele sunt de multe ori mai mari decât ar fi logic să fie. Aveți char addrbuf[1024]; când 17 caractere sunt suficiente pentru ipv4 și 40 sunt suficiente pentru ipv6. Și sizeof ifreq este de 40 de octeți, ceea ce ar însemna că alocați spațiu pentru 102 dintre acestea, deși acest lucru ar însemna că nu trebuie să verificați mai întâi cât de mare este bufferul de care aveți nevoie. De asemenea, ați folosit o buclă while când ar trebui să folosiți o buclă for. –  > Por zoran404.
  • De asemenea, ifr = (struct ifreq*)((char*)ifr +_SIZEOF_ADDR_IFREQ(*ifr)); poate fi înlocuit cu ++ifr –  > Por zoran404.
  • Bună, pe linux, acest lucru funcționează dacă interfața are adresă ip. de exemplu, dacă eliminați partea AF_INET6, interfețele fără ipv4 nu vor apărea. –  > Por John.
Rață

Sondaj ca și cum ai vrea să fii notificat dacă o interfață este adăugată sau eliminată? Sau „polled” în sensul că vreți doar să aflați numele interfețelor o singură dată din sistem? În acest din urmă caz, aruncați o privire la getifaddrs().

Tags:, ,