SNMP authentication methods (asynchronous authentication and direct authentication)

Article directory

  • code
  • Verification results on actual machines

Code

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.event.ResponseListener;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.*;
import org.snmp4j.transport.DefaultUdpTransportMapping;

import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * qipengshang <2023-5-16>
 */
@Slf4j
public class SnmpUtil {<!-- -->

    /*Default parameters */
    public static final int DEFAULT_VERSION = SnmpConstants.version2c; //Default SNMP version
    public static final String DEFAULT_PROTOCOL = "udp"; //Default transport protocol
    public static final int DEFAULT_PORT = 161; //Default port number
    public static final long DEFAULT_TIMEOUT = 3 * 1000L; //Default timeout (milliseconds)
    public static final int DEFAULT_RETRY = 3; //Default number of retries

    /**
     * Create CommunityTarget object
     *
     * @return CommunityTarget
     */
    public static CommunityTarget createDefault(String ip, String community) {<!-- --> // Create a CommunityTarget object based on IP and community string
        Address address = GenericAddress.parse(DEFAULT_PROTOCOL + ":" + ip + "/" + DEFAULT_PORT); // Parse the Address object based on the default transmission protocol, IP address and port number
        CommunityTarget target = new CommunityTarget(); // Create CommunityTarget object
        target.setCommunity(new OctetString(community)); // Set community
        target.setAddress(address); //Set Address
        target.setVersion(DEFAULT_VERSION); // Set SNMP version
        target.setTimeout(DEFAULT_TIMEOUT); // Set timeout
        target.setRetries(DEFAULT_RETRY); //Set the number of retries
        return target;
    }

    /* getting information */
    public static JSONArray snmpGet(String ip, String community, String oid) {<!-- --> // Implement SNMP GET operation and obtain the corresponding variable value according to OID
        CommunityTarget target = createDefault(ip, community); // Create CommunityTarget object
        JSONArray jsonArray = new JSONArray(); // Create JSONArray object
        Snmp snmp = null; // Create Snmp object
        try {<!-- -->
            PDU pdu = new PDU(); // Create PDU object
            pdu.add(new VariableBinding(new OID(oid))); // Add VariableBinding
            DefaultUdpTransportMapping transport = new DefaultUdpTransportMapping(); // Create a DefaultUdpTransportMapping object
            snmp = new Snmp(transport); // Create Snmp object
            snmp.listen(); // Start SNMP service
            log.info("-------> Send PDU <-------"); // Output log information
            pdu.setType(PDU.GET); //Set the PDU type to GET
            ResponseEvent respEvent = snmp.send(pdu, target); //Send PDU and return response event
            log.info("PeerAddress:" + respEvent.getPeerAddress()); // Output log information
            PDU response = respEvent.getResponse(); // Get the response PDU
            if (response == null) {<!-- --> // If the response is empty
                log.info("response is null, request time out"); // Output log information
            } else {<!-- -->
                log.info("response pdu size is " + response.size()); // Output log information
                for (int i = 0; i < response.size(); i + + ) {<!-- --> // Traverse the VariableBinding in the response
                    VariableBinding vb = response.get(i);
                    JSONObject jsonObject = new JSONObject(); // Create JSONObject object
                    jsonObject.put("oid", vb.getOid().toString()); // Add OID string to JSONObject
                    jsonObject.put("value", vb.getVariable().toString()); // Add variable value to JSONObject
                    jsonArray.add(jsonObject); // Add JSONObject to JSONArray
// log.info(vb.getOid() + " = " + vb.getVariable());
                }
            }
            log.info("SNMP GET one OID value finished!"); // Output log information
            return jsonArray;
        } catch (Exception e) {<!-- --> // Catch exceptions
            e.printStackTrace(); // Output exception stack information
            log.info("SNMP Get Exception:" + e); // Output log information
        } finally {<!-- -->
            if (snmp != null) {<!-- --> // If the Snmp object is not empty
                try {<!-- -->
                    snmp.close(); // Close Snmp service
                } catch (IOException ex1) {<!-- -->
                    snmp = null;
                }
            }
        }
        return jsonArray; // Return JSONArray object
    }


