Сравнение ipv4-адреса интерфейса и исходного адреса пакета (libpcap) - PullRequest
0 голосов
/ 09 октября 2019

Я использую модификацию кода C в https://www.tcpdump.org/sniffex.c для печати информации о TCP-пакетах, проходящих через интерфейс, используя libpcap.

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

// retrieve IP address of interface    
char * dev_name = "eth0";
struct ifreq ifr;
int fd;
char *dev_ip;

fd = socket(AF_INET, SOCK_DGRAM, 0);

// type of address to retrieve (IPv4)
ifr.ifr_addr.sa_family = AF_INET;

// copy the interface name in the ifreq structure
strncpy(ifr.ifr_name , dev_name , IFNAMSIZ-1);

ioctl(fd, SIOCGIFADDR, &ifr);
close(fd);

dev_ip = inet_ntoa(( (struct sockaddr_in *)&ifr.ifr_addr )->sin_addr);

printf("IPv4 address: %s\n", dev_ip);
printf("inet_ntoa: %s\n",inet_ntoa(ip->ip_src));

if (strcmp(dev_ip,inet_ntoa(ip->ip_src)) == 0)
    printf("EQUAL!\n");

Однако, как вы можете видеть на следующем скриншоте, даже если IP-адрес источника (inet_ntoa) и IP-адресадреса интерфейса (IPv4 address) различны, их значения всегда равны в зависимости от программы.

Output of program

В чем может быть проблема?

1 Ответ

1 голос
/ 10 октября 2019

inet_ntoa возвращает указатель на строку, созданную в статической памяти, которая является внутренней по отношению к inet_ntoa. Он повторно использует ту же самую статическую память каждый раз, когда она вызывается. Когда вы делаете это:

    dev_ip = inet_ntoa(...);

dev_ip устанавливается для указания на этот внутренний статический буфер. В этот момент статический буфер содержит строку, представляющую адрес интерфейса, поэтому ваш:

    printf("IPv4 address: %s\n", dev_ip);

показывает ожидаемый результат. Но затем вы делаете это:

    printf("inet_ntoa: %s\n",inet_ntoa(ip->ip_src));

и перезаписывает внутренний буфер inet_ntoa строкой, представляющей адрес пакета.

Но помните, что dev_ip все еще указывает на этот внутренний буфер. Поэтому, когда вы делаете это:

    if (strcmp(dev_ip,inet_ntoa(ip->ip_src)) == 0)

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

Чтобы исправить, либо сделайте локальную копию строки, сгенерированнойinet_ntoa сразу после вызова, путем копирования в локальный буфер или выполнения чего-то вроде:

    dev_ip = strdup(inet_ntoa(...));

(и не забывайте free(dev_ip), когда вам больше не нужна эта строка) или, что еще лучше,используйте потокобезопасный вариант inet_ntoa, называемый inet_ntoa_r, если ваша платформа имеет эту функцию. inet_ntoa_r не использует (и повторно использует) внутренний буфер. Требуется, чтобы вызывающий указывал буфер, в который будет помещена строка.

...