Фильтры сокета

Фильтр сокета является фильтром, связанным с определенным сокетом, как показано на рисунке 4-1. Эти расширения могут отфильтровать входящий или исходящий трафик на сокете. Они также могут отфильтровать внеполосную коммуникацию, включая вызовы к setsockopt, getsockopt, ioctl, connect, listen, и bind.

  Сокет рисунка 4-1 просачивается Сетевой стек
Socket filters in the Networking Stack

Фильтры сокета могут работать в одном из двух режимов: программируемый или глобальный. Глобальный фильтр автоматически включен для новых сокетов типа, указанного для фильтра. Программируемый фильтр включен только под программным управлением при помощи setsockopt на определенном сокете. (В самом коде единственная разница между глобальной переменной и программируемыми фильтрами то, ли флаг SFLT_GLOBAL или SFLT_PROG был установлен в фильтре sf_flags поле.)

Когда KEXT вызывает sock_socket или приложение вызывает socket для создания сокета любые глобальные фильтры, связанные с соответствующим протоколом, присоединены к структуре сокета. В зависимости от того, фильтрует ли фильтр входящие или исходящие данные, он изменит данные или непосредственно перед тем, как входящие данные хранятся в буфер сокета или сразу после того, как исходящие данные получены от того буфера ядром.

Поочередно, приложение может вызвать setsockopt использование опции сокета SO_NKE вставить программируемый фильтр в цепочку фильтра того сокета, следующим образом:

setsockopt(s, SOL_SOCKET, SO_NKE, &so_nke, sizeof (struct so_nke);

so_nke структура определяется следующим образом:

struct so_nke {
    unsigned int nke_handle;
    unsigned int nke_where;
    int nke_flags;
};

Значения nke_where и nke_flags проигнорированы. Эти поля сохраняются только для совместимости.

nke_handle указывает фильтр, который будет соединен с сокетом. Это - задача программиста определить местоположение KEXT, содержащего надлежащий фильтр и удостовериться, что это загружается.

nke_handle значения присваиваются Apple Computer от того же пространства имен как тип и коды создателя, используемые в Mac OS 8 и Mac OS 9 и использование того же регистрационного механизма.

Однако можно также использовать механизм выделения идентификатора события ядра для получения значения уникального дескриптора для фильтра сокета. Приложение пространства пользователя может тогда использовать SIOCGKEVVENDOR ioctl на событии ядра снабжают сокетом для определения динамического значения дескриптора для данного фильтра сокета. Этот механизм описан в Использовании kern_event API для Уведомлений Ядра.

Создание фильтра сокета

Жизненному циклу фильтра сокета можно подвести итог следующим образом:

Как часть вызова к sflt_register, Ваш KEXT передает в a struct sflt_filter объект. Эта структура содержит много полей, содержащих различные обратные вызовы и флаги, связанные с Вашим фильтром.

Каждый фильтр сокета содержит много обратных вызовов (указатели функции). Эти обратные вызовы вызывают автоматически когда соответствие socket функции вызваны. Обратные вызовы разрешают фильтру выборочно прерывать операции сокета.

Например, прототип для sf_bind_func похож на это:

int (*sf_bind_func)(void *cookie, socket_t so, const struct sockaddr *to);

Ядро sobind вызовы функции фильтр sf_bind_func обратный вызов со значением cookie, что фильтр sf_attach_func обратный вызов возвратился, когда фильтр был сначала присоединен, вместе с экземпляром сокета (so) и имя локальной связываемой конечной точки (to).

Большинство этих обратных вызовов может возвратить целочисленное значение (за исключением detach и notify, которые, как предполагается, всегда успешно выполняются). Возвращаемое значение нуля интерпретируется, чтобы означать, что вызывающая сторона должна продолжать обрабатывать, как обычно. Ненулевое возвращаемое значение интерпретируется как ошибка (как определено в <sys/errno.h>) это заставляет обработку пакета или работы сокета останавливаться; ошибка тогда распространяет через штабель.

Одно исключение является возвращаемым значением EJUSTRETURN. Если Вы возвращаете это значение, функция вызова (например, sobind) возвраты в той точке со значением нуля (никакая ошибка). Таким образом фильтр может «глотать» пакет или работу. Фильтр может повторно ввести данные или работу в более позднее время. Для других ненулевых возвращаемых значений функция вызова возвращает ненулевой код ошибки.

Когда любой фильтр будет глотать и повторно вводит пакет или работу, он должен ожидать, что соответствующая функция фильтра будет вызвана снова на введенных данных или работе. Это может произойти многократно — каждый раз, когда пакет глотают и повторно вводят.

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

Для использования тегирования mbuf необходимо сначала установить идентификатор тега для KEXT в его подпрограмме запуска использование mbuf_tag_id_find функция Затем при записи в Ваш sf_data_in_func обратный вызов, используйте mbuf_tag_find функция, чтобы видеть, тегировал ли Ваш фильтр уже этот пакет. В противном случае это должно обработать пакет. Иначе, Ваша функция фильтра должна возвратиться 0 сразу.

Как только Вы закончили обрабатывать пакет, необходимо вызвать mbuf_tag_allocate на заголовке пакета mbuf для тегирования пакета, указывая, что Вы уже обработали его. Когда mbuf будет позже освобожден, любые ссылки тега будут также освобождены.

tcplognke выборка обеспечивает пример того, как должным образом глотать и повторно ввести пакеты.

Пример Фильтра сокета: tcplognke

tcplognke фильтр является фильтром сокета, вызывающимся для каждого сокета TCP. Это записывает подробную информацию о каждом соединении, включая число байтов, отправленных в и от системы, время, на которое соединение возросло, и удаленный IP-адрес.

tcplog утилита демонстрирует использование PF_SYSTEM сокет, чтобы позволить/запретить войти в систему tcplognke, считать информации журнала из фильтра и указать различные критерии журналирования.

Когда tcplognke загружается и инициализируется, это устанавливает себя как глобальный фильтр для протокола TCP и регистрирует управление ядром. tcplognke фильтр тогда сохраняет буфер записей соединения. Если никакая управляющая программа не присоединяет к нему, буфер постоянно перезаписывается, поскольку соединения установлены и завершены. Сохранить или просмотреть информацию что tcplognke фильтр собирается, используйте вложенное tcplog утилита командной строки. Инструмент конфигурирует tcplognke фильтр для отправки записей журнала в tcplog программа. tcplog инструмент тогда циклы, выводя на экран и пишущий записи журнала как tcplognke фильтр создает их.

Исходный код для tcplognke фильтр и для tcplog утилита командной строки доступна от веб-сайта примера кода ADC. Посмотрите Чтение Меня файл с tcplognke примером кода для большего количества инструкций на проекте и использовании демонстрационного KEXT.