如何做到只查询当前子树,而不前往下一级子树进行搜索

在 SNMP 中,要确保 [nextCmd] 函数只遍历当前的 MIB 子树而不进入下一级子树,可以通过设置 [lexicographicMode]参数来实现。将这个参数已经被设置为 [False],这是关键设置。

lexicographicMode=False

当 [lexicographicMode]设置为 false 时,[nextCmd]函数的行为会受到限制,使其只在指定的 OID 子树内进行遍历。这是因为 SNMP 的 WALK 操作本质上是通过连续发送 SNMP GETNEXT 请求来实现的,每个请求基于上一个请求的结果来获取下一个 OID。

工作原理

  1. OID 排序:

    • OID(对象标识符)在 MIB(管理信息库)中是按照字典顺序排列的。每个 OID 都可以看作是一个节点,可能有多个子节点形成一个子树。
  2. GETNEXT 请求:

    • SNMP GETNEXT 请求用于查询字典顺序中当前 OID 的下一个 OID。如果当前 OID 是某个子树的最后一个节点,那么正常情况下(lexicographicMode=True),下一个 GETNEXT 请求将返回紧接着的下一个子树的第一个 OID。
  3. 限制遍历范围:

    • 当 [lexicographicMode]设置为 false,[nextCmd] 会在到达当前子树的逻辑末端时停止发送 GETNEXT 请求。这是通过检查每个新获取的 OID 是否仍然属于初始指定的 OID 子树来实现的。如果新的 OID 不再属于起始 OID 的子树,[nextCmd] 将不再继续请求更多的 OID,从而结束遍历。

实际效果

这意味着,如果开始于一个特定的 OID,比如 .1.3.6.1.2.1.1,并且设置 [lexicographicMode=False],[nextCmd] 将只遍历 .1.3.6.1.2.1.1 下的所有子节点,直到这个分支的末端。一旦到达这个分支的逻辑末端,即使 MIB 中还有更多的 OID,[nextCmd] 也不会继续前进到其他分支,如 .1.3.6.1.2.1.2

这种设置对于限制 SNMP 查询的范围非常有用,特别是在大型网络中,可以显著减少不必要的网络流量和处理时间,同时确保查询结果的相关性和精确性。

在 SNMP 中,当使用 [nextCmd] 函数并设置 [lexicographicMode=False]时,内部逻辑会自动处理判断当前 OID 是否为初始子树的逻辑末端。这个判断基于 OID 的结构和排序规则。下面是如何进行这种判断的详细解释:

OID 结构和比较

OIDs (对象标识符) 是按照树状结构组织的,每个 OID 可以视为一个路径,从根开始,通过一系列的数字(节点)来唯一标识信息的位置。例如,OID .1.3.6.1.2.1.1 可以被视为从根节点开始的路径。

判断逻辑

当 [nextCmd] 发送 SNMP GETNEXT 请求并接收到响应时,它会获取当前 OID 的“下一个” OID。这里的“下一个”是基于字典顺序的。[nextCmd] 会检查这个新的 OID 是否仍然是初始 OID 的子节点。这是通过比较 OID 前缀来实现的:

  • 前缀匹配:如果新的 OID 在字典顺序中仍然以初始 OID 作为前缀,那么它被认为是初始子树的一部分。例如,如果初始 OID 是 .1.3.6.1.2.1.1,那么 .1.3.6.1.2.1.1.1.1.3.6.1.2.1.1.2 都是它的子节点。
  • 前缀不匹配:如果新的 OID 不以初始 OID 作为前缀,这意味着 [nextCmd]已经越过了初始子树的边界。例如,从 .1.3.6.1.2.1.1.1.3.6.1.2.1.2 就是越过了边界。

自动停止

当 [lexicographicMode=False],如果 [nextCmd] 检测到新的 OID 越过了初始子树的边界,它将自动停止发送进一步的 GETNEXT 请求。这个停止是内部实现的,不需要用户额外编码来控制。

这种机制确保了 SNMP WALK 操作的效率和准确性,只获取相关的 MIB 数据,避免了不必要的网络负载和处理开销。

解释 [lexicographicMode] 参数:

  • lexicographicMode=True:

    • 当设置为 [True] 时,[nextCmd]将按字典顺序遍历整个 MIB 树,从指定的起始 OID 开始,直到 MIB 的末尾。这意味着它会超出原始指定的子树范围,进入其他子树进行搜索。
  • lexicographicMode=False:

    • 当设置为 [False]时,[nextCmd]会在到达当前子树的末端时停止。这意味着它只会遍历从指定 OID 开始的那部分子树,一旦到达这个子树的逻辑末端,即使 MIB 中还有更多的 OID,它也不会继续前进。

实现细节:

当 [nextCmd] 遍历到一个 OID,它会检查这个 OID 是否仍然属于初始指定的子树。如果当前的 OID 超出了起始 OID 的范围(即不再是起始 OID 的子节点),并且 [lexicographicMode] 设置为 [False],则 [nextCmd] 会停止遍历。

这种方式非常适合于需要精确控制 SNMP 查询范围的情况,确保查询只限于特定的子树,从而提高效率并减少不必要的网络流量和处理时间。

