packet – Interface de paquets au niveau du
périphérique
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <net/ethernet.h> /* Les protocoles L2 */
packet_socket = socket(AF_PACKET, int type_socket, int protocole);
Les sockets packet sont utilisés pour envoyer ou recevoir
des paquets bruts au pilote de périphérique (couche 2
OSI). Ils permettent d'implémenter des modules de protocole dans
l'espace utilisateur au-dessus de la couche physique.
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.
Pour pouvoir créer des sockets packet, un processus doit
posséder la capacité CAP_NET_RAW dans l’espace
de noms utilisateur qui régit son espace de noms réseau.
Les paquets SOCK_RAW sont transmis depuis et vers le pilote
de périphérique sans aucune modification des données
des paquets. Lors de la réception d’un paquet, l'adresse est
toujours examinée et fournie dans une structure standard
d’adresse sockaddr_ll. Lors de l'émission d'un paquet,
le tampon fourni par l'utilisateur doit contenir l'en-tête de couche
physique. Le paquet est alors mis en attente sans modification à
l'attention du pilote de périphérique correspondant à
l'interface définie par l'adresse de destination. Certains pilotes de
périphérique ajoutent toujours d'autres en-têtes.
SOCK_RAW est similaire mais non compatible avec l'ancien
AF_INET/SOCK_PACKET de Linux 2.0.
SOCK_DGRAM opère à un niveau
légèrement plus élevé. L'en-tête de
couche physique est supprimé avant que le paquet ne soit transmis
à l'utilisateur. Les paquets envoyés par un socket packet
SOCK_DGRAM reçoivent un en-tête de couche physique
correct basé sur les informations dans l'adresse destination
sockaddr_ll avant d'être mis en attente.
Par défaut, tous les paquets du type de protocole
indiqué sont passés au socket packet. Pour ne recevoir que les
paquets d'une interface donnée, utilisez bind(2) en indiquant
une adresse dans une struct sockaddr_ll pour attacher le socket
à une interface. Les champs utilisés pour la liaison sont
sll_family (devrait être AF_PACKET),
sll_protocol et sll_ifindex.
L'opération connect(2) n'est pas prise en charge sur
les sockets packet.
Lorsque l'attribut MSG_TRUNC est transmis à
recvmsg(2), recv(2) ou recvfrom(2), la véritable
longueur du paquet sur le réseau est toujours renvoyée,
même si elle est plus grande que le tampon.
La structure sockaddr_ll est une adresse de couche physique
indépendante du périphérique.
struct sockaddr_ll {
unsigned short sll_family; /* Toujours AF_PACKET */
unsigned short sll_protocol; /* Protocole couche physique */
int sll_ifindex; /* Numéro d'interface */
unsigned short sll_hatype; /* Type de matériel ARP */
unsigned char sll_pkttype; /* Type de paquet */
unsigned char sll_halen; /* Longueur de l'adresse */
unsigned char sll_addr[8]; /* Adresse couche physique */
};
Les membres de cette structure sont les suivants :
- 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.
Lorsque des paquets sont envoyés, il suffit d'indiquer
sll_family, sll_addr, sll_halen, sll_ifindex et
sll_protocol. Les autres champs devraient être à
zéro. sll_hatype et sll_pkttype sont remplis en
réception pour information.
Les options du socket packet sont configurées en appelant
setsockopt(2) avec le niveau SOL_PACKET.
- PACKET_ADD_MEMBERSHIP
- PACKET_DROP_MEMBERSHIP
- Les options des sockets packet permettent de configurer le multicasting de
couche physique et le mode promiscuous. PACKET_ADD_MEMBERSHIP
ajoute une liaison et PACKET_DROP_MEMBERSHIP la supprime. Les deux
options attendent une structure packet_mreq en
paramètre :
-
struct packet_mreq {
int mr_ifindex; /* Numéro d'interface */
unsigned short mr_type; /* Action */
unsigned short mr_alen; /* Longueur d'adresse */
unsigned char mr_address[8]; /* Adresse couche physique */
};
- mr_ifindex contient le numéro de l'interface dont
l'état doit être modifié. Le champ mr_type
indique l'action à effectuer. PACKET_MR_PROMISC valide la
réception de tous les paquets circulant sur le segment de
réseau commun (souvent appelé « mode
promiscuous »), PACKET_MR_MULTICAST attache le socket
au groupe multicast de couche physique indiqué dans
mr_address et mr_alen, et PACKET_MR_ALLMULTI demande
au socket de recevoir tous les paquets multicast arrivant sur
l'interface.
- De plus, les ioctls classiques SIOCSIFFLAGS, SIOCADDMULTI et
SIOCDELMULTI peuvent parvenir au même résultat.
- PACKET_AUXDATA
(depuis Linux 2.6.21)
- Si cette option est activée, le socket packet fournit avec chaque
paquet une structure de métadonnées à l’aide
du champ de contrôle de recvmsg(2). La structure peut
être lue avec cmsg(3). Elle est définie
ci-dessous :
-
struct tpacket_auxdata {
__u32 tp_status;
__u32 tp_len; /* Longueur du paquet */
__u32 tp_snaplen; /* Longueur capturée */
__u16 tp_mac;
__u16 tp_net;
__u16 tp_vlan_tci;
__u16 tp_vlan_tpid; /* Depuis Linux 3.14 ; précédemment
c’était des octets de remplissage
non utilisés */
};
- PACKET_FANOUT
(depuis Linux 3.1)
- Pour s’adapter au nombre de traitements des threads, les sockets
packet peuvent former un groupe de déploiement. Dans ce mode, tous
les paquets correspondants sont mis en attente dans un seul socket du
groupe. Un socket rejoint un groupe de déploiement en appelant
setsockopt(2) avec le niveau SOL_PACKET et l’option
PACKET_FANOUT. Tous les espaces de noms réseau peuvent avoir
jusqu’à 65536 groupes indépendants. Un socket
sélectionne un groupe en encodant l’identifiant dans les
16 premiers bits de la valeur d’entier de cette option. Le
premier socket packet à rejoindre un groupe le crée
implicitement. Pour réussir à rejoindre un groupe existant,
les sockets packet suivants doivent avoir le même protocole, la
même configuration de périphérique, le même
mode de déploiement et les mêmes attributs (voir
ci-dessous). Les sockets packet ne peuvent quitter un groupe de
déploiement qu’en fermant le socket. Le groupe est
supprimé quand le dernier socket est fermé.
- Le déploiement gère plusieurs algorithmes pour
répartir le trafic entre les sockets comme suit :
- Le mode par défaut, PACKET_FANOUT_HASH, envoie les paquets
du même flux au même socket pour maintenir l’ordre
par flux. Pour chaque paquet, il choisit un socket en prenant le hachage
du flux de paquets modulo le nombre de sockets dans le groupe, où
le hachage du flux est un hachage sur les adresses de la couche
réseau et les champs facultatifs de port de la couche
transport.
- Le mode répartition de charge PACKET_FANOUT_LB met en
œuvre un algorithme de tourniquet (round-robin).
- PACKET_FANOUT_CPU sélectionne le socket en se basant sur le
CPU sur lequel le paquet arrive.
- PACKET_FANOUT_ROLLOVER traite toutes les données sur un seul
socket, allant sur le suivant quand le socket devient
débordé.
- PACKET_FANOUT_RND sélectionne le socket en utilisant un
générateur de nombres pseudo-aléatoires.
- PACKET_FANOUT_QM (disponible depuis Linux 3.14)
sélectionne le socket en utilisant le queue_mapping
enregistré du tampon de socket (SKB) reçu.
- Les modes de déploiement acceptent des options
supplémentaires. La fragmentation d’IP force les paquets du
même flux à avoir des hachages de flux différents.
L’attribut PACKET_FANOUT_FLAG_DEFRAG, si défini,
force la défragmentation de paquets avant l’application du
déploiement, pour conserver l’ordre même dans ce cas.
Le mode de déploiement et les options sont communiqués sur
les deuxièmes 16 bits de la valeur d’entier de cette
option. L’attribut PACKET_FANOUT_FLAG_ROLLOVER active le
mécanisme de déplacement comme une stratégie de
sauvegarde : si l’algorithme de déploiement originel
sélectionne un socket débordé, le paquet se
déplace vers le suivant disponible.
- PACKET_LOSS
(avec PACKET_TX_RING)
- Lorsqu'un paquet malformé est trouvé dans le tampon
circulaire de transmission, le comportement par défaut est de
réinitialiser son tp_status à
TP_STATUS_WRONG_FORMAT et d'abandonner immédiatement la
transmission. Le paquet malformé ainsi que les paquets suivants mis
en file d'attente voient leur transmission bloquée. L'erreur de
format doit être corrigée, la valeur tp_status
associée doit être réinitialisée à
TP_STATUS_SEND_REQUEST et le processus de transmission
redémarré par l'intermédiaire de l'interface
send(2). Cependant, si PACKET_LOSS est défini, tout
paquet malformé est ignoré, son tp_status est
réinitialisé à TP_STATUS_AVAILABLE et le
processus de transmission continue.
- PACKET_RESERVE
(avec PACKET_RX_RING)
- Par défaut, un tampon circulaire de réception des paquets
écrit les paquets juste après la structure de
métadonnées et le remplissage d'alignement. La valeur
d’entier de cette option réserve une possibilité de
transmission supplémentaire.
- PACKET_RX_RING
- Créer un tampon circulaire projeté en mémoire pour la
réception asynchrone de paquets. Le socket packet réserve
une zone contiguë d’espace d’adresse
d’application, la dispose dans un tableau d’emplacements de
paquet et copie les paquets (jusqu’à tp_snaplen) dans
les emplacements suivants. Tous les paquets sont
précédés d’une structure de
métadonnées similaire à tpacket_auxdata. Les
champs de protocole encodent la position des données dès le
début de l’en-tête de métadonnées.
tp_net stocke la position de la couche réseau. Si le socket
packet est de type SOCK_DGRAM, alors tp_mac est la
même. S’il est de type SOCK_RAW, alors ce champ
stocke la position de la trame de couche liaison. Le socket packet et
l’application communiquent le début et la fin du tampon
circulaire à l’aide du champ tp_status. Tous les
emplacements avec tp_status valant TP_STATUS_KERNEL
appartiennent au socket packet. Après avoir rempli un emplacement,
il modifie l’état de l’emplacement pour qu’il
appartienne à l’application. Lors d’une
opération normale, la nouvelle valeur de tp_status a au
moins son bit TP_STATUS_USER activé, pour signaler
qu’un paquet reçu a été stocké. Lorsque
l’application a terminé de traiter un paquet, elle
transfère la propriété de l’emplacement au
socket en redéfinissant tp_status à
TP_STATUS_KERNEL.
- Les sockets packet mettent en œuvre plusieurs variantes du tampon
circulaire de paquets. Des précisions sur cette mise en place sont
disponibles dans Documentation/networking/packet_mmap.rst dans
l'arborescence des sources du noyau Linux.
- PACKET_STATISTICS
- Récupérer les statistiques du socket packet sous la forme
d'une structure
-
struct tpacket_stats {
unsigned int tp_packets; /* Décompte total des paquets */
unsigned int tp_drops; /* Décompte des paquets jetés */
};
- Recevoir les statistiques réinitialise les compteurs internes. La
structure de statistiques est différente lorsque le tampon
circulaire utilisé est de type TPACKET_V3.
- PACKET_TIMESTAMP
(avec PACKET_RX_RING ; depuis Linux 2.6.36)
- Le tampon circulaire de réception des paquets stocke un horodatage
dans l’en-tête de métadonnées. Par
défaut, c’est un horodatage logiciel
généré quand le paquet est copié dans le
tampon circulaire. Cette option d’entier sélectionne le type
d’horodatage. En plus du fonctionnement par défaut, il
gère deux formats matériels décrits dans
Documentation/networking/timestamping.rst dans l'arborescence des
sources du noyau Linux.
- PACKET_TX_RING
(depuis Linux 2.6.31)
- Créer un tampon circulaire projeté en mémoire pour la
transmission de paquets. Cette option est similaire à
PACKET_RX_RING et accepte les mêmes arguments.
L’application écrit des paquets dans des emplacements avec
tp_status égal à TP_STATUS_AVAILABLE et les
programme pour transmission en modifiant tp_status à la
valeur TP_STATUS_SEND_REQUEST. Quand les paquets sont prêts
à être transmis, l’application appelle send(2)
ou une de ses variantes. Les champs buf et len de cet appel
sont ignorés. Si une adresse est passée en utilisant
sendto(2) ou sendmsg(2), alors cela écrase le socket
par défaut. En cas de transmission réussie, le socket
réinitialise tp_status à TP_STATUS_AVAILABLE.
Il interrompt immédiatement la transmission en cas d’erreur
sauf si PACKET_LOSS est définie.
- PACKET_VERSION
(avec PACKET_RX_RING ; depuis Linux 2.6.27)
- Par défaut, PACKET_RX_RING crée un tampon circulaire
de réception des paquets de variante TPACKET_V1. Pour
créer une autre variante, configurer la variante voulue en
définissant l’option d’entier avant de créer
le tampon circulaire.
- PACKET_QDISC_BYPASS
(depuis 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.
SIOCGSTAMP peut servir à obtenir l'horodatage du
dernier paquet reçu. Le paramètre est une variable struct
timeval.
De plus, les ioctls standards définis dans
netdevice(7) et socket(7) sont valables sur les sockets
packet.
Les sockets packet ne gèrent pas d'autres erreurs que
celles se produisant durant la transmission des paquets au pilote de
périphérique. Elles ne traitent pas le concept de file
d'erreurs.
- EADDRNOTAVAIL
- Adresse de groupe multicast inconnue.
- EFAULT
- Adresse mémoire incorrecte.
- EINVAL
- Argument incorrect.
- EMSGSIZE
- Le paquet est plus grand que le MTU de l'interface.
- ENETDOWN
- L'interface n'est pas active.
- ENOBUFS
- Pas assez de mémoire pour le paquet.
- ENODEV
- Le nom du périphérique ou le numéro
d’interface indiqué dans l'adresse de l'interface est
inconnu.
- ENOENT
- Pas de paquet reçu.
- ENOTCONN
- Aucune adresse d'interface n'a été passée.
- ENXIO
- Numéro d'interface non valable dans son adresse.
- EPERM
- L'utilisateur n'a pas les privilèges nécessaires pour
l'opération.
De plus, d'autres erreurs peuvent être engendrées
par le pilote bas niveau.
AF_PACKET est une nouveauté de Linux 2.2. Les
versions précédentes de Linux ne prenaient en charge que
SOCK_PACKET.
Pour la portabilité, il est conseillé d'utiliser les
fonctionnalités AF_PACKET par l'intermédiaire de
l'interface pcap(3), bien que cela ne couvre qu'un sous-ensemble des
possibilités de AF_PACKET.
Les sockets packet SOCK_DGRAM n'essayent pas de
créer ou de traiter les en-têtes IEEE 802.2 LLC
pour une trame IEEE 802.3. Lorsque le protocole ETH_P_802_3
est indiqué en émission, le noyau crée la trame 802.3
et remplit le champ de longueur. L'utilisateur doit fournir l'en-tête
LLC pour obtenir un paquet entièrement conforme. Les paquets 802.3
entrants ne sont pas multiplexés sur les champs du protocole
DSAP/SSAP. À la place, ils sont fournis à l'utilisateur sous
le protocole ETH_P_802_2 avec un en-tête LLC ajouté. La
liaison ETH_P_802_3 n’est donc pas possible, la liaison
ETH_P_802_2 doit être utilisée à la place, et
vous devez réaliser le multiplexage de protocoles vous-même.
Le comportement par défaut en émission est
l’encapsulation Ethernet DIX standard, avec le protocole
renseigné.
Les sockets packet ne sont pas soumis aux chaînes de
pare-feu en entrée ou sortie.
Avec Linux 2.0, la seule façon d’obtenir un
socket paquet était avec l’appel :
socket(AF_INET, SOCK_PACKET, protocol)
C’est encore pris en charge mais obsolète et
fortement déconseillé. La principale différence entre
les deux méthodes est que SOCK_PACKET utilise l'ancienne
struct sockaddr_pkt pour indiquer l'interface, ce qui ne fournit
aucune indépendance vis-à-vis de la couche physique.
struct sockaddr_pkt {
unsigned short spkt_family;
unsigned char spkt_device[14];
unsigned short spkt_protocol;
};
spkt_family contient le type de périphérique,
spkt_protocol est le type de protocole IEEE 802.3 comme
défini dans <sys/if_ether.h> et spkt_device est
le nom du périphérique sous forme de chaîne
terminée par un octet NULL, par exemple eth0.
Cette structure est obsolète et ne doit pas être
employée dans des nouveaux programmes.
La gestion des en-têtes LLC IEEE 802.2/802.3 devrait
être considérée comme un bogue.
L'extension MSG_TRUNC de recvmsg(2) est une
bidouille horrible et devrait être remplacée par un message de
contrôle. Il n'y a actuellement aucun moyen d'obtenir l'adresse de
destination originelle des paquets à l’aide de
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.
Les filtres des sockets ne sont pas documentés.
socket(2), pcap(3), capabilities(7),
ip(7), raw(7), socket(7), ip(8),
RFC 894 pour l'encapsulation IP Ethernet standard.
RFC 1700 pour l'encapsulation IP IEEE 802.3.
Le fichier d'en-tête <linux/if_ether.h> pour
les protocoles de couche physique.
L'arbre des sources du noyau Linux.
/Documentation/networking/filter.rst décrit comment appliquer
des filtres Berkeley de paquets aux sockets packet.
/tools/testing/selftests/net/psock_tpacket.c contient un exemple de
code source pour toutes les versions de PACKET_RX_RING et
PACKET_TX_RING.
La traduction française de cette page de manuel a
été créée par Christophe Blaess
<https://www.blaess.fr/christophe/>, Stéphan Rafin
<stephan.rafin@laposte.net>, Thierry Vignaud
<tvignaud@mandriva.com>, François Micaux, Alain Portal
<aportal@univ-montp2.fr>, Jean-Philippe Guérard
<fevrier@tigreraye.org>, Jean-Luc Coulon (f5ibh)
<jean-luc.coulon@wanadoo.fr>, Julien Cristau
<jcristau@debian.org>, Thomas Huriaux
<thomas.huriaux@gmail.com>, Nicolas François
<nicolas.francois@centraliens.net>, Florentin Duneau
<fduneau@gmail.com>, Simon Paillard
<simon.paillard@resel.enst-bretagne.fr>, Denis Barbier
<barbier@debian.org>, David Prévot <david@tilapin.org> et
Jean-Paul Guillonneau <guillonneau.jeanpaul@free.fr>
Cette traduction est une documentation libre ; veuillez
vous reporter à la
GNU General
Public License version 3 concernant les conditions de copie et de
distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.
Si vous découvrez un bogue dans la traduction de cette page
de manuel, veuillez envoyer un message à
debian-l10n-french@lists.debian.org.