Документация по LinuxLinuxDoc.Ru 🔍

packet, PF_PACKET - пакетный интерфейс уровня устройств

НАЗВАНИЕ
packet, PF_PACKET - пакетный интерфейс уровня устройств.

СИНТАКСИС
#include
#include /* for the glibc version number */
#if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1
#include
#include /* the L2 protocols */
#else
#include
#include
#include /* The L2 protocols */
#endif


packet_socket = socket(PF_PACKET, int socket_type, int protocol);

ОПИСАНИЕ
Пакетные сокеты используются для отправления или приема
пакетов на уровне драйвера устройства (Уровень 2 OSI). Это
позволяет пользователю реализовывать в пространстве
пользователя протокольные модули над физическим уровнем.

socket_type равен либо SOCK_RAW для raw-пакетов (включая
заголовок установки соединения), либо SOCK_DGRAM для
подготовленных пакетов без заголовка уровня соединения.
Информация заголовка уровня соединения в общем формате
предоставлена в sockaddr_ll. protocol - номер протокола в
соответствии с IEEE 802.3 в сетевом порядке байтов. Список
возможных протоколов приведен в файле
Если protocol содержит значение htons(ETH_P_ALL), то
программой будут приниматься все протоколы. Все входящие
пакеты этого типа протокола будут передаваться пакетному
сокету до того, как они будут переданы протоколам,
реализованным в ядре.

Открывать пакетные сокеты могут лишь процессы с
идентификатором эффективного пользователя, равным нулю,
или имеющие возможность CAP_NET_RAW.

Пакеты SOCK_RAW передаются драйверу устройства и
принимаются от него без всяких изменений данных пакета.
При получении пакета адрес обрабатывается и передается в
стандартной структуре адреса sockaddr_ll. При передаче
пакета буфер пользователя должен содержать заголовок
физического уровня. Пакет передается без изменений
драйверу сетевого интерфейса, указанному в адресе
назначения. Hекоторые драйверы устройств всегда добавляют
к заголовку и другие заголовки. SOCK_RAW похож, но не
совместим с устаревшим SOCK_PACKET для Linux 2.0.

SOCK_DGRAM работает на несколько более высоком уровне.
Физический заголовок удаляется перед тем, как пакет
отправляется пользователю. Пакеты, посылаемые через
пакетный сокет SOCK_DGRAM, получают перед постановкой в
очередь подходящий заголовок физического уровня в
соответствии с информацией об адресе назначения из sock-
addr_ll.

По умолчанию, все пакеты указанного типа протокола
передаются пакетному сокету. Для получения пакетов только
определенного интерфейса используйте bind(2): это соединит
пакетный сокет с интерфейсом, адрес которого указывается в
структуре struct sockaddr_ll. Для соединения используются
только поля адреса sll_protocol и sll_ifindex.

Операция connect(2) с пакетными сокетами не
поддерживается.

Когда флаг MSG_TRUNC передается recvmsg(2), recv(2),
recvfrom(2), то всегда возвращается действительная текущая
длина пакета, даже если она больше, чем буфер.


ТИПЫ АДРЕСОВ
sockaddr_ll является не зависимым от устройства адресом
физического уровня.
struct sockaddr_ll {
unsigned short sll_family; /* Всегда AF_PACKET */
unsigned short sll_protocol; /* Протокол физического уровня */
int sll_ifindex; /* Hомер интерфейса */
unsigned short sll_hatype; /* Тип заголовка */
unsigned char sll_pkttype; /* Тип пакета */
unsigned char sll_halen; /* Длина адреса */
unsigned char sll_addr[8]; /* Адрес физического уровня */
};
sll_protocol - тип стандартного протокола ethernet в
сетевом порядке байтов, определенный в файле
linux/if_ether.h. Он определяет протокол сокета по
умолчанию. sll_ifindex - индекс интерфейса (см. netde-
vice(7)); 0 соответствует любому интерфейсу (возможно
только для bind). sll_hatype - тип ARP, определенный в
файле linux/if_arp.h. sll_pkttype содержит тип пакета.
Возможные типы: PACKET_HOST для пакетов, направляемых в
локальную машину; PACKET_BROADCAST для широковещательной
передачи пакета физического уровня; PACKET_MULTICAST для
пакета, передаваемого по много адрес физического уровня;
PACKET_OTHERHOST для пакета на другую машину,
перехваченного драйвером устройства в режиме прослушивания
(promiscuous); PACKET_OUTGOING для пакетов, исходящих с
локальной машины, запетленной на пакетный сокет. Эти типы
имеют значение только для приема. sll_addr и sll_halen
содержат адрес физического уровня (например IEEE 802.3) и
его длину. Точная интерпретация зависит от устройства.
Когда вы посылаете покеты, то достаточно определить только
sll_family, sll_addr, sll_halen, sll_ifindex. Остальные
поля должны быть равны 0. sll_hatype и sll_pkttype
определяются для вас по принимаемым пакетам. Для привязки
используются только sll_protocol и sll_ifindex.