    // Check whether the Walk has been completed and the target OID is the incoming targetOID
    private static boolean checkWalkFinished(OID targetOID, PDU pdu, VariableBinding vb) {<!-- -->
        // Mark whether the Walk has been completed, the default is not completed
        boolean finished = false;
        // If there is an error status in the PDU, it means that the Walk has been completed.
        if (pdu.getErrorStatus() != 0) {<!-- -->
            log.info("[true] responsePDU.getErrorStatus() != 0 ");
            log.info(pdu.getErrorStatusText());
            finished = true;
        }
        // If the OID in VariableBinding is empty, it means that the Walk has been completed
        else if (vb.getOid() == null) {<!-- -->
            log.info("[true] vb.getOid() == null");
            finished = true;
        }
        // If the length of the OID in VariableBinding is less than the length of the target OID, it means that the Walk has been completed.
        else if (vb.getOid().size() < targetOID.size()) {<!-- -->
            log.info("[true] vb.getOid().size() < targetOID.size()");
            finished = true;
        }
        // If the OID in VariableBinding is different from the left part of the target OID, it means that the Walk has been completed.
        else if (targetOID.leftMostCompare(targetOID.size(), vb.getOid()) != 0) {<!-- -->
            log.info("[true] targetOID.leftMostCompare() != 0");
            finished = true;
        }
        // If the value in VariableBinding is a Null exception, it means that the Walk has been completed.
        else if (Null.isExceptionSyntax(vb.getVariable().getSyntax())) {<!-- -->
            System.out
                    .println("[true] Null.isExceptionSyntax(vb.getVariable().getSyntax())");
            finished = true;
        }
        // If the OID in VariableBinding is less than or equal to the target OID, it means that the Walk has been completed
        else if (vb.getOid().compareTo(targetOID) <= 0) {<!-- -->
            log.info("[true] Variable received is not "
                     + "lexicographic successor of requested " + "one:");
            log.info(vb.toString() + " <= " + targetOID);
            finished = true;
        }
        //Return the mark value of Walk completion
        return finished;
    }

    /*Get the table asynchronously*/
    public static JSONArray snmpAsynWalk(String ip, String community, String oid) {<!-- -->

        // Generate CommunityTarget using the given IP and Community
        final CommunityTarget target = createDefault(ip, community);

        //Create an empty JSONArray object
        JSONArray jsonArray = new JSONArray();

        //Define an SNMP instance object, the initial value is null
        Snmp snmp = null;

        try {<!-- -->
            //Print log - "----> snmp start <----"
            log.info("----> snmp start <----");

            //Create a default UDP transport mapping object
            DefaultUdpTransportMapping transport = new DefaultUdpTransportMapping();

            //Initialize an Snmp instance object and pass in the transport object created above
            snmp = new Snmp(transport);

            // Turn on listening
            snmp.listen();

            //Construct PDU object
            final PDU pdu = new PDU();

            // Construct OID object
            final OID targetOID = new OID(oid);

            //Create a countdown deadbolt with an initial value of 1
            final CountDownLatch latch = new CountDownLatch(1);

            //Add the VariableBinding corresponding to the OID to the PDU
            pdu.add(new VariableBinding(targetOID));

            // Create a ResponseListener anonymous inner class object and implement the onResponse method
            ResponseListener listener = new ResponseListener() {<!-- -->
                public void onResponse(ResponseEvent event) {<!-- -->
                    ((Snmp) event.getSource()).cancel(event.getRequest(), this);
                    try {<!-- -->
                        // Get response PDU
                        PDU response = event.getResponse();

                        // If response is null, print log - "[ERROR]: response is null"
                        if (response == null) {<!-- -->
                            log.info("[ERROR]: response is null");

                            // If the error status of the response is not 0, print the log - "[ERROR]: response status" + response.getErrorStatus() + " Text:" + response.getErrorStatusText()
                        } else if (response.getErrorStatus() != 0) {<!-- -->
                            log.info("[ERROR]: response status" + response.getErrorStatus() + " Text:" + response.getErrorStatusText());

                        } else {<!-- -->
                            // Get the VariableBinding object
                            VariableBinding vb = response.get(0);

                            // Check if the entire SNMP Walk is completed
                            boolean finished = checkWalkFinished(targetOID, pdu, vb);

                            // If the entire SNMP Walk has not been completed yet
                            if (!finished) {<!-- -->
                                //Create a JSONObject object
                                JSONObject jsonObject = new JSONObject();

                                //Add OID and corresponding value to JSONObject
                                jsonObject.put("oid", vb.getOid().toString());
                                jsonObject.put("value", vb.getVariable().toString());

                                // Add JSONObject to jsonArray
                                jsonArray.add(jsonObject);

                                // Update PDU request ID and VariableBinding
                                pdu.setRequestID(new Integer32(0));
                                pdu.set(0, vb);

                                // Continue to execute the getNext method for the next step of asynchronous processing
                                ((Snmp) event.getSource()).getNext(pdu, target, null, this);
                            } else {<!-- -->
                                // Print log - "SNMP Asyn walk OID value success !"
                                log.info("SNMP Asyn walk OID value success!");

                                // Count down the door latch minus one
                                latch.countDown();
                            }
                        }
                    } catch (Exception e) {<!-- -->
                        e.printStackTrace();

                        // Count down the door latch minus one
                        latch.countDown();
                    }
                }
            };

            //Send an asynchronous request, execute the getNext method, and perform the first step of asynchronous processing
            snmp.getNext(pdu, target, null, listener);

            // Print log - "pdu has been sent, waiting for asynchronous processing results..."
            log.info("pdu has been sent, waiting for asynchronous processing results...");

            // Wait for 3 seconds until the countdown latch is completely reduced to zero. If it has not been reduced to zero at this time, continue to execute the following code
            boolean wait = latch.await(3, TimeUnit.SECONDS);

            //Print log - "latch.await =:" + wait
            log.info("latch.await =:" + wait);
            snmp.close();
            log.info("----> snmp end <----");
            return jsonArray;
        } catch (Exception e) {<!-- -->
            e.printStackTrace();
            log.info("SNMP Asyn Walk Exception:" + e);
            return jsonArray;
        }
    }

