参考http://www.linuxtcpipstack.com/685.html#NF_INET_PRE_ROUTING

https://opengers.github.io/openstack/openstack-base-netfilter-framework-overview/

http://blog.chinaunix.net/uid-26517122-id-4293010.html

https://netfilter.org/documentation/HOWTO/netfilter-hacking-HOWTO-3.html

https://en.wikipedia.org/wiki/Netfilter

在三层IPv4数据包的处理过程中,可能经过Netfilter的五个钩子点,分别为NF_INET_PRE_ROUTING、NF_INET_LOCAL_IN、NF_INET_FORWARD、NF_INET_LOCAL_OUT、NF_INET_POST_ROUTING,在每个点都可以设置一些规则,来对数据包进行匹配检查处理,这些规则的配置、布局和匹配流程。

Netfilter 提供了一个基本的报文拦截框架,即hook机制;

Netfilter 中定义了一个全局二维数组,来存放注册了的处理函数。

struct list_head hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS] __read_mostly;

在每个关键点上,有很多已经按照优先级预先注册了的回调函数;

每个钩子函数最后必须向Netfilter框架返回下列几个值其中之一

#define NF_DROP 0 /* 丢包,不再传输 */
#define NF_ACCEPT 1 /* 接受数据包,继续正常传输 这个返回值告诉 Netfilter:到目前为止,该数据包还是被接受的并且该数据包应当被递交到网络协议栈的下一个阶段 */
#define NF_STOLEN 2 /* 数据包已经被接管,回调函数处理该包,NF不再处理,该回调函数将从此开始对数据包的处理,并且Netfilter应当放弃对该数据包做任何的处理。但是,这并不意味着该数据包的资源已经被释放。这个数据包以及它独自的sk_buff数据结构仍然有效,只是回调函数从Netfilter 获取了该数据包的所有权 */
#define NF_QUEUE 3 /*对该数据报进行排队 ,通常用于将数据包交给用户空间的进程处理 */
#define NF_REPEAT 4 /* 再次调用该回调函数,应当谨慎使用这个值,以免造成死循环*/
#define NF_STOP 5    /*结束执行, 数据包通过了挂载点的所有规则。但与NF_ACCEPT不同的一点时,当某条规则的判定结果为NF_STOP,那么可以直接返回结果NF_STOP,无需进行后面的判定了。而NF_ACCEPT需要所以的规则都为ACCEPT,才能返回NF_ACCEPT */
#define NF_MAX_VERDICT NF_STOP
 

netfilter 回调函数注册

nf_hook_ops是注册的钩子函数的核心结构,字段含义如下所示,一般待注册的钩子函数会组成一个nf_hook_ops数组,在注册过程中调用nf_register_net_hooks将所有规则加入到指定的钩子点;

/*
list:因为在一个HOOK点有可能注册多个钩子函数,因此这个变量用来将某个HOOK点所注册的所有钩子函数组织
成一个双向链表;
hook:该参数是一个指向nf_hookfn类型的函数的指针,由该函数指针所指向的回调函数在该hook被激活时调用【nf_hookfn在后面做解释】;
owner:表示这个hook是属于哪个模块的
pf:该hook函数所处理的协议。目前我们主要处理IPv4,所以该参数总是PF_INET;
hooknum:钩子函数的挂载点,即HOOK点;
priority:优先级。前面也说过,一个HOOK点可能挂载了多个钩子函数,当Netfilter在这些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; /* 钩子点 */
/* Hooks are ordered in ascending priority. */
int priority; /* 优先级 */
};

钩子函数原型为:

typedef unsigned int nf_hookfn(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state);

nf_register_net_hook为钩子函数注册的主流程,首先找到钩子点函数的入口,然后根据优先级将当前注册的钩子函数插入到链表中;

int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg)
{
struct list_head *hook_list;
struct nf_hook_entry *entry;
struct nf_hook_ops *elem;
/* 分配钩子入口结构 */
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
return -ENOMEM; entry->orig_ops = reg;
entry->ops = *reg;
/* 找到钩子点链表头部 */
hook_list = nf_find_hook_list(net, reg);
if (!hook_list) {
kfree(entry);
return -ENOENT;
} mutex_lock(&nf_hook_mutex);
/* 找到钩子应该插入的位置 */
list_for_each_entry(elem, hook_list, list) {
if (reg->priority < elem->priority)
break;
}
/* 插入钩子点 */
list_add_rcu(&entry->ops.list, elem->list.prev);
mutex_unlock(&nf_hook_mutex);
#ifdef CONFIG_NETFILTER_INGRESS
if (reg->pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS)
net_inc_ingress_queue();
#endif
#ifdef HAVE_JUMP_LABEL
static_key_slow_inc(&nf_hooks_needed[reg->pf][reg->hooknum]);
#endif
return 0;
}
/*
对于nf
其钩子函数入口形式为hooks[协议族][钩子点],在二维数组的每个节点都对应着一个钩子函数链表,内部多个nf_hook_entry通过优先级从小到大排列;
*/
struct netns_nf {
#if defined CONFIG_PROC_FS
struct proc_dir_entry *proc_netfilter;
#endif
const struct nf_queue_handler __rcu *queue_handler;
const struct nf_logger __rcu *nf_loggers[NFPROTO_NUMPROTO];
#ifdef CONFIG_SYSCTL
struct ctl_table_header *nf_log_dir_header;
#endif
struct list_head hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
}; 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,
};
//IPv4钩子点的定义如下:
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
};

