Converting an Agent from SNMPv2 to SNMPV3

So I have been playing around with creating simulated agents to run in our system. So far I have successfully implemented V1 and V2 using the TestAgent example. However, I am having issues configuring the code to allow for V3. I was wondering if you could lend some assistance showing me what configuration setting I’m missing?

Given the Simulated V1 I am able to get a Server response with

    snmpwalk.exe -v1 -c public 127.0.0.3:16100 1.3.6.1.2.2.0

AgentCodeV1-

  public class TestAgent extends BaseAgent {

  // initialize Log4J logging
  static {
    LogFactory.setLogFactory(new Log4jLogFactory());
  }

  protected String address;

  /**
   * Creates the test agent with a file to read and store the boot counter and
   * a file to read and store its configuration.
   *
   * @param bootCounterFile
   *    a file containing the boot counter in serialized form (as expected by
   *    BaseAgent).
   * @param configFile
   *    a configuration file with serialized management information.
   * @throws IOException
   *    if the boot counter or config file cannot be read properly.
   */
  public TestAgent(File bootCounterFile, File configFile) throws IOException {
    super(bootCounterFile, configFile,
          new CommandProcessor(new OctetString(MPv3.createLocalEngineID())));
  }

  protected void registerManagedObjects() {
    try {
      VariableBinding vb = new VariableBinding(new OID("1.3.6.1.4.1.73.1.8.2.1.1.1.10.1"),new OctetString("WinsXP"));
      StaticMOGroup group = new StaticMOGroup(new OID("1.2.3.4.5.6.7"),new     VariableBinding[]{vb});
      
      MOScalar mo = new MOScalar(new OID("1.3.6.1.2.2.0"), MOAccessImpl.ACCESS_READ_WRITE, new OctetString("This is a test"));
      server.register(mo, new OctetString("public"));
    }
    catch (DuplicateRegistrationException ex) {
      ex.printStackTrace();
    }
  }

  protected void addNotificationTargets(SnmpTargetMIB targetMIB,
                                        SnmpNotificationMIB notificationMIB) {}

  protected void addViews(VacmMIB vacm) {
    
    vacm.addGroup(SecurityModel.SECURITY_MODEL_SNMPv1,
    		new OctetString("cpublic"),
    		new OctetString("v1v2group"),
    		StorageType.nonVolatile);
    
	
    vacm.addAccess(new OctetString("v1v2group"),
    		new OctetString("public")
    		, SecurityModel.SECURITY_MODEL_ANY,
    		SecurityLevel.NOAUTH_NOPRIV,
    		MutableVACM.VACM_MATCH_EXACT,
    		new OctetString("fullReadView"),
    		new OctetString("fullWriteView"),
    		new OctetString("fullNotifyView"),
    		StorageType.nonVolatile);
    
    
    vacm.addViewTreeFamily(new OctetString("fullReadView"), new OID("1.3"),
                           new OctetString(), VacmMIB.vacmViewIncluded,
                           StorageType.nonVolatile);
    
    vacm.addViewTreeFamily(new OctetString("fullWriteView"), new OID("1.3"),
                           new OctetString(), VacmMIB.vacmViewIncluded,
                           StorageType.nonVolatile);

  }

  protected void addUsmUser(USM usm) {
  }

  protected void initTransportMappings() throws IOException {
    transportMappings = new TransportMapping[1];
    Address addr = GenericAddress.parse(address);
    TransportMapping tm =
        TransportMappings.getInstance().createTransportMapping(addr);
    transportMappings[0] = tm;
  }

  public static void main(String[] args) {
    String address;
    if (args.length > 0) {
      address = args[0];
    }
    else {
      address = "127.0.0.3/16100";
    }
    BasicConfigurator.configure();
    try {
      TestAgent testAgent1 = new TestAgent(new File("SNMP4JTestAgentBC.cfg"),
                                           new File("SNMP4JTestAgentConfig.cfg"));
      testAgent1.address = address;
      testAgent1.init();
      testAgent1.loadConfig(ImportModes.REPLACE_CREATE);
      testAgent1.addShutdownHook();
      testAgent1.getServer().addContext(new OctetString("public"));
      testAgent1.finishInit();
      testAgent1.run();
      testAgent1.sendColdStartNotification();
      /* Try to rerun agent:
      try {
        Thread.sleep(30000);
      }
      catch (InterruptedException ex2) {
      }
      testAgent1.stop();
      testAgent1.run();
      */
      while (true) {
        try {
          Thread.sleep(1000);
        }
        catch (InterruptedException ex1) {
          break;
        }
      }
    }
    catch (IOException ex) {
      ex.printStackTrace();
    }

  }

  protected void unregisterManagedObjects() {
    // here we should unregister those objects previously registered...
  }

  protected void addCommunities(SnmpCommunityMIB communityMIB) {
    Variable[] com2sec = new Variable[] {
        new OctetString("public"),              // community name
        new OctetString("cpublic"),              // security name
        getAgent().getContextEngineID(),        // local engine ID
        new OctetString("public"),              // default context name
        new OctetString(),                      // transport tag
        new Integer32(StorageType.nonVolatile), // storage type
        new Integer32(RowStatus.active)         // row status
    };
    SnmpCommunityMIB.SnmpCommunityEntryRow row =
        communityMIB.getSnmpCommunityEntry().createRow(
          new OctetString("public2public").toSubIndex(true), com2sec);
    communityMIB.getSnmpCommunityEntry().addRow(row);
//    snmpCommunityMIB.setSourceAddressFiltering(true);
  }

}

