sockaddr_ll
在Linux下接收数据链路层的数据包
- 原始的方法,即创建一个类型为SOCK_PACKET的socket,该方法很普遍,但是缺乏灵活性;
- 新的方法,引入了帧过滤功能和性能上的提升,即创建一个指定协议簇为 PF_PACKET的socket,这需要root权限(类似于创建一个raw socket),并且socket的第三个参数必须指定一个以太网帧类型(Ethernet frame type,可以在头文件<linux/if_ether.h>中找到);使用第二种方法时,socket的第二个参数可以被设置为SOCK_DGRAM,主要区别是当指定SOCK_DGRAM时,获取的数据包是去掉了数据链路层的头(link-layer header),当指定SOCK_RAW时,获取的数据包是一个完整的数据链路层数据包, SOCK_PACKET只返返回完整的数据链路层数据包,示例,接收完整的数据链路层数据包,可以这样写:
fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))
sockaddr_ll 定义在头文件 <linux/if_packet.h> 中
struct sockaddr_ll {
unsigned short sll_family;
__be16 sll_protocol;
int sll_ifindex;
unsigned short sll_hatype; // 接收时使用
unsigned char sll_pkttype; // 接收时使用
unsigned char sll_halen;
unsigned char sll_addr[8];
};
sll_family : 一般为AF_PACKET
sll_protocol : 标准以太网协议类型,按网络字节顺序。定义在中。
sll_ifindex : interface索引,0 匹配所有的网络接口卡;
sll_hatype : ARP 硬件地址类型(hardware address type) 定义在中,常用 ARPHRD_ETHER
sll_pkttype : 包含了packet类型。
名称 | 值 | 目标 |
---|---|---|
PACKET_HOST | 0 | 本地主机 |
PACKET_BROADCAST | 1 | 广播 |
PACKET_MULTICAST | 2 | 物理层多播地址 |
PACKET_OTHERHOST | 3 | 其它在混杂模式下被设备捕获的主机 |
PACKET_OUTGOING | 4 | 本地回环包 |
... | ... | ... |
sll_addr : 物理层地址
ssl_halen : 物理层地址长度
当发送数据包时,指定 sll_family, sll_addr, sll_halen, sll_ifindex, sll_protocol 就足够了。其它字段设置为0; sll_hatype和 sll_pkttype是在接收数据包时使用的; 如果要bind, 只需要使用 sll_protocol和 sll_ifindex;