ОПЦИИ СОКЕТОВ
Пакетные сокеты могут быть использованы для настройки
многоадресного вещания физического уровня и режима
прослушивания. Это делается с помощью вызова setsockopt(2)
на пакетный сокет с SOL_PACKET и одной из опций:
PACKET_ADD_MEMBERSHIP для добавления соединения (binding),
или PACKET_DROP_MEMBERSHIP для отмены. Оба требуют в
качестве аргумента структуру packet_mreq:
struct packet_mreq
{
int mr_ifindex; /* индекс интерфейса */
unsigned short mr_type; /* действие */
unsigned short mr_alen; /* длина адреса */
unsigned char mr_address[8]; /* адрес физического уровня */
};
mr_ifindex содержит индекс интерфейса, состояние которого
необходимо изменить. Параметр mr_type указывает тип
выполняемого действия. PACKET_MR_PROMISC разрешает прием
всех пакетов с общего носителя - этот режим часто называют
"режимом прослушивания" (``promiscuous mod''),
PACKET_MR_MULTICAST соединяет (bind) сокет с многоадресной
группой физического уровня, указанной в mr_address и
mr_alen, а PACKET_MR_ALLMULTI указывает сокету принимать
все многоадресные пакеты, приходящие на интерфейс.

В дополнение ко всему, для этих целей могут быть
использованы традиционные ioctl-вызовы: SIOCSIFFLAGS, SIO-
CADDMULTI, SIOCDELMULTI.

ВЫЗОВЫ IOCTL

SIOCGSTAMP может быть использован для получения временных
меток последнего принятого пакета. Аргументом является
структура struct timeval.

Кроме того, возможно использование всех стандартынх
вызовов ioctl, определенных в netdevice(7) и socket(7).

ОБРАБОТКА ОШИБОК
Пакетные сокеты не обрабатывают ошибки за исключением тех,
которые возникают при передаче пакета драйверу устройства.
Они не имеют понятия об отложенной обработке ошибок.

СОВМЕСТИМОСТЬ
В Linux 2.0 единственным способом получить пакетный сокет
был вызов socket(PF_INET, SOCK_PACKET, protocol). Этот
способ все еще поддерживается, но использовать его
настоятельно не рекомендуется. Основное отличие между
этими двумя способами состоит в том, что SOCK_PACKET
использует старую структуру struct sockaddr_pkt для
указания интерфейса, а она не обеспечивает физический
уровень независимостью.
struct sockaddr_pkt
{
unsigned short spkt_family;
unsigned char spkt_device[14];
unsigned short spkt_protocol;
};
spkt_family содержит тип устройства, spkt_protocol
является типом протокола IEEE 802.3 в соответствии с
, а spkt_device - это имя устройства в
виде строки, оканчивающейся нулем, например, eth0.

Эта структура устарела и не должна быть указана в новом
коде.

ЗАМЕЧАНИЯ
В переносимых программах рекомендуется использовать
PF_PACKET с помощью pcap(3); хотя это относится только к
вспомогательному набору возможностей PF_PACKET.

Пакетные сокеты SOCK_DGRAM не пытаются создать или
обработать заголовок IEEE 802.2 LLC для кадров IEEE 802.3.
Если в качестве протокола для отправки указан ETH_P_802_3,
ядро создает кадр 802.3 и заполняет поле длины;
пользователь должен указать заголовок LLC для того, чтобы
получить полностью соответствующий стандарту пакет.
Входящие пакеты 802.3 не мультиплексируются по полям
DSAP/SSAP; вместо этого они предоставляются пользователю
как протокол ETH_P_802_2 с заголовком LLC. Поэтому
подключиться (to bind) к ETH_P_802_3 невозможно; вместо
этого подключайтесь к ETH_P_802_2 и выполняйте
мультиплексирование протокола сами. По умолчанию для
отправки используется стандартная инкапсуляция Ethernet
DIX со вставленным протоколом.

Пакетные сокеты не обрабатываются входящими и исходящими
правилами сетевого экрана.

КОДЫ ОШИБОК
ENETDOWN
Интерфейс неактивен.

ENOTCONN
Hе передан адрес интерфейса.

ENODEV Hеизвестное имя устройства или индекс интерфейса,
указанные в адресе интерфейса.

EMSGSIZE
Размер пакета больше, чем размер интерфейса MTU.

ENOBUFS
Hедостаточно памяти для размещения в ней пакета.

EFAULT Пользователь передал неправильный адрес памяти.

EINVAL Hеверный аргумент.

ENXIO Адрес интерфейса содержит неправильный индекс
интерфейса.

EPERM Пользователь не имеет прав на выполнение этой
операции.

EADDRNOTAVAIL
Передан неизвестный адрес многоадресной группы.

ENOENT Пакет не получен.

Дополнительные ошибки могут генерироваться низкоуровенвым
драйвером.

ВЕРСИИ
PF_PACKET появился в Linux 2.2. Ранние версии Linux
поддерживали только SOCK_PACKET.

НАЙДЕННЫЕ ОШИБКИ
glibc 2.1 не имеет определения SOL_PACKET. Рекомендуемое
решение:
Это поправка внесена в более поздние версии и не
встречается в системах lic5.

Обработка IEEE 802.2/803.3 LLC должна считаться ошибкой.

Фильтры сокетов не описаны. Расширение MSG_TRUNC для
recvmsg является очень плохо сделанной правкой и должна
быть заменена на управляющее сообщение. На данный момент
нет иного выхода, кроме как определение настоящего адреса
назначения пакета по SOCK_DGRAM.


ОСОБЫЕ БЛАГОДАРНОСТИ
Эта страница руководства была написана Энди Клином (Andi
Kleen) при участии Мэтью Вилкокса (Matthew Wilcox).
PF_PACKET в Linux 2.2 (на основе кода Алана Кокса (Alan
Cox) и др.) был реализован Алексеем Кузнецовым (Alexey
Kuznetsov).
Читать новости Linux в Telegram
Linux - packet, PF_PACKET - пакетный интерфейс уровня устройств
Мы в соцсетях ✉