Search code examples
javasnmpsnmp4j

Can't get SNMP authentication work correctly with snmp4j


I am writing a SNMP v3 trap/informs sender using snmp4j with authentication, but I'm surprised that informs are correctly acknowledged even if there's an authentication failure. I also developed the trap receiver using snmp4j to help me debugging.

I've noticed several unexpected scenarios:

1st scenario: sending an INFORM with Auth / NoPriv, with unknown username or wrong password => the INFORM is not acknowledged, there's just no response, the sender has to wait for timeout. On the receiver side however, an AuthenticationFailureEvent is fired, but I would have expected that snmp4j responds something to the sender with an error. Overridden method processPdu is not called. I guess it may depends on the receiver implementations, or there is a standard behaviour for this?

2nd scenario: sending an INFORM with existing username but no password (with NoAuth / NoPriv), whereas it's configured with a password on the receiver => the INFORM is acknowledged with RESPONSE, without any error, and my trap receiver even doesn't fire an AuthenticationFailureEvent as it should. I would expect that the receiver rejects the request if it's unauthenticated. Did I forget to initialize something? I can't imagine there's such a security hole in snmp4j.

The code I use for initializing receiver: (I don't show here overridden methods processPdu and authenticationFailure)

EmbeddedSNMPReceiver(final int port, final Optional<UsmUser> user) throws IOException {
    final MessageDispatcherImpl dispatcher = new MessageDispatcherImpl();
    dispatcher.addAuthenticationFailureListener(this);
    final UdpAddress listenAddress = new UdpAddress("localhost/" + port);
    final TransportMapping transport = new DefaultUdpTransportMapping(listenAddress);
    SecurityProtocols.getInstance().addDefaultProtocols();
    final USM usm = new USM(SecurityProtocols.getInstance(), new OctetString("RECEIVER"), 0);
    snmp = new Snmp(dispatcher, transport);

    snmp.getMessageDispatcher().addMessageProcessingModel(new MPv1());
    snmp.getMessageDispatcher().addMessageProcessingModel(new MPv2c());
    snmp.getMessageDispatcher().addMessageProcessingModel(new MPv3(usm));
    SecurityModels.getInstance().addSecurityModel(usm);
    if (user.isPresent()) {
        snmp.getUSM().addUser(user.get().getSecurityName(), user.get());
    }

    snmp.addCommandResponder(this);
    snmp.listen();
}

public static void main(String[] args) {
    // FOR DEBUG
    try {
        final OctetString octUsername = new OctetString("zaza");
        final OID userAuthOID = AuthSHA.ID;
        final OctetString octUserPassphrase = new OctetString("12345678");
        final UsmUser user = new UsmUser(octUsername, userAuthOID, octUserPassphrase, null, null);
        final EmbeddedSNMPReceiver server = new EmbeddedSNMPReceiver(1099, Optional.of(user));
        Thread.sleep(500000);
        server.stop();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

PS: to clarify, I start the receiver in a separate process than sender to avoid issues with snmp4j stateful nature / singletons...


Solution

  • You might read carefully RFC 3414 section 4 to see if you in fact hit the desired behaviors of discovery process.

    1st should not acknowledged and it follows v1 and v2c convention.

    2nd is expected if the reply message is REPORT.