libpcap: как получить активный сетевой интерфейс (Mac OSX)

Я использую libpcap для прослушивания трафика. Я хотел бы сделать это на активном в данный момент сетевом устройстве (например, на том, которому назначен IP-адрес и т. д.). Как лучше всего это сделать? Я предполагаю, что мне нужно будет сделать следующее:

pcap_findalldevs(&alldevs, errbuf)

чтобы получить все сетевые устройства, затем выполните цикл и проверьте, какое из них активно в данный момент.


Изменить: следующая функция

(pcap_lookupnet(dev, &net, &mask, errbuf) 

возвращает сетевой адрес и маску подсети для сетевого устройства. Я провел несколько тестов с различными адаптерами Ethernet на своем компьютере, и он возвращает -1, когда я вызываю его на адаптере, который не подключен к сети. Будет ли это пуленепробиваемым способом получить активный интерфейс? Есть ли крайние случаи, которые он пропустит?


person David    schedule 05.12.2010    source источник
comment
Что, если я использую две разные сети одновременно или даже просто два адаптера, подключенных к одной сети? На самом деле я использую этот сценарий на регулярной основе, назначая адаптеры различным процессам.   -  person Jim Brissom    schedule 05.12.2010
comment
возвращаясь к ответу Адирау, если бы я запустите netstat -nr (unix), пока подключены 2 сетевых адаптера, будут ли показаны оба адаптера для маршрута по умолчанию?   -  person David    schedule 05.12.2010


Ответы (4)


API pcap для поиска интерфейсов, соответствующих некоторым пользовательским правилам, тривиален. Вы действительно можете использовать pcap_findalldevs() для взаимодействия со всеми подходящими для использования сетевыми устройствами или использовать pcap_lookupdev() для получения следующего сетевого устройства, которое вы можете использовать с pcap. Определение того, какой интерфейс вы хотите использовать со своим сниффером, может быть проблематичным (с точки зрения кода) в системах с несколькими сетевыми устройствами, и вы хотели бы определить более четкие правила для выбора такого интерфейса. Такие правила обычно определены статически (например, «активный интерфейс с установленным маршрутом по умолчанию»). Однако у вас может быть несколько маршрутов по умолчанию (подумайте о балансировке нагрузки), и здесь вы можете либо захотеть обнюхать все из них, либо (например) только интерфейс ppp. Таким образом, выбор целевого интерфейса, я бы сказал, является задачей, которая должна решаться вне сниффера, а не во время выполнения в коде сниффера.

Например:

Если под «активным интерфейсом» мы понимаем интерфейс, на котором установлен маршрут по умолчанию (здесь я предполагаю систему Linux):

ip route show 0.0.0.0/0 | awk ' { print $5 ; } ' | xargs ./sniffer

если вы хотите получить активный интерфейс с установленным маршрутом по умолчанию из вашего кода сниффера, вы предпочтете использовать netlink(7) или proc(5) (/proc/net/route), а не API поиска устройства pcap, но сложность высокий.

В заключение, логика поиска интерфейса может быть легко запрограммирована в какой-либо программе-оболочке на любой системе, а результат(ы) передается в качестве параметра(ов) вашему анализатору.

person user237419    schedule 05.12.2010
comment
Я обновил свой вопрос, будет ли достаточно pcap_lookupnet? В идеале я хотел бы проверить в коде сниффера. - person David; 05.12.2010
comment
если вы используете pcap_findalldevs() для перебора всех интерфейсов, вам не нужен pcap_lookupnet() для получения информации ipv4 на каждом устройстве, возвращенном первым. эта информация содержится в информации об устройствах, возвращаемой функцией pcap_findalldevs(). опять же, это действительно зависит от того, что вы понимаете под активным интерфейсом. если это просто любой интерфейс, который работает и имеет настроенный адрес ipv4, то да. мне не ясно, что pcap_lookupnet() вернет в некоторых системах (например, FreeBSD), если несколько псевдонимов загружены на один и тот же интерфейс (без виртуальных интерфейсов, скорее всего, будет возвращен первый ip) - person user237419; 05.12.2010

Почему вы не записываете на «любое» устройство (псевдоустройство, которое записывает на всех интерфейсах)?

В любом случае, вот небольшой фрагмент, который поможет вам найти «активные» интерфейсы.

#include <stdio.h>
#include <pcap.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

static void
dump_addresses (pcap_addr_t *addresses)
{
 pcap_addr_t *addr = addresses;
 printf("(");
 while (addr) {
  struct sockaddr_in *ip = (struct sockaddr_in *)addr->addr;
  struct sockaddr_in *nm = (struct sockaddr_in *)addr->netmask;
  if (ip && nm)
   printf("%s/%s ",
     inet_ntoa(ip->sin_addr), inet_ntoa(nm->sin_addr));
  addr = addr->next;
 }
 printf(")");
}

static void
devs_dump (pcap_if_t *devs)
{
 pcap_if_t *dev = devs;
 while (dev) {
  printf("dev: %s - %s - ",
    dev->name, dev->description);
  dump_addresses(dev->addresses);
  printf("\n");
  dev = dev->next;
 }
}

int
main(int argc, char *argv[])
{
 int r;
 char errbuf[PCAP_ERRBUF_SIZE];
 pcap_if_t *devs;

 r = pcap_findalldevs (&devs, errbuf);
 if (r) {
  printf("Findalldevs: %d (%s)\n", r, errbuf);
  return -1;
 }
 devs_dump(devs);
 pcap_freealldevs (devs);

 return 0;
}
person gchain    schedule 05.12.2010
comment
Существуют ли значительные накладные расходы, связанные с захватом на всех устройствах? Я бы хотел, чтобы сниффер работал в фоновом режиме с минимальным использованием ресурсов. Я спрашиваю, потому что читал, что единственный способ прослушивания на всех устройствах — это прослушивание каждого сетевого интерфейса в отдельном потоке. Это правда? - person David; 05.12.2010
comment
Я думаю, что более эффективно захватывать «любой», а не eth{0,1...N} - person gchain; 05.12.2010
comment
Как бы вы захватили на любой; устройство? - person David; 05.12.2010
comment
Можете ли вы уточнить? любое не является поддерживаемым ключевым словом. pcap_open_live(любой, SNAP_LEN, 1, 1000, errbuf) выдает ошибку не удалось открыть устройство любое - person David; 06.12.2010
comment
Согласно моему комментарию к другому ответу, любой работает только в Linux и, с поставляемым системой libpcap, в OS X Mavericks и более поздних версиях. - person ; 11.12.2014

Я несколько раз шел по этому пути и обычно возвращаюсь к добавлению переключателя -i, чтобы пользователь мог точно идентифицировать интерфейс.

Это упрощает вашу работу и позволяет избежать любых граничных условий.

person J.J.    schedule 05.12.2010

Согласно pcap_open_live (3):

DESCRIPTION
pcap_open_live() is used to obtain a packet capture handle to
   look at packets on the network.   device  is  a  string  that
   specifies  the  network device to open; on Linux systems with
   2.2 or later kernels, a device argument of "any" or NULL  can
   be used to capture packets from all interfaces.

Но кажется, что сейчас это устарело, вы должны использовать pcap_create(3)

person gchain    schedule 08.12.2010
comment
Извините, я забыл упомянуть, что делаю это на OS X. Это было бы очень удобно! - person David; 08.12.2010
comment
pcap_create() также поддерживает любое устройство, но как в pcap_open_live(), так и в pcap_create() оно поддерживается только в Linux и OS X Mavericks или более поздних версиях, и только системная libpcap (не версия с tcpdump.org) поддерживает любое устройство на OS X Mavericks и более поздних версиях. - person ; 11.12.2014