在协议栈的FIB(Forwarding Information Base)模块中,结构体struct fib_info是一个很基本的单位,它表示一个路由信息,一个路由信息可以被多个路由共享。下面是其完整的定义:
    struct fib_info {
        struct hlist_node   fib_hash;
        struct hlist_node   fib_lhash;
        int             fib_treeref;
        atomic_t        fib_clntref;
        int             fib_dead;
        unsigned        fib_flags;
        int             fib_protocol;
        u32             fib_prefsrc;
        u32             fib_priority;
        u32             fib_metrics[RTAX_MAX];
#define fib_mtu fib_metrics[RTAX_MTU-1]
#define fib_window fib_metrics[RTAX_WINDOW-1]
#define fib_rtt fib_metrics[RTAX_RTT-1]
#define fib_advmss fib_metrics[RTAX_ADVMSS-1]
        int             fib_nhs;
#ifdef CONFIG_IP_ROUTE_MULTIPATH
        int             fib_power;
#endif
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
        u32             fib_mp_alg;
#endif
        struct fib_nh   fib_nh[0];
#define fib_dev         fib_nh[0].nh_dev
    };
    现在就结合模块加载并初始化过程中为一个本地网络接口生成路由信息的实例,分析路由信息的创建过程。本地主机的网络设备接口eth0上配置的ip地址是 172.16.48.2。协议栈的fib_add_ifaddr函数会在模块被加载的时候主动往FIB表中插入五条路由相关信息,下面是一个完整列表:
    类型                            目的地址        地址长度
    RTN_LOCAL             172.16.48.2         32
    RTN_BROADCAST  172.16.48.255       32
    RTN_UNICAST         172.16.48.0         24
    RTN_BROADCAST   172.16.48.0         32
    RTN_BROADCAST   172.16.48.255       32
    其中第二条跟第五条完全相同,所以实际插入的是四条。第一条是本地接收,第二条是本地接收的广播,第三条是子网内的直接路由或者网关路由。第四条是子网广播。
        首先看第一条会产生怎么样的路由信息struct fib_info。在这之前,fib_magic函数要为它产生三个结构体信息,用于传递给路由信息创建函数:
    struct nlmsghdr
    {
        __u32       nlmsg_len = sizeof( struct nlmsghdr + struct rtmsg );
        __u16       nlmsg_type = RTM_NEWROUTE;
        __u16       nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_APPEND;
        __u32       nlmsg_seq = 0;
        __u32       nlmsg_pid = 0;
    };
    这是一个消息头结构,表示本条消息的内容是创建一个新的路由(RTM_NEWROUTE),这是一个请求消息(NLM_F_REQUEST),如果新的路 由不存在,则要求创建(NLM_F_CREATE),并且新创建的路由加到列表尾部(NLM_F_APPEND)。由于这是内核发出的请求命令,所以序列 号跟进程号都为0。
    struct rtmsg
    {
        unsigned char       rtm_family;
        unsigned char       rtm_dst_len = 32;
        unsigned char       rtm_src_len;
        unsigned char       rtm_tos;
        unsigned char       rtm_table = RT_TABLE_LOCAL;
        unsigned char       rtm_protocol = RTPROT_KERNEL;
        unsigned char       rtm_scope = RT_SCOPE_HOST;
        unsigned char       rtm_type = RTN_LOCAL;
        unsigned                rtm_flags;
    };
    这是消息体,表示这一条由内核发起的消息(RTPROT_KERNEL),因为路由类型是本地接收(RTN_LOCAL),所以操作对象是本地路由表 (RT_TABLE_LOCAL),同时目的地址也就是本地地址(RT_SCOPE_HOST),目的地址长度是32位。
    struct kern_rta {
        void        *rta_dst = 172.16.48.2;
        void        *rta_src;
        int         *rta_iif;
        int         *rta_oif = indexof(eth0);
        void        *rta_gw;
        u32         *rta_priority;
        void        *rta_prefsrc = 172.16.48.2  //接口上的primary地址。
        struct rtattr   *rta_mx;
        struct rtattr   *rta_mp;
        unsigned char   *rta_protoinfo;
        u32             *rta_flow;
        struct rta_cacheinfo    *rta_ci;
        struct rta_session  *rta_sess;
        u32                 *rta_mp_alg;
    };
    该结构体提供该路由的属性,即本地地址,目的地址,输出接口。
    函数fib_create_info用于创建路由信息,它首先要对请求信息的scope的有效性作一个判断,关于scope,内核定义了如下的枚举量:
    enum rt_scope_t
    {
        RT_SCOPE_UNIVERSE=0,
        /* User defined values  */
        RT_SCOPE_SITE=200,
        RT_SCOPE_LINK=253,
        RT_SCOPE_HOST=254,
        RT_SCOPE_NOWHERE=255
    };
    当前路由请求信息的type为RTN_LOCAL,它对应的scope应该是RT_SCOPE_HOST,如果scope小于这个值,则错误。
    新创建的struct fib_info结构都会维护在一个哈希表struct hlist_head *fib_info_hash中备用。该哈项表的长度由变量fib_hash_size记录,变量fib_info_cnt记录哈希表中当前的路由信息数 量。函数fib_create_info总是确保fib_hash_size>fib_info_cnt,如果不够了,就把哈希表扩大一倍。
    结构体struct fib_info的最后一个成员是struct fib_nh fib_nh[0],它是一个路由的下一跳信息,目前还没看到它的实际用途。缺省struct fib_nh的数量为1,如果不为1,则由struct kern_rta的rta_mp传入具体信息。下面是该结构体的定义:
    struct fib_nh {
        struct net_device   *nh_dev;
        struct hlist_node   nh_hash;
        struct fib_info     *nh_parent;
        unsigned            nh_flags;
        unsigned char       nh_scope;
#ifdef CONFIG_IP_ROUTE_MULTIPATH
        int                 nh_weight;
        int                 nh_power;
#endif
#ifdef CONFIG_NET_CLS_ROUTE
        __u32           nh_tclassid;
#endif
        int             nh_oif;
        u32             nh_gw;
    };
    新创建的struct fib_info需要进行部分值的初始化,下面是被初始化的内容:
    struct fib_info{
        .fib_protocol   = RTPROT_KERNEL;
        .fib_nhs        = 1;
        .fib_flags      = 0;
        .fib_prefsrc    = 172.16.48.2;
        struct fib_nh{
            .nh_oif     = indexof(eth0);
            .nh_flags   = 0;
            .nh_weight  = 1;
            .nh_scope   = RT_SCOPE_NOWHERE;
            .nh_dev     = eth0;
        }
    }
    由于创建完成的struct fib_info,还要拿到哈项表fib_info_hash中去匹配,因为有可能哈希表中已存在同样的一个路由信息了,如果存在,则要删掉刚刚创建的 struct fib_info,把表中已有的那项的成员fib_treeref加1即可。判断两个路由信息相同的依据 是:fib_protocol,fib_prefsrc,fib_priority,fib_metrics,fib_flags全部相同,并且 fib_nh的数量和内容全部相同。
    如果哈希表中还不存在,则把新创建的fib_info添加到哈项表中。并且,如果成员fib_prefsrc不为0,则同时把fib_info添加到哈希 表fib_info_laddrhash中,fib_info_laddrhash是一个跟fib_info_hash同步维护的哈希表。
    最后,还要把fib_info的所有struct fib_nh成员放到哈希表fib_info_devhash中,nh_dev相同的放到同一项中。
    同理,第二项创建的struct fib_info如下:
    struct fib_info{
        .fib_protocol   = RTPROT_KERNEL;
        .fib_nhs        = 1;
        .fib_flags      = 0;
        .fib_prefsrc    = 172.16.48.2;
        struct fib_nh{
            .nh_oif     = indexof(eth0);
            .nh_flags   = 0;
            .nh_weight  = 1;
            .nh_scope   = RT_SCOPE_HOST;
            .nh_dev     = eth0;
        }
    }
    依次类推,第三,第四项创建的struct fib_info与第二项完全相同,所以,最后,为网络设备接口eth0创建的struct fib_info共有两个,第一个的fib_treeref为1,第二个为3。

