ИМЯ
packet -
пакетный
интерфейс
на уровне
устройства
СИНТАКСИС
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <net/ethernet.h> /* протоколы L2 */
packet_socket = socket(AF_PACKET, int socket_type, int protocol);
ОПИСАНИЕ
Пакетные
сокеты
используются
для приёма
и передачи
неструктурированных
пакетов на
уровне
драйвера
устройства
(второй
уровень OSI).
Они
позволяют
пользователю
реализовывать
модули
протоколов
в
пользовательском
пространстве
поверх
физического
уровня.
The socket_type is either SOCK_RAW for raw packets
including the link-level header or SOCK_DGRAM for cooked packets with
the link-level header removed. The link-level header information is
available in a common format in a sockaddr_ll structure.
protocol is the IEEE 802.3 protocol number in network byte order. See
the <linux/if_ether.h> include file for a list of allowed
protocols. When protocol is set to htons(ETH_P_ALL), then all
protocols are received. All incoming packets of that protocol type will be
passed to the packet socket before they are passed to the protocols
implemented in the kernel. If protocol is set to zero, no packets are
received. bind(2) can optionally be called with a nonzero
sll_protocol to start receiving packets for the protocols
specified.
Для
создания
пакетного
сокета
процесс
должен
иметь
мандат CAP_NET_RAW в
пользовательском
пространстве
имён,
определяемом
по его
сетевому
пространству
имён.
Пакеты SOCK_RAW
передаются
в и из
драйвера
устройства
без
каких-либо
изменений
в данных
пакета. При
получении
пакета,
адрес
по-прежнему
анализируется
и
передаётся
в
стандартной
адресной
структуре
sockaddr_ll. При
отправке
пакета,
выделенный
пользователем
буфер
должен
содержать
заголовок
физического
уровня.
Этот пакет
затем
ставится
без
изменений
в очередь
сетевого
драйвера
интерфейса,
определяемого
адресом
назначения.
Некоторые
драйверы
устройств
всегда
добавляют
другой
заголовок.
Пакеты SOCK_RAW
похожи, но
не
совместимы
с
устаревшими
AF_INET/SOCK_PACKET из Linux 2.0.
При типе
SOCK_DGRAM
обработка
происходит
на чуть
более
высоком
уровне.
Физический
заголовок
удаляется
перед
передачей
пакета
пользователю.
Пакеты,
посылаемые
через
пакетный
сокет SOCK_DGRAM,
перед
постановкой
в очередь
получают
подходящий
заголовок
физического
уровня на
основе
информации
из адреса
назначения
в sockaddr_ll.
По
умолчанию,
все пакеты
заданного
типа
протокола
передаются
в пакетный
сокет. Для
получения
пакетов
только из
определённого
интерфейса
используйте
bind(2), задав
адрес в struct sockaddr_ll
для
привязки
пакетного
сокета к
интерфейсу.
Поля,
используемые
для
привязывания:
sll_family (должно
быть равно
AF_PACKET), sll_protocol и sll_ifindex.
Операция
connect(2) не
поддерживается
для
пакетных
сокетов.
Если в recvmsg(2),
recv(2) или recvfrom(2)
передаётся
флаг MSG_TRUNC, то
возвращается
реальная
длина
пакета в
канале,
даже если
значение
длиннее
буфера.
Типы
адресов
Структура
sockaddr_ll
описывает
независимый
от
устройства
адрес на
физическом
уровне.
struct sockaddr_ll {
unsigned short sll_family; /* всегда равно AF_PACKET */
unsigned short sll_protocol; /* протокол физического уровня */
int sll_ifindex; /* номер интерфейса */
unsigned short sll_hatype; /* тип аппаратного ARP */
unsigned char sll_pkttype; /* тип пакета */
unsigned char sll_halen; /* длина адреса */
unsigned char sll_addr[8]; /* адрес на физическом уровне */
};
Поля этой
структуры
имеют
следующее
назначение:
- sll_protocol
- is the standard ethernet protocol type in network byte order as defined in
the <linux/if_ether.h> include file. It defaults to the
socket's protocol.
- sll_ifindex
- is the interface index of the interface (see netdevice(7)); 0
matches any interface (only permitted for binding). sll_hatype is
an ARP type as defined in the <linux/if_arp.h> include
file.
- sll_pkttype
- contains the packet type. Valid types are PACKET_HOST for a packet
addressed to the local host, PACKET_BROADCAST for a physical-layer
broadcast packet, PACKET_MULTICAST for a packet sent to a
physical-layer multicast address, PACKET_OTHERHOST for a packet to
some other host that has been caught by a device driver in promiscuous
mode, and PACKET_OUTGOING for a packet originating from the local
host that is looped back to a packet socket. These types make sense only
for receiving.
- sll_addr
- sll_halen
- contain the physical-layer (e.g., IEEE 802.3) address and its length. The
exact interpretation depends on the device.
Когда вы
посылаете
пакеты,
достаточно
указать sll_family,
sll_addr, sll_halen, sll_ifindex и
sll_protocol.
Остальные
поля
должны
равняться 0.
Поля sll_hatype и
sll_pkttype
заполняются
в
получаемых
пакетах
для вашей
информированности.
Параметры
сокета
Параметры
пакетных
сокетов
настраиваются
вызовом
setsockopt(2) с
уровнем
SOL_PACKET.
- PACKET_ADD_MEMBERSHIP
- PACKET_DROP_MEMBERSHIP
- Пакетные
сокеты
можно
использовать
для
настройки
неразборчивого
режима и
групповой
рассылки
на
физическом
уровне.
Параметр
PACKET_ADD_MEMBERSHIP
добавляет
привязку,
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
включает
приём всех
пакетов из
общего
носителя
(часто
называется
«неразборчивый
режим»),
PACKET_MR_MULTICAST
привязывает
сокет к
групповой
рассылке
физического
уровня,
задаваемой
в mr_address и mr_alen, а
PACKET_MR_ALLMULTI
заставляет
сокет
принимать
все пакеты
групповых
рассылок,
поступающих
на
интерфейс.
- Также, для
тех же
целей
можно
использовать
обычные ioctl
SIOCSIFFLAGS, SIOCADDMULTI, SIOCDELMULTI.
- PACKET_AUXDATA
(начиная с Linux
2.6.21)
- Если
включён
этот
двоичный
параметр,
то
пакетный
сокет
передаёт
структуру
метаданных
вместе с
каждым
пакетом в
управляющем
поле recvmsg(2).
Структуру
можно
прочитать
с помощью
cmsg(3). Она
определена
как:
-
struct tpacket_auxdata {
__u32 tp_status;
__u32 tp_len; /* packet length */
__u32 tp_snaplen; /* captured length */
__u16 tp_mac;
__u16 tp_net;
__u16 tp_vlan_tci;
__u16 tp_vlan_tpid; /* Since Linux 3.14; earlier, these
were unused padding bytes */
};
- PACKET_FANOUT
(начиная с Linux
3.1)
- To scale processing across threads, packet sockets can form a fanout
group. In this mode, each matching packet is enqueued onto only one socket
in the group. A socket joins a fanout group by calling
setsockopt(2) with level SOL_PACKET and option
PACKET_FANOUT. Each network namespace can have up to 65536
independent groups. A socket selects a group by encoding the ID in the
first 16 bits of the integer option value. The first packet socket to join
a group implicitly creates it. To successfully join an existing group,
subsequent packet sockets must have the same protocol, device settings,
fanout mode, and flags (see below). Packet sockets can leave a fanout
group only by closing the socket. The group is deleted when the last
socket is closed.
- Для
разветвления
поддерживается
несколько
алгоритмов
распределения
трафика по
сокетам:
- •
- Режим по
умолчанию
PACKET_FANOUT_HASH
посылает
пакеты из
одного
потока в
один и тот
же сокет
для
обеспечения
упорядочивания
по потоку.
Для
каждого
пакета
выбирается
сокет,
получаемый
из хэша
потока
пакетов,
взятого по
модулю
количества
сокетов в
группе, где
хэш потока
— это хэш
адреса
сетевого
уровня и
необязательных
полей
портов
транспортного
уровня.
- •
- Режим
балансировки
нагрузки
PACKET_FANOUT_LB
реализует
карусельный
алгоритм.
- •
- В режиме
PACKET_FANOUT_CPU
выбираются
сокеты
исходя из
ЦП, на
который
поступил
пакет.
- •
- В режиме
PACKET_FANOUT_ROLLOVER все
данные
обрабатываются
одним
сокетом,
следующий
задействуется,
если
текущий
занят (backlogged).
- •
- В режиме
PACKET_FANOUT_RND сокет
выбирается
согласно
генератору
псевдослучайных
чисел.
- •
- В режиме
PACKET_FANOUT_QM
(доступен,
начиная с Linux
3.14) сокет
выбирается
с помощью
записанного
queue_mapping из
полученной
skb.
- Режимы
разветвления
могут
учитывать
дополнительные
параметры.
Фрагментация
IP приводит
к тому, что
пакеты
одного
потока
имеют
разные
хэши
потоков.
Если
установлен
флаг PACKET_FANOUT_FLAG_DEFRAG,
то пакеты
будут
дефрагментироваться
перед
применением
разветвления,
что
позволит
сохранить
порядок
даже в этом
случае.
Параметры
режима
разветвления
задаются
во вторых 16
битах
целочисленного
значения
параметра.
Флаг PACKET_FANOUT_FLAG_ROLLOVER
включает
механизм
перекатывания
в качестве
запасного:
если
первоначальный
алгоритм
разветвления
выбрал
занятый
сокет, то
пакет
переходит
на
следующий
доступный.
- PACKET_LOSS
(с PACKET_TX_RING)
- Когда в
кольце
передачи
обнаруживается
некорректный
пакет, то
по
умолчанию
его
состояние
в tp_status
сбрасывается
в TP_STATUS_WRONG_FORMAT и
происходит
немедленная
отмена
передачи.
Некорректный
пакет
блокирует
как свою
отправку,
так и всех
следующих
пакетов в
очереди.
Ошибка в
формате
должна
быть
исправлена,
соответствующий
tp_status сброшен
в значение
TP_STATUS_SEND_REQUEST, а
передача
перезапущена
с помощью
send(2). Однако,
если задан
параметр
PACKET_LOSS, то все
некорректные
пакеты
будут
пропускаться,
их tp_status
сбрасываться
в TP_STATUS_AVAILABLE и
процесс
передачи
продолжаться.
- PACKET_RESERVE
(с PACKET_RX_RING)
- По
умолчанию,
в кольцо
приёма
пакетов
сразу за
пакетом
записывается
структура
метаданных
и
заполнитель
для
выравнивания.
Этот
целочисленный
параметр
резервирует
дополнительное
свободное
место.
- PACKET_RX_RING
- Включает
создание
отображаемого
в памяти
кольцевого
буфера
асинхронного
приёма
пакетов.
Пакетный
сокет
резервирует
непрерывную
область в
адресном
пространстве
приложения,
размечает
её как
массив
пакетных
слотов и
последовательно
копирует
пакеты (не
более tp_snaplen) в
слоты. В
начале
каждого
пакета
помещается
структура
метаданных,
похожая на
tpacket_auxdata. В поле
протокола
кодируется
смещение
данных от
начала
заголовка
метаданных.
В tp_net
хранится
смещение
сетевого
уровня.
Если тип
пакетного
сокета —
SOCK_DGRAM, то это
делается и
для tp_mac. Если
тип — SOCK_RAW, то
в этом поле
хранится
смещение
на кадр
канального
уровня.
Пакетный
сокет и
приложение
обмениваются
началом и
концом
кольца
через поле
tp_status.
Пакетному
сокету
принадлежат
все слоты
со
значением
tp_status равным
TP_STATUS_KERNEL. После
заполнения
слота,
изменяется
состояние
слота и
права на
него
передаются
приложению.
При
нормальной
работе в
новом
значении
tp_status, как
минимум,
установлен
бит TP_STATUS_USER, что
показывает,
что
принятый
пакет был
сохранён.
Когда
приложение
заканчивает
обработку
пакета, оно
передаёт
права на
слот
обратно
сокету
посредством
установки
tp_status в
значение
TP_STATUS_KERNEL.
- Packet sockets implement multiple variants of the packet ring. The
implementation details are described in
Documentation/networking/packet_mmap.rst in the Linux kernel source
tree.
- PACKET_STATISTICS
- Возвращает
статистику
по
пакетному
сокету в
виде
структуры
-
struct tpacket_stats {
unsigned int tp_packets; /* общее количество пакетов */
unsigned int tp_drops; /* кол-во отброшенных пакетов */
};
- При
получении
статистики
сбрасываются
внутренние
счётчики.
Если
используется
вариант
кольца TPACKET_V3,
то
статистика
имеет
другую
структуру.
- PACKET_TIMESTAMP
(с PACKET_RX_RING;
начиная с Linux
2.6.36)
- The packet receive ring always stores a timestamp in the metadata header.
By default, this is a software generated timestamp generated when the
packet is copied into the ring. This integer option selects the type of
timestamp. Besides the default, it support the two hardware formats
described in Documentation/networking/timestamping.rst in the Linux
kernel source tree.
- PACKET_TX_RING
(начиная с Linux
2.6.31)
- Включает
создание
отображаемого
в памяти
кольцевого
буфера
передачи
пакетов.
Этот
параметр
подобен
PACKET_RX_RING и имеет
те же
аргументы.
Приложение
записывает
пакеты в
слоты со
значением
tp_status равным
TP_STATUS_AVAILABLE и
планирует
их для
передачи
делая
значение
tp_status равным
TP_STATUS_SEND_REQUEST. Когда
пакеты
готовы к
передаче,
приложение
вызывает
send(2) или его
вариант.
Поля buf и len в
этом
вызове
игнорируются.
Если
передаётся
адрес с
помощью sendto(2)
или sendmsg(2), то
он
заменяет
сокетное
значение
по
умолчанию.
При
успешной
передаче
сокет
сбрасывает
значение
tp_status в TP_STATUS_AVAILABLE.
При ошибке
передача
немедленно
прерывается,
если не
задан PACKET_LOSS.
- PACKET_VERSION
(с PACKET_RX_RING;
начиная с Linux
2.6.27)
- По
умолчанию,
PACKET_RX_RING
создаёт
кольцо
приёма
пакетов по
варианту
TPACKET_V1. Для
создания
другого
варианта,
задайте
желаемый,
указав
целочисленное
значение в
этом
параметре
перед
созданием
кольца.
- PACKET_QDISC_BYPASS
(начиная с Linux
3.14)
- By default, packets sent through packet sockets pass through the kernel's
qdisc (traffic control) layer, which is fine for the vast majority of use
cases. For traffic generator appliances using packet sockets that intend
to brute-force flood the network—for example, to test devices under
load in a similar fashion to pktgen—this layer can be bypassed by
setting this integer option to 1. A side effect is that packet buffering
in the qdisc layer is avoided, which will lead to increased drops when
network device transmit queues are busy; therefore, use at your own
risk.
Вызовы ioctl
Вызов SIOCGSTAMP
можно
использовать
для
получения
метки
времени
последнего
полученного
пакета.
Аргументом
является struct
timeval.
Также, для
пакетных
сокетов
работают
все
стандартные
ioctl,
определённые
в netdevice(7) и socket(7).
Обработка
ошибок
Пакетные
сокеты не
выполняют
обработку
ошибок,
кроме
ошибок,
которые
возникают
при
передаче
пакета
драйверу
устройства.
В них не
заложен
принцип
ожидания
ошибки.
ОШИБКИ
- EADDRNOTAVAIL
- Передан
неизвестный
адрес
групповой
рассылки.
- EFAULT
- Пользователь
передал
неправильный
адрес
памяти.
- EINVAL
- Неверный
аргумент.
- EMSGSIZE
- Пакет
больше, чем
интерфейс
MTU.
- ENETDOWN
- Интерфейс
не поднят.
- ENOBUFS
- Недостаточно
памяти для
размещения
пакета.
- ENODEV
- В адресе
интерфейса
указано
неизвестное
имя
устройства
или индекс
интерфейса.
- ENOENT
- Пакет не
принят.
- ENOTCONN
- Не передан
адрес
интерфейса.
- ENXIO
- В адресе
интерфейса
содержится
некорректный
индекс
интерфейса.
- EPERM
- У
пользователя
недостаточно
прав для
выполнения
этой
операции.
Также,
драйвером
низкого
уровня
могут
генерироваться
другие
ошибки.
ВЕРСИИ
AF_PACKET
появился в
Linux 2.2. В ранних
версиях Linux
поддерживался
только SOCK_PACKET.
ЗАМЕЧАНИЯ
Для
переносимых
программ
предлагается
использовать
AF_PACKET в pcap(3), хотя
это
покрывает
не весь
набор
возможностей
AF_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. То есть
невозможно
выполнить
привязку к
ETH_P_802_3; вместо
этого
выполняйте
привязку к
ETH_P_802_2 и
выполняйте
протокольное
уплотнение
самостоятельно.
По
умолчанию,
отправка
происходит
в
стандартной
упаковке Ethernet
DIX с
заполненным
полем
протокола.
Пакетные
сокеты
недоступны
(not subject) во
входной и
выходной
цепочках
межсетевого
экрана.
Совместимость
В Linux 2.0
единственным
способом
получить
пакетный
сокет
является
вызов:
socket(AF_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,
определённый
в <sys/if_ether.h>, а в spkt_device
— имя
устройства
в виде
строки с null в
конце,
например, eth0.
Эта
структура
устарела и
не должна
использоваться
в новом
коде.
ДЕФЕКТЫ
Способ
обработки
IEEE 802.2/803.3 LLC не
считается
за
дефектный.
Расширение
MSG_TRUNC recvmsg(2)
является
неудачным
решением и
должно
быть
заменено
на
управляющее
сообщение.
Пока нет
способа
получить
первоначальный
адрес
назначения
пакетов
через SOCK_DGRAM.
The spkt_device field of sockaddr_pkt has a size of
14 bytes, which is less than the constant IFNAMSIZ defined in
<net/if.h> which is 16 bytes and describes the system limit for
a network interface name. This means the names of network devices longer
than 14 bytes will be truncated to fit into spkt_device. All these
lengths include the terminating null byte ('\0')).
Issues from this with old code typically show up with very long
interface names used by the Predictable Network Interface Names
feature enabled by default in many modern Linux distributions.
The preferred solution is to rewrite code to avoid
SOCK_PACKET. Possible user solutions are to disable Predictable
Network Interface Names or to rename the interface to a name of at most
13 bytes, for example using the ip(8) tool.
Не
описаны
сокетные
фильтры.
СМ. ТАКЖЕ
socket(2), pcap(3), capabilities(7),
ip(7), raw(7), socket(7), ip(8),
В RFC 894
описана
упаковка
стандартного
IP Ethernet. В RFC 1700
описана
упаковка IP IEEE
802.3.
Заголовочный
файл <linux/if_ether.h>
содержит
протоколы
физического
уровня.
The Linux kernel source tree.
Documentation/networking/filter.rst describes how to apply Berkeley
Packet Filters to packet sockets.
tools/testing/selftests/net/psock_tpacket.c contains example source
code for all available versions of PACKET_RX_RING and
PACKET_TX_RING.
ПЕРЕВОД
Русский
перевод
этой
страницы
руководства
был сделан
Alexey, Azamat Hackimov <azamat.hackimov@gmail.com>,
kogamatranslator49 <r.podarov@yandex.ru>, Kogan, Max Is
<ismax799@gmail.com>, Yuri Kozlov <yuray@komyakino.ru> и
Иван
Павлов
<pavia00@gmail.com>
Этот
перевод
является
бесплатной
документацией;
прочитайте
Стандартную
общественную
лицензию GNU
версии 3
или более
позднюю,
чтобы
узнать об
условиях
авторского
права. Мы не
несем
НИКАКОЙ
ОТВЕТСТВЕННОСТИ.
Если вы
обнаружите
ошибки в
переводе
этой
страницы
руководства,
пожалуйста,
отправьте
электронное
письмо на
man-pages-ru-talks@lists.sourceforge.net.