using System; using ln.snmp.types; using System.Net; using System.Collections.Generic; using System.Linq; using ln.snmp.endpoint; using System.Reflection; using ln.types; namespace ln.snmp { public enum SnmpVersion : int { V1 = 0, V2c = 1, V3 = 3 } public abstract class SnmpInterface : IDisposable { public static SnmpInterface FromURI(URI uri) => FromURI(uri, SNMPEngine.DefaultEngine); public static SnmpInterface FromURI(URI uri,SNMPEngine engine) { if (uri.Scheme.Equals("snmp")) { switch (uri.Fragment) { case "1": return new SnmpV1Endpoint(engine, new IPEndPoint(IPAddress.Parse(uri.Host), 161), uri.UserInfo[0]); case "2": return new SnmpV2Endpoint(engine, new IPEndPoint(IPAddress.Parse(uri.Host), 161), uri.UserInfo[0]); case "3": string[] auth = uri.UserInfo; USMEndpoint endpoint = new USMEndpoint(engine, new IPEndPoint(IPAddress.Parse(uri.Host), 161)); if (auth.Length > 0) endpoint.Username = auth[0]; if (auth.Length > 1) { endpoint.AuthMethod = SnmpV3AuthMethod.SHA; endpoint.AuthKeyPhrase = auth[1]; } if (auth.Length > 2) { endpoint.PrivMethod = SnmpV3PrivMethod.DES; endpoint.PrivKeyPhrase = auth[2]; } return endpoint; } } throw new NotSupportedException(); } public abstract SnmpVersion SnmpVersion { get; } public SnmpInterface() { } public abstract PDU DispatchRequest(PDU pdu); private List snmpRequest(IEnumerable objectIdentifiers) where T: PDU, new() { PDU pdu = new T(); foreach (ObjectIdentifier oid in objectIdentifiers) { pdu.Add(new Sequence(new Variable[] { oid, NullValue.Instance })); } PDU responsePDU = DispatchRequest(pdu); if (responsePDU.Error.LongValue != 0) { string indicator = responsePDU.ErrorIndex > 0 && responsePDU.ErrorIndex <= pdu.VarBinds.Items.Length ? ((pdu.VarBinds.Items[(int)responsePDU.ErrorIndex - 1] as Sequence).Items[0] as ObjectIdentifier).AsString : ""; throw new SnmpError(responsePDU.Error, responsePDU.ErrorIndex, indicator); } Sequence varBinds = responsePDU.VarBinds as Sequence; List results = new List(); foreach (Variable varBind in varBinds.Items) { results.Add(varBind as Sequence); } return results; } public List snmpGet(IEnumerable objectIdentifiers) { return snmpRequest(objectIdentifiers); } public Variable snmpGet(ObjectIdentifier objectIdentifier) { return snmpGet(new ObjectIdentifier[] { objectIdentifier })[0].Items[1]; } public Variable snmpGet(string objectIdentifier) { return snmpGet(new ObjectIdentifier[] { new ObjectIdentifier(objectIdentifier) })[0].Items[1]; } public List snmpGet(IEnumerable objectIdentifiers) { return snmpGet(objectIdentifiers.Select((x) => new ObjectIdentifier(x))); } public List snmpGetNext(IEnumerable objectIdentifiers) { return snmpRequest(objectIdentifiers); } public Sequence snmpGetNext(ObjectIdentifier objectIdentifier) { return snmpGetNext(new ObjectIdentifier[] { objectIdentifier })[0]; } public Sequence snmpGetNext(string objectIdentifier) { return snmpGetNext(new ObjectIdentifier[] { new ObjectIdentifier(objectIdentifier) })[0]; } public List snmpGetNext(IEnumerable objectIdentifiers) { return snmpGetNext(objectIdentifiers.Select((x) => new ObjectIdentifier(x))); } private PDU TryBulk(GetBulkRequest bulkRequest) { try { return DispatchRequest(bulkRequest); } catch (SnmpError se) { if ((se.Error == 1)&&(bulkRequest.MaxRepetitions.LongValue > 1)) { bulkRequest.MaxRepetitions.LongValue >>= 1; return TryBulk(bulkRequest); } throw se; } } /* * ToDO: Algorithm is not perfect, when receiving an inclomplete "row", the already received partial row is ignored */ public Sequence[][] snmpGetBulk(IEnumerable objectIdentifiers, int maxRepetitions = 32) { ObjectIdentifier[] OIDs = objectIdentifiers.ToArray(); int ncolumns = OIDs.Length; GetBulkRequest pdu = new GetBulkRequest(); pdu.MaxRepetitions.LongValue = maxRepetitions; foreach (ObjectIdentifier oid in objectIdentifiers) { pdu.Add(new Sequence(new Variable[] { oid, NullValue.Instance })); } List result = new List(); int nchunk; bool inTree = false; do { PDU responsePDU = TryBulk(pdu); Variable[] values = responsePDU.VarBinds.Items; nchunk = values.Length / ncolumns; for (int n = 0; n < nchunk; n++) { inTree = false; Sequence[] row = new Sequence[ncolumns]; for (int c = 0; c < ncolumns; c++) { Sequence v = values[(n * ncolumns) + c] as Sequence; ObjectIdentifier oid = v.Items[0] as ObjectIdentifier; if (OIDs[c].Contains(oid)) { row[c] = new Sequence(new Variable[] { OIDs[c].IndexTo(oid), v.Items[1] }); inTree = true; } } if (inTree) result.Add(row); else { break; } } pdu.VarBinds.RemoveAll(); for (int c = 0; c < ncolumns; c++) { pdu.VarBinds.Add(new Sequence(new Variable[] { (responsePDU.VarBinds.Items[(ncolumns * (nchunk - 1)) + c] as Sequence).Items[0], NullValue.Instance })); } pdu.RequestID.LongValue++; } while (inTree); //((nchunk == pdu.MaxRepetitions.LongValue) && inTree); return result.ToArray(); } public List snmpGetBulk(ObjectIdentifier objectIdentifier) { List results = new List(); List parts; do { parts = snmpRequest(new ObjectIdentifier[] { objectIdentifier }); foreach (Sequence ps in parts) { ObjectIdentifier oid = ps.Items[0] as ObjectIdentifier; if (objectIdentifier.Contains(oid)) { results.Add(new Sequence(new Variable[] { objectIdentifier.IndexTo(oid), ps.Items[1] })); } else return results; } } while (parts.Count >= 32); return results; } public List snmpGetBulk(String objectIdentifier) { return snmpGetBulk(new ObjectIdentifier(objectIdentifier)); } public Sequence[][] snmpWalk(IEnumerable objectIdentifiers) { if (SnmpVersion == SnmpVersion.V1) { ObjectIdentifier[] OIDs = objectIdentifiers.ToArray(); ObjectIdentifier[] lastOIDs = objectIdentifiers.ToArray(); List results = new List(); bool cont = true; while (cont) { cont = false; List next = snmpGetNext(lastOIDs); Sequence[] row = new Sequence[lastOIDs.Length]; for (int n = 0; n < lastOIDs.Length; n++) { lastOIDs[n] = next[n].Items[0] as ObjectIdentifier; if (OIDs[n].Contains(lastOIDs[n])) { cont = true; row[n] = next[n]; row[n].Items = new Variable[] { OIDs[n].IndexTo(lastOIDs[n]), next[n].Items[1] }; } else { row[n] = null; } } if (cont) results.Add(row); } return results.ToArray(); } else { return snmpGetBulk(objectIdentifiers); } } public Sequence[][] snmpWalk(IEnumerable objectIdentifiers) { return snmpWalk(objectIdentifiers.Select((x) => new ObjectIdentifier(x))); } public List snmpWalk(ObjectIdentifier objectIdentifier) { if (SnmpVersion == SnmpVersion.V1) { List results = new List(); ObjectIdentifier oiLast = objectIdentifier; while (objectIdentifier.Contains(oiLast)) { Sequence next = snmpGetNext(oiLast); oiLast = next.Items[0] as ObjectIdentifier; if (objectIdentifier.Contains(oiLast)) results.Add(next); } return results; } else { return snmpGetBulk(objectIdentifier); } } public List snmpWalk(string objectIdentifier) { return snmpWalk(new ObjectIdentifier(objectIdentifier)); } public virtual void Dispose() { } } }