I have attempted to configure this to V3 by adding a UsmUser

protected void addUsmUser(USM usm) {
    UsmUser user = new UsmUser(new OctetString("TEST"),
                               AuthSHA.ID,
                               new OctetString("maplesyrup"),
                               PrivDES.ID,
                               new OctetString("maplesyrup"));
    usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  }

And adding security settings to the VacmView

 protected void addViews(VacmMIB vacm) {
	  
    vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
                  new OctetString("TEST"),
                  new OctetString("v3test"),
                  StorageType.nonVolatile);

    vacm.addAccess(new OctetString("v3test"),
    		new OctetString("public")
    		, SecurityModel.SECURITY_MODEL_USM,
    		SecurityLevel.NOAUTH_NOPRIV,
    		MutableVACM.VACM_MATCH_EXACT,
    		new OctetString("fullReadView"),
    		new OctetString("fullWriteView"),
    		new OctetString("fullNotifyView"),
    		StorageType.nonVolatile);

Attempting to reach the server Via Net-SNMP command results in undesired results. .

snmpwalk -v3 -l noAuthNoPriv -u TEST -a SHA -A "maplesyrup" -x DES -X "maplesyrup" 127.0.0.3:16100

Complete AgentCodeV3 example:

	public class TestAgent extends BaseAgent {

  // initialize Log4J logging
  static {
    LogFactory.setLogFactory(new Log4jLogFactory());
  }

  protected String address;

  /**
   * Creates the test agent with a file to read and store the boot counter and
   * a file to read and store its configuration.
   *
   * @param bootCounterFile
   *    a file containing the boot counter in serialized form (as expected by
   *    BaseAgent).
   * @param configFile
   *    a configuration file with serialized management information.
   * @throws IOException
   *    if the boot counter or config file cannot be read properly.
   */
  public TestAgent(File bootCounterFile, File configFile) throws IOException {
    super(bootCounterFile, configFile,
          new CommandProcessor(new OctetString(MPv3.createLocalEngineID())));
  }

  protected void registerManagedObjects() {
    try {
      VariableBinding vb = new VariableBinding(new OID("1.3.6.1.4.1.73.1.8.2.1.1.1.10.1"),new OctetString("WinsXP"));
      StaticMOGroup group = new StaticMOGroup(new OID("1.2.3.4.5.6.7"),new     VariableBinding[]{vb});
      
      MOScalar mo = new MOScalar(new OID("1.3.6.1.2.2.0"), MOAccessImpl.ACCESS_READ_WRITE, new OctetString("This is a test"));
      server.register(mo, new OctetString("public"));
    }
    catch (DuplicateRegistrationException ex) {
      ex.printStackTrace();
    }
  }

  protected void addNotificationTargets(SnmpTargetMIB targetMIB,
                                        SnmpNotificationMIB notificationMIB) {}

  protected void addViews(VacmMIB vacm) {
	  
    vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
                  new OctetString("TEST"),
                  new OctetString("v3test"),
                  StorageType.nonVolatile);
    /*
    vacm.addGroup(SecurityModel.SECURITY_MODEL_SNMPv1,
    		new OctetString("cpublic"),
    		new OctetString("v1v2group"),
    		StorageType.nonVolatile);
    */
	/*
    vacm.addAccess(new OctetString("v1v2group"),
    		new OctetString("public")
    		, SecurityModel.SECURITY_MODEL_ANY,
    		SecurityLevel.NOAUTH_NOPRIV,
    		MutableVACM.VACM_MATCH_EXACT,
    		new OctetString("fullReadView"),
    		new OctetString("fullWriteView"),
    		new OctetString("fullNotifyView"),
    		StorageType.nonVolatile);
    		*/
    
    vacm.addAccess(new OctetString("v3test"),
    		new OctetString("public")
    		, SecurityModel.SECURITY_MODEL_USM,
    		SecurityLevel.NOAUTH_NOPRIV,
    		MutableVACM.VACM_MATCH_EXACT,
    		new OctetString("fullReadView"),
    		new OctetString("fullWriteView"),
    		new OctetString("fullNotifyView"),
    		StorageType.nonVolatile);
    
    
    vacm.addViewTreeFamily(new OctetString("fullReadView"), new OID("1.3"),
                           new OctetString(), VacmMIB.vacmViewIncluded,
                           StorageType.nonVolatile);
    
    vacm.addViewTreeFamily(new OctetString("fullWriteView"), new OID("1.3"),
                           new OctetString(), VacmMIB.vacmViewIncluded,
                           StorageType.nonVolatile);

  }

  protected void addUsmUser(USM usm) {
    UsmUser user = new UsmUser(new OctetString("TEST"),
                               AuthSHA.ID,
                               new OctetString("maplesyrup"),
                               PrivDES.ID,
                               new OctetString("maplesyrup"));
    usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  }

  protected void initTransportMappings() throws IOException {
    transportMappings = new TransportMapping[1];
    Address addr = GenericAddress.parse(address);
    TransportMapping tm =
        TransportMappings.getInstance().createTransportMapping(addr);
    transportMappings[0] = tm;
  }

  public static void main(String[] args) {
    String address;
    if (args.length > 0) {
      address = args[0];
    }
    else {
      address = "127.0.0.3/16100";
    }
    BasicConfigurator.configure();
    try {
      TestAgent testAgent1 = new TestAgent(new File("SNMP4JTestAgentBC.cfg"),
                                           new File("SNMP4JTestAgentConfig.cfg"));
      testAgent1.address = address;
      testAgent1.init();
      testAgent1.loadConfig(ImportModes.REPLACE_CREATE);
      testAgent1.addShutdownHook();
      testAgent1.getServer().addContext(new OctetString("public"));
      testAgent1.finishInit();
      testAgent1.run();
      testAgent1.sendColdStartNotification();
      /* Try to rerun agent:
      try {
        Thread.sleep(30000);
      }
      catch (InterruptedException ex2) {
      }
      testAgent1.stop();
      testAgent1.run();
      */
      while (true) {
        try {
          Thread.sleep(1000);
        }
        catch (InterruptedException ex1) {
          break;
        }
      }
    }
    catch (IOException ex) {
      ex.printStackTrace();
    }

  }

  protected void unregisterManagedObjects() {
    // here we should unregister those objects previously registered...
  }

  protected void addCommunities(SnmpCommunityMIB communityMIB) {
    Variable[] com2sec = new Variable[] {
        new OctetString("public"),              // community name
        new OctetString("cpublic"),              // security name
        getAgent().getContextEngineID(),        // local engine ID
        new OctetString("public"),              // default context name
        new OctetString(),                      // transport tag
        new Integer32(StorageType.nonVolatile), // storage type
        new Integer32(RowStatus.active)         // row status
    };
    SnmpCommunityMIB.SnmpCommunityEntryRow row =
        communityMIB.getSnmpCommunityEntry().createRow(
          new OctetString("public2public").toSubIndex(true), com2sec);
    communityMIB.getSnmpCommunityEntry().addRow(row);
//    snmpCommunityMIB.setSourceAddressFiltering(true);
  }

}

