ARTICLE AD BOX
Following is the Java Code for SNMP Simulator:
package org.example; import org.snmp4j.*; import org.snmp4j.agent.*; import org.snmp4j.agent.mo.*; import org.snmp4j.agent.mo.snmp.*; import org.snmp4j.agent.security.MutableVACM; import org.snmp4j.mp.*; import org.snmp4j.security.*; import org.snmp4j.smi.*; import org.snmp4j.transport.DefaultUdpTransportMapping; import java.io.*; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class CsvSnmpSimulator2 extends BaseAgent { private TransportMapping<UdpAddress> transport; private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); private final String csvPath; private final int listenPort; private final String v2cCommunity; private final String v3User; private final String v3AuthPass; private final String v3PrivPass; private final MOFactory moFactory; public CsvSnmpSimulator2(File bootCounterFile, File configFile, String csvPath, int listenPort, String v2cCommunity, String v3User, String v3AuthPass, String v3PrivPass) throws Exception { super(bootCounterFile, configFile, new CommandProcessor(new OctetString(MPv3.createLocalEngineID())) ); this.csvPath = csvPath; this.listenPort = listenPort; this.v2cCommunity = v2cCommunity; this.v3User = v3User; this.v3AuthPass = v3AuthPass; this.v3PrivPass = v3PrivPass; this.moFactory = DefaultMOFactory.getInstance(); } // ---------------- BaseAgent hooks ---------------- @Override protected void initTransportMappings() throws IOException { // IMPORTANT: do NOT call transport.listen() here. BaseAgent will call listen/startup. transport = new DefaultUdpTransportMapping(new UdpAddress("0.0.0.0/" + listenPort)); transportMappings = new TransportMapping[]{ transport }; } @Override protected void addCommunities(SnmpCommunityMIB communityMIB) { // SNMP-COMMUNITY-MIB columns order: // communityName, securityName, contextEngineID, contextName, transportTag, storageType, rowStatus Variable[] vars = new Variable[]{ new OctetString(v2cCommunity), // communityName new OctetString(v2cCommunity), // securityName (map community to same secName) getAgent().getContextEngineID(), // contextEngineID new OctetString(), // contextName (default context) new OctetString(), // transportTag new Integer32(StorageType.nonVolatile), // storageType new Integer32(RowStatus.active) // rowStatus (active) }; SnmpCommunityMIB.SnmpCommunityEntryRow row = communityMIB.getSnmpCommunityEntry() .createRow(new OctetString(v2cCommunity).toSubIndex(true), vars); communityMIB.getSnmpCommunityEntry().addRow(row); } @Override protected void addUsmUser(USM usm) { // Register protocols FIRST before USM user creation SecurityProtocols.getInstance().addPrivacyProtocol(new PrivAES128()); SecurityProtocols.getInstance().addAuthenticationProtocol(new AuthSHA()); // Now create/add v3 user UsmUser user = new UsmUser( new OctetString(v3User), AuthSHA.ID, new OctetString(v3AuthPass), PrivAES128.ID, new OctetString(v3PrivPass)); usm.addUser(user.getSecurityName(), null, user); } @Override protected void addViews(VacmMIB vacm) { // Allow read/write/notify for subtree 1.3 for demo OctetString group = new OctetString("v3group"); vacm.addGroup(SecurityModel.SECURITY_MODEL_USM, new OctetString(v3User), group, StorageType.nonVolatile); // Use default (empty) context consistently via new OctetString() vacm.addAccess(group, new OctetString(), SecurityModel.SECURITY_MODEL_USM, SecurityLevel.AUTH_PRIV, MutableVACM.VACM_MATCH_EXACT, new OctetString("readView"), new OctetString("writeView"), new OctetString("notifyView"), StorageType.nonVolatile); OID subtree = new OID("1.3"); vacm.addViewTreeFamily(new OctetString("readView"), subtree, new OctetString(), VacmMIB.vacmViewIncluded, StorageType.nonVolatile); vacm.addViewTreeFamily(new OctetString("writeView"), subtree, new OctetString(), VacmMIB.vacmViewIncluded, StorageType.nonVolatile); vacm.addViewTreeFamily(new OctetString("notifyView"), subtree, new OctetString(), VacmMIB.vacmViewIncluded, StorageType.nonVolatile); } @Override protected void registerManagedObjects() { List<Row> rows = loadCsv(csvPath); if (rows.isEmpty()) { System.err.println("No rows loaded from " + csvPath); return; } // Ensure contexts exist (use new OctetString() for default context) Set<OctetString> contexts = new HashSet<>(); for (Row r : rows) { OctetString ctx = r.context == null || r.context.isEmpty() ? new OctetString() : new OctetString(r.context); if (!contexts.contains(ctx)) { contexts.add(ctx); server.addContext(ctx); } } for (Row r : rows) { try { OID oid = new OID(r.oid); Variable initial = toVariable(r.type, r.value); boolean writable = "RW".equalsIgnoreCase(r.access); MOAccess access = writable ? MOAccessImpl.ACCESS_READ_WRITE : MOAccessImpl.ACCESS_READ_ONLY; @SuppressWarnings("unchecked") MOScalar<Variable> scalar = new MOScalar<>(oid, access, initial) { @Override public synchronized Variable getValue() { Variable v = super.getValue(); System.out.println("[GET] OID " + oid + " requested → returning: " + v); return v; } }; OctetString ctx = r.context == null || r.context.isEmpty() ? new OctetString() : new OctetString(r.context); server.register(scalar, ctx); // Optional: auto-behavior for TimeTicks if (r.type.equalsIgnoreCase("TIME_TICKS") || r.type.equalsIgnoreCase("TIMETICKS")) { scheduler.scheduleAtFixedRate(() -> { try { Variable v = scalar.getValue(); if (v instanceof TimeTicks) { TimeTicks t = (TimeTicks) v; scalar.setValue(new TimeTicks(t.getValue() + 100)); // increment by 1 second (100 hundredths) } } catch (Exception ignored) {} }, 1, 1, TimeUnit.SECONDS); } } catch (Exception ex) { System.err.println("Failed to register OID " + r + " : " + ex.getMessage()); } } } @Override protected void unregisterManagedObjects() { // no-op } @Override protected void addNotificationTargets(SnmpTargetMIB targetMIB, SnmpNotificationMIB notificationMIB) { // noop } // ---------------- Utility: CSV parsing & type coercion ---------------- private static class Row { String oid; String type; String value; String context; // optional String access; // RO/RW @Override public String toString() { return oid + "," + type + "," + value + "," + context + "," + access; } } private static List<Row> loadCsv(String path) { List<Row> rows = new ArrayList<>(); try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(path), StandardCharsets.UTF_8))) { String line; while ((line = br.readLine()) != null) { line = line.trim(); if (line.isEmpty() || line.startsWith("#")) continue; String[] parts = splitCsv(line); if (parts.length < 3) { System.err.println("Skipping malformed line: " + line); continue; } Row r = new Row(); r.oid = parts[0].trim(); r.type = parts[1].trim(); r.value = parts[2].trim(); if (parts.length >= 4) r.context = parts[3].trim(); if (parts.length >= 5) r.access = parts[4].trim(); rows.add(r); } } catch (IOException e) { System.err.println("Error reading CSV " + path + ": " + e.getMessage()); } return rows; } private static String[] splitCsv(String line) { List<String> tokens = new ArrayList<>(); boolean inQuote = false; StringBuilder sb = new StringBuilder(); for (int i = 0; i < line.length(); i++) { char c = line.charAt(i); if (c == '"') { inQuote = !inQuote; } else if (c == ',' && !inQuote) { tokens.add(sb.toString()); sb.setLength(0); } else { sb.append(c); } } tokens.add(sb.toString()); return tokens.toArray(new String[0]); } private static Variable toVariable(String type, String value) { String t = type.trim().toUpperCase(Locale.ROOT); switch (t) { case "INTEGER": return new Integer32(Integer.parseInt(value)); case "OCTET_STRING": return new OctetString(value); case "OID": return new OID(value); case "COUNTER32": return new Counter32(Long.parseLong(value)); case "GAUGE32": return new Gauge32(Long.parseLong(value)); case "TIMETICKS": case "TIME_TICKS": return new TimeTicks(Long.parseLong(value)); case "IPADDRESS": return new IpAddress(value); case "COUNTER64": return new Counter64(Long.parseLong(value)); case "NULL": return Null.noSuchObject; default: throw new IllegalArgumentException("Unsupported type: " + type); } } // ---------------- Main ---------------- public static void main(String[] args) throws Exception { String csv = args.length > 0 ? args[0] : "data.csv"; int port = args.length > 1 ? Integer.parseInt(args[1]) : 10161; String community = args.length > 2 ? args[2] : "public"; String user = args.length > 3 ? args[3] : "usr-sha-aes"; String auth = args.length > 4 ? args[4] : "authpass123"; String priv = args.length > 5 ? args[5] : "privpass123"; File boot = new File("bootCounter.dat"); File cfg = new File("simulator.cfg"); CsvSnmpSimulator2 sim = new CsvSnmpSimulator2(boot, cfg, csv, port, community, user, auth, priv); sim.init(); sim.addShutdownHook(); // contexts are created from CSV; don't add duplicate default context here sim.run(); System.out.printf("SNMP simulator listening on UDP/%d (v1/v2c/v3). Data: %s%n", port, csv); System.out.println("v2c community: " + community + " | v3 user: " + user); } }Following is the data.csv:
# OID,Type,Value,Context,Access 1.3.6.1.2.1.1.1.0,OCTET_STRING,Simulated Router R9000,default,read-only 1.3.6.1.2.1.1.3.0,TIME_TICKS,123456,default,read-only 1.3.6.1.2.1.1.4.0,OCTET_STRING,[email protected],default,read-write 1.3.6.1.2.1.1.5.0,OCTET_STRING,TestDevice01,default,read-only 1.3.6.1.2.1.1.6.0,OCTET_STRING,Lab Environment,default,read-write 1.3.6.1.2.1.2.2.1.1.1,INTEGER,1,default,read-only 1.3.6.1.2.1.2.2.1.2.1,OCTET_STRING,eth0,default,read-only 1.3.6.1.2.1.2.2.1.8.1,INTEGER,1,default,read-writeThe above program running well but below command giving time out response:
snmpget -v2c -c public localhost:10161 1.3.6.1.2.1.1.1.0
The error is:
Timeout: No Response from localhost:10161.
Could you please let me know what exact mistake I am doing here.
