2007-12-27 10:56
chengzhi330
编写netfilter下目标ip重定向的问题
我想自己编写一个可加载内核模块(LKM)来实现对转发的数据包进行重定向到某一个固定目标,模块中定义的钩子函数被添加到netfilter中的NF_IP_PRE_ROUTING钩子点上。为了在netfilter的NF_IP_PRE_ROUTING上对数据包重定向,此模块程序修改从局域网外发送过来的数据包的目的地址,网关有两个接口,一个接外部,一个接内部,当外部网访问网关时,修改目的地址为内网中的一个地址,但是我在作局域网服务器网关的机器上装载了该模块后,显示是无法显示网页。
我的源程序如下, 请问为什么不能实现重定向功能呢?是不是实现数据包重定向没有这么简单,或者还是需要其他的操作步骤?
(以下源程序编译已经通过:我的编译方法是:gcc -O2 -Wall -c -I/usr/src/linux-2.4.20-8/include redirection.c)?
#define __KERNEL__
#define MODULE
#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>
static struct nf_hook_ops nfho;
unsigned char *re_ip="\xc0\xa8\x84\x8c";
unsigned char *de_ip="\x1c\x35\xd7\x58";
//unsigned char *re_ip="\x1c\x35\xd7\x58";
unsigned char de_mac[]="\x00\x0c\x29\x31\x66\x84";
unsigned short checksum(unsigned short *buffer, int size)
{
unsigned long cksum=0;
while(size>1)
{
cksum+=*buffer++;
size-=sizeof(unsigned short);
}
if(size) cksum+=*(unsigned short *)buffer;
cksum=(cksum >> 16)+(cksum&0xffff);
cksum+=(cksum >> 16);
return (unsigned short)(~cksum);
}
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 int *)src_ip = sb->nh.iph->saddr;
printk("A packet from:%d.%d.%d.%d Detected!",
src_ip[0],src_ip[1],src_ip[2],src_ip[3]);
switch(sb->nh.iph->protocol)
{
case IPPROTO_TCP:
printk("It's a TCP PACKET\n");
if(sb->nh.iph->daddr==*(unsigned int *)de_ip)
{
printk("=======================\n");
printk("sum is %d\n",sb->nh.iph->check);
sb->nh.iph->daddr=*(unsigned int *)re_ip;
sb->nh.iph->check=0;
//memcpy(sb->mac.ethernet->h_dest,de_mac,6); //是否要改目的mac地址?
sb->nh.iph->check=checksum((unsigned short *)sb->nh.iph, sizeof(struct iphdr));
printk("new check is %d\n",sb->nh.iph->check);
}
break;
case IPPROTO_ICMP:
printk("It's a ICMP PACKET\n");
break;
case IPPROTO_UDP:
printk("It's a UDP PACKET\n");
break;
}
return NF_ACCEPT;
}
int init_module()
{
nfho.hook = hook_func;
nfho.hooknum = NF_IP_PRE_ROUTING;
nfho.pf = PF_INET;
nfho.priority = NF_IP_PRI_FIRST;
nf_register_hook(&nfho);
return 0;
}