I pretty much went off of the examples provided in the TestAgent exaple, but I feel like I am still missing something… I could use some help being pointed in the right direction.

For now I would just like to set up the Agent server so that I may connect to it in a similar manner to “SNMPWALK -v1 -c public < Ip:Socket > < OID >”

Eventaully I want to create a client application to connect to the agent and allows for custom user input. I have configured a simple app for SNMPV1 and V2. Will need to configure it for SNMPV3. For now I would just like to be able to establish communication using NET-SNMP tools.

The above is the most problematic code snippet you provided. You define a SNMPv3 context match “TEST” and a matching “exact” but do not specify a SNMPv3 context in your SNMP request. That combination cannot work obviously.

Another issue is: if specifying authentication and privacy passphrase but using noAuthNoPriv security level, some tools might not execute the request as expected (because the provided parameters are contradictory).

I believe this is the correct SNMP request to send when configured to SECURITY_MODEL_USM correct me if I am wrong?

  • Snmpwalk -v3 -l noAuthNoPriv -u TEST -a SHA -A “maplesyrup” -x DES -X “maplesyrup” 127.0.0.3:16100

I’ll try modifying the SecurityModel to AUTHPRIV later to see if that changes anything.

That depends on your agent USM and VACM configuration. The request you quoted above does not specify a SNMPv3 context. So it will not work for the above quoted VACM access entry.

