Главная » 2017 » Ноябрь » 18 » man 7 packet
21:24
man 7 packet

SEO sprint - Всё для максимальной раскрутки!





ИМЯ


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). Они позволяют пользователю
реализовывать модули протоколов в пользовательском пространстве поверх физического
уровня.

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

Для создания пакетного сокета процесс должен иметь мандат 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, то
возвращается реальная длина пакета в канале, даже если значение длиннее буфера.

Типы адресов
unsigned char sll_halen; /* длина адреса */
unsigned char sll_addr[8]; /* адрес на физическом уровне */
};

Поля этой структуры имеют следующее назначение:

* Поле sll_protocol содержит стандартные типы протокола ethernet в сетевом
порядке байт; значения определены в заголовочном файле <linux/if_ether.h>. Это
значение по умолчанию для протокола сокета.

* Поле sll_ifindex содержит индекс интерфейса (смотрите netdevice(7)); 0 означает
любой интерфейс (допустимо только для привязывания). Поле sll_hatype содержит
тип ARP; значения хранятся в заголовочном файле <linux/if_arp.h>.

* В поле sll_pkttype содержится тип пакета. Допустимые типы: PACKET_HOST — пакет
предназначен локальному узлу, PACKET_BROADCAST — широковещательный пакет
физического уровня, PACKET_MULTICAST — пакет, посланный на групповой
(multicast) адрес физического уровня, PACKET_OTHERHOST — пакет предназначен не
тому узлу, где он пойман драйвером устройства в неразборчивом режиме,
PACKET_OUTGOING — пакет, поступивший от локального узла и завёрнутый обратно в
пакетный сокет. Эти типы имеют смысл только для принятых пакетов.

* В полях sll_addr и sll_halen содержится адрес физического уровня (например,
IEEE 802.3) и его длина. Конкретный смысл зависит от устройства.

Когда вы посылаете пакеты, достаточно указать 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.
__u32 tp_snaplen; /* захваченная длина */
__u16 tp_mac;
__u16 tp_net;
__u16 tp_vlan_tci;
__u16 tp_padding;
};

PACKET_FANOUT (начиная с Linux 3.1)
Для масштабирования обработки на несколько нитей, пакетные сокеты можно
объединять в разветвлённую группу (fanout group). В этом режиме каждый
подходящий пакет ставится в очередь только одного сокета в группе. Сокет
добавляется в разветвлённую группу вызовом setsockopt(2) с уровнем
SOL_PACKET и параметром PACKET_FANOUT. Каждое сетевое пространство имён
может включать до 65536 независимых групп. Сокет выбирает группу по
закодированному ID в первых 16 битах целочисленного значения параметра.
Первый пакетный сокет, подключаемый к группе неявно её создаёт. Для
успешного подключения к существующей группе все дальнейшие пакетные сокеты
должны иметь тот же протокол, настройки устройства, режим разветвления и
флаги (смотрите далее). Пакетные сокеты могут покинуть группу только при
закрытия сокета. Группа удаляется после закрытия последнего сокета.

Для разветвления поддерживается несколько алгоритмов распределения трафика
по сокетам:

* Режим по умолчанию 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)

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.

Для пакетных сокетов реализовано несколько вариантов пакетных колец.
Информацию о реализации можно найти в файле
Documentation/networking/packet_mmap.txt из дерева исходного кода ядра
Linux.

PACKET_STATISTICS
Возвращает статистику по пакетному сокету в виде структуры

struct tpacket_stats {
unsigned int tp_packets; /* общее количество пакетов */
unsigned int tp_drops; /* кол-во отброшенных пакетов */
};

При получении статистики сбрасываются внутренние счётчики. Если
используется вариант кольца TPACKET_V3, то статистика имеет другую
структуру.

PACKET_TIMESTAMP (с PACKET_RX_RING; начиная с Linux 2.6.36)
В кольце приёма пакетов всегда сохраняется метка времени в заголовке
метаданных. По умолчанию, это метка генерируется ПО при копировании пакета
в кольцо. Данный целочисленный параметр задаёт тип метки времени. Кроме
значения по умолчанию, поддерживается два аппаратных формата, описанных в
файле Documentation/networking/timestamping.txt из дерева исходного кода
ядра Linux.

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 в этом вызове

PACKET_QDISC_BYPASS (начиная с Linux 3.14)
По умолчанию, пакеты, посылаемые через пакетные сокеты, проходят через
уровень ядра qdisc (управление трафиком), что правильно в подавляющем
большинстве случаев. Для программно-аппаратных комплексов, использующих
пакетные фильтры для затопления сети — например, для тестирования устройств
под нагрузкой, подобно тому, как это делает pktgen — этот уровень можно не
задействовать, установив целочисленной параметр в 1. Побочным эффектом
будет отмена пакетной буферизации на уровне qdisc, что приведёт к
увеличению отброшенных пакетов при занятости передающих очередей сетевого
устройства; поэтому, пользуйтесь с осторожностью.

Вызовы 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.
не уплотняются по полям протокола 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, протокол)

Он всё ещё поддерживается, но устарел и настоятельно не рекомендуется. Основным
отличием между методами — для указания интерфейса через 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.



СМОТРИТЕ ТАКЖЕ


socket(2), pcap(3), capabilities(7), ip(7), raw(7), socket(7)

В RFC 894 описана упаковка стандартного IP Ethernet. В RFC 1700 описана упаковка
IP IEEE 802.3.

Заголовочный файл <linux/if_ether.h> содержит протоколы физического уровня.

Дерево исходного кода ядра Linux. В /Documentation/networking/filter.txt описано
как к пакетным сокетам применять Berkeley Packet Filters. В
/tools/testing/selftests/net/psock_tpacket.c содержится пример исходного кода для
всех доступных версий PACKET_RX_RING и PACKET_TX_RING.



Категория: (7) Различные описания, соглашения и прочее | Просмотров: 4003 | Добавил: Администратор | Рейтинг: 0.0/0
Всего комментариев: 0
avatar