From b8e9ba6e9a4f180942afbae1342e608be121f078 Mon Sep 17 00:00:00 2001 From: Harald Wolff Date: Mon, 4 Mar 2019 06:50:05 +0100 Subject: [PATCH] Initial commit --- .gitignore | 41 +++++++ BasicEncodingRules.cs | 240 +++++++++++++++++++++++++++++++++++++ Properties/AssemblyInfo.cs | 35 ++++++ SNMPClient.cs | 32 +++++ ln.snmp.csproj | 56 +++++++++ packages.config | 4 + types/Boolean.cs | 33 +++++ types/Integer.cs | 36 ++++++ types/NullValue.cs | 33 +++++ types/ObjectIdentifier.cs | 48 ++++++++ types/OctetString.cs | 38 ++++++ types/PDU.cs | 71 +++++++++++ types/Sequence.cs | 97 +++++++++++++++ types/Variable.cs | 87 ++++++++++++++ 14 files changed, 851 insertions(+) create mode 100644 .gitignore create mode 100644 BasicEncodingRules.cs create mode 100644 Properties/AssemblyInfo.cs create mode 100644 SNMPClient.cs create mode 100644 ln.snmp.csproj create mode 100644 packages.config create mode 100644 types/Boolean.cs create mode 100644 types/Integer.cs create mode 100644 types/NullValue.cs create mode 100644 types/ObjectIdentifier.cs create mode 100644 types/OctetString.cs create mode 100644 types/PDU.cs create mode 100644 types/Sequence.cs create mode 100644 types/Variable.cs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bf793ed --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +# Autosave files +*~ + +# build +[Oo]bj/ +[Bb]in/ +packages/ +TestResults/ + +# globs +Makefile.in +*.DS_Store +*.sln.cache +*.suo +*.cache +*.pidb +*.userprefs +*.usertasks +config.log +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.user +*.tar.gz +tarballs/ +test-results/ +Thumbs.db +.vs/ + +# Mac bundle stuff +*.dmg +*.app + +# resharper +*_Resharper.* +*.Resharper + +# dotCover +*.dotCover diff --git a/BasicEncodingRules.cs b/BasicEncodingRules.cs new file mode 100644 index 0000000..2ff8e95 --- /dev/null +++ b/BasicEncodingRules.cs @@ -0,0 +1,240 @@ +// /** +// * File: EncodingRules.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using System.IO; +using System.Net; +using System.Collections.Generic; +namespace ln.snmp +{ + public enum IdentifierClass : int + { + UNIVERSAL = 0, + APPLICATION = 1, + CONTEXT = 2, + PRIVATE = 3 + } + public struct Identifier + { + public IdentifierClass IdentifierClass; + public bool Constructed; + public ulong Number; + + public Identifier(IdentifierClass identifierClass,bool constructed,ulong number) + { + IdentifierClass = identifierClass; + Constructed = constructed; + Number = number; + } + + public override string ToString() + { + return String.Format("[ASN.1 Type Class={0} Constructed={1} Number={2}]",IdentifierClass,Constructed,Number); + } + } + + public static class BasicEncodingRules + { + + public static Identifier ReadIdentifier(Stream stream) + { + Identifier identifier = new Identifier(); + + int b = stream.ReadByte(); + identifier.IdentifierClass = (IdentifierClass)((b >> 6) & 0x03); + identifier.Constructed = (b & 0x20) != 0; + identifier.Number = (ulong)(b & 0x1F); + + if (identifier.Number == 0x1F) + { + identifier.Number = 0; + do + { + b = stream.ReadByte(); + if (b == -1) + throw new EndOfStreamException(); + + identifier.Number <<= 7; + identifier.Number |= ((uint)(b & 0x7F)); + } while ((b & 0x80) == 0x80); + } + + return identifier; + } + + public static void WriteIdentifier(Stream stream,Identifier identifier) + { + if (identifier.Number < 31) + { + byte bid = (byte)( + ((int)identifier.IdentifierClass << 6) | + ( identifier.Constructed ? 0x20 : 0x00) | + (int)identifier.Number + ); + stream.WriteByte(bid); + } + else + { + byte bid = (byte)( + ((int)identifier.IdentifierClass << 6) | + (identifier.Constructed ? 0x20 : 0x00) | + (int)0x1F + ); + stream.WriteByte(bid); + byte[] n = EncodeInteger((long)identifier.Number); + stream.Write(n, 0, n.Length); + } + } + + + public static int ReadLength(Stream stream) + { + int b = stream.ReadByte(); + if ((b & 0x80) == 0) + { + return b; + } + + b &= 0x7F; + int length = 0; + + for (int n=0;n 1) && ( + ((bits[n-1] == 0xFF) && ((bits[n - 2] & 0x80) == 0x80)) || + ((bits[n-1] == 0x00) && ((bits[n - 2] & 0x80) == 0x00)) + ) + ) + { + n--; + } + + if (n == 8) + { + Array.Reverse(bits); + return bits; + } + else + { + byte[] encodedbits = new byte[n]; + Array.Copy(bits, encodedbits, n); + Array.Reverse(encodedbits); + return encodedbits; + } + } + public static long DecodeInteger(byte[] bits) + { + byte[] decodedbits = bits; + if (bits.Length < 8) + { + decodedbits = new byte[8]; + Array.Copy(bits, decodedbits, bits.Length); + byte fill = (byte)(((bits[bits.Length - 1] & 0x80) == 0x80) ? 0xFF : 0x00); + for (int n=bits.Length;n<8;n++) + { + decodedbits[n] = fill; + } + } + return BitConverter.ToInt64(decodedbits,0); + } + + + public static int[] DecodeOID(byte[] bytes) + { + List oid = new List(); + + MemoryStream memoryStream = new MemoryStream(bytes); + int b = memoryStream.ReadByte(); + int e = 0; + + oid.Add(b / 40); + oid.Add(b % 40); + + while (memoryStream.Position < memoryStream.Length) + { + e = 0; + do + { + b = memoryStream.ReadByte(); + e <<= 7; + e |= (ushort)(b & 0x7F); + + if ((b & 0x80) == 0x00) + { + oid.Add(e); + e = 0; + } + } + while ((b & 0x80) == 0x80); + } + + return oid.ToArray(); + } + public static byte[] EncodeOID(int[] oid) + { + MemoryStream memoryStream = new MemoryStream(); + byte pseudo = (byte)( (oid[0] * 40) + oid[1] ); + memoryStream.WriteByte(pseudo); + + for (int n = 2; n < oid.Length; n++) + { + int e = oid[n]; + + if (e < 128) + { + memoryStream.WriteByte((byte)e); + } + else + { + List bytes = new List(); + bytes.Add((byte)(e & 0x7f)); + + while (e > 127) + { + e >>= 7; + bytes.Add((byte)(0x80 | (e & 0x7f))); + } + bytes.Reverse(); + + memoryStream.Write(bytes.ToArray(), 0, bytes.Count); + } + } + + return memoryStream.ToArray(); + } + + + } +} diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..78df363 --- /dev/null +++ b/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +// /** +// * File: AssemblyInfo.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("ln.snmp")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("${AuthorCopyright}")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] diff --git a/SNMPClient.cs b/SNMPClient.cs new file mode 100644 index 0000000..15bd84f --- /dev/null +++ b/SNMPClient.cs @@ -0,0 +1,32 @@ +// /** +// * File: MyClass.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using System.Collections.Generic; +using Lextm.SharpSnmpLib; + +namespace ln.snmp +{ + public abstract class SNMPClient + { + public SNMPClient() + { + + } + + public abstract List Walk(ObjectIdentifier baseOID); + public abstract List Get(List baseOID); + + public virtual Variable Get(ObjectIdentifier oid) + { + return Get(new List(new ObjectIdentifier[] { oid }))[0]; + } + + } +} diff --git a/ln.snmp.csproj b/ln.snmp.csproj new file mode 100644 index 0000000..865d4df --- /dev/null +++ b/ln.snmp.csproj @@ -0,0 +1,56 @@ + + + + Debug + AnyCPU + {C7A43B82-55F2-4092-8DBE-6BE29CBF079D} + Library + ln.snmp + ln.snmp + v4.7 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + + + true + bin\Release + prompt + 4 + false + + + + + ..\packages\Lextm.SharpSnmpLib.11.1.0\lib\net452\SharpSnmpLib.dll + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages.config b/packages.config new file mode 100644 index 0000000..509e2ef --- /dev/null +++ b/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/types/Boolean.cs b/types/Boolean.cs new file mode 100644 index 0000000..71624b2 --- /dev/null +++ b/types/Boolean.cs @@ -0,0 +1,33 @@ +// /** +// * File: Boolean.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +namespace ln.snmp.types +{ + public class Boolean : Variable + { + public bool BooleanValue { get; set; } + + public Boolean() + : base(new Identifier(IdentifierClass.UNIVERSAL, false, 1)) + { + } + + public override byte[] Bytes + { + get => BooleanValue ? new byte[] { 0xFF } : new byte[] { 0x00 }; + set => BooleanValue = value[0] == 0 ? false : true; + } + public override object Value + { + get => BooleanValue; + set => BooleanValue = (bool)value; + } + } +} diff --git a/types/Integer.cs b/types/Integer.cs new file mode 100644 index 0000000..a9aa70d --- /dev/null +++ b/types/Integer.cs @@ -0,0 +1,36 @@ +// /** +// * File: Integer.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +namespace ln.snmp.types +{ + public class Integer : Variable + { + public long LongValue { get; set; } + + public Integer() + :base(new Identifier(IdentifierClass.UNIVERSAL, false, 0x02)) + { + } + + public Integer(long value) + :this() + { + LongValue = value; + } + + public override byte[] Bytes + { + get => BasicEncodingRules.EncodeInteger(LongValue); + set => LongValue = BasicEncodingRules.DecodeInteger(value); + } + public override object Value { get => LongValue; set => LongValue = (long)value; } + + } +} diff --git a/types/NullValue.cs b/types/NullValue.cs new file mode 100644 index 0000000..fefc8f1 --- /dev/null +++ b/types/NullValue.cs @@ -0,0 +1,33 @@ +// /** +// * File: NullValue.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +namespace ln.snmp.types +{ + public class NullValue : Variable + { + public static NullValue Instance = new NullValue(); + + byte[] value = new byte[0]; + + private NullValue() + :base(new Identifier(IdentifierClass.UNIVERSAL,false,0x05)) + { + } + + public override byte[] Bytes { get => value; + set + { + if (value.Length > 0) + throw new NotImplementedException(); + } + } + public override object Value { get => null; set => throw new NotImplementedException(); } + } +} diff --git a/types/ObjectIdentifier.cs b/types/ObjectIdentifier.cs new file mode 100644 index 0000000..e2f0cb3 --- /dev/null +++ b/types/ObjectIdentifier.cs @@ -0,0 +1,48 @@ +// /** +// * File: ObjectIdentifier.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using System.Linq; +namespace ln.snmp.types +{ + public class ObjectIdentifier : Variable + { + public int[] OIDValue { get; set; } + + public ObjectIdentifier() + :base(new Identifier(IdentifierClass.UNIVERSAL,false,6)) + { + } + + public ObjectIdentifier(int[] oid) + : this() + { + OIDValue = oid; + } + public ObjectIdentifier(string oid) + : this() + { + int[] ioid = oid.Split(new char[] { '.' }, StringSplitOptions.None).Select((x)=> int.Parse(x)).ToArray(); + OIDValue = ioid; + } + + + public override byte[] Bytes + { + get => BasicEncodingRules.EncodeOID(OIDValue); + set => OIDValue = BasicEncodingRules.DecodeOID(value); + } + public override object Value + { + get => OIDValue; + set => OIDValue = value as int[]; + } + + } +} diff --git a/types/OctetString.cs b/types/OctetString.cs new file mode 100644 index 0000000..8051893 --- /dev/null +++ b/types/OctetString.cs @@ -0,0 +1,38 @@ +// /** +// * File: OctetString.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using System.Text; +namespace ln.snmp.types +{ + public class OctetString : Variable + { + public string StringValue { get; set; } + + public OctetString() + :base(new Identifier(IdentifierClass.UNIVERSAL, false, 4)) + { + } + + public OctetString(String text) + :this() + { + StringValue = text; + } + + public override byte[] Bytes { + get => Encoding.UTF8.GetBytes(StringValue); + set => StringValue = Encoding.UTF8.GetString(value); + } + public override object Value { + get => StringValue; + set => StringValue = value as string; + } + } +} diff --git a/types/PDU.cs b/types/PDU.cs new file mode 100644 index 0000000..01609af --- /dev/null +++ b/types/PDU.cs @@ -0,0 +1,71 @@ +// /** +// * File: PDU.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using System.IO; +namespace ln.snmp.types +{ + public class PDU : AbstractSequence + { + public Integer RequestID { get; private set; } + public Integer Error { get; private set; } + public Integer ErrorIndex { get; private set; } + + public Sequence VarBinds { get; private set; } + + private Variable[] items; + + public PDU(Identifier identifier) + :base(identifier) + { + RequestID = new Integer(1); // Environment.TickCount + Error = new Integer(); + ErrorIndex = new Integer(); + + VarBinds = new Sequence(); + + items = new Variable[] { RequestID, Error, ErrorIndex, VarBinds }; + } + + public override Variable[] Items => items; + + public override void Add(Variable item) + { + VarBinds.Add(item); + } + + public override void Remove(Variable item) + { + VarBinds.Remove(item); + } + + public override byte[] Bytes + { + set + { + MemoryStream bytes = new MemoryStream(value); + + RequestID = Variable.Read(bytes) as Integer; + Error = Variable.Read(bytes) as Integer; + ErrorIndex = Variable.Read(bytes) as Integer; + VarBinds = Variable.Read(bytes) as Sequence; + } + } + + + + } + + public class GetRequest : PDU + { + public GetRequest() : base(new Identifier(IdentifierClass.CONTEXT,true,0x00)) + { + } + } +} diff --git a/types/Sequence.cs b/types/Sequence.cs new file mode 100644 index 0000000..b5c2e5a --- /dev/null +++ b/types/Sequence.cs @@ -0,0 +1,97 @@ +// /** +// * File: Sequence.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.IO; +namespace ln.snmp.types +{ + public class Sequence : AbstractSequence + { + private List items = new List(); + + public Sequence() + :base(new Identifier(IdentifierClass.UNIVERSAL,true,0x10)) + { } + + public Sequence(IEnumerable variables) + :this() + { + foreach (Variable variable in variables) + Add(variable); + } + + public override Variable[] Items => items.ToArray(); + public override void Add(Variable item) + { + this.items.Add(item); + } + public override void Remove(Variable item) + { + this.items.Remove(item); + } + public override void Remove(int n) + { + this.items.RemoveAt(n); + } + } + + public abstract class AbstractSequence : Variable + { + protected AbstractSequence(Identifier identifier) + :base(identifier) + { + } + + /* Items */ + public abstract Variable[] Items { get; } + public abstract void Add(Variable item); + public abstract void Remove(Variable item); + public virtual void Remove(int n) + { + Remove(Items[n]); + } + public virtual void RemoveAll() + { + foreach (Variable item in Items) + Remove(item); + } + + /* SNMP Variable */ + public override object Value { + get => Items; + set => throw new NotImplementedException(); + } + public override byte[] Bytes + { + get + { + MemoryStream payload = new MemoryStream(); + + foreach (Variable item in Items) + { + item.Write(payload); + } + + return payload.ToArray(); + } + set + { + MemoryStream bytes = new MemoryStream(value); + + while (bytes.Position < bytes.Length) + { + Add(Variable.Read(bytes)); + } + } + } + + } +} diff --git a/types/Variable.cs b/types/Variable.cs new file mode 100644 index 0000000..7bcdb10 --- /dev/null +++ b/types/Variable.cs @@ -0,0 +1,87 @@ +// /** +// * File: Variable.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using System.IO; +namespace ln.snmp.types +{ + public abstract class Variable + { + public Identifier Identifier { get; private set; } + + public Variable(Identifier identifier) + { + Identifier = identifier; + } + + public abstract byte[] Bytes { get; set; } + public abstract object Value { get; set; } + + public virtual void Write(Stream stream) + { + byte[] payload = Bytes; + + BasicEncodingRules.WriteIdentifier(stream,Identifier); + BasicEncodingRules.WriteLength(stream, payload.Length); + stream.Write(payload, 0, payload.Length); + } + + public static Variable Read(Stream stream) + { + Variable variable = null; + + Identifier identifier = BasicEncodingRules.ReadIdentifier(stream); + int length = BasicEncodingRules.ReadLength(stream); + byte[] payload = new byte[length]; + stream.Read(payload, 0, length); + + variable = FromIdentifier(identifier); + variable.Bytes = payload; + + return variable; + } + + public static void Write(Stream stream,Variable variable) + { + variable.Write(stream); + } + + + public static Variable FromIdentifier(Identifier identifier) + { + if (identifier.IdentifierClass == IdentifierClass.UNIVERSAL) + { + switch (identifier.Number) + { + case 0x02: + return new Integer(); + case 0x04: + return new OctetString(); + case 0x05: + return NullValue.Instance; + case 0x06: + return new ObjectIdentifier(); + case 0x10: + return new Sequence(); + } + } else if (identifier.IdentifierClass == IdentifierClass.CONTEXT) + { + switch (identifier.Number) + { + case 0x00: + return new GetRequest(); + } + } + + throw new NotSupportedException(String.Format("Unsupported ASN Type: {0}",identifier)); + } + + } + +}