79 Signal(SIGINT, cleanup);
80 Signal(SIGHUP, cleanup);
81 test_udp();
82 cleanup(0);
83 }
Обработка имени узла и порта получателя, затем локального имени узла и порта
46-49
Мы убеждаемся, что остается ровно два аргумента командной строки: имя узла получателя и название службы. Мы вызываем функцию host_serv
для преобразования их в структуру адреса сокета, указатель на которую мы сохраняем в переменной dest
.
Обработка локального имени и порта
50-74
Если в командной строке был указан соответствующий параметр, мы преобразуем имя локального узла и номер порта, сохраняя указатель на структуру адреса сокета под именем local
. В противном случае для определения локального IP-адреса мы подключаемся через дейтаграммный сокет к нужному адресату и сохраняем полученный при этом локальный адрес под тем же именем local
. Поскольку мы формируем собственные заголовки IP и UDP, мы должны знать IP-адрес отправителя при записи дейтаграммы UDP. Нельзя оставить адрес нулевым и предоставить уровню IP выбрать его самостоятельно, потому что адрес является частью псевдозаголовка UDP (о котором мы вскоре расскажем), используемого при вычислении контрольной суммы UDP.
Создаем символьный сокет и открываем устройство для захвата пакетов
75-76
Функция open_output
выбирает метод отправки пакетов (символьный сокет или libnet
). Функция open_pcap
открывает устройство захвата пакетов. Она будет рассмотрена далее.
Изменение прав и установка обработчиков сигналов
77-80
Для создания символьного сокета необходимо иметь права привилегированного пользователя. Обычно такие привилегии нужны нам для того, чтобы открыть устройство для захвата пакетов, но это зависит от реализации. Например, в случае BPF администратор может установить разрешения для устройств /dev/bpf
любым способом в зависимости от того, что требуется для данной системы. Здесь мы не используем эти дополнительные разрешения, предполагая, что для файла программы установлен бит SUID. Процесс выполняется с правами привилегированного пользователя, а когда они становятся не нужны, при вызове функции setuid фактический идентификатор пользователя (real user ID), эффективный идентификатор пользователя (effective user ID) и сохраненный SUID принимают значение фактического идентификатора пользователя ( getuid
). Мы устанавливаем обработчики сигналов на тот случай, если пользователь завершит программу раньше, чем будут изменены права.
Выполнение теста и очистка
81-82
Функция test_udp
(см. листинг 29.6) выполняет тестирование и возвращает управление. Функция cleanup
(см. листинг 29.14) выводит итоговую статистику библиотеки захвата пакетов, а затем завершает процесс.
В листинге 29.5 показана функция open_pcap
, которую мы вызвали из функции main
, чтобы открыть устройство для захвата пакетов.
Листинг 29.5. Функция open_pcap: открытие и инициализация устройства для захвата пакетов
//udpcksum/pcap.c
1 #include "udpcksum.h"
2 #define CMD "udp and src host %s and src port %d"
3 void
4 open_pcap(void)
5 {
6 uint32_t localnet, netmask;
7 char cmd[MAXLINE], errbuf[PCAP_ERRBUF_SIZE], strl[INET_ADDRSTRLEN],
8 str2[INET_ADDRSTRLEN];
9 struct bpf_program fcode;
10 if (device == NULL) {
11 if ((device = pcap_lookupdev(errbuf)) == NULL)
12 err_quit("pcap_lookup: %s", errbuf);
13 }
14 printf("device = %s\n", device);
15 /* жестко задано; promisc=0, to_ms=500 */
16 if ((pd = pcap_open_live(device, snaplen, 0, 500, errbuf)) == NULL)
17 err_quit("pcap_open_live: %s", errbuf);
18 if (pcap_lookupnet(device, &localnet, &netmask, errbuf)
19 err_quit("pcap_lookupnet %s", errbuf);
20 if (verbose)
21 printf("localnet = %s, netmask = %s\n",
22 Inet_ntop(AF_INET, &localnet, str1, sizeof(str1)),
23 Inet_ntop(AF_INET, &netmask. str2, sizeof(str2)));
24 snprintf(cmd, sizeof(cmd), CMD,
25 Sock_ntop_host(dest, destlen),
26 ntohs(sock_get_port(dest, destlen)));
27 if (verbose)
28 printf("cmd = %s\n", cmd);
29 if (pcap_compile(pd, &fcode, cmd, 0, netmask)
30 err_quit("pcap_compile: %s", pcap_geterr(pd));
31 if (pcap_setfilter(pd, &fcode)
32 err_quit("pcap_setfilter: %s", pcap_geterr(pd));
33 if ((datalink = pcap_datalink(pd))
34 err_quit("pcap_datalink: %s", pcap_geterr(pd));
35 if (verbose)
36 printf("datalink = %d\n", datalink);
37 }
Выбор устройства для захвата пакетов
10-14
Если устройство для захвата пакетов не было задано (с помощью параметра командной строки -i
), то выбор этого устройства осуществляется с помощью функции pcap_lookupdev
. С помощью запроса SIOCGIFCONF
функции ioctl
выбирается включенное устройство с минимальным порядковым номером, но только не устройство обратной связи. Многие из библиотечных функций pcap
возвращают сообщения об ошибках в виде строк. Единственным аргументом функции pcap_lookupdev
является массив, в который записывается строка с сообщением об ошибке.
Читать дальше
Конец ознакомительного отрывка
Купить книгу