Книга: UNIX: разработка сетевых приложений
29.4. Linux: SOCK_PACKET и PF_PACKET
29.4. Linux: SOCK_PACKET и PF_PACKET
Существует два метода получения пакетов канального уровня в Linux. Первоначальный метод получил более широкое распространение, но является менее гибким. Он состоит в создании сокета типа SOCK_PACKET
. Новый метод, предоставляющий больше возможностей для настройки фильтров и оптимизации производительности, состоит в создании сокета семейства PF_PACKET
. В любом случае мы должны обладать правами привилегированного пользователя (аналогичные необходимым для создания символьного сокета), а третий аргумент функции socket должен быть ненулевым значением, задающим тип кадра Ethernet. При использовании сокетов PF_PACKET
второй аргумент socket
может быть константой SOCK_DGRAM
(для получения обработанных пакетов без заголовка канального уровня) или SOCK_RAW
(для получения пакетов целиком). Сокеты SOCK_PACKET
передают пакеты только целиком. Например, для получения всех кадров канального уровня мы пишем:
fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); /* в новых системах */
или
fd = socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL)); /* в старых системах */
В результате этого будут возвращены кадры для всех протоколов, получаемые канальным уровнем. Если нам нужны кадры IPv4, то вызов будет таким:
fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP)); /* в новых системах */
fd = socket(AF_INET, SOCK_PACKET, htons(ETH_P_IP)); /* в старых системах */
Другие константы, которые могут использоваться в качестве последнего аргумента, — это, например, ETH_P_ARP
и ETH_P_IPV6
.
Указывая протокол ETH_P_ххх
, мы тем самым сообщаем канальному уровню, какой тип из получаемых канальным уровнем кадров передавать сокету. Если канальный уровень поддерживает смешанный режим (например, Ehternet), то устройство тоже должно работать в смешанном режиме. Это осуществляется при помощи параметра сокета PACKET_ADD_MEMBERSHIP
с использованием структуры packet_mreq
. При этом необходимо указать конкретный интерфейс и задать тип действия PACKET_MR_PROMISC
. В старых системах для этого нужно вызвать функцию ioctl
с запросом SIOCGIFFLAGS
для получения флагов, установить флаг IFF_PROMISC
и далее сохранить флаги с помощью SIOCSIFFLAGS
. К сожалению, при использовании этого метода программы, работающие в смешанном режиме, могут мешать друг другу, а если в одной из них содержатся ошибки, то она может и не отключить смешанный режим по завершении.
Сравнивая это средство Linux с BPF и DLPI, мы можем отметить некоторые различия.
1. В Linux не обеспечивается буферизация. Фильтрация на уровне ядра доступна только в новых системах (при помощи параметра SO_ATTACH_FILTER
). Существует обычный буфер приема сокета, но отсутствует возможность буферизации и отправки приложению нескольких кадров с помощью одной операции считывания. Это увеличивает накладные расходы, связанные с копированием потенциально возможных больших объемов данных из ядра в приложение.
2. В Linux не предусмотрена фильтрация на уровне устройства. Сокеты PF_PACKET
могут быть связаны с устройством функцией bind
. Если в вызове функции socket
указан аргумент ETH_P_IP
, то все пакеты IPv4 со всех устройств (например, Ethernet, каналы PPP, каналы SLIP и закольцовка) будут переданы на сокет. Функция recvfrom
возвращает общую структуру адреса сокета, а элемент sa_data
содержит имя устройства (например, eth0
). Тогда приложение само должно игнорировать данные с тех устройств, которые не представляют для него интереса. Здесь мы сталкиваемся фактически с той же проблемой: возможно, что приложение будет получать слишком много данных, особенно в случае наблюдения за высокоскоростной сетью.
- InterBase Classic Server под Linux
- Каталог BIN в InterBase Classic Server для Linux
- DUMMY PACKET INTERVAL
- Chapter 16. Commercial products based on Linux, iptables and netfilter
- Packet type match
- State NEW packets but no SYN bit set
- 1 Введение в Linux
- 4 Файловая система Linux
- 1.2. Что такое Linux?
- 1.5.1. Red Hat Linux
- 1.5.3. SuSE Linux
- 3.6.1. Адресация в Linux