    public static void main(String[] args) {<!-- -->
        String ip = "127.0.0.1";
        String community = "public";
        String oidval = "1.3.6.1.2.1.1";
        String oid = "1.3.6.1.2.1.1.1.0";
        ip = args[0];
        community = args[1];
        String flag = args[2];
        if (flag.equals("1")) {<!-- -->
            oidval = args[3];

            // This method can obtain the information of all oids subordinate to the specified oid.
            JSONArray jsonArray2 = SnmpUtil.snmpAsynWalk(ip, community, oidval);

            System.out.println("The ip for snmp communication is: " + ip);
            System.out.println("oid is:'" + oidval + "'All the information obtained by the snmpAsynWalk method is: " + jsonArray2);

            // Currently only the oid 1.3.6.1.2.1.1 can do all the analysis
            if (oidval.equals("1.3.6.1.2.1.1")) {<!-- -->
                for (Object o : jsonArray2) {<!-- -->
                    JSONObject jsonObject = (JSONObject) o;
                    if (jsonObject.getString("oid").equals(oidval + ".1.0")) {<!-- -->
                        System.out.println("The system description information of the machine obtained is: " + jsonObject.getString("value"));
                    }
                    if (jsonObject.getString("oid").equals(oidval + ".2.0")) {<!-- -->
                        System.out.println("The device identifier of the machine obtained is: " + jsonObject.getString("value"));
                    }
                    if (jsonObject.getString("oid").equals(oidval + ".3.0")) {<!-- -->
                        System.out.println("The system startup time of the machine obtained is: " + jsonObject.getString("value"));
                    }
                    if (jsonObject.getString("oid").equals(oidval + ".4.0")) {<!-- -->
                        System.out.println("The device contact of the machine obtained is: " + jsonObject.getString("value"));
                    }
                    if (jsonObject.getString("oid").equals(oidval + ".5.0")) {<!-- -->
                        System.out.println("The device name of the machine obtained is: " + jsonObject.getString("value"));
                    }
                    if (jsonObject.getString("oid").equals(oidval + ".6.0")) {<!-- -->
                        System.out.println("The device location information of the machine obtained is: " + jsonObject.getString("value"));
                    }
                    if (jsonObject.getString("oid").equals(oidval + ".7.0")) {<!-- -->
                        System.out.println("The device service status of the machine obtained is: " + jsonObject.getString("value"));
                    }
                }
            }
        } else if (flag.equals("2")) {<!-- -->
            oid = args[3];
            // This method can only obtain specific oid information
            JSONArray jsonArray = snmpGet(ip, community, oid);
            System.out.println("oid is:'" + oid + "'All the information obtained by the snmpGet method is: " + jsonArray);
        }
    }
}

Verification results on the actual machine

The following is the information obtained from the local machine through snmp4j: The information obtained is