创建struct fib_info函数分析相关推荐

  1. 创建struct fib_info

    在协议栈的FIB(Forwarding Information Base)模块中,结构体struct fib_info是一个很基本的单位,它表示一个路由信息,一个路由信息可以被多个路由共享.下面是其完 ...

  2. CorelDraw插件开发-文字功能-文本分列-创建文本-函数分析-Cdr插件开发教程(二)

    文章目录 1.函数-sub_2381FDE0-进程资源锁 2.大致分析了一下函数结构 3.动态调试 4.上一级函数分析 5.VBA宏功能 6.总结 逆向代码的学习需要耐心,往往高手的代码会用到你想不到 ...

  3. rt-thread源码分析篇十八:rt_system_scheduler_start函数分析

    一.rt_system_scheduler_start源码 {register struct rt_thread *to_thread;register rt_ubase_t highest_read ...

  4. linux arm 地址映射 ioremap_nocache 使用,ioremap_nocache 函数分析(二)

    ioremap_nocache函数分析(二) 非连续映射地址空间 static struct vm_struct *__get_vm_area_node(unsigned long size, uns ...

  5. dpdk内存管理之rte_eal_hugepage_init()函数分析

    dpdk版本:dpdk-stable-16.11.11 今天我们来看一下rte_eal_hugepage_init() 函数都干了哪些事. 1.计算大页总数 在调用rte_eal_hugepage_i ...

  6. 【Android 逆向】整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | DexPathList 构造函数分析 | makeDexElements 函数分析 )

    文章目录 前言 一.DexPathList 构造函数分析 二.DexPathList.makeDexElements 函数分析 三.Element 类分析 前言 上一篇博客 [Android 逆向]整 ...

  7. Windows事件等待学习笔记(三)—— WaitForSingleObject函数分析

    Windows事件等待学习笔记(三)-- WaitForSingleObject函数分析 要点回顾 WaitForSingleObject NtWaitForSingleObject KeWaitFo ...

  8. DB 查询分析器 方便地创建DB2自定义函数

    DB 查询分析器 方便地创建DB2自定义函数                            马根峰             (广东联合电子服务股份有限公司, 广州 510300) 摘要     ...

  9. fatfs文件系统详解之f_mkfs函数分析

    前序 前面两篇文章分析了FAT文件系统,没有代码总感觉很空虚寂寞冷,fatfs正好是一个开源专门应对fat文件系统的代码,从这篇文章开始分析fatfs代码,"理论+实践"才是悟道的 ...

最新文章

  1. python打包的exe如何免杀_通过Python实现Payload分离免杀过程详解
  2. 高并发设计方案二(秒杀架构)
  3. [译]Vulkan教程(32)生成mipmap
  4. Linux vi编辑器常见命令的使用
  5. html中怎么写jq,用jQuery替换HTML页面中的文本
  6. 最大的连续子段和的O(n)解法
  7. python计算目录大小_使用Python计算目录的大小?
  8. Ambari——大数据平台的搭建利器之进阶篇[配置spark]
  9. j$(function() j$(document).ready 区别
  10. 在CSDN发布付费资源
  11. SQL SERVER 2000数据库置疑处理
  12. LaTeX技巧001:ctex下使用其他中文字体
  13. Linux常用命令学习
  14. 自媒体会否是独立游戏的出路?
  15. Vector诊断系统开发流程及其工具链
  16. Fiddler工具的弱网模拟2G/3G/4G
  17. TFLearn循环神经网络识别验证码
  18. 查询mysql数据库表占用空间大小_查看 MySQL 数据库中每个表占用的空间大小-阿里云开发者社区...
  19. 中小企业如何选择适合的ERP系统?
  20. 动态分析和静态分析最主要的区别是什么?

热门文章

  1. Java 蓝桥杯 芯片测试
  2. html实现验证码效果,js实现验证码功能
  3. python获得对象对应的类名称
  4. ibatis 模糊查询 mysql_Mybatis使用MySQL模糊查询时输入中文检索不到结果怎么办
  5. 软件测试缺陷定义和管理
  6. 【AMAD】django-activity-stream
  7. 数据库事物隔离级别用到的锁再次理解
  8. 2345联盟通过流氓软件推广挖矿工具, 众多用户电脑沦为“肉鸡”
  9. SQL SERVER:开窗函数 SUM() OVER() 数据统计中一例使用
  10. VS调试时断点无法进入或命中的原因及解决方法(PDB引发的)