應用程序使用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; } |