欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于Netfilter框架, 编写自己的hook函数,修改经过hook点的数据包目的地址

程序员文章站 2022-07-13 16:17:27
...

参考连接

http://blog.chinaunix.net/uid-20662820-id-142433.html

修改经过钩子的数据包目的地址:

结果图:
基于Netfilter框架, 编写自己的hook函数,修改经过hook点的数据包目的地址

//linux 内核数据包转发模块
/**
myhook_func.c
Makefile
编译:make
加载:sudo insmod myhook_func.ko remark=0  dst=192.168.92.129  //remark默认0,dst 默认127.0.0.1
卸载:sudo rmmod myhook_func
dmesg查看打印
**/


//头文件包含
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/netfilter.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/ctype.h>
#include <linux/inet.h> /*in_aton() 将地址转换为码 */
#include <linux/socket.h> /*PF_INET */
#include <net/checksum.h>
#include <net/tcp.h>
#include <net/udp.h>

#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_expect.h>
#include <net/netfilter/nf_conntrack_ecache.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <linux/netfilter/nf_conntrack_ftp.h>
#include <linux/types.h>
#include <linux/skbuff.h> //skb_network_header(skb) CHECKSUM_UNNECESSARY

#include <linux/in.h> //IPPROTO_xxx

#include <linux/timer.h>
#include <net/xfrm.h>
#include <linux/netfilter.h>
#include <linux/netdevice.h> //netif_receive_skb netif_rx

#include <linux/if.h>
#include <linux/inetdevice.h>
#include <net/protocol.h>
#include <linux/netfilter_ipv4.h> /*NF_IP_PRE_FIRST  */
#include <linux/netfilter/x_tables.h>
#include <net/netfilter/nf_nat.h>

//#include <net/netfilter/nf_nat_rule.h>
#include <net/netfilter/nf_nat_core.h>

//模块信息
MODULE_LICENSE("GPL");
MODULE_AUTHOR("lxm");
MODULE_DESCRIPTION("myhook.c");

#define NIPQUAD(addr) \
  ((unsigned char *)&addr)[0], \
  ((unsigned char *)&addr)[1], \
  ((unsigned char *)&addr)[2], \
  ((unsigned char *)&addr)[3]




//全局变量 remark, dst 默认值如下
static int remark=1;
char *dst="127.0.0.1";//转发目的地址

//模块参数
module_param(remark,uint,0644);
module_param(dst,charp,0644);
//描述模块参数
MODULE_PARM_DESC(remark,"Copy the packet with the mark is remark");


