libpcap: как получить активный сетевой интерфейс (Mac OSX)
Я использую libpcap для отслеживания трафика. Я хотел бы сделать это на Активном в данный момент сетевом устройстве (например, имеющем назначенный IP-адрес и т. д.). Как лучше всего это сделать? Я предполагаю, что мне придется сделать следующее:
pcap_findalldevs(&alldevs, errbuf)
Чтобы получить все сетевые устройства, затем выполните цикл и проверьте, какое из них в данный момент активно.
Edit: следующая функция
(pcap_lookupnet(dev, &net, &mask, errbuf)
Возвращает сетевой адрес и маску подсети для сетевого устройства. Я провел несколько тестов с различные адаптеры ethernet на моем компьютере, и он возвращает -1, когда я вызываю его на адаптере, который не подключен к сети. Будет ли это пуленепробиваемым способом получить активный интерфейс? Есть ли какие-то крайние случаи, которые он пропустит?
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, но сложность высока.
В заключение, логика поиска интерфейса может быть легко запрограммирована в некоторую программу-оболочку на любой системе, и результат(ы) передается в качестве параметра(ов) вашему снифферу.
Почему вы не захватываете на "любом" устройстве (псевдо-устройстве, которое захватывает на всех интерфейсах)?
В любом случае, вот небольшой фрагмент, который поможет вам найти "активные" интерфейсы
#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; }
Я уже несколько раз проходил по этому пути и обычно возвращаюсь к добавлению переключателя
-i
, чтобы позволить пользователю точно идентифицировать интерфейс.Это упрощает вашу работу и позволяет избежать любых граничных условий.
Согласно 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)