linux netfilter 五个钩子点的更多相关文章

  1. Netfilter 之 五个钩子点

    概述 在协议栈的三层IPv4(IPv6还没看,不清楚)数据包的处理过程中,可能经过Netfilter的五个钩子点,分别为NF_INET_PRE_ROUTING.NF_INET_LOCAL_IN.NF_ ...

  2. 《sed的流艺术之四》-linux命令五分钟系列之二十四

    本原创文章属于<Linux大棚>博客,博客地址为http://roclinux.cn.文章作者为rocrocket. 为了防止某些网站的恶性转载,特在每篇文章前加入此信息,还望读者体谅. ...

  3. 《sed的流艺术之三》-linux命令五分钟系列之二十三

    本原创文章属于<Linux大棚>博客,博客地址为http://roclinux.cn.文章作者为rocrocket. 为了防止某些网站的恶性转载,特在每篇文章前加入此信息,还望读者体谅. ...

  4. 《sed的流艺术之二》-linux命令五分钟系列之二十二

    本原创文章属于<Linux大棚>博客,博客地址为http://roclinux.cn.文章作者为rocrocket. 为了防止某些网站的恶性转载,特在每篇文章前加入此信息,还望读者体谅. ...

  5. 《sed的流艺术之一》-linux命令五分钟系列之二十一

    本原创文章属于<Linux大棚>博客,博客地址为http://roclinux.cn.文章作者为rocrocket. 为了防止某些网站的恶性转载,特在每篇文章前加入此信息,还望读者体谅. ...

  6. 《paste命令》-linux命令五分钟系列之二十

    本原创文章属于<Linux大棚>博客,博客地址为http://roclinux.cn.文章作者为rocrocket. 为了防止某些网站的恶性转载,特在每篇文章前加入此信息,还望读者体谅. ...

  7. 《vi中的替换艺术》-linux命令五分钟系列之十一

    vi方面的内容不知道分类到哪里好,就放到<Linux命令五分钟系列>里吧! 今天编程,关于栈的一个小例子,其间我需要把”S.”替换为”S->”(替换不包括双引号). 其实这个不难,不 ...

  8. linux type 命令和Linux的五个查找命令

    type命令用来显示指定命令的类型.一个命令的类型可以是如下之一 alias 别名 keyword 关键字,Shell保留字 function 函数,Shell函数 builtin 内建命令,Shel ...

  9. Linux的五个查找命令find,locate,whereis,which,type

    Linux的五个查找命令 1. find 最常见且最强大的命令,可以查找任何文件. 格式 $ find   指定目录   指定条件   指定动作   指定目录: 所要搜索的目录及其子目录,默认当前目录 ...

随机推荐

  1. 空间视频和GIS

    摘要. GIS的空间数据基本单位表示通常是根据 点,线和面.但是,另一种类型的空间数据正在变得越来越频繁 捕获的是视频,但在GIS中却被很大程度上忽略了.数字录像时 是现代社会中常见的一种媒介,包含多 ...

  2. python数据清洗

    盖帽法 分箱法 简单随机抽和分层抽

  3. 如何从0到1的构建一款Java数据生成器-第一章

    前提 某天晚上老夫在神游时,想起白天公司同事说起的问题,这老表抱怨使用mysql生成大批的随机测试数据太过麻烦,问大家有没有好的工具推荐,老夫对这种事情当然不关心,毕竟我也不知道. 秉承着不懂就要问, ...

  4. 【循环矩阵乘优化DP】BZOJ 2510 弱题

    题目大意 有 \(M\) 个球,一开始每个球均有一个初始标号,标号范围为 \(1\) - \(N\) 且为整数,标号为 \(i\) 的球有 \(a_i\) 个,并保证 \(\sum a_i = M\) ...

  5. 机器分配----线性dp难题(对于我来说)

    题目: 总公司拥有高效设备M台, 准备分给下属的N个分公司.各分公司若获得这些设备,可以为国家提供一定的盈利.问:如何分配这M台设备才能使国家得到的盈利最大?求出最大盈利值.其中M <= 15, ...

  6. 痞子衡嵌入式:MCUBootUtility v2.4发布,轻松更换Flashloader文件

    -- 痞子衡维护的NXP-MCUBootUtility工具距离上一个版本(v2.3.1)发布过去2个月了,这一次痞子衡为大家带来了版本升级v2.4.0,这个版本主要有一个非常重要的更新需要跟大家特别说 ...

  7. 解决Django本地接口不能跨域访问的问题

    1.安装django-cors-headers模块: pip install django-cors-headers 2.插入Django的APP配置中: # 修改settings.py中的INSTA ...

  8. 在Linux上成功启动Jenkins却无法访问的问题

    本鸟最近打算学习Jenkins,正准备在Linux上面鼓捣一番,,却没想被入门级别问题当头一棒 下载完jenkins.war,使用java -jar命令在8088端口开启服务:java -jar je ...

  9. JS变量作用域与解构赋值

    用var变量是有作用域的 变量在函数内部声明时,那么该变量只属于整个函数体,函数外不可调用 当两个不同的函数里,使用了用一个相同的变量名,二者不互相影响,相互独立 遇到嵌套函数时,外部函数不可调用内部 ...

  10. ansible-hoc命令行

    ansible一种开源的自动化工具 ansible: hoc命令行: 是一款开源的自动化运维工具 python paramiko #模拟ssh协议批量管理主机 jinja2 #模板语言,主要用来传递变 ...