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

时间:2024-03-27 22:03:09

本篇文章使用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即可查看运行结果
利用netfilter抓包(二)----------抓包函数的实现