一、linux内核中neitfilter的处理过程

1.5个HOOK点的执行点说明:
数据包从进入系统,进行IP校验以后,首先经过第一个HOOK函数NF_IP_PRE_ROUTING进行处理;
然后就进入FORWARD路由匹配,其决定该数据报是需要转发还是发给本机的;
若该数据包是发给本机的,则该数据经过HOOK函数NF_IP_LOCAL_IN处理以后然后传递给上层协议;
若该数据报应该被转发则它被NF_IP_FORWARD处理;
经过转发的数据报经过最后一个HOOK函数NF_IP_POST_ROUTING处理以后,再传输到网络上。
本地产生的数据经过HOOK函数NF_IP_LOCAL_OUT 处理后,进行路由选择处理,然后经过NF_IP_POST_ROUTING处理后发送出去。

2.nf_hooks结构:

3.协议头字段

#include <linux/netfilter.h>/* only for userspace compatibility */#include <limits.h> /* for INT_MIN, INT_MAX *//* IP Cache bits. */
/* Src IP address. */
#define NFC_IP_SRC      0x0001
/* Dest IP address. */
#define NFC_IP_DST      0x0002
/* Input device. */
#define NFC_IP_IF_IN        0x0004
/* Output device. */
#define NFC_IP_IF_OUT       0x0008
/* TOS. */
#define NFC_IP_TOS      0x0010
/* Protocol. */
#define NFC_IP_PROTO        0x0020
/* IP options. */
#define NFC_IP_OPTIONS      0x0040
/* Frag & flags. */
#define NFC_IP_FRAG     0x0080/* Per-protocol information: only matters if proto match. */
/* TCP flags. */
#define NFC_IP_TCPFLAGS     0x0100
/* Source port. */
#define NFC_IP_SRC_PT       0x0200
/* Dest port. */
#define NFC_IP_DST_PT       0x0400
/* Something else about the proto */
#define NFC_IP_PROTO_UNKNOWN    0x2000

二、源码解析:

1.通过源码make编译,生成simple_nf_test.ko,加载进内核使用;
2.使用rmmod卸载模块,将内核计算数据保存进user file;
3.使用od -tu /root/netfilter.log查看保存的file数据。
#Makefile
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
obj-m += simple_nf_test.o
all:make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modulesclean:make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
[root@test02 netfilter-test]# insmod simple_nf_test.ko
[root@test02 netfilter-test]# ping 114.114.114.114
PING 114.114.114.114 (114.114.114.114) 56(84) bytes of data.
^C
--- 114.114.114.114 ping statistics ---
64 packets transmitted, 0 received, 100% packet loss, time 64552ms[root@test02 netfilter-test]# rmmod simple_nf_test
#dmesg日志
[22038.705777] ----------------------------------------------------------
[22038.705779] 114.114.114.114 is denied by netfilter!
[22038.705780] drop 114.114.114.114  packets count is : 20
[22039.575591] ----------------------------------------------------------
[22039.575602] # source address is 63baf772 , 114.247.186.99
[22039.575607] # dest address is bc14a8c0 , 192.168.20.188
[22039.575609] ----------------------------------------------------------
[22039.575611] ...packet pass filter...
[22039.575613] [simple_nf_test] packet_filter. end.
[22039.729706] ----------------------------------------------------------
[22039.729762] # source address is 72727272 , 114.114.114.114
[22039.729767] # dest address is bc14a8c0 , 192.168.20.188
[22039.729770] ----------------------------------------------------------
[22039.729772] 114.114.114.114 is denied by netfilter!
[22039.729774] drop 114.114.114.114  packets count is : 21
[22040.753807] ----------------------------------------------------------
[22040.753822] # source address is 72727272 , 114.114.114.114
[22040.753826] # dest address is bc14a8c0 , 192.168.20.188
[22040.753829] ----------------------------------------------------------
[22040.753830] 114.114.114.114 is denied by netfilter!
[22040.753832] drop 114.114.114.114  packets count is : 22
...
[22088.630236] ----------------------------------------------------------
[22088.630237] ...packet pass filter...
[22088.630239] [simple_nf_test] packet_filter. end.
[22089.055705] ----------------------------------------------------------
[22089.055722] # source address is 63baf772 , 114.247.186.99
[22089.055727] # dest address is bc14a8c0 , 192.168.20.188
[22089.055729] ----------------------------------------------------------
[22089.055731] ...packet pass filter...
[22089.055733] [simple_nf_test] packet_filter. end.
[22089.060209] packet fillter capture count: 64
[22089.060212] begin to write to netfilter.log
[22089.060258] record file write done .
[22089.060470] [simple_nf_test] remove hook lkm success!#netfilter.log记录(8byte)
[root@test02 netfilter-test]# od -tu /root/netfilter.log
0000000         64          0
0000010

