利用netfilter抓包(二)----------抓包函数的实现

本篇文章使用netfilter实现抓包并进行简单数据包的解析

eth_hdrip_hdrtcp_hdr分别是用过skb取以太网头部,ip头部,tcp头部
ntohs将网络字节序转换为主机字节序
由于内核中没有inet_ntoa函数,所以自己写了个函数将int的ip地址转换为点分十进制格式的ip地址
先转换为主机字节序ntohl(iphdr->daddr),然后将int类型的ip地址转换为2进制然后分别取第1,2,3,4个字节用十进制打印出来即可。

kfifo_alloc队列的初始化:

/** * kfifo_alloc - dynamically allocates a new fifo buffer * @fifo: pointer to the fifo * @size: the number of elements in the fifo, this must be a power of 2 * @gfp_mask: get_free_pages mask, passed to kmalloc() * * This macro dynamically allocates a new fifo buffer. * * The number of elements will be rounded-up to a power of 2. * The fifo will be release with kfifo_free(). * Return 0 if no error, otherwise an error code. */
#define kfifo_alloc(fifo, size, gfp_mask) \ __kfifo_int_must_check_helper( \ ({ \ typeof((fifo) + 1) __tmp = (fifo); \ struct __kfifo *__kfifo = &__tmp->kfifo; \ __is_kfifo_ptr(__tmp) ? \ __kfifo_alloc(__kfifo, size, sizeof(*__tmp->type), gfp_mask) : \ -EINVAL; \ }) \ )

代码实现:

/****************************************************************************** 文 件 名 : capkt.c 版 本 号 : V1.1 负 责 人 : Sophisticated 生成日期 : 2018年10月30日 最近修改 : 文件描述 : netfilter抓包函数 函数列表 : capkt_hook capture_exit capture_init print_inet_ntoa 修改历史 : 1.日 期 : 2018年10月30日 作 者 : Sophisticated 修改内容 : 创建文件 ******************************************************************************/

#include<linux/skbuff.h>
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/init.h>
#include<linux/ip.h>
#include<linux/in.h>
#include<linux/tcp.h>
#include<linux/netlink.h>
#include<linux/netfilter.h>
#include<linux/netfilter_ipv4.h>
#include<linux/if_ether.h>
#include<linux/kfifo.h>
#include<linux/spinlock.h>

#define FIFO_SIZE 4096

struct kfifo fifo;

/*将32位int类型ip地址转化为点分十进制格式的ip地址*/
void print_inet_ntoa(u32 ina)
{
    printk("%d.%d.%d.%d",
                    (ina & 0xff000000) >> (6 * 4),
                    (ina & 0x00ff0000) >> (4 * 4),
                    (ina & 0x0000ff00) >> (2 * 4),
                    ina & 0x000000ff);
   return;
}

int id = 1;

/***************************************************************************** 函 数 名 : capkt_hook 功能描述 : 钩子函数的实现 输入参数 : void *priv struct sk_buff *skb const struct nf_hook_state *state 输出参数 : 无 返 回 值 : static unsigned int 调用函数 : 被调函数 : 修改历史 : 1.日 期 : 2018年10月30日 作 者 : Sophisticated 审 核 人 : # 修改内容 : 新生成函数 *****************************************************************************/
static unsigned int capkt_hook(void *priv,struct sk_buff *skb,const struct nf_hook_state *state)
{
	/*设置了抓取十个数据包完毕,测试*/
    if (id < 10){
	    struct ethhdr *ethhdr = eth_hdr(skb);
	    struct iphdr *iphdr = ip_hdr(skb);
	    struct tcphdr *tcphdr = tcp_hdr(skb);
	    printk(KERN_ALERT "id: %d\n",id);
	    printk("eth protocol: %x\n",ntohs(ethhdr->h_proto));
	    printk("ip protocol: %x\n",iphdr->protocol);
	    printk("src mac:");
	    int i = 0;
	    for (i; i < 6; i++)
	    {
	        printk("%02x:",ethhdr->h_source[i]);
	    }
	    printk("\n");
	    printk("dst mac:");
	    int j = 0;
	    for (j; j < 6; j++)
	    {
	        printk("%02x:",ethhdr->h_dest[j]);
	    }
	    printk("\n");
	
	    printk("version: %d\n",iphdr->version);
	    printk("ttl: %d\n",iphdr->ttl);
	    printk("src ip:");
	    
	    printk("%ld\n", ntohl(iphdr->saddr));
	    print_inet_ntoa(ntohl(iphdr->saddr));
	    printk("\n");
	    printk("dst ip:");
	    printk("%ld\n", ntohl(iphdr->daddr));
	    print_inet_ntoa(ntohl(iphdr->daddr));
	    printk("\n");
	
	    printk("src port:");
	    printk("%d\n",ntohs(tcphdr->source));
	    printk("dst port:");
	    printk("%d\n",ntohs(tcphdr->dest));
	    id++;
		
		/*将抓取的数据包放入队列*/
	    kfifo_in(&fifo, skb, sizeof(*skb));
	    int len = kfifo_len(&fifo);
	    int size = kfifo_size(&fifo);
	    printk("kfifo size: %d\n",size);
	    printk("kfifo length: %d\n",len);
    } 
    return NF_ACCEPT;
}

struct nf_hook_ops capture_hook_ops = {
    .hook = capkt_hook,
    .pf = NFPROTO_IPV4,
    .hooknum = NF_INET_PRE_ROUTING,
    .priority = 0,
};

/***************************************************************************** 函 数 名 : capture_init 功能描述 : 模块初始化函数 输入参数 : void 输出参数 : 无 返 回 值 : static 调用函数 : 被调函数 : 修改历史 : 1.日 期 : 2018年10月30日 作 者 : Sophisticated 审 核 人 : # 修改内容 : 新生成函数 *****************************************************************************/
static int __init capture_init(void)
{    
    if (kfifo_alloc(&fifo, FIFO_SIZE, GFP_KERNEL))
    {
        printk("kfifo_alloc fail!\n");
    }
   
    if (nf_register_hook(&capture_hook_ops) != 0)
    {
        printk("netfilter register fail!\n");
        return -1;
    }
    printk("capture module insert success!\n");
    return 0;
}

/***************************************************************************** 函 数 名 : capture_init 功能描述 : 模块移除函数 输入参数 : void 输出参数 : 无 返 回 值 : static 调用函数 : 被调函数 : 修改历史 : 1.日 期 : 2018年10月30日 作 者 : Sophisticated 审 核 人 : # 修改内容 : 新生成函数 *****************************************************************************/
static int __exit capture_exit(void)
{
    kfifo_free(&fifo);
    nf_unregister_hook(&capture_hook_ops);
    printk("capture module remove success!\n");
    return;
}

module_init(capture_init);
module_exit(capture_exit);

MODULE_LICENSE("GPL");

使用dmesg命令或者cat /var/log/message即可查看运行结果
在这里插入图片描述