Linux内核构造数据包并发送(二)(dev_queue_xmit方式)
2013-05-06 10:27
357 查看
linux内核太构造数据包的第二种方式就是直接调用dev_queue_xmit函数,将构造完毕的数据包直接发送到网卡驱动。从NF框架来看,该函数的调用是在 POSTROUTING点之后了,也可以理解为直接通过调用二层的发送函数,将三层构造的数据包发送出去。该函数实际上会调用 skb->dev->hard_start_xmit,即对应网卡的驱动函数,将数据包直接发送的出去。
很显然,这个工作在二层的函数,发送数据包(数据包在二层的时候准确叫法应该是帧,我们这里是在三层直接调用的,权且还称作数据包)的方式是不需要再查路由了。
但是,二层发送的时候是需要根据目的MAC来进行的。在第一种方法构造的数据包中,仅仅交换了IP地址,而没有对MAC做任何修改。这样直接调用 dev_queue_xmit是会产生问题的,并且该函数发送的内容应该是从二层头部开始,到数据包的结束。因此,如果三层构造的数据包,想调用该函数直接发送数据包的话,则需要修改数据包的源和目的MAC,并将skb->data指针指向MAC头部,以及skb->len的值也要加上头部的长度方法。以下是可参考的示例代码:
C代码
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);
[c]
view plaincopyprint?
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);
(1)第一种发送数据包的实现,对于send_reset函数的实现中,由于单独申请了nskb的内存,并构造的新的数据包。新数据包接着走NF的流程了。而对于原始的skb,就通过模块的返回值return NF_DROP做出了处理。
(2)第二种发送数据包的实现,若是基于已有数据包的基础上重新构造的数据包,那么实际上原始数据包的内容已经不复存在,而且调用完毕 dev_queue_xmit已将同一块缓冲区,只是填充了新数据的数据包发送出去,因此,这里已经没有原始数据包的存在了,需要返回 NF_STOLEN,告诉协议栈不用关心原始的包即可。否则,若是新数据包是单独申请的内存,那么对于原数据包还应该是返回NF_DROP.
很显然,这个工作在二层的函数,发送数据包(数据包在二层的时候准确叫法应该是帧,我们这里是在三层直接调用的,权且还称作数据包)的方式是不需要再查路由了。
但是,二层发送的时候是需要根据目的MAC来进行的。在第一种方法构造的数据包中,仅仅交换了IP地址,而没有对MAC做任何修改。这样直接调用 dev_queue_xmit是会产生问题的,并且该函数发送的内容应该是从二层头部开始,到数据包的结束。因此,如果三层构造的数据包,想调用该函数直接发送数据包的话,则需要修改数据包的源和目的MAC,并将skb->data指针指向MAC头部,以及skb->len的值也要加上头部的长度方法。以下是可参考的示例代码:
C代码
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);
[c]
view plaincopyprint?
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);
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内核构造数据包并发送(二)(dev_queue_xmit方式)
- Linux网络之设备接口层:发送数据包流程dev_queue_xmit
- Linux网络之设备接口层:发送数据包流程dev_queue_xmit(二)
- Linux内核发送构造数据包的方式
- Linux内核构造数据包并发送(Netfilter方式)
- Linux内核发送构造数据包的方式
- Linux网络之设备接口层:发送数据包流程dev_queue_xmit
- Linux发送函数dev_queue_xmit分析 --转
- 使用dev_queue_xmit发送定制报文
- 网络数据包发送之dev_hard_start_xmit
- 使用dev_queue_xmit发送定制报文
- 【Linux4.1.12源码分析】二层报文发送之dev_queue_xmit
- Linux发送函数dev_queue_xmit
- Linux发送函数dev_queue_xmit分析
- 使用dev_queue_xmit发送定制报文
- tcp/ip 发包时,函数调用:从 tcp_connect() 到 __dev_queue_xmit()
- Linux内核构造和发送vlan&udp数据报文
- 使用SharpPcap发送虚假构造的伪IP的UDP数据包
- Linux 网络协议栈开发代码分析篇之数据收发(二) —— dev_queue_xmit()函数
- Linux发送函数dev_queue_xmit分析&…