Эффективное программирование TCP-IP

       

Как работает tcpdump


Посмотрим, как работает программа t cpdump и на каком уровне протоколов она перехватывает пакеты. Как и большинство сетевых анализаторов, tcpdump состоит из двух компонент: первая работает в ядре и занимается перехватом и, возможно фильтрацией пакетов, а вторая действует в адресном пространстве пользователя и определяет интерфейс пользователя, а также выполняет форматирование и фильтрацию пакетов, если последнее не делается ядром.

Пользовательская компонента tcpdump взаимодействует с компонентой в ядре при помощи библиотеки libpcap (библиотека для перехвата пакетов), которая абстрагирует системно-зависимые детали общения с канальным уровнем стека протоколов. Например, в системах на основе BSD libpcap взаимодействует с пакетным фильтром BSD (BSD packet filter - BPF) [McCanne and Jacobson 1993]. BPF исследует каждый пакет, проходящий через канальный уровень, и сопоставляет его с фильтром, заданным пользователем. Если пакет удовлетворяет критерию фильтрации, то его копия помещается в выделенный ядром буфер, который ассоциируется с данным фильтром. Когда буфер заполняется или истекает заданный пользователем тайм-аут, содержимое буфера передается приложению с помощью libpcap.

Этот процесс изображен на рис. 4.4. Показано, как tcpdump и любая другая программа считывают необработанные пакеты с помощью BPF, а также изображено еще одно приложение, читающее данные из стека TCP/IP, как обычно.

Примечание: Хотя на этом рисунке и tcpdump, и программа используют библиотеку libpcap, можно напрямую общаться с ВРF или иным интерфейсом, о чем будет сказано ниже. Достоинство libpcap в том, что она предоставляет системно-независимые средства доступа к необработанным пакетам. В настоящее время эта библиотека поддерживает BPF; интерфейс канального провайдера (data link provider interface – DLPI); систему SunOS NIT; потоковую NIT; сокеты типа SOCK_PACKET, применяемые в системе Linux; интерфейс snoop (IRIX) и разработанный в Стэнфордском университете интерфейс enet. В дистрибутив WinDump входит также версия libpcap для Windows.


Обратите внимание, что BPF перехватывает сетевые пакеты на уровне драйвера устройства, то есть сразу после того, как они считаны с носителя. Это не то же самое что чтение из простого сокета. В ситуации с простым сокетом вы получаете IР-датаграммы, уже обработанные уровнем IP и переданные непосредственно приложению минуя транспортный уровень (TCP или UDP). Об этом рассказывается в совете 40.

Начиная с версии 2.0, архитектура WinDump очень напоминает используемую в системах BSD. Эта программа пользуется специальным NDIS-драйвером (NDIS- Network Driver Interface Specification - спецификация стандартного интерфейса сетевых адаптеров), предоставляющим совместимый с BPF фильтр и интерфейс. В архитектуре WinDump NDIS-драйвер фактически представляет собой часть стека протоколов, но функционирует он так же, как показано на рис. 4.4, только надо заменить BPF на пакетный драйвер NDIS.



Рис. 4.4. Перехват пакетов с помощью BPF

Другие операционные системы используют несколько иные механизмы. В системах, производных от SVR4, для доступа к простым сокетам применяется интерфейс DLPI [Unix International 1991]. DLPI - это не зависящий от протокола, основанный на системе STREAMS [Ritchie 1984] интерфейс к канальному уровню, С помощью DLPI можно напрямую получить доступ к канальному уровню, но по соображениям эффективности обычно вставляют в поток STREAMS-модули pfmod и bufmod. Модуль bufmod предоставляет услуги по буферизации сообщений и увеличивает эффективность за счет ограничения числа контекстных переключений, требуемых для доставки данных.

Примечание: Это аналогично чтению полного буфера из сокета вместо побайтного чтения.

Модуль pfmod - это фильтр, аналогичный BPF. Поскольку он несовместим с фильтром BPF, tcpdump вставляет этот модуль в поток, а фильтрацию выполняет в пространстве пользователя. Это не столь эффективно, как при использовании BPF, так как в пространство пользователя приходится передавать каждый пакет, даже если он не нужен программе tcpdump.

На рис. 4.5 показаны tcpdump без модуля pf mod и приложение, которое получает необработанные пакеты с использованием находящегося в ядре фильтра.



На рис. 4. 5 также представлены приложения, пользующиеся библиотекой libpcap, но, как и в случае BPF, это необязательно. Для отправки сообщений непосредственно в поток и получения их обратно можно было бы воспользоваться вызовами getmsg и putmsg. Книга [Rago 1993] - отличный источник информации о программировании системы STREAMS, DLPI и системных вызовах getmsg и putmsq. Более краткое обсуждение вопроса можно найти в главе 33 книги [Stevens 1998].



Рис. 4.5. Перехват пакетов с помощью DLPI

Наконец, есть еще и архитектура Linux. В этой системе доступ к необработанным сетевым пакетам производится через интерфейс сокетов типа SOCK_PACKET. Для использования этого простого механизма надо открыть подобный сокет, привязать к нему требуемый сетевой интерфейс, включить режим пропускания всех пакетов (promiscuous mode) и читать из сокета.

Примечание: Начиная с версии 2.2 ядра Linux, рекомендуется несколько другой интерфейс, но последняя версия libpcap по-прежнему поддерживает описанный выше.

Например, строка

s = socket( AF_INET, SOCK_PACKET, htons( ETH_P_ALL ) );

открывает сокет, предоставляющий доступ ко всем Ethernet-пакетам. В качестве третьего параметра можно также указать ЕТН_Р_IР (пакеты IP), ETH_P_IPV6 (пакеты IPv6) или ETH_P_ARP (пакеты ARP). Будем считать, что этот интерфейс аналогичен простым сокетам (SOCK_RAW), только доступ производится к канальному, а не сетевому (IP) уровню.

К сожалению, несмотря на простоту и удобство этого интерфейса, он не очень эффективен. В отличие от обычных сокетов, ядро в этом случае не осуществляет никакой буферизации, так что каждый пакет доставляется приложением сразу после поступления. Отсутствует также фильтрация на уровне ядра (если не считать параметра ЕТН_Р_* ). Поэтому фильтровать приходится на прикладном уровне, а это означает, что приложение должно получать все пакеты без исключения.


Содержание раздела