使用SNMP4j(org.snmp4j)v3和用户身份验证时,代理未返回正确的OID值?

时间:2017-09-07 06:20:34

标签: snmp snmp4j

我编写了一个SNMP代理并注册了一个托管对象(创建/设置了一个MIB OID的值)。 当我使用SNMPv2c检索此值时,正确返回值 - 来自ResponseEvent.getResponse的PDU具有type = GET,并且变量绑定具有预期数据 - 正确的OID等。 当我使用SNMPv3和用户身份验证检索此值时,未正确返回值 - 来自ResponseEvent.getResponse的PDU具有type = REPORT并且变量绑定具有 与请求中的OID不同 - 从我到目前为止所看到的,这表示配置/身份验证错误。 以下是用于客户端的示例代码(片段)。代理商 - 请你告诉我如何创建代理商&客户 - 我出错的地方?

// TestSNMPAgent:
public class TestSNMPAgent {

    private OID sysDescr = new OID("1.3.6.1.2.1.1.1.0");
    ...
    public static void main(String[] args) throws IOException {
        TestSNMPAgent agent = new TestSNMPAgent();
        agent.init("0.0.0.0/4071");

    private void init(String agentIp) throws IOException {

        agent = new SNMPAgent(agentIp);

        agent.start();

        agent.unregisterManagedObject(agent.getSnmpv2MIB());

        agent.registerManagedObject(new MOScalar(oid,
            MOAccessImpl.ACCESS_READ_WRITE,
            getVariable(value),sysDescr,
            "1")));
        ...
    }

}

// SNMPAgent:
public class SNMPAgent extends BaseAgent {
...
    @Override
    protected void addUsmUser(USM arg0) {
       UsmUser user = new UsmUser(new OctetString("SHADES"), 
       AuthSHA.ID, 
       new OctetString("SHADESAuthPassword"), 
       PrivDES.ID, 
       new OctetString("SHADESPrivPassword"));
    }

    @Override
    protected void addViews(VacmMIB vacm) {
        vacm.addGroup(SecurityModel.SECURITY_MODEL_USM, 
                  new OctetString("SHADES"), 
                  new OctetString("v3group"), 
                  StorageType.nonVolatile); 

        vacm.addAccess(new OctetString("v3group"), new OctetString(), 
                   SecurityModel.SECURITY_MODEL_USM, 
                   SecurityLevel.NOAUTH_NOPRIV, VacmMIB.vacmExactMatch, 
                   new OctetString("fullReadView"), 
                   new OctetString("fullWriteView"), 
                   new OctetString("fullNotifyView"), 
                   StorageType.nonVolatile); 
    }

    public void registerManagedObject(ManagedObject mo) {
        try {
            server.register(mo, null);
        } catch (DuplicateRegistrationException ex) {
        throw new RuntimeException(ex);
    }
}

// TestSNMPMgr
public class TestSNMPMgr {

    public static void main(String[] args) throws IOException {

        TestSNMPMgr client = new TestSNMPMgr();
        client.init();
    }

    public void init() {
        SNMPMgr client = new SNMPMgr();
        client.start();
        // Get back Value which is set
        String value = client.getAsString(new OID("1.3.6.1.2.1.1.1.0"));
    }
}

// SNMPMgr
public class SNMPMgr {

    Snmp snmp = null;
    Address address = null;

    public SNMPMgr()
    {
        address = "1.3.6.1.2.1.1.1.0";
    }

    /**
     * Start the Snmp session. If you forget the listen() method you will not
     * get any answers because the communication is asynchronous
     * and the listen() method listens for answers.
     * @throws IOException
    */
    public void start() throws IOException {
       address = GenericAddress.parse("udp:127.0.0.1/4701");
       TransportMapping transport = new DefaultUdpTransportMapping();
       snmp = new Snmp(transport);
       USM usm = new USM(SecurityProtocols.getInstance(),
                         new OctetString(MPv3.createLocalEngineID()), 0);
       SecurityModels.getInstance().addSecurityModel(usm);
       transport.listen();
    }

    public void end() {
        try {
            snmp.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * Method which takes a single OID and returns the response from the agent as a String.
     * @param oid
     * @return
     * @throws IOException
     */
    public String getAsString(OID oid) throws IOException {
        ResponseEvent event = get(new OID[] { oid });
        return event.getResponse().get(0).getVariable().toString();
    }


    public ResponseEvent get(OID oids[]) throws IOException {
       PDU pdu = new ScopedPDU();
       for (OID oid : oids) {
            pdu.add(new VariableBinding(oid));
       }

       pdu.setType(PDU.GET);

       // add user to the USM
       snmp.getUSM().addUser(new OctetString("SHADES"),
               new UsmUser(new OctetString("SHADES"),
               AuthSHA.ID, 
               new OctetString("SHADESAuthPassword"), 
               PrivDES.ID, 
               new OctetString("SHADESPrivPassword")));


       // send the PDU
       ResponseEvent event = snmp.send(pdu, getTarget(), null);

       if(event != null) {
           return event;
       }
       throw new RuntimeException("GET timed out");
    }

    /**
     * This method returns a Target, which contains information about
     * where the data should be fetched and how.
     * @return
     */
    private UserTarget getTarget() {
       UserTarget target = new UserTarget();
       target.setAddress(address);
       target.setRetries(1);
       target.setTimeout(5000);
       target.setVersion(SnmpConstants.version3);
       target.setSecurityLevel(SecurityLevel.NOAUTH_NOPRIV);
       target.setSecurityName(new OctetString("SHADES"));
       return target;
    }

}

1 个答案:

答案 0 :(得分:0)

报告PDU中的OID应该告诉您发生了什么。在典型情况下,将有一个或两个(或两个)请求/报告交换,以在管理器和代理(或者更确切地说,分别是非权威和权威引擎)之间建立初始SNMPv3通信。

第一个通常是usmStatUnknownEngineIDs报告,允许管理员发现代理的引擎ID(密钥本地化等所需),如果您没有指定正确的,则会发生初始请求中的引擎ID。如果使用auth/noPrivauth/priv级别安全性,那么第二个/另一个会发生,这是usmStatsNotInTimeWindows,如果请求未在适当的时间内指定引擎启动/引擎时间值,则会发送user代理商的价值范围。这些值可以通过使请求不再有效来防止消息重放攻击,如果它们超出时间窗口,并且管理器通常不知道它们是什么,直到它通过报告PDU从代理接收它们为止。

管理员拥有正确的引擎ID,引导和时间,并在必要时具有引擎ID的本地化密钥,然后正常的请求/响应交换可以按预期进行。一些SNMP API将为您处理此交换,因此您只需发送您的请求并在交换后获得最终结果。似乎SNMP4j没有,如果它是其中一个报告,你可能必须自己处理它。

如果它不是这些报告之一,那么您的配置可能不匹配。