本篇文章使用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
即可查看运行结果