All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.oneandone.snmpman.configuration.Walks Maven / Gradle / Ivy

The newest version!
package com.oneandone.snmpman.configuration;

import com.google.common.primitives.UnsignedLong;
import lombok.extern.slf4j.Slf4j;
import org.snmp4j.smi.Counter32;
import org.snmp4j.smi.Counter64;
import org.snmp4j.smi.Gauge32;
import org.snmp4j.smi.Integer32;
import org.snmp4j.smi.IpAddress;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.TimeTicks;
import org.snmp4j.smi.Variable;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/** Helper class for reading SNMP walks.
 * */
@Slf4j
public class Walks {

    /**
     * The default charset for files being read.
     */
    private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

    /**
     * The pattern of variable bindings in a walk file.
     */
    private static final Pattern VARIABLE_BINDING_PATTERN = Pattern.compile("(((iso)?\\.[0-9]+)+) = ((([a-zA-Z0-9-]+): (.*)$)|(\"\"$))");

    /**
     * The pattern of a Hex-STRING continuation line in a walk file.
     */
    private static final Pattern HEX_STRING_PATTERN = Pattern.compile("([0-9a-fA-F]{2})( [0-9a-fA-F]{2})* *");

    private Walks() {

    }

    /** Reads a walk from a file.
     * @param walk the walk file to read.
     * @return the map of oid to variable binding from the file.
     * @throws IOException if the file could not be read.
     * */
    public static Map readWalk(final File walk) throws IOException {
        log.debug("Reading walk from file {}", walk);
        try (final FileInputStream fileInputStream = new FileInputStream(walk);
             final BufferedReader reader = new BufferedReader(new InputStreamReader(fileInputStream, DEFAULT_CHARSET))) {
            Map result = readVariableBindings(walk, reader);
            log.debug("Walk contains {} variable bindings", result.size());
            return result;
        }
        catch (final FileNotFoundException e) {
            log.error("walk file {} not found", walk.getAbsolutePath());
            throw e;
        } catch (final IOException e) {
            log.error("could not read walk file " + walk.getAbsolutePath(), e);
            throw e;
        }
    }

    /**
     * Reads all variable bindings using {@link #VARIABLE_BINDING_PATTERN}.
     *
     * @param reader the reader to read the bindings from.
     * @return the map of oid to variable binding.
     */
    private static Map readVariableBindings(final File walk, final BufferedReader reader) throws IOException {
        final Map bindings = new HashMap<>();
        OID lastOid = null;
        String lastType = null;
        String line;
        int lineNumber = 0;
        while ((line = reader.readLine()) != null) {
            lineNumber++;
            boolean match = false;
            Matcher matcher = VARIABLE_BINDING_PATTERN.matcher(line);
            if (matcher.matches()) {
                match = true;
                final OID oid = new OID(matcher.group(1).replace("iso", ".1"));
                lastOid = oid;

                try {
                    final Variable variable;
                    if (matcher.group(7) == null) {
                        lastType = "STRING";
                        variable = getVariable("STRING", "\"\"");
                    } else {
                        lastType = matcher.group(6);
                        variable = getVariable(lastType, matcher.group(7));
                    }

                    bindings.put(oid, variable);
                    log.trace("added binding from line {} with oid \"{}\" and variable \"{}\"", lineNumber, oid, variable);
                } catch (final Exception e) {
                    log.warn("could not parse line {} with \"{}\" of walk file {} with exception: {}", lineNumber, line, walk.getCanonicalPath(), e.getMessage());
                }
            }

            // if we have a continuation line for a Hex-STRING, append to it
            if (!match && lastType != null && lastOid != null && lastType.equals("STRING")) {
                OctetString octetStringToExtend = (OctetString) bindings.get(lastOid);
                if (octetStringToExtend != null) {
                    match = true;
                    String oldString = octetStringToExtend.toString();
                    String newString;
                    if (line.endsWith("\"")) {
                        newString = line.substring(0, line.length() - 1);
                    } else {
                        newString = line;
                    }
                    String combined = oldString + "\n" + newString;
                    bindings.put(lastOid, new OctetString(combined));
                } else {
                    log.warn("Could not find the previous octet string of OID {} in walk file {} at line {}",
                            lastOid, walk.getAbsolutePath(), lineNumber);
                }
            }

            // if we have a continuation line for a Hex-STRING, append to it
            if (!match && lastType != null && lastOid != null && lastType.equals("Hex-STRING")) {
                matcher = HEX_STRING_PATTERN.matcher(line);
                if (matcher.matches()) {
                    match = true;
                    OctetString octetStringToExtend = (OctetString) bindings.get(lastOid);
                    if (octetStringToExtend != null) {
                        byte[] oldBytes = octetStringToExtend.getValue();
                        byte[] newBytes = OctetString.fromHexString(matcher.group(0), ' ').toByteArray();
                        byte[] combined = new byte[oldBytes.length + newBytes.length];
                        System.arraycopy(oldBytes, 0, combined, 0, oldBytes.length);
                        System.arraycopy(newBytes, 0, combined, oldBytes.length, newBytes.length);
                        bindings.put(lastOid, new OctetString(combined));
                    } else {
                        log.warn("Could not find the previous octet string of OID {} in walk file {} at line {}",
                                lastOid, walk.getAbsolutePath(), lineNumber);
                    }
                }
            }

            if (!match) {
                log.warn("Could not parse line number {} with content \"{}\" of walk file {}", lineNumber, line, walk.getAbsolutePath());
            }
        }
        return bindings;
    }

    /**
     * Returns a {@link Variable} instance for the specified parameters.
     *
     * @param type  the type of the variable
     * @param value the value of this variable
     * @return a a {@link Variable} instance with the specified type and value
     * @throws IllegalArgumentException if the type could not be mapped to a {@link Variable} implementation
     */
    private static Variable getVariable(final String type, final String value) {
        switch (type) {
            // TODO add "BITS" support
            case "STRING":
                String use = value;
                if (use.startsWith("\"")) {
                    use = use.substring(1);
                }
                if (use.endsWith("\"")) {
                    use = use.substring(0, use.length() - 1);
                }
                if (use.length() == 0) {
                    return new OctetString();
                }
                return new OctetString(use);
            case "OID":
                return new OID(value);
            case "Gauge32":
                return new Gauge32(Long.parseLong(value.replaceAll("[^-?0-9]+", "")));
            case "Timeticks":
                final int openBracket = value.indexOf("(") + 1;
                final int closeBracket = value.indexOf(")");
                if (openBracket == 0 || closeBracket < 0) {
                    throw new IllegalArgumentException("could not parse time tick value in " + value);
                }
                return new TimeTicks(Long.parseLong(value.substring(openBracket, closeBracket)));
            case "Counter32":
                return new Counter32(Long.parseLong(value.replaceAll("[^-?0-9]+", "")));
            case "Counter64":
                // Parse unsigned long
                return new Counter64(UnsignedLong.valueOf(value).longValue());
            case "INTEGER":
                return new Integer32(Integer.parseInt(value.replaceAll("[^-?0-9]+", "")));
            case "Hex-STRING":
                return OctetString.fromHexString(value, ' ');
            case "IpAddress":
                return new IpAddress(value);
            default:
                throw new IllegalArgumentException("illegal type \"" + type + "\" in walk detected");
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy