Netfilter再来亿遍

Netfilter/IPTables
Linux 2.4 版本以上新加入的防火墙机制
Netfilter与IP协议栈是无缝契合的,工具模块IPTables从用户态的iptables连接到内核态的Netfilter的架构中

主要功能
1.数据报过滤
2.链接跟踪 (一条tcp会话)
3.网络地址转换(NAT)
4.数据报修改(mangle)

可以这么说,Netfilter是表的容器,表是链的容器,链是规则的容器,最终形成对数据报处理规则的实现。
Netfilter再来亿遍
以下的绿底图,都是复制的别人的
每个链挂有一系列规则,链称为钩子点
链的实际拓扑是下面这样的,
Netfilter再来亿遍
他说明了三种 数据流向
1.pre -> local_in -> 上层
2.pre -> forward -> post
3.上层 -> local_out ->post

理解这个流向很重要,因为刚开始接触的时候很可能以为
pre -> local_in ->上层 ->local_out ->post 是一条 ,这个认知会为理解nf带来很大阻碍

对于数据的实际处理,是在链上的规则(钩子函数nf_hook_ops)内进行的
经过规则的判断,会返回一个值,告诉ntfilter 应该 丢掉这个包还是放行,或者其他操作
具体的返回值,及动作可以再去查看

上面的链 拓扑看起来是 一个平面的, 实际上, netfilter 是一个三维的结构,更高一维是协议
,每选择一种协议, 对应的二维平面,都是像上面的图展示的一样,只不过,里面的规则会有差别

Netfilter再来亿遍

Netfilter再来亿遍

NF_HOOK 是一个宏,指明了 要调用哪一个协议层的哪个钩子点,
使用 NF_HOOK 可以将流程切入到netfilter之中 在头文件(include/linux/netfilter.h)
#define NF_HOOK(pf, hook, skb, indev, outdev,okfn)
NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, INT_MIN)

调用
NF_HOOK(刚才所说的协议, 钩子,skb(数据),输入设备, 输出设备,处理走完钩子状态的回调函数)
最后一个参数指定通过该宏去遍历钩子函数时的优先级,越小越优先

NF_HOOK_THRESH宏只增加了一个thresh参数,这个参数就是用来指定通过该宏去遍历钩子函数时的优先级,同时,该宏内部又调用了nf_hook_thresh函数:
static inline int nf_hook_thresh(int pf, unsignedint hook,
                           struct sk_buff **pskb,
                           struct net_device *indev,
                           struct net_device *outdev,
                           int (*okfn)(struct sk_buff *), int thresh,
                           int cond)
{
if (!cond)
return 1;
#ifndef CONFIG_NETFILTER_DEBUG
if (list_empty(&nf_hooks[pf][hook]))
        return 1;
#endif
return nf_hook_slow(pf, hook, pskb, indev, outdev,okfn, thresh);
}

这个函数又只增加了一个参数cond,该参数为0则放弃遍历,并且也不执行okfn函数;为1则执行nf_hook_slow去完成钩子函数okfn的顺序遍历(优先级从小到大依次执行)。

可以看到函数的最后调用了 nf_hook_slow, 主要就是通过这个函数,根据优先级,遍历 钩子点上的钩子函数 ,钩子点都在 nf_hooks[][] 上


pre钩子 在ip_rcv()调用
(优先级顺序):Conntrack(-200)、mangle(-150)、DNAT(-100)
主要是对数据报作报头检测处理,以捕获异常情况。

local_in 钩子 ,在ip_local_deliver()调用
(优先级顺序):mangle(-150)、filter(0)、SNAT(100)、Conntrack(INT_MAX-1)
防火墙一般建立在这个HOOK上。

forward钩子 ,在ip_forward()调用
(优先级顺序)mangle(-150)、filter(0)

local_out 钩子,在 ip_build_and_send_pkt()调用
(优先级顺序) Conntrack(-200)、mangle(-150)、DNAT(-100)、filter(0)

post钩子 在ip_finish_output() 中调用
mangle(-150)、SNAT(100)、Conntrack(INT_MAX)

可以发现, 钩子函数的优先顺序 (相对于一条流来说)
都是 先 跟踪链接(ct), 然后 mangle nat 、filter ,最后再 链接跟踪(ct)



接下来 是 更具体的代码

要注册一个钩子函数 需要调用 nf_register_hook() 函数,并且准备一个数据 结构nf_hook_ops
nf_register_hook(&nf_hook_ops) 能完成对钩子函数的注册
nf_unregister_hook(&nf_hook_ops) 能完成对钩子函数的注销
钩子函数对应的结构就是下面这个
struct nf_hook_ops {
struct list_head list;

              /* 此下的值由用户填充 */
              nf_hookfn *hook;
              int pf;
              int hooknum;
              /* Hook以升序的优先级排序 */
              int priority;
      };
  • list 即 netfilter 的链表结构,链接各个钩子函数
  • nf_hookfn *hook 真正的 处理函数,具体执行的内容

nf_hookfn 函数指针
Netfilter再来亿遍
okfn 即用来处理

  • pf 是 协议 ,
  • hooknum 即 表明是在哪个钩子点上的 pre post foward ,由宏定义
  • priority 调用优先级

上一篇:664-Linux高效的wakeupfd进程间通信


下一篇:从认识串口到串口通讯