[求助]在netfilter挂载点对sk_buff进行操作的问题
时间:2010-11-02
来源:互联网
两台主机(A,B)通信,A->B发送数据报。
A,B都加载模块。A发时,对数据报进行“包裹”;B收时,进行“解包”。我所说的“包裹”,就是在ip包头和四层数据之间,添加一个数据结构(保存一些信息);“解包”时恢复原数据。
基本思路是:仿照aodv-uu网关功能的实现。在A(192.168.3.3)的NF_IP_LOCAL_OUT,对源为192.168.3.3的skb_buff进行重新封装(申请一个新的skb_buff,把原始报的所有数据复制进新skb_buff,并在ip包头和四层数据之间添加一个数据结构,然后释放原始skb_buff),然后然后让新的skb_buff沿netfiter继续流动;在B(192.168.3.4)的NF_IP_PRE_ROUTING,对源为192.168.3.3的sk_buff,进行恢复。
但是,我测试发现在A的NF_IP_LOCAL_OUT对192.168.3.3的skb_buff做任何修改都会引起内核崩溃,不知缘故,特来求救。
代码如下
/*#define _KERNEL_ */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/netdevice.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <net/tcp.h>
#include <linux/netfilter_ipv4.h>
#include <linux/timer.h>
#include <net/xfrm.h>
#include <linux/netdevice.h>
#define NF_IP_PRE_ROUTING 0
#define NF_IP_LOCAL_IN 1
#define NF_IP_FORWARD 2
#define NF_IP_LOCAL_OUT 3
#define NF_IP_POST_ROUTING 4
/*定义新的四层协议*/
#define IPPROTO_MIPE 55
/*在ip包头和四层数据之间添加数据结构*/
struct ip_add_hdr
{
u_int8_t protocol;
u_int8_t res:7;
u_int8_t s:1;
u_int16_t check;
u_int32_t saddr;
};
u_int16_t
my_re_check (u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
{
u_int32_t diffs[] = { oldvalinv, newval };
return
csum_fold (csum_partial
((char *) diffs, sizeof (diffs), oldcheck ^ 0xFFFF));
}
/* Simple function (based on R. Stevens) to calculate IP header checksum */
static u_int16_t
ip_csum (unsigned short *buf, int nshorts)
{
u_int32_t sum;
for (sum = 0; nshorts > 0; nshorts--)
{
sum += *buf++;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return ~sum;
}
/*重新封包*/
struct sk_buff *
ip_mpkt_encapsulate (struct sk_buff *skb, __u32 src)
{
struct ip_add_hdr *ipahr;
struct sk_buff *nskb;
struct iphdr *iph;
/*复制原始数据到新sk_buff*/
nskb = skb_copy_expand (skb, skb_headroom (skb),
skb_tailroom (skb) + sizeof (struct ip_add_hdr),
GFP_ATOMIC);
if (nskb == NULL)
{
printk ("Could not allocate new skb\n");
kfree_skb (skb);
return NULL;
}
if (skb->sk != NULL)
skb_set_owner_w (nskb, skb->sk);
iph = (struct iphdr *) skb->network_header;
skb_put (nskb, sizeof (struct ip_add_hdr));
memcpy (nskb->data, skb->data, (iph->ihl << 2));
memcpy (nskb->data + (iph->ihl << 2) + sizeof (struct ip_add_hdr),
skb->data + (iph->ihl << 2), skb->len - (iph->ihl << 2));
memcpy (nskb->data + (iph->ihl << 2),
skb->data + (iph->ihl << 2), skb->len - (iph->ihl << 2));
kfree_skb (skb);
skb = nskb;
iph = (struct iphdr *) skb->data;
skb->network_header = skb->data;
/*对添加的数据结构进行赋值*/
ipahr = (struct ip_add_hdr *) (skb->data + (iph->ihl << 2));
ipahr->protocol = iph->protocol;
ipahr->s = 0;
ipahr->res = 0;
ipahr->check = 0;
ipahr->saddr = iph->saddr;
/*修改ip包头*/
iph->saddr = src;
iph->protocol = IPPROTO_MIPE;
iph->tot_len = htons (ntohs (iph->tot_len) + sizeof (struct ip_add_hdr));
ipahr->check = ip_csum ((unsigned short *) ipahr, 4);
ip_send_check (iph);
if (iph->id == 0)
{
if (skb->dst)
ip_select_ident (iph, skb->dst, NULL);
}
return skb;
}
/*解包*/
struct sk_buff *
ip_mpkt_decapsulate (struct sk_buff *skb)
{
struct ip_add_hdr *ipahdr;
struct iphdr *iph = (struct iphdr *) skb->network_header;
ipahdr = (struct ip_add_hdr *) ((char *) iph + (iph->ihl << 2));
iph->protocol = ipahdr->protocol;
iph->saddr = ipahdr->saddr;
memmove (skb->data + (iph->ihl << 2),
skb->data + (iph->ihl << 2) + sizeof (struct ip_add_hdr),
skb->len - (iph->ihl << 2) - sizeof (struct ip_add_hdr));
skb_trim (skb, skb->len - sizeof (struct ip_add_hdr));
iph = (struct iphdr *) skb->data;
skb->network_header = skb->data;
iph->tot_len = htons (ntohs (iph->tot_len) - sizeof (struct ip_add_hdr));
ip_send_check (iph);
return skb;
}
unsigned int
hook_func (unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out, int (*okfn) (struct sk_buff *))
{
struct sk_buff *sb = skb;
unsigned char src_ip[4];
unsigned char des_ip[4];
struct iphdr *iph = (struct iphdr *) (skb->network_header);
*(unsigned int *) src_ip = ip_hdr (sb)->saddr;
*(unsigned int *) des_ip = ip_hdr (sb)->daddr;
if (iph == NULL)
return NF_ACCEPT;
switch (hooknum)
{
/*NF_IP_PRE_ROUTING解包处理*/
case NF_IP_PRE_ROUTING:
if (iph->protocol == IPPROTO_MIPE && src_ip[0] == 192
&& src_ip[1] == 168 && src_ip[2] == 3 && src_ip[3] == 3)
{
ip_mpkt_decapsulate(skb);
return NF_ACCEPT;
}
break;
/*NF_IP_LOCAL_OUT重新封包处理*/
case NF_IP_LOCAL_OUT:
if (src_ip[0] == 192 && src_ip[1] == 168 && src_ip[2] == 3
&& src_ip[3] == 3)
{
skb = ip_mpkt_encapsulate (skb, iph->saddr);
if (!skb)
return NF_STOLEN;
ip_route_me_harder(skb,RTN_LOCAL);
}
}
return NF_ACCEPT;
}
static struct nf_hook_ops hook_ops[] = {
{
.hook = hook_func,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_IP_PRE_ROUTING,
.priority = NF_IP_PRI_FIRST,
},
{
.hook = hook_func,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_IP_LOCAL_OUT,
.priority = NF_IP_PRI_FILTER,
},
};
static int __init nat_init (void)
{
int ret;
ret = nf_register_hook (&hook_ops[0]);
if (ret < 0)
goto cleanup_hook0;
ret = nf_register_hook (&hook_ops[1]);
if (ret < 0)
goto cleanup_hook1;
return ret;
cleanup_hook1:
nf_unregister_hook (&hook_ops[1]);
cleanup_hook0:
nf_unregister_hook (&hook_ops[0]);
return ret;
}
void __exit nat_exit (void)
{
nf_unregister_hook (&hook_ops[1]);
nf_unregister_hook (&hook_ops[0]);
}
module_init(nat_init);
module_exit(nat_exit);
A,B都加载模块。A发时,对数据报进行“包裹”;B收时,进行“解包”。我所说的“包裹”,就是在ip包头和四层数据之间,添加一个数据结构(保存一些信息);“解包”时恢复原数据。
基本思路是:仿照aodv-uu网关功能的实现。在A(192.168.3.3)的NF_IP_LOCAL_OUT,对源为192.168.3.3的skb_buff进行重新封装(申请一个新的skb_buff,把原始报的所有数据复制进新skb_buff,并在ip包头和四层数据之间添加一个数据结构,然后释放原始skb_buff),然后然后让新的skb_buff沿netfiter继续流动;在B(192.168.3.4)的NF_IP_PRE_ROUTING,对源为192.168.3.3的sk_buff,进行恢复。
但是,我测试发现在A的NF_IP_LOCAL_OUT对192.168.3.3的skb_buff做任何修改都会引起内核崩溃,不知缘故,特来求救。
代码如下
/*#define _KERNEL_ */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/netdevice.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <net/tcp.h>
#include <linux/netfilter_ipv4.h>
#include <linux/timer.h>
#include <net/xfrm.h>
#include <linux/netdevice.h>
#define NF_IP_PRE_ROUTING 0
#define NF_IP_LOCAL_IN 1
#define NF_IP_FORWARD 2
#define NF_IP_LOCAL_OUT 3
#define NF_IP_POST_ROUTING 4
/*定义新的四层协议*/
#define IPPROTO_MIPE 55
/*在ip包头和四层数据之间添加数据结构*/
struct ip_add_hdr
{
u_int8_t protocol;
u_int8_t res:7;
u_int8_t s:1;
u_int16_t check;
u_int32_t saddr;
};
u_int16_t
my_re_check (u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
{
u_int32_t diffs[] = { oldvalinv, newval };
return
csum_fold (csum_partial
((char *) diffs, sizeof (diffs), oldcheck ^ 0xFFFF));
}
/* Simple function (based on R. Stevens) to calculate IP header checksum */
static u_int16_t
ip_csum (unsigned short *buf, int nshorts)
{
u_int32_t sum;
for (sum = 0; nshorts > 0; nshorts--)
{
sum += *buf++;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return ~sum;
}
/*重新封包*/
struct sk_buff *
ip_mpkt_encapsulate (struct sk_buff *skb, __u32 src)
{
struct ip_add_hdr *ipahr;
struct sk_buff *nskb;
struct iphdr *iph;
/*复制原始数据到新sk_buff*/
nskb = skb_copy_expand (skb, skb_headroom (skb),
skb_tailroom (skb) + sizeof (struct ip_add_hdr),
GFP_ATOMIC);
if (nskb == NULL)
{
printk ("Could not allocate new skb\n");
kfree_skb (skb);
return NULL;
}
if (skb->sk != NULL)
skb_set_owner_w (nskb, skb->sk);
iph = (struct iphdr *) skb->network_header;
skb_put (nskb, sizeof (struct ip_add_hdr));
memcpy (nskb->data, skb->data, (iph->ihl << 2));
memcpy (nskb->data + (iph->ihl << 2) + sizeof (struct ip_add_hdr),
skb->data + (iph->ihl << 2), skb->len - (iph->ihl << 2));
memcpy (nskb->data + (iph->ihl << 2),
skb->data + (iph->ihl << 2), skb->len - (iph->ihl << 2));
kfree_skb (skb);
skb = nskb;
iph = (struct iphdr *) skb->data;
skb->network_header = skb->data;
/*对添加的数据结构进行赋值*/
ipahr = (struct ip_add_hdr *) (skb->data + (iph->ihl << 2));
ipahr->protocol = iph->protocol;
ipahr->s = 0;
ipahr->res = 0;
ipahr->check = 0;
ipahr->saddr = iph->saddr;
/*修改ip包头*/
iph->saddr = src;
iph->protocol = IPPROTO_MIPE;
iph->tot_len = htons (ntohs (iph->tot_len) + sizeof (struct ip_add_hdr));
ipahr->check = ip_csum ((unsigned short *) ipahr, 4);
ip_send_check (iph);
if (iph->id == 0)
{
if (skb->dst)
ip_select_ident (iph, skb->dst, NULL);
}
return skb;
}
/*解包*/
struct sk_buff *
ip_mpkt_decapsulate (struct sk_buff *skb)
{
struct ip_add_hdr *ipahdr;
struct iphdr *iph = (struct iphdr *) skb->network_header;
ipahdr = (struct ip_add_hdr *) ((char *) iph + (iph->ihl << 2));
iph->protocol = ipahdr->protocol;
iph->saddr = ipahdr->saddr;
memmove (skb->data + (iph->ihl << 2),
skb->data + (iph->ihl << 2) + sizeof (struct ip_add_hdr),
skb->len - (iph->ihl << 2) - sizeof (struct ip_add_hdr));
skb_trim (skb, skb->len - sizeof (struct ip_add_hdr));
iph = (struct iphdr *) skb->data;
skb->network_header = skb->data;
iph->tot_len = htons (ntohs (iph->tot_len) - sizeof (struct ip_add_hdr));
ip_send_check (iph);
return skb;
}
unsigned int
hook_func (unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out, int (*okfn) (struct sk_buff *))
{
struct sk_buff *sb = skb;
unsigned char src_ip[4];
unsigned char des_ip[4];
struct iphdr *iph = (struct iphdr *) (skb->network_header);
*(unsigned int *) src_ip = ip_hdr (sb)->saddr;
*(unsigned int *) des_ip = ip_hdr (sb)->daddr;
if (iph == NULL)
return NF_ACCEPT;
switch (hooknum)
{
/*NF_IP_PRE_ROUTING解包处理*/
case NF_IP_PRE_ROUTING:
if (iph->protocol == IPPROTO_MIPE && src_ip[0] == 192
&& src_ip[1] == 168 && src_ip[2] == 3 && src_ip[3] == 3)
{
ip_mpkt_decapsulate(skb);
return NF_ACCEPT;
}
break;
/*NF_IP_LOCAL_OUT重新封包处理*/
case NF_IP_LOCAL_OUT:
if (src_ip[0] == 192 && src_ip[1] == 168 && src_ip[2] == 3
&& src_ip[3] == 3)
{
skb = ip_mpkt_encapsulate (skb, iph->saddr);
if (!skb)
return NF_STOLEN;
ip_route_me_harder(skb,RTN_LOCAL);
}
}
return NF_ACCEPT;
}
static struct nf_hook_ops hook_ops[] = {
{
.hook = hook_func,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_IP_PRE_ROUTING,
.priority = NF_IP_PRI_FIRST,
},
{
.hook = hook_func,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_IP_LOCAL_OUT,
.priority = NF_IP_PRI_FILTER,
},
};
static int __init nat_init (void)
{
int ret;
ret = nf_register_hook (&hook_ops[0]);
if (ret < 0)
goto cleanup_hook0;
ret = nf_register_hook (&hook_ops[1]);
if (ret < 0)
goto cleanup_hook1;
return ret;
cleanup_hook1:
nf_unregister_hook (&hook_ops[1]);
cleanup_hook0:
nf_unregister_hook (&hook_ops[0]);
return ret;
}
void __exit nat_exit (void)
{
nf_unregister_hook (&hook_ops[1]);
nf_unregister_hook (&hook_ops[0]);
}
module_init(nat_init);
module_exit(nat_exit);
作者: 令人愉悦的忧伤 发布时间: 2010-11-02
QUOTE:
struct sk_buff *sb = skb;
unsigned char src_ip[4];
unsigned char des_ip[4];
struct iphdr *iph = (struct iphdr *) (skb->network_header);
*(unsigned int *) src_ip = ip_hdr (sb)->saddr;
*(unsigned int *) des_ip = ip_hdr (sb)->daddr;
if (iph == NULL)
return NF_ACCEPT;
unsigned char src_ip[4];
unsigned char des_ip[4];
struct iphdr *iph = (struct iphdr *) (skb->network_header);
*(unsigned int *) src_ip = ip_hdr (sb)->saddr;
*(unsigned int *) des_ip = ip_hdr (sb)->daddr;
if (iph == NULL)
return NF_ACCEPT;
这块代码写的有点乱啊。而且前后的一致性不太好
BTW,贴出 oops 信息吧
作者: Godbach 发布时间: 2010-11-02
QUOTE:
struct sk_buff *sb = skb;
unsigned char src_ip[4];
unsigned char des_ip[4];
struct iphdr *iph = (struct iphdr *) (skb->network_header);
*(unsigned int *) src_ip = ip_hdr (sb)->saddr;
*(unsigned int *) des_ip = ip_hdr (sb)->daddr;
if (iph == NULL)
return NF_ACCEPT;
unsigned char src_ip[4];
unsigned char des_ip[4];
struct iphdr *iph = (struct iphdr *) (skb->network_header);
*(unsigned int *) src_ip = ip_hdr (sb)->saddr;
*(unsigned int *) des_ip = ip_hdr (sb)->daddr;
if (iph == NULL)
return NF_ACCEPT;
改成这样,看起来舒服一些
QUOTE:
struct sk_buff *sb = skb;
unsigned char src_ip[4];
unsigned char des_ip[4];
struct iphdr *iph =ip_hdr (sb);
if (iph == NULL)
return NF_ACCEPT;
*(unsigned int *) src_ip =iph->saddr;
*(unsigned int *) des_ip = iph->daddr;
unsigned char src_ip[4];
unsigned char des_ip[4];
struct iphdr *iph =ip_hdr (sb);
if (iph == NULL)
return NF_ACCEPT;
*(unsigned int *) src_ip =iph->saddr;
*(unsigned int *) des_ip = iph->daddr;
作者: Godbach 发布时间: 2010-11-02
相关阅读 更多
热门阅读
-
office 2019专业增强版最新2021版激活秘钥/序列号/激活码推荐 附激活工具
阅读:74
-
如何安装mysql8.0
阅读:31
-
Word快速设置标题样式步骤详解
阅读:28
-
20+道必知必会的Vue面试题(附答案解析)
阅读:37
-
HTML如何制作表单
阅读:22
-
百词斩可以改天数吗?当然可以,4个步骤轻松修改天数!
阅读:31
-
ET文件格式和XLS格式文件之间如何转化?
阅读:24
-
react和vue的区别及优缺点是什么
阅读:121
-
支付宝人脸识别如何关闭?
阅读:21
-
腾讯微云怎么修改照片或视频备份路径?
阅读:28