BIND中基数树的建立

2023-05-16

BIND9新引入了视图的概念,简单的来讲就是能根据不同的来源IP来返回不同的数据。其中网段的存储,网段的快速匹配都是用基数树来实现的。下面是BIND创建基数树的代码。

BIND的IP地址结构

struct isc_netaddr {
    unsigned int family;
    union {
        struct in_addr in;
        struct in6_addr in6;
#ifdef ISC_PLATFORM_HAVESYSUNH
        char un[sizeof(((struct sockaddr_un *)0)->sun_path)];
#endif
    } type;
    isc_uint32_t zone;
};

BIND 二叉树中表示网段的结构,该结构由sturct in_addr结构处理转换而来, bitlen表示掩码位

typedef struct isc_prefix {
    unsigned int family;    /* AF_INET | AF_INET6, or AF_UNSPEC for "any" */
    unsigned int bitlen;    /* 0 for "any" */
    isc_refcount_t refcount;
    union {
        struct in_addr sin;
        struct in6_addr sin6;
    } add;
} isc_prefix_t;

IP结构转换为节点结构

#define NETADDR_TO_PREFIX_T(na,pt,bits) \
    do { \
        memset(&(pt), 0, sizeof(pt)); \
        if((na) != NULL) { \
            (pt).family = (na)->family; \
            (pt).bitlen = (bits); \
            if ((pt).family == AF_INET6) { \
                memcpy(&(pt).add.sin6, &(na)->type.in6, \
                       ((bits)+7)/8); \
            } else \
                memcpy(&(pt).add.sin, &(na)->type.in, \
                       ((bits)+7)/8); \
        } else { \
            (pt).family = AF_UNSPEC; \
            (pt).bitlen = 0; \
        } \
        isc_refcount_init(&(pt).refcount, 0); \
    } while(0)

节点结构,其中的bit表示网段的掩码位,决定着redix tree的结构,redix tree的插入和匹配过程都会用到它

typedef struct isc_radix_node {
   isc_uint32_t bit;            /* bit length of the prefix */
   isc_prefix_t *prefix;        /* who we are in radix tree */
   struct isc_radix_node *l, *r;    /* left and right children */
   struct isc_radix_node *parent;   /* may be used */
   void *data[2];           /* pointers to IPv4 and IPV6 data */
   int node_num[2];         /* which node this was in the tree,
                       or -1 for glue nodes */
} isc_radix_node_t;

根节点结构

typedef struct isc_radix_tree {
   unsigned int     magic;
   isc_mem_t        *mctx;
   isc_radix_node_t     *head;
   isc_uint32_t     maxbits;    /* for IP, 32 bit addresses */
   int num_active_node;         /* for debugging purposes */
   int num_added_node;          /* total number of nodes */
} isc_radix_tree_t;

插入节点函数,其中redix是树的根节点,prefix是要插入的节点。

isc_result_t
isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target,
         isc_radix_node_t *source, isc_prefix_t *prefix)
{

从根节点开始往下搜寻插入位置,bitlen是新插入节点的掩码位。addr是4字节的char型字符串,占32位, 存储着要插入的节点IP地址。根据bit,addr来查找“插入位置”: 判断addr的第bit位是不是为1,如果是,则与右节点进行比较,否则与左节点进行比较。直到匹配到bit值大于或者等于bitlen的叶节点。(内部节点的IP是网段的中间值,比如网段是192.168.8.0/24,那么节点的ip就是192.168.8.128, 比较时先假设网段相同,IP小的在左边,IP大的在右边)

while (node->bit < bitlen || node->prefix == NULL) {
    if (node->bit < radix->maxbits &&
        BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07)))
    {
        if (node->r == NULL)
            break;
        node = node->r;
    } else {

        if (node->l == NULL)
            break;
        node = node->l;
    }

    INSIST(node != NULL);
}

比较新节点和node,找到第一个不同的位

/* Find the first bit different. */
check_bit = (node->bit < bitlen) ? node->bit : bitlen;
differ_bit = 0;

