Linux下的packet socket使用总结

上节讲到的RAW socket虽然已经能处理IP层的数据了,但是在实际的应用中可能需要获取更加底层的报文信息。这就需要用到另一种更加强大的socket创建方式——packet socket,创建之后直接可以操作包括以太层在内的报文数据。

packet socket的创建方式如下:

socket(AF_PACKET, int socket_type, int protocol);

其中socket_type有SOCK_RAW 和 SOCK_DGRAM两种类型,它们的区别如下:
使用SOCK_RAW参数创建的packet socket收到的数据包含以太头及以太头以上的数据;
使用SOCK_DGRAM参数创建的packet socket收到的数据不包含以太头。

protocol参数常用的有ETH_P_IP,ETH_P_ARP和ETH_P_ALL三种,指定为ETH_P_IP后可以抓取ARP报文,指定ETH_P_ARP后可以抓取ARP报文,指定ETH_P_ALL后可以抓取所有报文。需要注意的是这个参数在指定时需要将协议类型转换为网络序传入,如htons(ETH_P_ALL),否则会导致无法抓取到预期的报文。更多的以太层协议类型可以在linux/if_ether.h头文件中找到。
创建了packet socket后,默认情况下所有网口的报文都能收到,如果只想收到指定网口的报文,需要使用bind接口传入struct sockaddr_ll结构来设置。struct 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是标准的以太层协议,默认为创建socket时的指定的协议类型,具体定义见linux/if_ether.h;
sll_ifindex是网卡的接口索引,传入0将匹配所有接口,接口索引可以使用if_nametoindex接口获取;
sll_hatype是ARP的类型,具体定义见linux/if_arp.h;
sll_pkttype指定报文的类型,有效的类型有PACKET_HOST, PACKET_BROADCAST, PACKET_MULTICAST, PACKET_OTHERHOST,PACKET_OUTGOING五种,分别表示发往本地主机、以太层广播报文、以太层多播报文、发往其他主机的报文和本地主机的环回报文。这些类型只在接收报文时有效;
sll_halen和sll_addr分别用来表示报文的MAC地址长度和报文的MAC地址。

如果用packet socket来发送报文,sll_family,sll_addr, sll_halen和sll_ifindex这四个参数就够了,其他参数应该都赋值为0。在调用bind接口时只有sll_protocol和sll_ifindex会被用到。

你可能感兴趣的:(Linux)