packet(7)

PACKET(7) 2008-08-08

NAME

       packet, AF_PACKET —— 设备层的包接口。

SYNOPSIS

#include <sys/socket.h>
#include <netpacket/packet.h>
#include <net/ethernet.h> /* the L2 protocols */

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

 

DESCRIPTION

 包套接字用于收发设备层(OSI二层)的原始数据包。这允许用户在用户空间实现物理层顶部的协议模块。

若指定socket_type为SOCK_RAW则意味着原始数据包包含了链路层头部,若指定为SOCK_DGRAM则将做一些处理以剥掉链路层头部。链路层头部信息的通用格式是一个sockaddr_ll结构。protocol填入网络字节序的IEEE 802.3协议号。参见<linux/if_ether.h>头文件了解允许的协议。如果protocol被设置为htons(ETH_P_ALL),则意味着接受所有协议。所有接入的协议类型为protocol的数据包将在传递给内核之前传递到PACKET套接字。
只有有效UID为0或具备CAP_NET_RAW特权的进程可以打开PACKET套接字。
从设备驱动收发的SOCK_RAW包数据的过程中将不会做任何更改。当收到一个包,地址仍然可以传递给标准的sockaddr_ll地址结构进行解析。当发送一个包,用户提高的缓冲应该包含一个物理层头部,然后它就直接不加修改地加入目标地址定义的设备队列。一些设备驱动总是添加其他头部。SOCK_RAW类似但不兼容过时的AF_INET/SOCK_PACKET套接字。
收发SOCK_DGRAM的操作稍稍高级一些。物理层头部在包传递给用户之前被移除了。通过SOCK_DGRAM的包套接字发送的包将在其排队之前免费获得一个合适的物理层头部,基于目的地址sockaddr_ll提供的信息。
默认情况下,指定协议的所有报文都将传递到一个包套接字。为了只接收一个指定接口的包,需要传递一个包含地址的sockaddr_ll结构给bind以将包套接字绑定到一个接口。只有sll_protocol和sll_ifindex地址字段用于这样的目的。
connect操作在包套接字上是不支持的。
当传递了MSG_TRUNC标记给recvmsg,recv和recvfrom,线路上的数据包的真实长度总是被返回,即便长于缓冲区。
地址类型
sockaddr_ll是一个独立于设备的物理层地址。
struct sockaddr_ll {
unsigned short sll_family; /* Always AF_PACKET */
unsigned short sll_protocol; /* Physical layer protocol */
int sll_ifindex; /* Interface number */
unsigned short sll_hatype; /* Header type */
unsigned char sll_pkttype; /* Packet type */
unsigned char sll_halen; /* Length of address */
unsigned char sll_addr[8]; /* Physical layer address */
};
sll_protocol是网络字节序的标准以太网协议类型,其定义在头文件<linux/if_ether.h>。其默认取套接字的协议。sll_ifindex是接口索引(参见netdevice(7)),0匹配任何接口(只允许用于绑定)。sll_hatype是一个ARP类型,定义在<linux/if_arp.h>。sll_pkttype包含包类型,有效的包类型有:PACKET_HOST表示到本地主机的包,PACKET_BROADCAST表示物理层广播包,PACKET_OTHERHOST表示设备驱动在混杂模式下抓到的发往其他主机的包,PACKET_OUTGOING是一个来自本地主机的回环到包套接字。这些类型都是接收时遇到。sll_addr和sll_halen包含物理层(如IEEE 802.3)地址和其长度。确切的解释依赖于设备。
当你发送一个包时只需要指定sll_family,sll_addr,sll_halen和sll_ifindex就够了,其他的字段都应该清零。sll_hatype和sll_pkttype只在接收包时使用,sll_protocol和sll_ifindex只用于bind。
套接字选项
包套接字可以配置物理层多播和混杂模式。在一个包套接字上以SOL_PACKET调用setsockopt,一个选项PACKET_ADD_MEMBERSHIP可以加入,PACKET_DROP_MEMBERSHIP可以退出。它们都期望一个packet_mreq结构作为参数:
struct packet_mreq {
int mr_ifindex; /* interface index */
unsigned short mr_type; /* action */
unsigned short mr_alen; /* address length */
unsigned char mr_address[8]; /* physical layer address */
};
mr_ifindex包含目标接口索引。mr_type参数指定执行哪个动作。PACKET_MR_PROMISC启用在共享媒介上接收所有的包(常称之为“混杂模式”);PACKET_MR_MULTICAST绑定套接字到一个物理层多播组,该组地址由mr_address和mr_alen指定;PACKET_MR_ADDMULTI设置套接字接收所有到达接口的多播数据包。
此外,传统的ioctls SIOCSIFFLAGS、SIOCADDMULTI、SIOCDELMULTI可以做同样的事情。
Ioctls
SIOCGSTAMP可以用于接收最后到达的时间戳。参数是timeval结构。
其余的定义在netdevice(7)和socket(7)的所有标准的ioctl操作对包套接字都是有效的。
出错处理
包套接字与设备驱动传递包时出错并不红醋栗错误,这里没有未决错误的概念。
ERRORS
       EADDRNOTAVAIL
              传递了未知的多播组地址。
       EFAULT 用户传递了非法内存地址。
       EINVAL 无效参数。
       EMSGSIZE
              包的大小超过MTU。
       ENETDOWN
              接口未启用。
       ENOBUFS
              没有足够的内存来分配给包。Not enough memory to allocate the packet.
       ENODEV 指定的接口地址内包含未知的设备名或接口索引。
       ENOENT 没有收到包。
       ENOTCONN
              没有传递接口地址。
       ENXIO  接口地址包含无效的接口索引。
       EPERM  用户操作的权限不足。
              此外,其他的错误可能被低层设备生成。
