Способы задания параметров фильтра

Для создания фильтра, необходимо составить его текстовое описание и затем использовать текстовую строку с параметрами фильтра в качестве одного из аргументов функции pcap_compile(). Текстовое описание фильтра обусловливается правилами, принятыми для описания фильтра в программе TCPDUMP и ее Win32-версии WinDUMP, включенную в состав дистрибутива WinPCap. Рассмотрим способы задания программы-фильтра.

В текстовом виде фильтр выглядит как выражение, состоящее из одного или нескольких примитивов. Примитивы в выражении определяют возможность приема фильтром входящего пакета. Каждый примитив определяет конкретный элемент пакета протокола стандартной структуры и его значение, сравниваемое фильтром со значением соответствующего элемента входящего пакета. Если значение примитива совпадает со значением элемента пакета, фильтр отмечает его как «логическую истину» (True) и переходит к сравнению следующего примитива. При совпадении всех значений выражения со значениями проверенных элементов пакета фильтр принимает решение о приеме данного пакета, в противном случае входящий пакет игнорируется.

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

type определяет тип имени или номера идентификатора. Возможные значения: host (хост), net (сеть), port (порт) или proto (протокол). Например: ‘host foo’, ‘net 128.3’, ‘port 20’. Если квалификатор отсутствует, по умолчанию принимается host.

dir определяет возможное направление приема и передачи данных объектом, указанным в качестве идентификатора: к нему и/или от него. Допускается указание следующих значений: src (источник), dst (приемник), src and dst (источник и приемник), src or dst (источник или приемник). Например: ‘src host foo’, ‘dst net 128.3’, ‘src or dst port ftp-data’. Если квалификатор не указан, по умолчанию принимается src or dst.

proto определяет тип протокола, используемого объектом, указанным в качестве идентификатора. Возможные значения: ether, fddi, ip, arp, rarp, decnet, lat, sca, moprc, mopdl, tcp и udp. Например: ‘ether src foo’, ‘arp net 128.3’, ‘tcp port 21’. При отсутствии квалификатора значение по умолчанию выбирается по максимальному соответствию указанному идентификатору. Например, ‘src foo’ означает ‘(ip, arp или rarp) src foo’, ‘net bar’ означает ‘(ip, arp или rarp) net bar’, ‘port 53’ означает ‘(tcp или udp) port 53’.

Общие выражения строятся путем объединения примитивов при помощи логических операторов and (&&), or (||) и not (!). Например: ‘host foo and not port ftp and not port ftp-data’. В целях экономии занимаемого строкой объема памяти одинаковые квалификаторы могут не указываться. Например, ‘tcp dst port ftp or ftp-data or domain’ означает то же самое, что и ‘tcp dst port ftp or tcp dst port ftp-data or tcp dst port domain’.

Родственные группы примитивов могут объединяться с помощью тех же логических операторов. Например, tcp and (port ftp or ftp-data). Однако при объединении следует учесть, что операция отрицания имеет высший приоритет, а операции «И» и «ИЛИ» имеют одинаковый приоритет.

Ниже перечислены примеры примитивов, которые можно использовать при построении выражений фильтра:

dst host хост True, если поле IP-пакета «адрес приемника» совпадает со значением идентификатора host (может указываться имя или адрес хоста).

ether host хост True, если поле «источник» или «приемник» ethernet-кадра совпадает со значением идентификатора host (при этом имя или адрес хоста указывается в формате, определяемом квалификатором, в данном случае – ethernet).

ip proto протокол True, если IP-пакет соответствует указанному типу протокола (может указываться номер или имя соответствующего протокола: icmp, igrp, udp, nd или tcp).

При отборе пакетов определенного протокола имя протокола можно указывать без соответствующих квалификаторов ether или ip. Например, вместо ether proto arp можно указать arp, или вместо ip proto tcp можно указать tcp.

В дополнение к перечисленному выше, имеется еще несколько специальных примитивов, состоящих из одного ключевого слова:

gateway (шлюз) Используется следующим образом: gateway хост. Эквивалентное выражение для данного примитива выглядит так: ether host хост and not host хост. Фактически это означает, что хост является шлюзом, поскольку ethernet-адрес в пакете совпадает с адресом хост, однако в IP-заголовке адрес хост отсутствует.

mask (маска) Используется совместно с квалификатором net для задания сетевой маски. Например, net сеть mask маска означает отбор пакетов, IP-адрес которых удовлетворяет заданной маске.

broadcast (широковещательный адрес), multicast (групповой адрес) Используется совместно с квалификаторами ip и ehter для определения широковещательных и групповых пакетов. Например: ether broadcast, ip multicast.

less (меньше), greater (больше) Используется для отбора пакетов определенной длины. В качестве идентификатора указывается длина пакета. Например, выражение less 520 означает, что будут приняты все пакеты, длина которых не превышает 520 байт.

Кроме этого, имеется возможность отбора пакетов путем проверки отдельных байт и даже бит независимо от того, где они находятся – в заголовке, данных или концевике пакета. Для этого предусмотрен специальный математический примитив:

expr relop expr True, если математическое выражение истинно. relop это один из символов >, <, >=, =<, =,!=, а expr – выражение, составленное из целочисленных констант по правилам синтаксиса языка С, нормальных двоичных операторов [+, -, *, /, &, | ], оператора длины len и специальных выражений для доступа к данным пакета.

Для доступа к данным пакета используется следующее выражение:

proto [expr:size] Proto - это один из следующих протоколов: ip, ether, fddi, arp, rarp, tcp, udp, icmp. Эта переменная определяет уровень протокола для операции индексации. Переменная expr определяет смещение в байтах применительно к указанному протоколу. Переменная size определяет размер поля, применительно к которому будет выполнена дальнейшая операция сравнения. Эта переменная может принимать значения 1, 2 или 4. Если она не указана, по умолчанию выбирается значение 1. Оператор len дает длину всего пакета.

Например, выражение ether[0]&1!= 0 позволяет перехватывать весь групповой трафик. Выражение ip[0]&0xf!= 5 означает отбор IP-пакетов с наличием опций, а выражение ip[6:2]&0x1fff = 0 отбирает только не фрагментированные дейтаграммы.

Приведем несколько примеров выражений для описания фильтра:

host sundown – принимать все пакеты от хоста с именем sundown

host helios and (hot or ace) – перехватывать трафик между хостами helios и hot и helios и ace

ip host helios and not ace – перехватывать трафик между хостом helios и всеми хостами, исключая ace

gateway snup and (port ftp or ftp-data) – перехватывать весь ftp-трафик, проходящий через шлюз snup

tcp[13]&3!= 0 and not src and dst net localnet – принимать только TCP SYN и FIN пакеты, не предназначенные локальному хосту localnet и не отправленные им.

7. Отличия библиотеки Winpcap от библиотеки libpcap.

Архитектура PCAP изначально разрабатывалась для операционных систем с открытым исходным кодом. Закрытые коммерческие операционные системы остались без внимания разработчиков. Этот факт явился одной из причин, из-за которых практически все более-менее серьезные сетевые приложения написаны для UNIX, Linux, BSD и т.д. Windows в этом плане заметно отставала.

Однако программирование приложений на языках высокого уровня под Windows – процесс куда более приятный, чем под той же Linux. Удобство отладки, наличие удобной системы помощи, быстрая разработка приложений и визуальных интерфейсов и масса других положительных качеств средств разработки приложений (Delphi, C++ Builder, Visual Studio) и отсутствие возможности низкоуровневого управления сетевым интерфейсом привели к возникновению необходимости создания архитектуры, аналогичной PCAP, для семейства ОС Windows. Естественно, разработчики архитектуры WinPCAP не стали изобретать велосипед, а адаптировали существующую архитектуру PCAP для ОС Windows.

Процесс переноса PCAP на Windows заключался в адаптации pcap-драйвера и библиотеки libpcap для работы под Win32. Оригинальная версия libpcap написана на языке C с учетом возможности переноса библиотеки на различные версии UNIX. ОС Windows не поддерживает всех вызовов POSIX-систем, однако предоставляет некоторые аналогичные им функции через API. Модели памяти UNIX и Windows одинаковы (Windows и большинство UNIX являются 32-х битными ОС) и имеют аналогичный размер целых чисел.

