应用程序使用RAW socket从内核中抓取指定协议的数据包流程分析;
应用程序:
int init_sockets() { struct ifreq ifr; struct sockaddr_ll addr; struct sockaddr_in addr2;
drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));//802.1x协议(0x888e) if (drv->sock < 0) { perror("socket[PF_PACKET,SOCK_RAW]"); return -1; }
os_memset(&ifr, 0, sizeof(ifr)); os_strlcpy(ifr.ifr_name, “eth0”, sizeof(ifr.ifr_name));//指定接口eth0 if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {//获取eth0接口的index perror("ioctl(SIOCGIFINDEX)"); return -1; }
os_memset(&addr, 0, sizeof(addr)); addr.sll_family = AF_PACKET; addr.sll_ifindex = ifr.ifr_ifindex;
if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {//绑定sock perror("bind"); return -1; } ... return 0; }
void read(int sock...) { int len; unsigned char buf[3000]; len = recv(sock, buf, sizeof(buf), 0); ... } int send(int sock, char *buf, int bufsize) { return send(sock, buf, bufsize, 0); ... }
|
内核协议:(net/packet/af_packet.c)
函数 | 说明 |
static int packet_create(struct net *net, struct socket *sock, int protocol) | Create a packet of type SOCK_PACKET. |
static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | Bind the sock to the protocol |
static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 protocol) | Attach a packet hook |
void dev_add_pack(struct packet_type *pt) | Add a protocol handler to the networking stack |
static int packet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | ioctl |
static int packet_notifier(struct notifier_block *this, unsigned long msg, void *data) | setup a packet notifier |
static int packet_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) | getsocket() |
static int packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) | setsocket() |
static int packet_mc_add(struct sock *sk, struct packet_mreq_max *mreq) | join in multicast group |
static int packet_mc_drop(struct sock *sk, struct packet_mreq_max *mreq) | leave multicast group |
static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags) | Pull a packet from our receive queue and hand it to the user. If necessary we block. |
static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len) | send msg to |
static int packet_release(struct socket *sock) | Close a PACKET socket. This is fairly simple. We immediately go to 'closed' state and remove our protocol entry in the device list. |
用户空间 | 内核空间 | 说明 |
socket() | packet_create() | 创建特定类型socket |
ioctl() | packet_ioctl() |
|
bind() | packet_bind() | 绑定socket |
recv() | packet_recvmsg() |
|
send() | packet_sendmsg() |
|
setsocket() | packet_setsockopt() |
|
getsocket() | packet_getsockopt() |
|
注意:如果没有注册对802.1x协议包的监听操作,则802.1x协议包在netif_receive_skb()函数中将在最后被丢弃。
if (pt_prev) { //监听并处理802.1x协议包 ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev); } else { //如果没有监听操作,802.1x协议包将在这里丢弃 kfree_skb(skb); /* Jamal, now you will not able to escape explaining * me how you were going to use this. :-) */ ret = NET_RX_DROP; } |