zoukankan      html  css  js  c++  java
  • Netfilter 之 五个钩子点

    概述

    在协议栈的三层IPv4(IPv6还没看,不清楚)数据包的处理过程中,可能经过Netfilter的五个钩子点,分别为NF_INET_PRE_ROUTING、NF_INET_LOCAL_IN、NF_INET_FORWARD、NF_INET_LOCAL_OUT、NF_INET_POST_ROUTING,在每个点都可以设置一些规则,来对数据包进行匹配检查处理,这些规则的配置、布局和匹配流程,后续文章会详细介绍,本篇主要介绍这五个钩子点以及所处的上下文调用关系;

    五个钩子点的位置如下图所示;

    代码分析
    NF_INET_PRE_ROUTING

    当二层收包结束后,会根据注册的协议和回调函数分发数据包,其中ipv4的数据包会分发到ip_rcv函数进行三层协议栈处理,该函数对数据包的合法性进行检查,并且设置一些必要字段之后,经过PRE_ROUTING钩子点;

     1 int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
     2 {
     3         /* IP数据报的合法性检查和一些必要字段设置,此处省略 */
     4 
     5     /* 经过PRE_ROUTING钩子点 */
     6     return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING,
     7                net, NULL, skb, dev, NULL,
     8                ip_rcv_finish);
     9 
    10 }
    NF_INET_LOCAL_IN

    上面的ip_rcv函数在经过了PRE_ROUTING钩子点之后,会调用ip_rcv_finish函数,该函数的主要功能是查路由,决定数据包是输入到本地还是转发,并调用dst_input函数;当数据包输入本地时,dst_input函数实际调用了ip_local_deliver函数,函数首先对分片进行检查,如果是分片则需要进行重组,然后经过NF_INET_LOCAL_IN钩子点,之后调用ip_local_deliver_finish继续进行输入本地的其他工作;

     1 int ip_local_deliver(struct sk_buff *skb)
     2 {
     3     struct net *net = dev_net(skb->dev);
     4 
     5     /* 分片重组 */
     6     if (ip_is_fragment(ip_hdr(skb))) {
     7         if (ip_defrag(net, skb, IP_DEFRAG_LOCAL_DELIVER))
     8             return 0;
     9     }
    10 
    11     /* 经过LOCAL_IN钩子点 */
    12     return NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_IN,
    13                net, NULL, skb, skb->dev, NULL,
    14                ip_local_deliver_finish);
    15 }
    NF_INET_FORWARD

    上面的ip_rcv函数在经过了PRE_ROUTING钩子点之后,会调用ip_rcv_finish函数,该函数的主要功能是查路由,决定数据包是输入到本地还是转发,并调用dst_input函数;当数据包输入本地时,dst_input函数实际调用了ip_forward函数,函数数据包进行合法性检查,然后经过NF_INET_FORWARD钩子点,之后调用ip_forward_finish继续进行转发的其他工作,ip_forward_finish在输出数据包的时候,实际上又调用dst_output,实际上就是ip_output函数;

     1 static int ip_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
     2 {
     3         /* 合法性检查等,此处省略 */
     4 
     5         /* 经过FORWARD钩子点 */
     6     return NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD,
     7                net, NULL, skb, skb->dev, rt->dst.dev,
     8                ip_forward_finish);
     9 
    10 }
    NF_INET_LOCAL_OUT

    从本机发出的数据包,在查询路由成功之后,会调用__ip_local_out函数,函数首先进行必要字段设置和校验和计算,然后经过NF_INET_LOCAL_OUT钩子点,之后会调用dst_output继续完成数据包输出的其他工作,ipv4的路由输出函数实际上就是ip_output函数;

     1 int __ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
     2 {
     3     struct iphdr *iph = ip_hdr(skb);
     4 
     5     /* 设置总长度 */
     6     iph->tot_len = htons(skb->len);
     7     /* 计算校验和 */
     8     ip_send_check(iph);
     9 
    10     /* if egress device is enslaved to an L3 master device pass the
    11      * skb to its handler for processing
    12      */
    13     skb = l3mdev_ip_out(sk, skb);
    14     if (unlikely(!skb))
    15         return 0;
    16 
    17     /* 设置ip协议 */
    18     skb->protocol = htons(ETH_P_IP);
    19 
    20     /* 经过NF的LOCAL_OUT钩子点 */
    21     return nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT,
    22                net, sk, skb, NULL, skb_dst(skb)->dev,
    23                dst_output);
    24 }
    NF_INET_POST_ROUTING

    转发的数据包或者是本地输出的数据包,最后都会经过ip_output进行输出,函数设置设备和协议之后,经过NF_INET_POST_ROUTING钩子点,之后调用ip_finish_output进行后续输出操作,其中包括了分片等;

     1 int ip_output(struct net *net, struct sock *sk, struct sk_buff *skb)
     2 {
     3     struct net_device *dev = skb_dst(skb)->dev;
     4 
     5     IP_UPD_PO_STATS(net, IPSTATS_MIB_OUT, skb->len);
     6 
     7     /* 设置输出设备和协议 */
     8     skb->dev = dev;
     9     skb->protocol = htons(ETH_P_IP);
    10 
    11     /* 经过NF的POST_ROUTING钩子点 */
    12     return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING,
    13                 net, sk, skb, NULL, dev,
    14                 ip_finish_output,
    15                 !(IPCB(skb)->flags & IPSKB_REROUTED));
    16 }
  • 相关阅读:
    世纪末的星期
    马虎的算式
    蜜蜂飞舞
    Torry 的困惑
    级数调和
    数列
    最大最小公倍数
    蚂蚁感冒
    12.integer to Roman
    13.Roman to Integer
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/11755552.html
Copyright © 2011-2022 走看看