Версия PCAP для Win32 основана на драйвере захвата пакетов, структура и принцип действия которого аналогичен его предшественнику для UNIX. Это значительно облегчает процесс переноса приложений с одной ОС на другую. Библиотеки и функции ОС UNIX, отсутствующие в Windows (например, getnetbyname) и необходимые для компиляции libpcap на Windows-машине, разработчикам пришлось включить в исходный код драйвера (директория Win32-Include дистрибутива).

Часть исходного кода, отвечающая за взаимодействие с сетевым адаптером, была изменена для поддержки его NDIS-драйвера. В соответствии с обозначениями, принятыми в оригинальной версии libpcap, исходный код для взаимодействия с драйвером находится в наборе файлов pcap-XXX.c (и соответствующий ему pcap-XXX.h), где XXX – указывает на операционную систему (например, pcap-linux.c). К уже существующим файлам были добавлены pcap-win32.c и pcap-win32.h.

Основному изменению подвергся принцип взаимодействия приложения пользователя с драйвером захвата пакетов. Libpcap для Win32 взаимодействует с аппаратным обеспечением через интерфейс, предоставляемый динамической библиотекой packet.dll (в отличие от Windows, в ОС UNIX сетевой адаптер или модем «виден» как стандартный файл, поэтому нет необходимости в использовании промежуточных библиотек – достаточно просто создать пакет необходимой структуры и записать его в этот файл). Это не влияет на нормальную работу libpcap, однако может создать определенные проблемы программисту, желающему получить доступ непосредственно к драйверу захвата пакетов. Например, в ОС UNIX возможно использовать системный вызов SELECT для того, чтобы узнать, поступил ли пакет на вход адаптера. В ОС Windows такая возможность отсутствует.

Программист может использовать функции libpcap для обеспечения работоспособности исходного кода приложения на различных операционных системах, но при этом возможности приложения будут ограничены (например, libpcap не позволяет отправлять пакеты через сетевой интерфейс). Если программист решит воспользоваться функциями packet.dll, то его приложение будет работать только под управлением ОС семейства Win32, однако при этом возможности приложения будут практически неограниченными.

Для обеспечения максимальной совместимости исходного кода libpcap различных ОС часть кода, предназначенная для ОС Windows, отделена от остального кода директивами #ifdef и #ifndef. Например:

#ifdef WIN32

/* исходный код для Windows */

#endif

Это позволяет компилировать исходный код libpcap как на ОС Windows, так и на UNIX.

8. Каркас приложения для прослушивания сети на основе библиотеки libpcap.

#include <pcap.h>

#include <stdio.h>

int main(int argc, char *argv[])

{

pcap_t *handle;/* Session handle */

char *dev;/* The device to sniff on */

char errbuf[PCAP_ERRBUF_SIZE];/* Error string */

struct bpf_program fp;/* The compiled filter */

char filter_exp[] = "port 23";/* The filter expression */

bpf_u_int32 mask;/* Our netmask */

bpf_u_int32 net;/* Our IP */

struct pcap_pkthdr header;/* The header that pcap gives us */

const u_char *packet;/* The actual packet */

/* Define the device */

dev = pcap_lookupdev(errbuf);

if (dev == NULL) {

fprintf(stderr, "Couldn't find default device: %s\n", errbuf);

return(2);

}

/* Find the properties for the device */

if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {

fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf);

net = 0;

mask = 0;

}

/* Open the session in promiscuous mode */

handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);

if (handle == NULL) {

fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);

return(2);

}

/* Compile and apply the filter */

if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {

fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));

return(2);

}

if (pcap_setfilter(handle, &fp) == -1) {

fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));

return(2);

}

/* Grab a packet */

packet = pcap_next(handle, &header);

/* Print its length */

printf("Jacked a packet with length of [%d]\n", header.len);

/* And close the session */

pcap_close(handle);

return(0);

}

9. Программирование сокетов. Функции локального управления.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: