UNIX: разработка сетевых приложений
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) < 0)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) < 0)30 err_quit("pcap_compile: %s", pcap_geterr(pd));31 if (pcap_setfilter(pd, &fcode) < 0)32 err_quit("pcap_setfilter: %s", pcap_geterr(pd));33 if ((datalink = pcap_datalink(pd)) < 0)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Открываем устройствоФункция15-17открывает устройство. Словоpcap_open_liveприсутствует в названии функции потому, что здесь имеется в виду фактическое устройство для захвата пакетов, а не файл, содержащий предыдущие сохраненные пакеты. Первым аргументом функции является имя устройства, вторым — количество байтов, которое нужно сохранять для каждого пакета (значениеlive, которое мы инициализировали числом 200 в листинге 29.2), а третий аргумент — это флаг, указывающий на смешанный режим. Четвертый аргумент — это значение времени ожидания в миллисекундах, а пятый — указатель на массив, содержащий сообщения об ошибках.shaplenЕсли установлен флаг смешанного режима, интерфейс переходит в этот режим, в результате чего он принимает все пакеты, проходящие по кабелю. Это обычное состояние программы
. Тем не менее в нашем примере ответы сервера DNS будут посланы непосредственно на наш узел (то есть можно обойтись без смешанного режима).tcpdumpЧетвертый аргумент — время ожидания при считывании. Вместо того чтобы возвращать пакет процессу каждый раз, когда приходит очередной пакет (что может быть весьма неэффективно, так как в этом случае потребуется выполнять множество операций копирования отдельных пакетов из ядра в процесс), это делается, когда считывающий буфер устройства оказывается заполненным либо когда истекает время ожидания. Если время ожидания при считывании равно нулю, то каждый пакет будет переправляться процессу, как только будет получен.
Получение сетевого адреса и маски подсетиФункция18-23возвращает сетевой адрес и маску подсети для устройства захвата пакетов. При вызове функцииpcap_lookupnet, которая будет вызвана следующей, нужно задать маску подсети, поскольку с помощью маски фильтр пакетов определяет, является ли IP-адрес адресом широковещательной передачи для данной подсети.pcap_compileКомпиляция фильтра пакетовФункция24-30получает строку, построенную нами как массивpcap_compile, и компилирует ее, создавая тем самым программу для фильтрации (записывая ее вcmd). Эта программа будет отбирать те пакеты, которые мы хотим получить.fcodeЗагрузка программы фильтрацииФункция31-32получает только что скомпилированную программу фильтрации и загружает ее в устройство для захвата пакетов. Таким образом инициируется захват пакетов, выбранных нами путем настройки фильтра.pcap_setfilterОпределение типа канального уровняФункция33-36возвращает тип канального уровня для устройства захвата пакетов. Эта информация нужна нам при захвате пакетов для того, чтобы определить размер заголовка канального уровня, который будет добавлен в начало каждого считываемого нами пакета (см. листинг 29.10).pcap_datalinkПосле вызова функции
функция main вызывает функциюopen_pcap, показанную в листинге 29.6. Эта функция посылает запрос DNS и считывает ответ сервера.test_udp