for (i = 0; i*8 < check_bit; i++) {
    if ((r = (addr[i] ^ test_addr[i])) == 0) {

        differ_bit = (i + 1) * 8;
        continue;
    }
    /* I know the better way, but for now. */
    for (j = 0; j < 8; j++) {
        if (BIT_TEST (r, (0x80 >> j)))
            break;
    }
    /* Must be found. */
    INSIST(j < 8);
    differ_bit = i * 8 + j;
    break;
}

如果differ_bit小于node->parent->bit,说明新节点和node不在同一个网段,node节点上移,直到node和新节点 同处于node的父节点网段下

if (differ_bit > check_bit)
    differ_bit = check_bit;

parent = node->parent;
while (parent != NULL && parent->bit >= differ_bit) {
    node = parent;
    parent = node->parent;
}

下面就分情况,具体就是确定父节点,子节点 和为节点的prefix赋值

1、 新节点和node是同一网段

if (differ_bit == bitlen && node->bit == bitlen) {
    ......
}

2、 新节点是node的子网段

if (node->bit == differ_bit) {
    ......
}

3、 node是新节点的子网段

if (bitlen == differ_bit) {
    ......
}

4、新节点和node是两个不相关的网段

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

BIND中基数树的建立 的相关文章

  • Android:java.net.DatagramSocket.bind:无效参数异常

    背景 我正在编写一个简单的 UDP 应用程序来 ping 一个测试版服务器 我每分钟左右管理一次 告诉我它仍在运行 对于那些想知道的人 我无法在服务器上启用 ping 我计划在手机上运行此命令 以便在服务器不再响应时向我发出警告 我正在尝试
  • 将列表绑定到 GridView

    我有一个信用卡对象列表 信用卡类别如下 using System using System Collections Generic using System Linq using System Web namespace Client pu
  • 将 Param 与参数数组绑定

    我有一个函数可以执行此操作 function registerUser firstName lastName address postcode email password params array firstName lastName a
  • 未捕获的类型错误:对象 [object Object] 没有方法“on”

    谁能帮我解决这个问题 当我使用最新 或较新 版本的 jQuery 时 下面的小脚本可以正常工作 但是 当我使用旧版本的 jQuery 时 我的脚本显示on函数不存在 这是我的脚本 不适用于旧版本的 jQuery document ready
  • “调用/应用”和“绑定”之间有什么区别[重复]

    这个问题在这里已经有答案了 var obj x 81 getX function console log this x var getX obj getX bind obj use obj as this getX 81 var getX
  • React.js - 即使在绑定后“this”也未定义

    我正在尝试捕捉onChange输入和调用事件setState使用新值 但是一旦我输入输入 我就会得到 Uncaught TypeError Cannot read property setState of undefined 尽管我已经打电
  • 将目录绑定到 docker 容器

    我正在构建一个测试项目 需要项目目录之外的模块 项目文件夹位于 docker 中 我想将该模块目录绑定到我的项目的 docker 容器 有可能做到吗 或者我问错了问题 顺便说一句 我对 docker 还很陌生 所以我只是尝试一下 我的理解是
  • 带参数的 Kivy 按钮绑定函数

    我正在尝试学习如何在 Kivy 中创建应用程序 但在向函数发送参数时遇到问题 我想将输入中的文本发送到函数并打印它 有人可以告诉我该怎么做吗 from kivy app import App from kivy uix boxlayout
  • Jquery:当用户单击除该 div 之外的任何内容时如何隐藏该 div。无叠加

    我在想 one在这种情况下会有用吗 但我不知道该怎么做 当我单击搜索链接时 会出现一个搜索框 我希望用户能够单击该 div 中的任何内容而不关闭它 但是当用户单击该 div 之外的任何内容时 div 就会淡出 嗯 这是一个example h
  • 如何将DataTemplate数据类型绑定到接口?

    我正在编写一个复合松散耦合的 MVVM WPF 应用程序 父 VM 中的子 VM 是接口而不是类实例 例如 public IChildViewModel get set 现在如何使用 DataTemplate 呈现此属性 喜欢
  • 删除通过绑定添加的事件侦听器

    在 JavaScript 中 删除使用 bind 添加为事件侦听器的函数的最佳方法是什么 Example function constructor MyClass function this myButton document getEle
  • React:搜索和过滤功能存在问题

    我正在开发一个组件 它应该能够 按输入搜索 使用输入字段 在触发 onBlur 事件后将调用一个函数 之后onBlur事件开始寻找 方法将运行 按所选流派过滤 用户可以从其他组件中从流派列表中选择流派 之后onClick事件启动过滤器 方法
  • 如何在特定接口上打开套接字并接收 IPv4 和 IPv6 流量

    使用 IPv4 我可以将 绑定到特定地址来选择将用于接收数据包的接口 在某些情况下 也用于发送数据包 但这不是重点 在双栈 IPv6 IPV4 机器上 我遇到这个问题 我可以创建一个 6 套接字并使用它接收 4 个流量 但如果我想绑定到特定
  • mem_fn 到成员对象的函数

    我正在摆弄std mem fn并且无法设法将其绑定到结构成员的数据 函数 更深一层 我希望代码能比我描述的更好地显示问题 因为我不熟悉这些术语 include
  • MySQLI 使用 call_user_func_array 绑定参数

    请看下面我的代码 我正在尝试将一系列参数绑定到我准备好的声明中 我一直在网上浏览 发现我必须使用 call user func array 但无法让它工作 我得到的错误是 第一个参数预计是一个有效的回调 给出了 Array 我可能是错的 但
  • jQuery:将 ajaxForm 绑定到通过 .load() 加载的页面上的表单

    我正在使用 jQuery 的 ajaxForm 插件在我的 web 应用程序上提交表单 然而 在应用程序的一部分中 我通过 jQuery 的 load 加载一些带有表单的内容 问题在于我无法让 ajaxForm 绑定到通过 ajax 加载的
  • 如果Service在另一个进程中,如何绑定它?

    显现
  • 在 Flask-SQLAlchemy 中的同一类中使用不同的绑定

    我目前有多个具有相同表和列 但内部数据不同 的数据库 很明显 我需要使用绑定来访问所有这些 但这显然不像这样做那么简单 class WhateverTable db Model tablename whatevertable whateve
  • 将函数绑定到 Kivy 按钮

    我正在尝试将以下函数绑定到Button在基维 def auth self print self username if self username Hendricko print self username Hendricko popup
  • 了解 ASP.NET Eval() 和 Bind()

    任何人都可以向我展示一些绝对最小的 ASP NET 代码来理解Eval and Bind 最好为我提供两个单独的代码片段或者可能是网络链接 对于只读控件 它们是相同的 对于 2 路数据绑定 使用要在其中通过声明性数据绑定更新 插入等的数据源

