snmp v3 通用方法
import lombok.extern.slf4j.Slf4j; import org.snmp4j.*; import org.snmp4j.mp.MPv3; import org.snmp4j.mp.SnmpConstants; import org.snmp4j.security.*; import org.snmp4j.smi.Address; import org.snmp4j.smi.GenericAddress; import org.snmp4j.smi.OID; import org.snmp4j.smi.OctetString; import org.snmp4j.util.DefaultPDUFactory; import org.snmp4j.util.TableEvent; import org.snmp4j.util.TableUtils; import org.snmp4j.util.TreeEvent; import org.snmp4j.util.TreeUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @Slf4j @Component public class SnmpService { // 全局单例,不复用每次新建 @Autowired private Snmp snmp; // 统一超时、重试 private static final long TIMEOUT = 2000; private static final int RETRIES = 1; /** * SNMP批量采集子树数据 * @param bearerConf 设备配置 * @param oidList 待采集OID列表 * @param useOid true key=父oid|子oid;false key=完整子oid * @return 采集结果 */ private Map<String, Object> snmpGetData(BearerNeInfo bearerConf, List<String> oidList, boolean useOid) { Map<String, Object> resultMap = new HashMap<>(16); // 1. 前置参数校验,提前拦截空指针 if (bearerConf == null || oidList == null || oidList.isEmpty()) { log.warn("SNMP采集参数为空,直接返回空"); return resultMap; } String manageIp = bearerConf.getManageIp(); Integer snmpPort = bearerConf.getSnmpPort(); if (Objects.isNull(manageIp) || manageIp.isBlank() || Objects.isNull(snmpPort) || snmpPort <= 0) { log.error("设备IP或端口非法, ip:{}, port:{}", manageIp, snmpPort); return resultMap; } Target target = null; try { Address address = GenericAddress.parse("udp:" + manageIp + "/" + snmpPort); String snmpVer = bearerConf.getSnmpVersion(); // 2. 区分v2c / v3 if ("v3".equalsIgnoreCase(snmpVer)) { target = buildV3Target(bearerConf, address); } else { target = buildV2cTarget(bearerConf, address); } // 统一设置超时、重试 target.setTimeout(TIMEOUT); target.setRetries(RETRIES); // 支持多上下文(OLT/BRAS必备) String contextName = bearerConf.getContextName(); OctetString contextOctet = null; if (Objects.nonNull(contextName) && !contextName.isBlank()) { contextOctet = new OctetString(contextName); } TreeUtils treeUtils = new TreeUtils(snmp, new DefaultPDUFactory(PDU.GETNEXT)); treeUtils.setIgnoreLexicographicOrder(true); for (String oidStr : oidList) { if (Objects.isNull(oidStr) || oidStr.isBlank()) { continue; } OID baseOid; try { baseOid = new OID(oidStr); } catch (Exception e) { log.error("非法OID格式:{}", oidStr, e); continue; } List<TreeEvent> treeEventList = treeUtils.getSubtree(target, baseOid, contextOctet, null); log.info("设备{} 查询父OID:{} 返回子节点数量:{}", manageIp, oidStr, treeEventList.size()); for (TreeEvent treeEvent : treeEventList) { // 跳过错误事件 if (treeEvent.isError()) { log.warn("OID {} 查询异常 msg:{}", oidStr, treeEvent.getErrorMessage()); continue; } List<VariableBinding> bindings = treeEvent.getVariableBindings(); if (bindings == null || bindings.isEmpty()) { continue; } for (VariableBinding vb : bindings) { String fullSubOid = vb.getOid().toString(); String key; // 修复原逻辑覆盖bug:useOid用父oid拼接完整子oid,不会覆盖 if (useOid) { key = oidStr + "|" + fullSubOid; } else { key = fullSubOid; } resultMap.put(key, vb.getVariable().toString()); } } } log.info("设备{} 采集完成,总数据条数:{}", manageIp, resultMap.size()); } catch (IllegalArgumentException e) { log.error("SNMP地址解析失败,设备IP:{}", bearerConf.getManageIp(), e); } catch (Exception e) { log.error("snmpGetData 采集异常 设备IP:{}", bearerConf.getManageIp(), e); } return resultMap; } /** * 构建SNMPv2c Target */ private CommunityTarget buildV2cTarget(BearerNeInfo bearerConf, Address address) { String community = bearerConf.getReadCommunity(); if (Objects.isNull(community) || community.isBlank()) { throw new IllegalArgumentException("v2c读团体字不能为空"); } CommunityTarget target = new CommunityTarget(); target.setVersion(SnmpConstants.version2c); target.setAddress(address); target.setCommunity(new OctetString(community)); return target; } /** * 构建SNMPv3 UserTarget + 安全用户(修复USM重复添加、算法逻辑) */ private UserTarget buildV3Target(BearerNeInfo bearerConf, Address address) { String secName = bearerConf.getSecurityName(); Integer secLevel = bearerConf.getSecurityLevel(); String authProto = bearerConf.getAuthProtocol(); String authPwd = bearerConf.getAuthPassphrase(); String privProto = bearerConf.getPrivateProtocol(); String privPwd = bearerConf.getPrivatePassphrase(); // 参数校验 if (Objects.isNull(secName) || secName.isBlank()) { throw new IllegalArgumentException("SNMPv3 securityName不能为空"); } if (Objects.isNull(secLevel) || secLevel < 0 || secLevel > 3) { throw new IllegalArgumentException("非法安全等级:" + secLevel); } // 解析鉴权算法OID OID authOid = parseAuthOid(authProto); OctetString authPwdOct = null; if (Objects.nonNull(authPwd) && !authPwd.isBlank()) { authPwdOct = new OctetString(authPwd); } // 解析加密算法OID OID privOid = parsePrivOid(privProto); OctetString privPwdOct = null; if (Objects.nonNull(privPwd) && !privPwd.isBlank()) { privPwdOct = new OctetString(privPwd); } USM usm = snmp.getUSM(); OctetString secNameOct = new OctetString(secName); // 避免重复添加同一用户 if (usm.getUserTable().getUser(secNameOct, null) == null) { UsmUser user = new UsmUser(secNameOct, authOid, authPwdOct, privOid, privPwdOct); usm.addUser(user); log.info("SNMPv3 新增安全用户:{}", secName); } UserTarget target = new UserTarget(); target.setVersion(SnmpConstants.version3); target.setAddress(address); target.setSecurityLevel(secLevel); target.setSecurityName(secNameOct); return target; } /** * 解析鉴权算法OID */ private OID parseAuthOid(String authProtocol) { if (Objects.isNull(authProtocol)) { return null; } return switch (authProtocol.toUpperCase()) { case "MD5" -> AuthMD5.ID; case "SHA" -> AuthSHA.ID; case "SHA256" -> AuthHMAC192SHA256.ID; case "SHA384" -> AuthHMAC256SHA384.ID; case "SHA512" -> AuthHMAC384SHA512.ID; default -> AuthSHA.ID; }; } /** * 解析加密算法OID */ private OID parsePrivOid(String privProtocol) { if (Objects.isNull(privProtocol)) { return null; } return switch (privProtocol.toUpperCase()) { case "DES" -> PrivDES.ID; case "AES", "AES128" -> PrivAES128.ID; case "AES192" -> PrivAES192.ID; case "AES256" -> PrivAES256.ID; default -> PrivAES128.ID; }; } }

浙公网安备 33010602011771号