//入口函数myhook_func
//函数参数:钩子位置hooknum  收发包缓存结构skb   in  out   
unsigned int myhook_func(unsigned int hooknum,struct sk_buff *skb,const struct net_device *in,const struct net_device *out,int(*okfn)(struct sk_buff*))
{
    printk(KERN_ALERT "enter myhook_func:===== get hook!\n");
    struct iphdr *nowiph;//定义ip头nowiph
    nowiph=(struct iphdr*)skb_network_header(skb);//从skb中获取ip头
   //获取源,目的ip 
 __be32 nsip, ndip;
 nsip=nowiph->saddr;
 ndip=nowiph->daddr;
//get mark
    __u32 mark=skb->mark;
    __be32 mydst;
    mydst = in_aton(dst);//转发地址
    //__be32 testip= in_aton("203.208.37.99");

    //if(nowiph->saddr==testip&&nowiph->daddr==mydst) printk("OK\n");
    printk(KERN_ALERT "mark=%d\n",mark);
   // printk(KERN_ALERT "mydst=%d.%d.%d.%d\n " NIPQUAD(mydst));
    if(ndip==mydst)//数据包目的地址和要转发的目的地址相同,不需要修改
    {
        printk("sameid: nsip: %d.%d.%d.%d\n  ndip: %d.%d.%d.%d\n mydst: %d.%d.%d.%d\n ",NIPQUAD(nsip),  NIPQUAD(ndip), NIPQUAD(mydst) );

        //if(mydst==in_aton("127.0.0.1")) skb->pkt_type=5;

        return NF_ACCEPT;
    }
   // printk(KERN_ALERT "mark=%d\n",mark);

    if(mark==remark)//数据包的mark标志和我的 remark一样,对数据包进行修改目的地址
    {
        //printk(KERN_ALERT "OK\n");
//打印数据包的源地址,目的地值和mark
printk("lu before: mark=%d\n source add: %d.%d.%d.%d\n destination add: %d.%d.%d.%d\n mydst: %d.%d.%d.%d\n ",mark, NIPQUAD(nsip), NIPQUAD(ndip),NIPQUAD(mydst));
        struct sk_buff *myskb=skb_copy(skb,GFP_ATOMIC);//复制skb
        struct iphdr *myiph;
        //myskb->pkt_type=PACKET_OTHERHOST;

        myiph=(struct iphdr*)skb_network_header(myskb);
        if(myiph==NULL)
        {
            kfree_skb(myskb);
            return NF_ACCEPT;
        }
        myiph->daddr=mydst;//修改ip头部目的地址

printk("lu after: mark=%d\n source add: %d.%d.%d.%d\n destination add: %d.%d.%d.%d\n ",mark, NIPQUAD(myiph->saddr), NIPQUAD(myiph->daddr) );

        if(myiph->protocol==IPPROTO_TCP)
        {
            __wsum csum=0;
            struct tcphdr *mytcphdr;
            unsigned int tcphoff;
            mytcphdr=(struct tcphdr*)(myskb->data+myiph->ihl*4);//检查tcp头
            if(mytcphdr==NULL)
            {
                kfree_skb(myskb);
                return NF_ACCEPT;
            }
            nf_reset(myskb);
            tcphoff=myiph->ihl*4;
            ip_send_check(myiph);//检验和
            mytcphdr->check=0;
            csum=skb_checksum(myskb,tcphoff,myskb->len-tcphoff,0);
            myskb->csum=csum;
            myskb->ip_summed=CHECKSUM_NONE;
            /*mytcphdr->check=csum_tcpudp_magic(myiph->saddr,myiph->daddr,myskb->len,IPPROTO_TCP,csum_partial((char *)mytcphdr,myskb->len-tcphoff,0));
            mytcphdr->check+=0x1400;*/
            mytcphdr->check=0;
            mytcphdr->check=tcp_v4_check(myskb->len-tcphoff,myiph->saddr,myiph->daddr,csum_partial(mytcphdr,myskb->len-tcphoff,0));
            //printk("%u--%u\n",ntohs(myiph->saddr),ntohs(myiph->daddr));

            netif_rx(myskb);
        }
        else if(myiph->protocol==IPPROTO_UDP)
        {
            int csum=0;
            struct udphdr *myudphdr;
            unsigned int udphoff;
            myudphdr=(struct udphdr*)(myskb->data+myiph->ihl*4);
            if(myudphdr==NULL)
            {
                kfree_skb(myskb);
                return NF_ACCEPT;
            }
            udphoff=myiph->ihl*4;
            myskb->csum=0;
            ip_send_check(myiph);
            csum=skb_checksum(myskb,udphoff,myskb->len-udphoff,0);
            myskb->csum=csum;
            myskb->ip_summed=CHECKSUM_NONE;
            myudphdr->check=0;
            myudphdr->check=csum_tcpudp_magic(myiph->saddr,myiph->daddr,myskb->len-udphoff,IPPROTO_UDP,csum_partial(myudphdr,myskb->len-udphoff,0));
            nf_reset(myskb);
            netif_rx(myskb);
        }
    }
    return NF_ACCEPT;
}

//定义钩子myhook变量
static struct nf_hook_ops myhook;

//注册钩子
static int __init myhook_init(void)
{
    printk(KERN_ALERT " *************myhook init*******************\n");
    memset(&myhook,0,sizeof(struct nf_hook_ops));
    myhook.hook=myhook_func;
   //min  myhook.owner=THIS_MODULE;
    myhook.pf=PF_INET;
    myhook.hooknum=NF_INET_PRE_ROUTING;
    //myhook.priority=INT_MAX;
    myhook.priority=NF_IP_PRI_NAT_DST;

if(nf_register_hook(&myhook)){
        //如果注册失败,打印内核级错误信息
	printk(KERN_ERR"myhook init failed=lu xiang min\n");
return -1;
}
printk(KERN_WARNING"myhook init succesful= lu xiangmin\n");
  return 0;
}
//注销钩子
static void __exit myhook_exit(void)
{
    nf_unregister_hook(&myhook);
    printk(KERN_WARNING"****************myhook exit**************\n");
}
//模块加载与卸载
module_init(myhook_init);
module_exit(myhook_exit);

Makefile 文件

ifneq ($(KERNELRELEASE),)
obj-m := myhook_func.o
else
        KERNELBUILD :=/lib/modules/$(shell uname -r)/build
        PWD :=$(shell pwd)
all:
         make -C $(KERNELBUILD) M=$(PWD) modules
clean:
         rm -rf *.o *.ko *.mod.c .*.cmd *.markers *.order *.symvers .tmp_versions
endif

写好源文件和Makefile文件之后,在其所在目录下,开始编译:
make
编译完成,将.ko文件加载到内核中:
insmod myhook_func.ko
查看内核模块打印输出:
dmesg
查看模块:
lsmod
卸载模块:
rmmod sample(注意,没有.ko后缀)
消除编译过程生成的文件:
make clean

相关标签: netfilter hook