Linux下的Packet Socket的使用
Hanse <hansel@163.com>
2009-4-3
Linux支持PF_PACKET类型的套接字,用于实现用户层的网络协议。通过该SOCK_RAW类型的Packet socket,应用程序可以直接接收带完整二层数据帧,处理完毕后再使用该socket发出二层数据帧。因此可以实现更底层的网络协议。也可以通过该类型的Socket实现网络抓包,当然,如果要抓取不是自己的网络报文,还需要把网卡设置为混杂模式。
1、创建Packet Socket
<pre>
#include <sys/socket.h>
#include <netpacket/packet.h>
#include <net/ethernet.h> /* the L2 protocols */
packet_socket = socket(PF_PACKET, int socket_type, int protocol);
</pre>
其中socket_type可以是SOCK_DGRAM,SOCK_RAW。设置为SOCK_RAW则接收到的报文中包含二层协议头,否则只有二层数据帧内容。
例如:
int skfd;
skfd = socket(PF_PACKET, SOCK_RAW, htons(protocol));
2、绑定到网络接口
这一步是可选的。如果不绑定,则所有接口上的二层数据帧都会收到。
struct sockaddr_ll ll;
struct ifreq ifr;
strncpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name));
memset(l2, 0, sizeof(*l2));
strncpy(l2->ifname, ifname, sizeof(l2->ifname));
memset(&ll, 0, sizeof(ll));
ll.sll_family = PF_PACKET;
ll.sll_ifindex = ifr.ifr_ifindex;
ll.sll_protocol = htons(protocol);
if (bind(l2->fd, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
perror("bind[PF_PACKET]");
close(l2->fd);
free(l2);
return NULL;
}
protocol是需要监听的协议类型,如果为ETH_P_ALL,则接收所有数据帧。
注意:
桥中接收不到转发的非自己的报文
ssize_t recvfrom(int s, void *buf, size_t len, int flags,
struct sockaddr *from, socklen_t *fromlen);
如果传入fromlen为0则不会填充from参数。
参考文档:
1、Linux Man: packet(7)