def walk_subtree(ip, oid):
    result_text = ""
    for (error_indication, error_status, error_index, var_binds) in nextCmd(
            SnmpEngine(),
            CommunityData('public', mpModel=0),
            UdpTransportTarget((ip, 161)),
            ContextData(),
            ObjectType(ObjectIdentity(oid)),
            lexicographicMode=False
    ):
        if error_indication:
            return f"SNMP WALK request failed: {error_indication}"
        elif error_status:
            return f"SNMP WALK error at {error_index}: {error_status.prettyPrint()}"
        else:
            for var_bind in var_binds:
                result_text += f"{var_bind[0].prettyPrint()} = {var_bind[1].prettyPrint()}\n"
    return result_text.strip() if result_text else "No entries found under this OID."
def snmp_walk(ip, community, oid):  
    iterator = nextCmd(  
        SnmpEngine(),  
        CommunityData(community, mpModel=0),  
        UdpTransportTarget((ip, 161)),  
        ContextData(),  
        ObjectType(ObjectIdentity(oid))  
    )  
  
    while True:  
        try:  
            errorIndication, errorStatus, errorIndex, varBinds = next(iterator)  
  
            if errorIndication:  
                print(errorIndication)  
                break  
            elif errorStatus:  
                print('%s at %s' % (  
                    errorStatus.prettyPrint(),  
                    errorIndex and varBinds[int(errorIndex) - 1][0] or '?'  
                ))  
            else:  
                for varBind in varBinds:  
                    print(' = '.join([x.prettyPrint() for x in varBind]))  
  
        except StopIteration:  
            break  
        except Exception as ex:  # 捕获所有其他异常  
            print(f"An error occurred: {ex}")

[snmp_walk]和的 [walk_subtree] 函数主要有以下几个区别:

  1. 异常处理:

    • 在 [snmp_walk] 中,除了处理 SNMP 的标准错误([errorIndication]和 [errorStatus]),还通过一个通用的 except Exception as ex 捕获了所有其他可能的异常,并打印出错误信息。这增加了代码的健壮性,能够处理更多意外情况。
    • walk_subtree 函数则没有显示地处理除 SNMP 错误以外的其他异常。
  2. 返回值:

    • walk_subtree 函数构建并返回一个结果字符串,包含所有遍历到的 OID 及其值。这使得函数的输出可以直接用于进一步处理或显示。
    • snmp_walk 函数则直接在控制台打印每个变量绑定的结果,不返回任何值。这适用于直接观察结果,但不便于程序内部进一步处理数据。
  3. 参数设置:

    • walk_subtree 函数中明确设置了 lexicographicMode=False,确保只遍历指定的子树。这是一个重要的设置,用于限制 SNMP WALK 的范围。
    • snmp_walk 函数没有设置 lexicographicMode,默认情况下,它可能会遍历整个 MIB,超出初始指定的子树。
  4. 社区字符串的使用:

    • walk_subtree 函数中硬编码了社区字符串为 “public”,而 snmp_walk 函数则将社区字符串作为参数传入,提供了更高的灵活性。

这些差异使得两个函数在实际应用中的适用场景有所不同。snmp_walk 更适合于调试和日志记录,而 walk_subtree 更适合于需要处理或分析返回数据的应用场景。

在之前的讨论中,我们提到了 [lexicographicMode]参数,这是 [nextCmd]函数的一个重要参数,用于控制 SNMP WALK 的行为。然而,在这里的 [snmp_walk]函数中,这个参数没有被显式设置,因此默认情况下,[lexicographicMode] 是 [True]。这意味着 SNMP WALK 操作可能会遍历整个 MIB,而不仅仅是指定的子树。

如何设置以确保只在当前子树进行查询

要确保 [nextCmd]函数只在当前子树进行查询,需要在调用 [nextCmd] 时设置 [lexicographicMode=False]。这样设置后,遍历将在到达子树的末端时停止,而不会继续到其他的 MIB 分支。

修改代码示例

可以修改 [snmp_walk]函数,添加 [lexicographicMode=False] 参数,如下所示:

def snmp_walk(ip, community, oid):  
    iterator = nextCmd(  
        SnmpEngine(),  
        CommunityData(community, mpModel=0),  
        UdpTransportTarget((ip, 161)),  
        ContextData(),  
        ObjectType(ObjectIdentity(oid)),
        lexicographicMode=False  # 确保只遍历当前子树
    )  
  
    while True:  
        try:  
            errorIndication, errorStatus, errorIndex, varBinds = next(iterator)  
  
            if errorIndication:  
                print(errorIndication)  
                break  
            elif errorStatus:  
                print('%s at %s' % (  
                    errorStatus.prettyPrint(),  
                    errorIndex and varBinds[int(errorIndex) - 1][0] or '?'  
                ))  
            else:  
                for varBind in varBinds:  
                    print(' = '.join([x.prettyPrint() for x in varBind]))  
  
        except StopIteration:  
            break  
        except Exception as ex:  # 捕获所有其他异常  
            print(f"An error occurred: {ex}")  

通过这种方式,可以确保 snmp_walk 函数只在指定的 OID 子树内进行 SNMP WALK 操作,避免不必要的网络流量和处理时间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zhaojiaqi006

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值