Awesome I got it working, thanks Frank!

So for the real agent that I have been using I have been registering all of my OIDS in a StaticMOGroup object and have been experimenting with my own extension of that class called DynamicMOGroup. For whatever reason when I run the SNMPV3 agent registered with either StaticMOGroup or DynamicMOGroup I get an error stating that it cannot find that OID. However, when I register a single MOScalar object everything seems to work just fine?

I have been parsing though the commandResponder class to find out what the difference between the two registrations is. I have been having a hard time determining what is causing the issue. I am just wondering if you would happen to know off hand why this would suddenly become an issue once configured for SNMPV3?

Maybe it is just a matter of expectation: The StaticMOGroup itself is not a managed object on SNMP MIB level. It is just a group of such “managed object instances”. Thus, you need to add managed objects like scalars (i.e. provided as a list of VariableBinding instances).

Another problem source, could be the VACM configuration. If the identical instrumentation works with SNMPv2c and does not work with SNMPv3, then the view access configuration is most likely the source of the problem.

Right, so registering a single instance of MOScalar works just fine in the SNMPV3 configuration, but when I try to register a StaticMOGroup object I cannot find that same oid when I run the same SNMPGET request.

protected void registerManagedObjects(){
  MOScalar mo  =  new MOScalar(new OID("1.3.6.1.4.1.73.17.1.8.6.1.3.1.4.116.105.1.0"),
  MOAccessImpl.ACCESS_READ_WRITE,
  new OctetString("This is a test")); 

 //server.register(mo, new OctetString("public"));

 VariableBinding[] agentOIDS = {
  new VariableBinding(new OID("1.3.6.1.4.1.73.17.1.8.6.1.3.1.4.116.105.1), new (OctetString("This is a test 1")),
 new VariableBinding(new OID("1.3.6.1.4.1.73.17.1.8.6.1.3.1.4.116.105.2), new (OctetString("This is a test 2")),
 new VariableBinding(new OID("1.3.6.1.4.1.73.17.1.8.6.1.3.1.4.116.105.3), new (OctetString("This is a test 3")),
}

 OID root = new OID("1.3.6.1.4.1");
StaticMOGroup staticOidGroup = new staticMOGroup(root, agentOIDS);

server.register(staticOidGroup, new OctetString("public"))


}

The only thing that I can think of is maybe there’s an issue with registering it with the OctetString("public ")
If that were the case I wouldn’t expect the MOScalar mo registration to work?
I’ll keep looking into it, I appreciate your feedback though!

Please append ".0" to all OIDs of the agentOIDs array. Each variable binding represents a scalar object instance, therefore the .0 is needed. Only if the objects in the group represent a table, other (index-conform) instance sub-identifiers are possible.

In addition, you register the staticOidGroup to the "public" context. Have you given access to the "public" SNMPv3 context in the VACM? That would be unusual, as beginner I would always use the default context ("") first.

To register the managed objects of a MOGroup use:

staticMOGroup.registerMOs(server, null);

Only with this method, all the objects included in the group will be registered.