VERSIONS
       AF_PACKET是Linux2.2的新特性。早期版本的Linux只支持SOCK_PACKET。
       当前需要头文件:<netpacket/packet.h>(since  glibc  2.1)。
       过去的系统需要:
#include <asm/types.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h> /* The L2 protocols */
NOTES
移植程序建议通过pcap(3)使用AF_PACKET。即便它只占AF_PACKET特性的一个子集。
SOCK_DGRAM包套接字不尝试创建或解析IEEE 802.2 LLC报头或IEEE 802.3帧。当ETH_P_802_3指定为发送协议时,内核创建802.3帧并填写长度字段;用户必须提供LLC头部以组成完整数据包。传入的802.3数据包不会复用DSAP/SSAP协议字段,而是当做带LLC头前缀的ETH_P_802_2提供给用户,因此而无法绑定到ETH_P_802_3,只能绑定到ETH_P_802_2来自己复用协议。默认发送的是填入协议的标准以太网DIX封装数据包。
包套接字不受限于防火墙的进出规则。
兼容性
Linux 2.0时,获取包套接字的唯一方式是调用socket(AF_INET, SOCK_PACKET, protocol)。这个仍然被支持但是已经很过时了。两种方法的主要不同在于SOCK_PACKET使用老式的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是空字符结尾的字串,如“eth0”。
此结构已经废弃,不应该再用在新的代码中。
BUGS
glibc 2.1没有SOL_PACKET定义,建议的解决方案如下:
#ifndef SOL_PACKET
#define SOL_PACKET 263
#endif
此值在后续的glibc版本是固定的,且不与libc5系统冲突。
IEEE 802.2/803.3的LLC处理可以视作BUG。
套接字过滤器尚无文档。
recvmsg的MSG_TRUNC扩展是一个ugly hack,应该用控制消息替换。当前没有办法通过SOCK_DGRAM获取数据包的原始目的地址。
SEE ALSO
       socket(2), pcap(3), capabilities(7), ip(7), raw(7), socket(7)
 
       RFC 894 for the standard IP Ethernet encapsulation.
 
       RFC 1700 for the IEEE 802.3 IP encapsulation.
 
       The <linux/if_ether.h> include file for physical layer protocols.
COLOPHON
       This  page  is  part of release 3.23 of the Linux man-pages project.  A
       description of the project, and information about reporting  bugs,  can
       be found at http://www.kernel.org/doc/man-pages/.
 
 
 
 

你可能感兴趣的:(c)