Linux内核构造数据包并发送(二)(dev_queue_xmit方式)

linux内核太构造数据包的第二种方式就是直接调用dev_queue_xmit函数,将构造完毕的数据包直接发送到网卡驱动。从NF框架来看,该函数的调用是在 POSTROUTING点之后了,也可以理解为直接通过调用二层的发送函数,将三层构造的数据包发送出去。该函数实际上会调用 skb->dev->hard_start_xmit,即对应网卡的驱动函数,将数据包直接发送的出去。 

       很显然,这个工作在二层的函数,发送数据包(数据包在二层的时候准确叫法应该是帧,我们这里是在三层直接调用的,权且还称作数据包)的方式是不需要再查路由了。 

但是,二层发送的时候是需要根据目的MAC来进行的。在第一种方法构造的数据包中,仅仅交换了IP地址,而没有对MAC做任何修改。这样直接调用 dev_queue_xmit是会产生问题的,并且该函数发送的内容应该是从二层头部开始,到数据包的结束。因此,如果三层构造的数据包,想调用该函数直接发送数据包的话,则需要修改数据包的源和目的MAC,并将skb->data指针指向MAC头部,以及skb->len的值也要加上头部的长度方法。以下是可参考的示例代码: 

 

unsigned char mac_temp[ETH_ALEN] = {0};  
  
 struct ethhdr *mach = NULL;  
  
 ……  
  
 /*code…… 构造数据包的IP即上层协议及数据*/  
  
 ……  
  
/*交换源和目的MAC*/  
  
  mach = (struct ethhdr *)skb->mac.raw;  
  
   memcpy(mac_temp, (unsigned char *)mach->h_dest, ETH_ALEN);  
  
   memcpy(mach->h_dest, (unsigned char *)mach->h_source, ETH_ALEN);  
  
   memcpy(mach->h_source, mac_temp, ETH_ALEN);  
  
/*修改skb->data指针,使其指向MAC头部,并且增加skb->len*/  
  
skb_push(skb , ETH_HLEN);  
  
/*直接调用该函数,将数据包从网卡上发送出去*/  
  
ret = dev_queue_xmit(skb);  
  这里还要顺便说一下构造的数据包发送完毕之后,对于hook函数的返回值问题。 

   (1)第一种发送数据包的实现,对于send_reset函数的实现中,由于单独申请了nskb的内存,并构造的新的数据包。新数据包接着走NF的流程了。而对于原始的skb,就通过模块的返回值return NF_DROP做出了处理。 
   (2)第二种发送数据包的实现,若是基于已有数据包的基础上重新构造的数据包,那么实际上原始数据包的内容已经不复存在,而且调用完毕 dev_queue_xmit已将同一块缓冲区,只是填充了新数据的数据包发送出去,因此,这里已经没有原始数据包的存在了,需要返回 NF_STOLEN,告诉协议栈不用关心原始的包即可。否则,若是新数据包是单独申请的内存,那么对于原数据包还应该是返回NF_DROP.

你可能感兴趣的:(框架,linux,工作)