本篇文章使用netfilter实现抓包并进行简单数据包的解析
eth_hdr
, ip_hdr
,tcp_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
即可查看运行结果