[{"oid":"1.3.6.1.2.1.1.1.0",
"value":"Hardware: Intel64 Family 6 Model 158 Stepping 10 AT/AT COMPATIBLE - Software: Windows Version 6.3 (Build 19044 Multiprocessor Free)"},{"oid":"1.3.6.1.2.1.1.2.0", "value":"1.3.6.1.4.1.311.1.1.3.1.1"},
{"oid":"1.3.6.1.2.1.1.3.0","value":"17:58:02.02"},{"oid":"1.3.6.1.2.1.1.4.0","value" :""},
{"oid":"1.3.6.1.2.1.1.5.0","value":"acer"},
{"oid":"1.3.6.1.2.1.1.6.0","value":""},
{"oid":"1.3.6.1.2.1.1.7.0","value":"76"}]

The first of these:

{"oid":"1.3.6.1.2.1.1.1.0",
"value":"Hardware: Intel64 Family 6 Model 158 Stepping 10 AT/AT COMPATIBLE - Software: Windows Version 6.3 (Build 19044 Multiprocessor Free)"}

This oid is the identifier used to obtain system description information

The first half of the content of value

“Hardware: Intel64 Family 6 Model 158 Stepping 10 AT/AT COMPATIBLE” describes the computer’s hardware information.

Among them, “Intel64” means that the CPU architecture is x86-64 (that is, the 64-bit Intel processor architecture),

“Family 6” and “Model 158” represent the CPU model.

And “Stepping 10” represents the version number of the CPU.

The “AT/AT COMPATIBLE” at the back means that the computer is compatible with the IBM PC/AT standard.

The second half, “Software: Windows Version 6.3 (Build 19044 Multiprocessor Free)” describes the operating system running on the computer and its version information.

“Windows” means the operating system is Windows series,

“Version 6.3” means the operating system version is Windows 8.1 or Windows Server 2012 R2.

“Build 19044” indicates the installed operating system patch version number.

The last “Multiprocessor Free” indicates that this operating system supports multiple processors.

In addition: the information returned by the Linux system is:

{"oid":"1.3.6.1.2.1.1.1.0",
"value":"Linux localhost.localdomain 3.10.0-1160.el7.x86_64 #1 SMP Mon Oct 19 16:18:59 UTC 2020 x86_64"}

The meaning of each parameter is:

Linux: the name of the operating system

localhost.localdomain: hostname

3.10.0-1160.el7.x86_64: Kernel version number

#1 SMP Mon Oct 19 16:18:59 UTC 2020: Kernel compilation time and date

x86_64: Processor architecture

second section:

{"oid":"1.3.6.1.2.1.1.2.0","value":"1.3.6.1.4.1.311.1.1.3.1.1"}

This OID represents the unique identifier of the device, and the returned value is “1.3.6.1.4.1.311.1.1.3.1.1”

Represents a private OID value for a specific vendor or department.

the third item:

{"oid":"1.3.6.1.2.1.1.3.0","value":"17:58:02.02"}

Indicates the system startup time of the device

The “17” in the return value “17:52:35.62” represents the hour, “52” represents the minute, “35” represents the second, and “.62” represents the millisecond. Therefore, the device’s system boot time was 5:52:35 and 620 milliseconds that day.

Item 4:

{"oid":"1.3.6.1.2.1.1.4.0","value":""}

Indicates the contact information of the device, and the returned value is an empty string.

Item 5:

{"oid":"1.3.6.1.2.1.1.5.0","value":"acer"}

Indicates the name of the device. The returned value is “acer”, which indicates that the name of the device is Acer.

Item 6:

{"oid":"1.3.6.1.2.1.1.6.0","value":""}

Indicates the location information of the device, and the returned value is an empty string.

Item 7:

{"oid":"1.3.6.1.2.1.1.7.0","value":"76"}

Indicates the service status of the device. The returned value is “76”, indicating that the device is currently running.
Convert the return value to binary and get: 01001100.

The first bit from left to right is the highest bit (MSB). Its value is 0, which means the device is running.

The second bit from left to right is the next bit, which has a value of 1, indicating that the device has been restarted at least once.

The 6-bit integer (010110) consisting of the third to eighth bits is converted into a decimal number of 44, indicating that the device has been running for 44 timing cycles after startup. The length and units of each timing cycle are device and implementation dependent.

Therefore, a return value of “76” indicates that the device is currently running, has been restarted at least once, and has been running for 44 ticks since the last restart. This information can help administrators understand the status of the device and perform diagnostics and debugging as needed.