NOMBRE¶
packet, PF_PACKET - Interfaz de paquetes a nivel de dispositivo.
SINOPSIS¶
#include <sys/socket.h>
#include <features.h> /* para el número de versión de glibc */
#if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1
#include <netpacket/packet.h>
#include <net/ethernet.h> /* los protocolos de nivel 2 */
#else
#include <asm/types.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h> /* los protocolos de nivel 2 */
#endif
packet_socket = socket(PF_PACKET, int socket_type, int protocol);
DESCRIPCIÓN¶
Los conectores de paquetes (packet sockets) se usan para recibir o enviar
paquetes directos (raw) en el nivel del manejador de dispositivo (Nivel 2 de
OSI). Permiten al usuario implementar módulos de protocolo en el espacio
de usuario por encima de la capa física.
socket_type es o bien
SOCK_RAW para paquetes directos incluyendo
la cabecera del nivel de enlace o bien
SOCK_DGRAM para paquetes
preparados con la cabecera del nivel de enlace eliminada. La información
de la cabecera del nivel de enlace está disponible en un formato
común en una estructura
sockaddr_ll.
protocol es el
protocolo IEEE 802.3 con los bytes en orden de red. Vea el fichero cabecera
<linux/if_ether.h> para una lista de los protocolos permitidos.
Cuando se asigna a
protocol el valor
htons(ETH_P_ALL), se
reciben todos los protocolos. Todos los paquetes de entrada con el tipo de
protocolo indicado se pasarán al conector de paquetes antes de que sean
pasados a los protocolos implementados dentro del núcleo.
Sólo los procesos con uid efectivo 0 o la capacidad
CAP_NET_RAW
pueden abrir conectores de paquetes.
Los paquetes
SOCK_RAW se pasan a y desde el manejador de dispositivo sin
ningún cambio en los datos del paquete. Cuando se recibe un paquete, la
dirección todavía se analiza y se pasa en una estructura de
dirección
sockaddr_ll estándar. Cuando se transmite un
paquete, el buffer proporcionado por el usuario debería contener la
cabecera de la capa física. A continuación, ese paquete se encola
sin modificar en la tarjeta de red de la interfaz definida por la
dirección de destino. Algunos manejadores (`drivers') de dispositivo
siempre añaden otras cabeceras.
SOCK_RAW es similar pero no
compatible con el obsoleto
SOCK_PACKET de la versión 2.0 de Linux.
SOCK_DGRAM opera en un nivel ligeramente superior. Se elimina la cabecera
física antes de que el paquete se pase al usuario. Los paquetes enviados
a través de un conector de paquetes
SOCK_DGRAM obtienen una
cabecera adecuada de la capa física según la información de la
dirección de destino
sockaddr_ll, antes de ser encolados.
Por defecto, todos los paquetes del tipo de protocolo especificado se pasan a un
conector de paquetes. Para obtener sólo los paquetes de una interfaz
específica, use
bind(2) especificando una dirección en una
estructura
struct sockaddr_ll para enlazar el conector de paquetes a
una interfaz. Sólo se usan para propósitos de enlace los campos de
dirección
sll_protocol y
sll_ifindex.
La operación
connect(2) no está soportada en conectores de
paquetes.
Cuando se pasa la opción
MSG_TRUNC a
recvmsg(2),
recv(2),
recvfrom(2) se devuelve siempre en última
instancia la longitud real del paquete, incluso cuando es mayor que la del
buffer.
TIPOS DE DIRECCIONES¶
sockaddr_ll es una dirección de la capa física independiente del
dispositivo.
struct sockaddr_ll {
unsigned short sll_family; /* Siempre es AF_PACKET */
unsigned short sll_protocol; /* Protocolo de la capa física */
int sll_ifindex; /* Número de la interfaz */
unsigned short sll_hatype; /* Tipo de cabecera */
unsigned char sll_pkttype; /* Tipo de paquete */
unsigned char sll_halen; /* Longitud de la dirección */
unsigned char sll_addr[8]; /* Dirección de la capa física */
};
sll_protocol es el tipo del protocolo ethernet estándar dado en
orden de red definido en el fichero cabecera
linux/if_ether.h. Su valor
por defecto es el protocolo del conector.
sll_ifindex es el índice
de la interfaz (vea
netdevice(7)); el valor 0 concuerda con cualquier
interfaz (sólo legal para enlazar).
sll_hatype es un tipo ARP de
los definidos en el fichero cabecera
linux/if_arp.h.
sll_pkttype
contiene el tipo del paquete. Los tipos válidos son
PACKET_HOST
para un paquete aplicado al anfitrión (host) local,
PACKET_BROADCAST para un paquete de difusión de la capa
física,
PACKET_MULTICAST para un paquete enviado a una
dirección multidestino de la capa física,
PACKET_OTHERHOST
para un paquete destinado a otros anfitriones que ha sido capturado por el
manejador del dispositivo en modo promiscuo y
PACKET_OUTGOING para un
paquete originado desde el anfitrión local que es devuelto de regreso a
un conector de paquetes. Estos tipos sólo tienen sentido para recibir.
sll_addr y
sll_halen contienen la dirección de la capa
física (por ejemplo, IEEE 802.3) y su longitud. La interpretación
exacta depende del dispositivo.
Cuando se envían paquetes es suficiente con especificar
sll_family,
sll_addr,
sll_halen,
sll_ifindex. Los otros campos
deberían estar a 0.
sll_hatype y
sll_pkttype toman sus
valores en los paquetes recibidos para su información. Para enlazar
sólo se utilizan
sll_protocol y
sll_ifindex.
OPCIONES DE LOS CONECTORES¶
Los conectores de paquetes sólo se pueden usar para configurar el
envío multidestino de la capa física y el modo promíscuo. Esto
funciona llamando a
setsockopt(2) con SOL_PACKET, para un conector de
paquetes, y una de las opciones
PACKET_ADD_MEMBERSHIP para añadir
un enlace o
PACKET_DROP_MEMBERSHIP para eliminarlo. Ambas esperan una
estructura
packet_mreq como argumento:
struct packet_mreq
{
int mr_ifindex; /* índice de la interfaz */
unsigned short mr_type; /* acción */
unsigned short mr_alen; /* longitud de la dirección */
unsigned char mr_address[8]; /* dirección de la capa física */
};
mr_ifindex contien el índice de la interfaz cuyo estado debe
cambiarse. El parámetro
mr_type indica la acción a realizar.
PACKET_MR_PROMISC habilita la recepción de todos los paquetes
sobre un medio compartido (conocido normalmente como ``modo promiscuo''),
PACKET_MR_MULTICAST enlaza el conector al grupo multidestino de la capa
física indicado en
mr_address y
mr_alen, y
PACKET_MR_ALLMULTI configura el conector para recibir todos los
paquetes multidestino que lleguen a la interfaz.
Además, se pueden usar las ioctls tradicionales,
SIOCSIFFLAGS,
SIOCADDMULTI y
SIOCDELMULTI, para el mismo propósito.
IOCTLS¶
SIOCGSTAMP se puede usar para recibir la marca de tiempo del último
paquete recibido. El argumento es una esctructura
struct timeval.
Además, todas las ioctls estándares definidas en
netdevice(7) y
socket(7) son válidas en los conectores de paquetes.
MANEJO DE ERRORES¶
Los conectores de paquetes no manejan otros errores que los ocurridos al pasar
el paquete al manejador del dispositivo. No poseen el concepto de error
pendiente.
COMPATIBILIDAD¶
En la versión 2.0 de Linux, la única forma de obtener un conector de
paquetes era llamando a
socket(PF_INET, SOCK_PACKET,
protocol). Esto todavía está soportado pero se
desaprueba fuertemente. La principal diferencia entre los dos métodos es
que
SOCK_PACKET, para especificar una interfaz, usa la antigua
struct sockaddr_pkt que no proporciona independencia de la capa
física.
struct sockaddr_pkt
{
unsigned short spkt_family;
unsigned char spkt_device[14];
unsigned short spkt_protocol;
};
spkt_family contiene el tipo del dispositivo,
spkt_protocol es el
tipo del protocolo IEEE 802.3 de los definidos en
<sys/if_ether.h> y
spkt_device es el nombre del
dispositivo dado como una cadena terminada en un nulo, por ejemplo, eth0.
Esta estructura está obsoleta y no debería usarse en código
nuevo.
OBSERVACIONES¶
Se sugiere que los programas transportables usen
PF_PACKET a través
de
pcap(3), aunque esto sólo cubre un subconjunto de las
características de
PF_PACKET.
Los conectores de paquetes
SOCK_DGRAM no intentan crear o analizar la
cabecera LLC IEEE 802.2 para una trama IEEE 802.3. Cuando se especifica
ETH_P_802_3 como protocolo para enviar, el núcleo crea la trama
802.3 y rellena el campo de longitud. El usuario tiene que proporcionar la
cabecera LLC para obtener un paquete totalmente conforme. Los paquetes 802.3
de entrada no son multiplexados en los campos DSAP/SSAP del protocolo. En su
lugar, se entregan al usuario como protocolo
ETH_P_802_2 con la
cabecera LLC añadida. Por tanto, es imposible enlazar con
ETH_P_802_3. Enlace en su lugar con
ETH_P_802_2 y haga usted
mismo la multiplexación del protocolo. Para enviar por omisión se
utiliza la encapsulación estándar Ethernet DIX con el dato del
protocolo lleno.
Los conectores de paquetes no están sujetos a las cadenas de entrada ni de
salida del cortafuegos.
ERRORES¶
- ENETDOWN
- La interfaz no está activa.
- ENOTCONN
- No se ha pasado una dirección de interfaz.
- ENODEV
- Nombre de dispositivo o índice de interfaz,
especificados en la dirección de interfaz, desconocidos.
- EMSGSIZE
- El paquete es más grande que la MTU de la interfaz.
- ENOBUFS
- No hay suficiente memoria para colocar el paquete.
- EFAULT
- El usuario ha pasado una dirección de memoria
inválida.
- EINVAL
- Argumento inválido.
- ENXIO
- La dirección de interfaz contiene un índice de
interfaz ilegal.
- EPERM
- El usuario no tiene privilegios suficientes para llevar a
cabo esta operación.
- EADDRNOTAVAIL
- Se ha pasado una dirección desconocida de grupo
multidestino.
- ENOENT
- No se ha recibido ningún paquete.
Además, el manejador de bajo nivel puede generar otros errores.
VERSIONES¶
PF_PACKET es una nueva característica de la versión 2.2 de
Linux. Las primeras versiones de Linux sólo soportaban
SOCK_PACKET.
FALLOS¶
glibc 2.1 no posee una macro "define" para
SOL_PACKET. La
solución sugerida es usar
#ifndef SOL_PACKET
#define SOL_PACKET 263
#endif
Esto se soluciona en versiones posteriores de glibc. Este problema tampoco se
produce en sistemas libc5.
El tratamiento del IEEE 802.2/803.3 LLC se podría considerar un fallo.
No se han documentado los filtros de los conectores.
La extensión
MSG_TRUNC de recvmsg es una solución chapucera y
debería ser reemplazada por un mensaje de control. Actualmente no hay
ninguna manera de obtener la dirección de destino original de paquetes
via SOCK_DGRAM.
CREDITOS¶
Esta página de manual fue escrita por Andi Kleen con la ayuda de Matthew
Wilcox.
Alexey Kuznetsov implementó la característica PF_PACKET de la
versión 2.2 de Linux basándose en el código de Alan Cox y
otros.
VÉASE TAMBIÉN¶
ip(7),
socket(7),
socket(2),
raw(7),
pcap(3)
RFC 894 for the standard IP Ethernet encapsulation.
RFC 1700 for the IEEE 802.3 IP encapsulation.
El fichero cabecera
<linux/if_ether.h> para los protocolos de la
capa física.