#simple_nf_test.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>//count变量用于统计filter hook的拦截次数
unsigned long int count = 0L;
//内核数据写入本地文件方法
static int  _fileWrite(unsigned long int count)
{unsigned long int  buf[]= { count };printk("packet fillter capture count: %ld \n",count);struct file *fp;mm_segment_t fs;loff_t pos;printk("begin to write to netfilter.log \n");//打开本地文件句柄fp =filp_open("/root/netfilter.log",O_RDWR|O_CREAT,0644);if (IS_ERR(fp)){printk("open file error\n");return -1;}//保护内核空间,地址参数检查fs =get_fs();//扩大空间限制到内核地址空间,从而可以在内核空间中使用文件系统调用set_fs(KERNEL_DS);//ssize_t kernel_write(struct file *file, const void *buf, size_t count, loff_t *pos)//内核数据写入用户态文件API,注意buf如果为Int类型,将以ascii码的方式,保存进文件。所以从文件中获取Int数据时,需要使用od -tu filename命令。pos =0;kernel_write(fp,buf, sizeof(buf), &pos);//关闭文件句柄filp_close(fp,NULL);//关闭内核空间的文件系统调用set_fs(fs);return 0;
}unsigned int packet_filter(unsigned int hooknum, struct sk_buff *skb,const struct net_device *in, const struct net_device *out,int (*okfn)(struct sk_buff *))
{      //ip协议头部struct iphdr *iph;//tcp协议头部struct tcphdr *tcph;//udp协议头部struct udphdr *udph;//如socket buffer指针为空,则当前hook点允许该数据包继续在协议栈中流转。 //define NF_ACCEPT 1 if(skb == NULL)return NF_ACCEPT;//如skb不为空,则从skb获取ip头,使用内核API ip_hdr()iph = ip_hdr(skb);//如ip头为空,则当前hook点允许该数据包继续在协议栈中流转。if(iph == NULL)return NF_ACCEPT;//打印经过hook的包信息printk("----------------------------------------------------------");printk("# source address is %x , %pI4 \n",iph->saddr,&iph->saddr);    printk("# dest address is %x , %pI4 \n",iph->daddr,&iph->daddr);printk("----------------------------------------------------------"); //示例增加对IP地址114.114.114.114(十六进制表示:0x72727272)的地址过滤if(iph->saddr == 0x72727272){printk("114.114.114.114 is denied by netfilter!\n");//命中计数器统计count++;printk("drop 114.114.114.114  packets count is : %ld \n",count);// 丢弃该数据包return NF_DROP;/*#include\uapi\linux\netfilter.h/* Responses from hook functions. */#define NF_DROP 0 // 丢弃该数据包#define NF_ACCEPT 1 // 当前hook点,允许该数据包继续在协议栈中流转#define NF_STOLEN 2 // 让netfilter框架忽略该数据包的处理#define NF_QUEUE 3 // 该数据包加入到用户队列,供用户程序处理#define NF_REPEAT 4#define NF_STOP 5   /* Deprecated, for userspace nf_queue compatibility. */#define NF_MAX_VERDICT NF_STOP*/}printk("...packet pass filter...");//协议层逻辑switch(iph->protocol){case IPPROTO_TCP:tcph = (struct tcphdr *)(skb->data + (iph->ihl * 4));//printk("#tcp source port is [%d].\n",ntohs(tcph->source));//printk("#tcp dest port is [%d].\n",ntohs(tcph->dest));//if TCP then do somethingbreak;case IPPROTO_UDP:udph = (struct udphdr *)(skb->data + (iph->ihl * 4));//printk("#udp source port is [%d].\n",ntohs(udph->source));//printk("#udp dest port is [%d].\n",ntohs(udph->source));//if UDP then do someting break;default ://放行数据包return NF_ACCEPT;}printk("[simple_nf_test] %s. end.\n", __func__);return NF_ACCEPT;};
/*
//hook结构体
struct nf_hook_ops {                             struct list_head   list;    /* 标准链表—由于链接所有钩子点 */ /* User fills in from here down. */nf_hookfn      *hook;  /* 钩子函数回调指针 */struct net_device *dev;    /* 网络设备指针 */void           *priv;      /* 私有数据,在钩子回调函数中使用 */u_int8_t        pf;             /* 协议族 */unsigned int       hooknum;        /* hook点   *//* Hooks are ordered in ascending priority. */int          priority;           /* 优先级 */
};
*/
//初始化hook参数
static struct nf_hook_ops packet_simple_nf_opt = {//hook函数packet_filter.hook = (nf_hookfn *)packet_filter,//协议指定为ip协议.pf = NFPROTO_INET,//hook点 NF_INET_PRE_ROUTING 优先级最高.hooknum = NF_INET_PRE_ROUTING,.priority = NF_IP_PRI_FIRST,/*//hook支持的协议enum {NFPROTO_UNSPEC =  0,NFPROTO_INET   =  1,        NFPROTO_IPV4   =  2,NFPROTO_ARP    =  3,NFPROTO_NETDEV =  5,NFPROTO_BRIDGE =  7,NFPROTO_IPV6   = 10,NFPROTO_DECNET = 12,NFPROTO_NUMPROTO,};*//*内核中注册的5个HOOK点如下:enum nf_inet_hooks {NF_INET_PRE_ROUTING,NF_INET_LOCAL_IN,NF_INET_FORWARD,NF_INET_LOCAL_OUT,NF_INET_POST_ROUTING,NF_INET_NUMHOOKS};*//*enum nf_ip_hook_priorities {NF_IP_PRI_FIRST = INT_MIN,NF_IP_PRI_RAW_BEFORE_DEFRAG = -450,NF_IP_PRI_CONNTRACK_DEFRAG = -400,NF_IP_PRI_RAW = -300,NF_IP_PRI_SELINUX_FIRST = -225,NF_IP_PRI_CONNTRACK = -200,NF_IP_PRI_MANGLE = -150,NF_IP_PRI_NAT_DST = -100,NF_IP_PRI_FILTER = 0,NF_IP_PRI_SECURITY = 50,NF_IP_PRI_NAT_SRC = 100,NF_IP_PRI_SELINUX_LAST = 225,NF_IP_PRI_CONNTRACK_HELPER = 300,NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,NF_IP_PRI_LAST = INT_MAX,};*/};static int simple_nf_init(void)
{   //注册函数钩子,内核版本大于4.3.0的内核函数API为nf_register_net_hook,否则为nf_register_hook#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0) //int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg)//网络系统在初始化的时候会初始化一个初始网络命名空间,即init_net命名空间。后续创建的net namespace命名空间会和init_net一起通过list项组织起来,且每个网络设备都对应一个命名空间nf_register_net_hook(&init_net, &packet_simple_nf_opt);#elsenf_register_hook(&packet_simple_nf_opt);#endifprintk("[simple_nf_test] network hooks success.\n");return 0;};static void simple_nf_exit(void)
{//write capute packets count  to user file._fileWrite(count);printk("record file write done.\n");//卸载hook函数#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0)nf_unregister_net_hook(&init_net, &packet_simple_nf_opt);#elsenf_unregister_hook(&packet_simple_nf_opt);#endifprintk("[simple_nf_test] remove hook lkm success!\n");
};
//内核模块加载和卸载时,执行的函数
module_init(simple_nf_init);
module_exit(simple_nf_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jeb");

Linux下使用Netfilter框架编写内核模块(统计协议层ping特定地址丢包数)相关推荐

  1. 走进Linux内核之Netfilter框架

    走进Linux内核之Netfilter框架 - 掘金笔者此前对Linux内核相关模块稍有研究,实现内核级通信加密.视频流加密等.话不多说直接上才艺,现在带你走进Linux内核之Netfilter框架. ...

  2. 交叉编译php-5.6.30,linux下用arm-none-linux-gnueabi交叉编译arm内核模块

    前不久导师要求交叉编译一个基于arm平台开发的内核模块来练手,在网上查了很多资料才弄出来,于是将这些零散的信息综合起来给和我一样的入门人员了解.水平有限,请谅解~ 1.安装arm-none-linux ...

  3. 【linux下用C语言编写带图形界面的成绩管理系统附带源代码】

    linux下用C语言编写带图形界面的成绩管理系统附带源代码:(下面内容请配合源代码看) 源代码下载地址:         点击打开链接 或留下联系方式,发给你 一.题目内容 嵌入式Linux数据库编程 ...

  4. 【转】Linux下c++调用自己编写的matlab函数:通过mcc动态链接库.so实现

    转自:Linux下c++调用自己编写的matlab函数:通过mcc动态链接库.so实现_Jaster_wisdom的专栏-CSDN博客 之前在这里和这里调用了matlab自带的一些函数,是通过matl ...

  5. Linux下C语言程序编写及执行和分步骤编译链接C源代码

    实验一:Linux下C语言程序编写及执行 //hello.c #include <stdio.h> int main(){int x = 1;int y = 2;int sum = x + ...

  6. linux下使用gtest框架进行c/c++单元测试

    原文地址linux下使用gtest框架进行c/c++单元测试 前言 google test(以下简称gtest)是谷歌的开源C++单元测试框架,用来做c/c++的单元测试比较方便.下面对于它在linu ...

  7. Linux下shell脚本/Makefile编写

    Linux下shell脚本/Makefile编写 一.基本概念 代码变成可执行文件,叫做编译(compile):先编译这个,还是先编译那个(即编译的安排),叫做构建(build). make只是一个指 ...

  8. iptables命令_理解 Linux 下的 Netfilter/iptables

    Netfilter/iptables 项目由 Rusty Russe 创建于1998年,并于 1999 年建立了 Netfilter Core team,并在此后负责维护此项目,同时也于2000年3月 ...

  9. Linux下程序时间消耗监控与统计

    良好的计时器可帮助程序开发人员确定程序的性能瓶颈,或对不同算法进行性能比较.但要精确测量程序的运行时间并不容易,因为进程切换.中断.共享的多用户.网络流量.高速缓存访问及转移预测等因素都会对程序计时产 ...

最新文章

  1. C语言常用算法 脚本之家,C/C++常用算法手册 秦姣华 中文pdf扫描版 22.5MB
  2. Hadoop Streaming框架使用(三)
  3. 对比Excel,学习pandas数据透视表
  4. Sping Cloud Eureka
  5. java 1.7 新特性
  6. mysql二进制备份配置_mysql针对于二进制数据的备份
  7. 推荐系统之粗排扮演的角色和算法发展历程
  8. Android Q共享音频输入
  9. 批量网址自动提取文字(newspaper)
  10. 谈谈数据挖掘和机器学习
  11. 用友u8服务器优化,用友U8erp软件运行的性能优化方案图文教程
  12. 许昌学院计算机学院张伶俐,【优秀毕业生故事系列】之四:厉害了,我的班!...
  13. Word文档中文繁体简体的转换
  14. Windows VScode Linter pylint is not installed
  15. Acwing1072 树的最长路径(树的直径)树形Dp 记忆化搜索
  16. os.system获取返回值 python3 cmd 获取返回值
  17. K-Means聚类 和 高斯混合模型(GMM)
  18. oracle 的SGA与PGA分析
  19. 信息系统项目管理师10大管理47个过程域输入输出工具(项目质量管理)
  20. 生成树协议STP、RSTP和MSTP原理的理解

热门文章

  1. cad画直角命令_在cad中怎么画角度?cad画角度三种方法介绍
  2. 轻奢消费人群画像报告
  3. 计算投资指数基金的预期收益率
  4. Unity3D热更设计:一款基于 HybridCLR的C#热更方案
  5. Recylerview刷新图片闪烁
  6. 网易云音乐 DBA 谈 TiDB 选型:效率的选择
  7. 手机号码、电子邮箱、身份证、银行卡正则验证
  8. Ubuntu 18.04配置静态IP地址
  9. 如何快速绘制一个等边三角形呢?
  10. python依照概率抽样_统计概率思维之总体与抽样