• DPDK(二):准备知识8 --- netfilter


    一、简介
    Netfilter是Linux 2.4.x引入的一个子系统,它作为一个通用的、抽象的框架,提供一整套的hook函数的管理机制,使得诸如数据包过滤、网络地址转换(NAT)和基于协议类型的连接跟踪成为了可能。Netfilter在内核中位置如下图所示:

    Netfilter在netfilter_ipv4.h中命名5个节点,这5个节点是netfilter发挥作用的地方。

    在数据包流经内核协议栈的整个过程中,在一些已预定义的关键点上PRE_ROUTING、LOCAL_IN、FORWARD、LOCAL_OUT和POST_ROUTING会根据数据包的协议簇PF_INET到这些关键点去查找是否注册有钩子函数。如果没有,则直接返回okfn函数指针所指向的函数继续走协议栈;如果有,则调用nf_hook_slow函数,从而进入到Netfilter框架中去进一步调用已注册在该过滤点下的钩子函数,再根据其返回值来确定是否继续执行由函数指针okfn所指向的函数。
    二、钩子介绍
    Netfilter使用NF_HOOK(include/linux/netfilter.h)宏在协议栈内部切入到Netfilter框架中。
    1、钩子函数
    #define NF_HOOK(pf, hook, skb, indev, outdev, okfn)
             NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, INT_MIN)
    关于宏NF_HOOK各个参数的解释说明:
    1)         pf:协议族名,Netfilter架构同样可以用于IP层之外,因此这个变量还可以有诸如PF_INET6,PF_DECnet等名字。
    2)         hook:HOOK点的名字,对于IP层,就是取上面的五个值;
    3)         skb:不解释;
    4)         indev:数据包进来的设备,以struct net_device结构表示;
    5)         outdev:数据包出去的设备,以struct net_device结构表示;
    (后面可以看到,以上五个参数将传递给nf_register_hook中注册的处理函数。)
    6)         okfn:是个函数指针,当所有的该HOOK点的所有登记函数调用完后,转而走此流程
    #define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh)               
    ({int __ret;                                                                               
    if ((__ret=nf_hook_thresh(pf, hook, &(skb), indev, outdev, okfn, thresh, 1)) == 1)
             __ret = (okfn)(skb);                                                      
    __ret;})
    NF_HOOK_THRESH宏增加的最后一个参数thresh用来指定通过该宏去遍历钩子函数时的优先级。
    static inline int nf_hook_thresh(int pf, unsigned int 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[][],找到对应的回调函数来处理数据包,然后根据其返回值判断是否需要执行okfn函数。
    2、HOOK点介绍
    从协议栈正常的流程切入到Netfilter框架中,然后顺序、依次去调用每个HOOK点所有的钩子函数的相关操作有如下几处:
    1)net/ipv4/ip_input.c里的ip_rcv函数。该函数主要用来处理网络层的IP报文的入口函数,它到Netfilter框架的切入点为:
    NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,ip_rcv_finish)
    2)net/ipv4/ip_forward.c中的ip_forward函数,它的切入点为:
    NF_HOOK(PF_INET, NF_IP_FORWARD, skb, skb->dev, rt->u.dst.dev,ip_forward_finish);
    3)net/ipv4/ip_output.c中的ip_output函数,它切入Netfilter框架的形式为:
    NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,ip_finish_output, !(IPCB(skb)->flags & IPSKB_REROUTED));
    这里我们看到切入点从无条件宏NF_HOOK改成了有条件宏NF_HOOK_COND,调用该宏的条件是:如果协议栈当前所处理的数据包skb中没有重新路由的标记,数据包才会进入Netfilter框架。否则直接调用ip_finish_output函数走协议栈去处理。除此之外,有条件宏和无条件宏再无其他任何差异。
    4)还是在net/ipv4/ip_input.c中的ip_local_deliver函数。该函数处理所有目的地址是本机的数据包,其切入函数为:
    NF_HOOK(PF_INET, NF_IP_LOCAL_IN, skb, skb->dev, NULL,ip_local_deliver_finish);
    5)net/ipv4/ip_output.c中的ip_push_pending_frames函数。该函数是将IP分片重组成完整的IP报文,然后发送出去。进入Netfilter框架的切入点为:
    NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output);

  • 相关阅读:
    截取字符串为20个字
    GitFlow
    CSS3盒模型display:box;box-flex:3;
    CSS移动端多行显示多余省略号
    2017年6大热门开源项目
    七周七学习成为数据分析师
    2017-写给5年后的自己
    XGeocoding使用手册
    读书的5个秘诀
    如何快速成为数据分析师?(知乎)
  • 原文地址:https://www.cnblogs.com/xiaomayi-cyj/p/10543019.html
Copyright © 2020-2023  润新知