随机推荐

  • 三维视觉论文实战:DenseDepth2019--网络结构及demo

    目的 本篇博客的主要目的是记录测试DenseDepth的demo的过程 xff0c 包括 pytorch模型构建 和 keras模型参数转pytorch 两大部分 xff0c 当然最后还有一个实验模块 注明以下 xff0c 本篇博客为啥要构
  • GTAV:原始影像和深度图获取

    背景 GTAV是一个非常好的游戏 xff0c 目前也已经被广泛应用到深度学习之中了 本篇博客简单介绍一下如何采集数据 1 数据采集 1 代码修改 本篇博客的代码来源于GTAVisionExport 但是上述代码中 xff0c 存在些许问题
  • Blender2.8:Blender Python渲染降噪节点(Cycles)

    参考 https www bilibili com read cv9221189 背景 Blender的Cycles渲染引擎存在非常多的噪声 方法 一个比较好的思路是利用 Denoising Data 和降噪节点 参考文档里的是手动设置 x
  • Ubuntu:显存占用及处理

    问题 在进行深度学习时 xff0c 显存是一种非常宝贵的资源 但是即便在Ubuntu下 xff0c 各种各样的系统配置都会不自觉的占用一些显存 xff0c 导致深度学习难以为继 在本博客中 xff0c 主要搬运一些查询显存占用原因及处理方法
  • Jittor:Jittor三千问

    Jittor三千问 记录一下在使用Jittor时遇到的问题和对应的解决方案 xff0c 持续更新 非常感谢梁盾博士的回复 1 Jittor如何指定显卡 xff1f 在运行脚本时 xff0c 使用 CUDA VISIBLE DEVICES 6
  • 机器学习:补课目录

    补课目录 xff1a xff08 已经完成 xff09 吴恩达DeepLearning ai xff1a Deep Learning Specialization xff08 正在进行 xff09 林轩田 机器学习基石 xff08 正在进行
  • conda:离线环境安装

    Aanconda的离线环境安装的必要条件是有一台可以联网的电脑 在后文中 xff0c 分别称可以联网的电脑为On line xff0c 不可以联网的电脑为Off line 以下即为对应的操作步骤 1 On line 下载annconda安装
  • Ubuntu:pip install gdal

    方法 sudo apt get update 必须首先安装gdal的lib xff0c python只是针对该lib的调用 sudo apt install gdal bin libgdal dev pip安装的版本必须和gdal一致 pi
  • Git:使用笔记

    git局部配置 git config user name 34 username 34 git config user email 34 email 34 git带用户密码clone git clone https username pas
  • Pytorch:conda安装不同版本的cuda

    我不会是最后一个知道可以用conda安装不同版本的cuda的人吧 通常的pytorch安装流程是 xff1a 首先安装NVIDIA驱动 xff0c 然后安装对应版本的cuda和cudnn最后再安装cuda支持的pytorch版本 然而实际上
  • obsidian使用技巧

    背景 obsidian是一个非常牛逼的本地笔记工具 xff0c 极大的提高了本人的学习能力 xff0c 卷的更加厉害了 此处简要记录一下在使用过程中遇到问题和对应的解决方案 xff0c 至于具体的使用方法网上多的是就不介绍了 三方插件推荐
  • ubuntu:命令行查询文件(夹)大小

    背景 使用命令行查询文件文件 夹 大小 参考 https www cnblogs com zhengyiqun1992 p 11183819 html 使用方法 查看当前文件夹下文件大小 ll h 输出如下 xff0c 其中文件夹大小是错误
  • VSCode:remote-ssh多级跳转

    背景 vscode目前是非常流行的编程工具 xff0c 提供了大量的插件 xff0c 尤其是其中的remote ssh xff0c 能够提供远程ssh连接服务器 xff0c 居家办公两不误 然而比较麻烦的事情是 xff0c 通常服务器为了保
  • Jittor:Jittor1.3.1之离线安装

    背景 Jittor是一个非常牛逼的框架 xff0c 维护了大量的官方demo xff0c 非常容易上手 与其他方法相比 xff0c 采用了即时编译的流程 xff0c 因此在效率上往往更高 但是在使用Jittor的过程中 xff0c 也遇到了
  • 灵活的按键处理程序 FlexibleButton,C程序编写,无缝兼容任意的处理器,支持任意 OS 和 non-OS

    灵活的按键处理程序 FlexibleButton 前言概述获取测试DEMO 程序说明程序入口用户初始化代码事件处理代码 FlexibleButton 代码说明按键事件定义按键注册接口按键事件读取接口按键扫描接口 问题和建议 前言 正好工作中
  • http请求头header、请求体body、请求行介绍

    HttpServletRequest对象代表客户端的请求 当客户端通过http协议请求访问 服务器的时候 http请求头的所有信息都封装在这个对象中 xff0c 通过这个对象 xff0c 可以获取客户端请求的所有信息 http请求包含请求行
  • 理解字节序 大端字节序和小端字节序

    以下内容参考了 http www ruanyifeng com blog 2016 11 byte order html https blog csdn net yishengzhiai005 article details 3967252
  • opencvSharp 学习笔记(二)

    参考文章 xff1a https github com shimat opencvsharp samples tree master SamplesCS Samples 参考opencvsharp的官方sample xff0c 在vs201
  • C++局部对象的析构

    class A span class hljs keyword public span A Func span class hljs attribute span span class hljs attribute span A A spa
  • BIND中基数树的建立

    BIND9新引入了视图的概念 xff0c 简单的来讲就是能根据不同的来源IP来返回不同的数据 其中网段的存储 xff0c 网段的快速匹配都是用基数树来实现的 下面是BIND创建基数树的代码 BIND的IP地址结构 span class hl