使用pysnmp时能否忽略返回报文的SNMP社区字符串?
让pysnmp忽略入站报文社区字符串的解决办法
问题根源
pysnmp默认会校验响应报文的社区字符串与请求时发送的是否一致,你遇到的情况是设备返回的社区字符串为public,和你发送的xxxxxx不匹配,所以被拦截导致无法正常工作。要解决这个问题,就得跳过这个校验逻辑。
具体实现方式
方法一:自定义社区数据类(推荐)
写一个继承自CommunityData的子类,重写校验方法让其直接返回True,以此绕过社区字符串的校验:
from pysnmp.hlapi import CommunityData, SnmpEngine, getCmd, ContextData, ObjectType, ObjectIdentity from pysnmp.proto.secmod.rfc1902 import CommunityData as BaseCommunityData class NoCheckCommunityData(BaseCommunityData): def verifyOutgoingMsg(self, *args): return True # 跳过出站报文校验(可选,核心是入站校验) def verifyIncomingMsg(self, *args): return True # 直接跳过入站报文的社区字符串校验 # 使用自定义类发起SNMP请求 snmp_engine = SnmpEngine() # 此处填入你实际要发送的社区字符串xxxxxx community_data = NoCheckCommunityData('xxxxxx') errorIndication, errorStatus, errorIndex, varBinds = next(getCmd( snmp_engine, community_data, ('目标设备IP', 161), ContextData(), ObjectType(ObjectIdentity('1.3.6.1.2.1.1.1.0')) # 替换为你需要查询的OID )) if errorIndication: print(errorIndication) else: if errorStatus: print(f'{errorStatus.prettyPrint()} at {errorIndex and varBinds[int(errorIndex)-1][0] or "?"}') else: for varBind in varBinds: print(f'{varBind[0].prettyPrint()} = {varBind[1].prettyPrint()}')
方法二:直接修改默认校验逻辑(不推荐)
如果不想自定义类,也可以直接替换CommunityData的校验方法,但这种方式会全局生效,在多请求、多线程场景下容易引发问题:
from pysnmp.proto.secmod.rfc1902 import CommunityData # 替换原有校验方法,直接返回True跳过校验 CommunityData.verifyIncomingMsg = lambda self, *args: True CommunityData.verifyOutgoingMsg = lambda self, *args: True # 之后正常使用pysnmp的API即可
注意事项
- 跳过社区字符串校验会降低SNMP通信的安全性,毕竟社区字符串是SNMPv2c最基础的身份验证机制,能不用尽量不用。
- 优先排查设备端的配置问题:为什么设备返回的社区字符串是
public而非你请求时的xxxxxx?这可能是设备配置错误,或者存在中转代理修改了报文。
内容的提问来源于stack exchange,提问作者Jeremy Palmer
相关产品推荐
相关产品推荐

