master
Harald Wolff 2019-03-11 08:57:19 +01:00
parent 1b4c13e5f5
commit e6b25374f3
26 changed files with 1115 additions and 276 deletions

View File

@ -47,7 +47,7 @@ namespace ln.snmp
public override string ToString()
{
return String.Format("[ASN.1 Type Class={0} Constructed={1} Number={2} FirstByte=0x{3,02:X}]",IdentifierClass,Constructed,Number,Firstbyte);
return String.Format("[ASN.1 Type Class={0} Constructed={1} Number={2} FirstByte=0x{3,2:X}]",IdentifierClass,Constructed,Number,Firstbyte);
}
}

View File

@ -13,6 +13,8 @@ using ln.snmp.types;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using ln.snmp.asn1;
using ln.logging;
namespace ln.snmp
{
@ -23,10 +25,14 @@ namespace ln.snmp
public UdpClient LocalEndpoint { get; private set; }
public int Timeout { get; set; } = 1000;
private Dictionary<IPEndPoint, InternalRequest> queuedRequests = new Dictionary<IPEndPoint, InternalRequest>();
private Dictionary<int, SnmpMessage> queuedRequests = new Dictionary<int, SnmpMessage>();
private bool shutdown = false;
private Thread ReceiverThread { get; set; }
private int nextMessageID = (int)DateTimeOffset.Now.ToUnixTimeSeconds();
public int NextMessageID => nextMessageID++;
public SNMPEngine()
{
LocalEndpoint = new UdpClient();
@ -55,86 +61,81 @@ namespace ln.snmp
IPEndPoint remoteEndpoint = null;
byte[] datagram = LocalEndpoint.Receive(ref remoteEndpoint);
Logging.Log(LogLevel.DEBUG,"SNMPClient: Received: {0}", BitConverter.ToString(datagram));
ASN1Value asn = new ASN1Value(datagram);
asn.Dump();
SnmpMessage snmpMessage = asn;
snmpMessage.Dump();
lock (queuedRequests)
{
if (queuedRequests.ContainsKey(remoteEndpoint))
if (queuedRequests.ContainsKey(snmpMessage.MessageID))
{
InternalRequest internalRequest = queuedRequests[remoteEndpoint];
internalRequest.Response = datagram;
lock (internalRequest)
SnmpMessage snmpRequestMessage = queuedRequests[snmpMessage.MessageID];
lock (snmpRequestMessage)
{
Monitor.PulseAll(internalRequest);
queuedRequests[snmpMessage.MessageID] = snmpMessage;
Monitor.PulseAll(snmpRequestMessage);
}
}
else
{
Logging.Log(LogLevel.WARNING, "SnmpEngine.Receiver(): Can't find pending request with MessageID {0} ( 0x{0:x8} )",snmpMessage.MessageID);
}
}
}
catch (SocketException se)
{
Logging.Log(se);
}
catch (Exception e)
{
Console.WriteLine("Receiver(): {0}", e);
Logging.Log(e);
}
}
}
private byte[] SendRequest(IPEndPoint remoteEndpoint,byte[] request,int timeout)
public SnmpMessage SNMPRequest(IPEndPoint remoteEndpoint,SnmpMessage snmpMessage,int timeout)
{
InternalRequest internalRequest = new InternalRequest();
internalRequest.RemoteEndpoint = remoteEndpoint;
lock(queuedRequests)
lock (queuedRequests)
{
if (queuedRequests.ContainsKey(remoteEndpoint))
throw new ArgumentException("Already pending request exists for this remote endpoint", nameof(remoteEndpoint));
ASN1Value snmpRequest = snmpMessage;
byte[] snmpRequestBytes = snmpRequest.AsByteArray;
queuedRequests.Add(remoteEndpoint,internalRequest);
queuedRequests.Add(snmpMessage.MessageID, snmpMessage);
if (DEBUG)
Console.WriteLine("SNMPClient: Send: {0}", BitConverter.ToString(request));
Logging.Log(LogLevel.DEBUG,"SNMPClient: Send: {0}", BitConverter.ToString(snmpRequestBytes));
Logging.Log(LogLevel.DEBUG,"sent snmpMessage with MessageID {0} ( 0x{0:x8} )",snmpMessage.MessageID);
snmpMessage.Dump();
LocalEndpoint.Send(request, request.Length, remoteEndpoint);
LocalEndpoint.Send(snmpRequestBytes, snmpRequestBytes.Length, remoteEndpoint);
lock (internalRequest)
lock (snmpMessage)
{
Monitor.Exit(queuedRequests);
bool success = Monitor.Wait(internalRequest, timeout);
bool success = Monitor.Wait(snmpMessage, timeout);
Monitor.Enter(queuedRequests);
if (!success)
{
queuedRequests.Remove(snmpMessage.MessageID);
throw new TimeoutException();
}
}
queuedRequests.Remove(remoteEndpoint);
SnmpMessage responseMessage = queuedRequests[snmpMessage.MessageID];
queuedRequests.Remove(snmpMessage.MessageID);
return responseMessage;
}
return internalRequest.Response;
}
public Variable SNMPRequest(IPEndPoint remoteEndpoint,Sequence request)
{
byte[] response = SendRequest(remoteEndpoint, request.ToBytes(), Timeout);
if (DEBUG)
Console.WriteLine("SNMPClient: Received: {0}", BitConverter.ToString(response));
Variable vreply = Variable.Read(response);
return vreply;
}
//public abstract List<Variable> Walk(ObjectIdentifier baseOID);
//public abstract List<Variable> Get(List<ObjectIdentifier> baseOID);
//public virtual Variable Get(ObjectIdentifier oid)
//{
// return Get(new List<ObjectIdentifier>(new ObjectIdentifier[] { oid }))[0];
//}
public void Dispose()
{
if (ReceiverThread != null)
@ -151,10 +152,5 @@ namespace ln.snmp
}
}
class InternalRequest
{
public IPEndPoint RemoteEndpoint;
public byte[] Response;
}
}
}

View File

@ -10,20 +10,20 @@ namespace ln.snmp
{
public enum SnmpVersion : int { V1 = 0, V2c = 1, V3 = 3 }
public class SNMPInterface
public abstract class SNMPInterface
{
public SnmpPDUChannel PDUChannel { get; set; }
public SNMPEngine SNMPEngine { get; }
public IPEndPoint RemoteEndpoint { get; set; }
public SnmpVersion SnmpVersion => PDUChannel.SnmpVersion;
public abstract SnmpVersion SnmpVersion { get; }
public SNMPInterface(SnmpPDUChannel PDUChannel,IPEndPoint remoteEndpoint)
public SNMPInterface(SNMPEngine snmpEngine,IPEndPoint remoteEndpoint)
{
this.PDUChannel = PDUChannel;
SNMPEngine = snmpEngine;
RemoteEndpoint = remoteEndpoint;
}
public abstract PDU snmpRequest(PDU pdu);
private List<Sequence> snmpRequest<T>(IEnumerable<ObjectIdentifier> objectIdentifiers) where T: PDU, new()
{
@ -34,6 +34,13 @@ namespace ln.snmp
}
PDU responsePDU = snmpRequest(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<Sequence> results = new List<Sequence>();
@ -44,12 +51,6 @@ namespace ln.snmp
return results;
}
private PDU snmpRequest(PDU pdu)
{
GetResponse responsePDU = PDUChannel.RequestResponse(pdu, RemoteEndpoint) as GetResponse;
return responsePDU;
}
public List<Sequence> snmpGet(IEnumerable<ObjectIdentifier> objectIdentifiers)
{
return snmpRequest<GetRequest>(objectIdentifiers);
@ -224,14 +225,10 @@ namespace ln.snmp
}
return results.ToArray();
}
else if (SnmpVersion == SnmpVersion.V2c)
else
{
return snmpGetBulk(objectIdentifiers);
}
else
{
throw new NotImplementedException();
}
}
public Sequence[][] snmpWalk(IEnumerable<String> objectIdentifiers)
{

185
asn1/ASN1Value.cs 100644
View File

@ -0,0 +1,185 @@
// /**
// * File: ASN1Value.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.IO;
using ln.snmp.types;
using ln.logging;
namespace ln.snmp.asn1
{
public class ASN1Value
{
public Identifier Identifier { get; set; }
private byte[] octets;
private List<ASN1Value> items;
public ASN1Value(byte[] source)
:this(new MemoryStream(source))
{
}
public ASN1Value(Stream stream)
{
Identifier = BasicEncodingRules.ReadIdentifier(stream);
int length = BasicEncodingRules.ReadLength(stream);
if (Identifier.Constructed)
{
items = new List<ASN1Value>();
long next = stream.Position + length;
while (stream.Position < next)
items.Add(new ASN1Value(stream));
}
else
{
octets = new byte[length];
stream.Read(octets, 0, length);
}
}
public ASN1Value(Identifier identifier)
{
Identifier = identifier;
if (Identifier.Constructed)
items = new List<ASN1Value>();
else
octets = new byte[0];
}
public byte[] AsByteArray
{
get
{
if (Identifier.Constructed)
{
byte[][] binaryItems = new byte[items.Count][];
int length = 0;
for (int n = 0; n < binaryItems.Length; n++)
{
binaryItems[n] = items[n].AsByteArray;
length += binaryItems[n].Length;
}
MemoryStream stream = new MemoryStream();
BasicEncodingRules.WriteIdentifier(stream, Identifier);
BasicEncodingRules.WriteLength(stream, length);
for (int n = 0; n < binaryItems.Length; n++)
stream.Write(binaryItems[n], 0, binaryItems[n].Length);
return stream.ToArray();
}
else
{
MemoryStream stream = new MemoryStream();
BasicEncodingRules.WriteIdentifier(stream, Identifier);
BasicEncodingRules.WriteLength(stream, octets.Length);
stream.Write(octets, 0, octets.Length);
return stream.ToArray();
}
}
}
public byte[] Bytes
{
get
{
if (!Identifier.Constructed)
{
return octets;
}
else
{
byte[][] binaryItems = new byte[items.Count][];
int length = 0;
for (int n = 0; n < binaryItems.Length; n++)
{
binaryItems[n] = items[n].AsByteArray;
length += binaryItems[n].Length;
}
byte[] bytes = new byte[length];
int offset = 0;
for (int n = 0; n < binaryItems.Length; n++)
{
Array.Copy(binaryItems[n], 0, bytes, offset, binaryItems[n].Length);
offset += binaryItems[n].Length;
}
return bytes;
}
}
set
{
if (!Identifier.Constructed)
{
octets = value;
}
else
{
throw new NotImplementedException();
}
}
}
public ASN1Value[] Items
{
get
{
if (!Identifier.Constructed)
throw new ArgumentOutOfRangeException("ASN1Value is not constructed");
return items.ToArray();
}
set
{
if (!Identifier.Constructed)
throw new ArgumentOutOfRangeException("ASN1Value is not constructed");
items = new List<ASN1Value>(value);
}
}
public void Add(ASN1Value item)
{
if (!Identifier.Constructed)
throw new ArgumentOutOfRangeException("ASN1Value is not constructed");
items.Add(item);
}
public override string ToString()
{
return String.Format("[ASN1Value Identifier={0}]",Identifier);
}
public void Dump()
{
Dump("");
}
public void Dump(string prefix)
{
if (Identifier.Constructed)
{
Logging.Log(LogLevel.DEBUG, "{1}{0}", this.Identifier, prefix);
foreach (ASN1Value item in items)
item.Dump(prefix + " ");
}
else
{
Logging.Log(LogLevel.DEBUG, "{2}{0} {1}",this.Identifier,BitConverter.ToString(Bytes),prefix);
}
}
}
}

View File

@ -1,20 +0,0 @@
using System;
using ln.snmp.types;
using System.Net;
namespace ln.snmp.channel
{
public abstract class SnmpPDUChannel
{
public SNMPEngine SNMPClient { get; set; }
public abstract SnmpVersion SnmpVersion { get; }
public SnmpPDUChannel(SNMPEngine client)
{
SNMPClient = client;
}
public abstract PDU RequestResponse(PDU pdu, IPEndPoint remoteEndpoint);
}
}

View File

@ -1,49 +0,0 @@
using System;
using ln.snmp.types;
using System.Net;
using System.Collections.Generic;
namespace ln.snmp.channel
{
public class SnmpV1Channel : SnmpPDUChannel
{
public override SnmpVersion SnmpVersion => SnmpVersion.V1;
public OctetString CommunityString { get; set; }
public SnmpV1Channel(SNMPEngine client)
:base(client)
{
CommunityString = "public";
}
public SnmpV1Channel(SNMPEngine client,string communityString)
:base(client)
{
CommunityString = communityString;
}
public override PDU RequestResponse(PDU pdu,IPEndPoint remoteEndpoint)
{
Integer version = new Integer((int)SnmpVersion);
Sequence snmpRequest = new Sequence();
snmpRequest.Add(version);
snmpRequest.Add(CommunityString);
snmpRequest.Add(pdu);
Variable reply = SNMPClient.SNMPRequest(remoteEndpoint, snmpRequest);
Sequence sreply = reply as Sequence;
PDU responsePDU = sreply.Items[2] as 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);
}
return responsePDU;
}
}
}

View File

@ -0,0 +1,42 @@
using System;
using ln.snmp.types;
using System.Net;
using System.Collections.Generic;
namespace ln.snmp.channel
{
public class SnmpV1Endpoint : SNMPInterface
{
public OctetString CommunityString { get; set; }
public override SnmpVersion SnmpVersion => SnmpVersion.V1;
public SnmpV1Endpoint(SNMPEngine snmpEngine, IPEndPoint remoteEndpoint)
: base(snmpEngine, remoteEndpoint)
{
CommunityString = "public";
}
public SnmpV1Endpoint(SNMPEngine snmpEngine, IPEndPoint remoteEndpoint, OctetString communityString)
: base(snmpEngine, remoteEndpoint)
{
CommunityString = communityString;
}
public SnmpV1Endpoint(SNMPEngine snmpEngine, IPEndPoint remoteEndpoint, String communityString)
: base(snmpEngine, remoteEndpoint)
{
CommunityString = new OctetString(communityString);
}
public override PDU snmpRequest(PDU pdu)
{
SnmpV1Message request = new SnmpV1Message();
request.MessageID = SNMPEngine.NextMessageID;
request.snmpCommunity = CommunityString;
request.snmpPDU = pdu;
SnmpV1Message response = SNMPEngine.SNMPRequest(RemoteEndpoint, request, SNMPEngine.Timeout) as SnmpV1Message;
return response.snmpPDU;
}
}
}

View File

@ -1,17 +0,0 @@
using System;
namespace ln.snmp.channel
{
public class SnmpV2Channel : SnmpV1Channel
{
public override SnmpVersion SnmpVersion => SnmpVersion.V2c;
public SnmpV2Channel(SNMPEngine client)
: base(client)
{
}
public SnmpV2Channel(SNMPEngine client, string communityString)
: base(client, communityString)
{ }
}
}

View File

@ -0,0 +1,42 @@
using System;
using ln.snmp.types;
using System.Net;
using System.Collections.Generic;
namespace ln.snmp.channel
{
public class SnmpV2Endpoint : SNMPInterface
{
public OctetString CommunityString { get; set; }
public override SnmpVersion SnmpVersion => SnmpVersion.V2c;
public SnmpV2Endpoint(SNMPEngine snmpEngine, IPEndPoint remoteEndpoint)
: base(snmpEngine, remoteEndpoint)
{
CommunityString = "public";
}
public SnmpV2Endpoint(SNMPEngine snmpEngine, IPEndPoint remoteEndpoint, OctetString communityString)
: base(snmpEngine, remoteEndpoint)
{
CommunityString = communityString;
}
public SnmpV2Endpoint(SNMPEngine snmpEngine, IPEndPoint remoteEndpoint, String communityString)
: base(snmpEngine, remoteEndpoint)
{
CommunityString = new OctetString(communityString);
}
public override PDU snmpRequest(PDU pdu)
{
SnmpV2Message request = new SnmpV2Message();
request.MessageID = SNMPEngine.NextMessageID;
request.snmpCommunity = CommunityString;
request.snmpPDU = pdu;
SnmpV2Message response = SNMPEngine.SNMPRequest(RemoteEndpoint, request, SNMPEngine.Timeout) as SnmpV2Message;
return response.snmpPDU;
}
}
}

View File

@ -0,0 +1,145 @@
using System;
using System.Net;
using ln.snmp.types;
using System.Text;
using System.Security.Cryptography;
using ln.snmp.asn1;
using System.Linq;
namespace ln.snmp.channel
{
public enum SnmpV3AuthMethod { MD5, SHA }
public enum SnmpV3PrivMethod { DES }
public enum SnmpAuthLevel : int { noAuthNoPriv = 0, authNoPriv = 0x01, authPriv = 0x03 }
public class USMEndpoint : SNMPInterface
{
public OctetString RemoteEngineID { get; set; }
public string Username { get; set; }
public string AuthKey { get; set; }
public string PrivKey { get; set; }
public SnmpV3AuthMethod AuthMethod { get; set; }
public SnmpV3PrivMethod PrivMethod { get; set; }
public override SnmpVersion SnmpVersion => SnmpVersion.V3;
public USMEndpoint(SNMPEngine snmpEngine,IPEndPoint remoteEndpoint)
:base(snmpEngine,remoteEndpoint)
{
}
public SnmpAuthLevel AuthLevel
{
get
{
if (PrivKey != null)
return SnmpAuthLevel.authPriv;
if (AuthKey != null)
return SnmpAuthLevel.authNoPriv;
return SnmpAuthLevel.noAuthNoPriv;
}
}
public override PDU snmpRequest(PDU pdu)
{
if ((RemoteEngineID == null)||(RemoteEngineID.Bytes.Length == 0))
{
QueryEngineID();
}
USMMessage request = new USMMessage();
ScopedPDU scopedPDU = new ScopedPDU();
request.MessageID = SNMPEngine.NextMessageID;
request.msgData = scopedPDU;
scopedPDU.contextEngineID = RemoteEngineID;
scopedPDU.PDU = pdu;
AuthenticateMessage(request);
SnmpMessage reply = SNMPEngine.SNMPRequest(RemoteEndpoint, request, SNMPEngine.Timeout);
USMMessage replyUSM = reply as USMMessage;
PDU responsePDU = (replyUSM.msgData as ScopedPDU).PDU;
return responsePDU;
}
public void QueryEngineID()
{
USMMessage queryMessage = new USMMessage();
queryMessage.MessageID = SNMPEngine.NextMessageID;
ScopedPDU scopedPDU = new ScopedPDU();
queryMessage.msgData = scopedPDU;
queryMessage.Dump();
SnmpMessage reply = SNMPEngine.SNMPRequest(RemoteEndpoint, queryMessage, SNMPEngine.Timeout);
USMMessage usmReply = reply as USMMessage;
RemoteEngineID = usmReply.SecurityParameters.msgAuthoritativeEngineID;
}
public bool AuthenticateMessage(USMMessage message)
{
message.msgGlobalData.msgFlags.Bytes = new byte[] { (byte)(int)AuthLevel };
message.SecurityParameters.msgUserName.StringValue = Username;
message.SecurityParameters.msgAuthoritativeEngineID = RemoteEngineID;
message.SecurityParameters.msgAuthenticationParameters.Bytes = new byte[12];
byte[] wholeMsg = ((ASN1Value)message).AsByteArray;
byte[] extendedAuthKey = new byte[64];
byte[] authKey = Encoding.ASCII.GetBytes(AuthKey);
//Array.Copy(authKey, extendedAuthKey, 16);
//byte[] K1 = new byte[64];
//for (int n = 0; n < 64; n++)
// K1[n] = (byte)(extendedAuthKey[n] ^ IPAD[n]);
//byte[] K2 = new byte[64];
//for (int n = 0; n < 64; n++)
//K2[n] = (byte)(extendedAuthKey[n] ^ OPAD[n]);
HMAC hmac = null;
switch (AuthMethod)
{
case SnmpV3AuthMethod.MD5:
hmac = HMACMD5.Create();
break;
case SnmpV3AuthMethod.SHA:
hmac = HMACSHA1.Create();
break;
}
hmac.Key = authKey;
byte[] mac = hmac.ComputeHash(wholeMsg);
message.SecurityParameters.msgAuthenticationParameters.Bytes = mac.Take(12).ToArray();
return true;
}
static byte[] IPAD = __PAD(0x36);
static byte[] OPAD = __PAD(0x5C);
public static byte[] __PAD(byte pad)
{
byte[] ipad = new byte[0x40];
for (int n = 0; n < ipad.Length; n++)
ipad[n] = pad;
return ipad;
}
}
}

View File

@ -46,13 +46,28 @@
<Compile Include="types\Counter64.cs" />
<Compile Include="SNMPInterface.cs" />
<Compile Include="SnmpError.cs" />
<Compile Include="channel\SnmpPDUChannel.cs" />
<Compile Include="channel\SnmpV1Channel.cs" />
<Compile Include="channel\SnmpV2Channel.cs" />
<Compile Include="channel\SnmpV1Endpoint.cs" />
<Compile Include="channel\SnmpV2Endpoint.cs" />
<Compile Include="channel\USMEndpoint.cs" />
<Compile Include="types\V3Packet.cs" />
<Compile Include="types\ScopedPDU.cs" />
<Compile Include="asn1\ASN1Value.cs" />
<Compile Include="types\SnmpV1Message.cs" />
<Compile Include="types\SnmpMessage.cs" />
<Compile Include="types\SnmpV2Message.cs" />
<Compile Include="types\USMMessage.cs" />
<Compile Include="types\UsmSecurityParameters.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="types\" />
<Folder Include="channel\" />
<Folder Include="asn1\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ln.logging\ln.logging.csproj">
<Project>{D471A566-9FB6-41B2-A777-3C32874ECD0E}</Project>
<Name>ln.logging</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -8,6 +8,8 @@
// *
// **/
using System;
using ln.snmp.asn1;
namespace ln.snmp.types
{
public class Boolean : Variable
@ -19,6 +21,7 @@ namespace ln.snmp.types
{
}
public override byte[] Bytes
{
get => BooleanValue ? new byte[] { 0xFF } : new byte[] { 0x00 };

View File

@ -8,6 +8,9 @@
// *
// **/
using System;
using ln.snmp.asn1;
using ln.logging;
using System.Linq;
namespace ln.snmp.types
{
public class Integer : Variable
@ -30,10 +33,11 @@ namespace ln.snmp.types
{
}
public override byte[] Bytes
{
get => BasicEncodingRules.EncodeInteger(LongValue);
set => LongValue = BasicEncodingRules.DecodeInteger(value);
set => LongValue = BasicEncodingRules.DecodeInteger(value.Reverse().ToArray());
}
public override object Value { get => LongValue; set => LongValue = (long)value; }

View File

@ -8,6 +8,7 @@
// *
// **/
using System;
using ln.snmp.asn1;
namespace ln.snmp.types
{
public class NullValue : Variable
@ -16,7 +17,7 @@ namespace ln.snmp.types
byte[] value = new byte[0];
private NullValue()
public NullValue()
:base(new Identifier(IdentifierClass.UNIVERSAL,false,0x05))
{
}

View File

@ -9,6 +9,8 @@
// **/
using System;
using System.Linq;
using ln.snmp.asn1;
namespace ln.snmp.types
{
public class ObjectIdentifier : Variable
@ -32,6 +34,7 @@ namespace ln.snmp.types
OIDValue = ioid;
}
/* Check is b is part of the my subtree or is equal*/
public bool Contains(ObjectIdentifier b)
{

View File

@ -9,35 +9,48 @@
// **/
using System;
using System.Text;
using ln.snmp.asn1;
namespace ln.snmp.types
{
public class OctetString : Variable
{
public string StringValue { get; set; }
public override byte[] Bytes { get; set; }
public string StringValue {
get => Encoding.UTF8.GetString(Bytes);
set => Bytes = Encoding.UTF8.GetBytes(value);
}
public char[] Characters
{
get => StringValue.ToCharArray();
set => StringValue = new string(value);
}
public override object Value { get => Bytes; set => Bytes = (byte[])value; }
public OctetString()
:base(new Identifier(IdentifierClass.UNIVERSAL, false, 4))
{
StringValue = "";
}
public OctetString(String text)
:this()
: 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;
}
public OctetString(byte[] bytes)
: this()
{
Bytes = bytes;
}
public override string ToString()
{
return String.Format("[OctetString StringValue={0}]", StringValue);
return String.Format("[OctetString StringValue={0}]", StringValue.Replace("\0","\\0"));
}
public static implicit operator String(OctetString octetString)

View File

@ -9,6 +9,7 @@
// **/
using System;
using System.IO;
using ln.snmp.asn1;
namespace ln.snmp.types
{
public class PDU : AbstractSequence
@ -22,9 +23,10 @@ namespace ln.snmp.types
private Variable[] items;
public PDU(Identifier identifier)
:base(identifier)
: base(identifier)
{
RequestID = new Integer(Environment.TickCount);
//RequestID = new Integer(Environment.TickCount);
RequestID = new Integer(0xDEADBEEF);
Error = new Integer();
ErrorIndex = new Integer();
@ -33,7 +35,27 @@ namespace ln.snmp.types
items = new Variable[] { RequestID, Error, ErrorIndex, VarBinds };
}
public override Variable[] Items => items;
public PDU(ASN1Value value)
: base(value.Identifier)
{
RequestID = (Integer)value.Items[0];
Error = (Integer)value.Items[1];
Error = (Integer)value.Items[2];
VarBinds = (Sequence)value.Items[3];
}
public override Variable[] Items
{
get => items;
set
{
RequestID = value[0] as Integer;
Error = value[1] as Integer;
ErrorIndex= value[2] as Integer;
VarBinds = value[3] as Sequence;
}
}
public override void Add(Variable item)
{
@ -45,18 +67,6 @@ namespace ln.snmp.types
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;
}
}
@ -67,20 +77,32 @@ namespace ln.snmp.types
public GetRequest() : base(new Identifier(IdentifierClass.CONTEXT, true, 0x00))
{
}
public GetRequest(ASN1Value value)
: base(value)
{ }
}
public class GetNextRequest : PDU
{
public GetNextRequest() : base(new Identifier(IdentifierClass.CONTEXT, true, 0x01))
{
}
public GetNextRequest(ASN1Value value)
: base(value)
{ }
}
public class GetResponse : PDU
{
public GetResponse() : base(new Identifier(IdentifierClass.CONTEXT, true, 0x02))
{
}
// public GetResponse(ASN1Value value)
//: base(value)
//{ }
}
public class GetBulkRequest: PDU
public class GetBulkRequest : PDU
{
public Integer NonRepeaters => Error;
public Integer MaxRepetitions => ErrorIndex;
@ -89,14 +111,22 @@ namespace ln.snmp.types
{
NonRepeaters.LongValue = 0;
MaxRepetitions.LongValue = 32;
}
}
public class SetRequest : PDU
{
public SetRequest() : base(new Identifier(IdentifierClass.CONTEXT, true, 0x03))
{
}
}
public class Report: PDU
{
public Report() : base(new Identifier(IdentifierClass.CONTEXT, true, 0x08))
{
}
}

44
types/ScopedPDU.cs 100644
View File

@ -0,0 +1,44 @@
// /**
// * File: ScopedPDU.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.Runtime.Remoting.Messaging;
namespace ln.snmp.types
{
public class ScopedPDU : AbstractSequence
{
public OctetString contextEngineID { get; set; }
public OctetString contextName { get; set; }
public PDU PDU { get; set; }
public ScopedPDU()
:base(new Identifier(IdentifierClass.UNIVERSAL,true,0x10))
{
contextEngineID = new OctetString();
contextName = new OctetString();
PDU = new GetRequest();
}
public override Variable[] Items
{
get => new Variable[] { contextEngineID, contextName, PDU };
set
{
contextEngineID = value[0] as OctetString;
contextName = value[1] as OctetString;
PDU = value[2] as PDU;
}
}
public override void Add(Variable item) => throw new NotImplementedException();
public override void Remove(Variable item) => throw new NotImplementedException();
}
}

View File

@ -12,6 +12,8 @@ using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using ln.snmp.asn1;
namespace ln.snmp.types
{
public class Sequence : AbstractSequence
@ -29,7 +31,13 @@ namespace ln.snmp.types
Add(variable);
}
public override Variable[] Items => items.ToArray();
public override Variable[] Items {
get => items.ToArray();
set
{
items = new List<Variable>(value);
}
}
public override void Add(Variable item)
{
this.items.Add(item);
@ -51,8 +59,9 @@ namespace ln.snmp.types
{
}
/* Items */
public abstract Variable[] Items { get; }
public abstract Variable[] Items { get; set; }
public abstract void Add(Variable item);
public abstract void Remove(Variable item);
public virtual void Remove(int n)
@ -74,29 +83,31 @@ namespace ln.snmp.types
{
get
{
MemoryStream payload = new MemoryStream();
MemoryStream stream = new MemoryStream();
foreach (Variable item in Items)
foreach (byte[] binaryItem in Items.Select((x) => (ASN1Value)x).Select((asn1) => asn1.AsByteArray).ToArray())
{
item.Write(payload);
stream.Write(binaryItem, 0, binaryItem.Length);
}
return payload.ToArray();
return stream.ToArray();
}
set
{
MemoryStream bytes = new MemoryStream(value);
List<ASN1Value> items = new List<ASN1Value>();
MemoryStream stream = new MemoryStream(value);
while (bytes.Position < bytes.Length)
while (stream.Position < stream.Length)
{
Add(Variable.Read(bytes));
items.Add(new ASN1Value(stream));
}
Items = items.Select((x) => (Variable)x).ToArray();
}
}
public override string ToString()
{
return string.Format("[Sequence {0}]",String.Join(", ",Items.Select((x) => x.ToString())));
return string.Format("[{1} {0}]",String.Join(", ",Items.Select((x) => x?.ToString())),GetType().Name);
}
}

View File

@ -0,0 +1,48 @@
// /**
// * File: SnmpMessage.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 ln.snmp.asn1;
namespace ln.snmp.types
{
public abstract class SnmpMessage : AbstractSequence
{
public SnmpVersion SnmpVersion { get; }
public abstract int MessageID { get; set; }
public SnmpMessage(SnmpVersion snmpVersion)
: base(new Identifier(IdentifierClass.UNIVERSAL, true, 0x10))
{
SnmpVersion = snmpVersion;
}
public override void Add(Variable item) => throw new NotImplementedException();
public override void Remove(Variable item) => throw new NotImplementedException();
public static implicit operator SnmpMessage(ASN1Value asn)
{
Integer snmpVersion = (Integer)(Variable)asn.Items[0];
switch (snmpVersion.LongValue)
{
case 0:
return new SnmpV1Message(asn);
case 1:
return new SnmpV2Message(asn);
case 3:
return new USMMessage(asn);
}
throw new ArgumentException();
}
}
}

View File

@ -0,0 +1,46 @@
// /**
// * File: SnmpV1Message.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 ln.snmp.asn1;
namespace ln.snmp.types
{
public class SnmpV1Message : SnmpMessage
{
public OctetString snmpCommunity { get; set; }
public PDU snmpPDU { get; set; }
public SnmpV1Message()
:base(SnmpVersion.V1)
{
}
public SnmpV1Message(ASN1Value value)
:this()
{
snmpCommunity = (OctetString)value.Items[1];
snmpPDU = (PDU)value.Items[2];
}
public override int MessageID
{
get => (int)snmpPDU.RequestID.LongValue;
set => snmpPDU.RequestID.LongValue = value;
}
public override Variable[] Items
{
get => new Variable[] { new Integer((int)SnmpVersion), snmpCommunity, snmpPDU };
set
{
snmpCommunity = value[1] as OctetString;
snmpPDU = value[2] as PDU;
}
}
}
}

View File

@ -0,0 +1,50 @@
// /**
// * File: SnmpV1Message.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 ln.snmp.asn1;
using ln.logging;
namespace ln.snmp.types
{
public class SnmpV2Message : SnmpMessage
{
public OctetString snmpCommunity { get; set; }
public PDU snmpPDU { get; set; }
public SnmpV2Message()
:base(SnmpVersion.V2c)
{
}
public SnmpV2Message(ASN1Value value)
:this()
{
snmpCommunity = (OctetString)value.Items[1];
Logging.Log(LogLevel.DEBUG, "ASN1Value->PDU: {0}", value.Items[2]);
snmpPDU = (PDU)value.Items[2];
Logging.Log(LogLevel.DEBUG, "PDU: {0}", snmpPDU);
}
public override Variable[] Items
{
get => new Variable[] { new Integer((int)SnmpVersion), snmpCommunity, snmpPDU };
set
{
snmpCommunity = value[1] as OctetString;
snmpPDU = value[2] as PDU;
}
}
public override int MessageID
{
get => (int)snmpPDU.RequestID.LongValue;
set => snmpPDU.RequestID.LongValue = value;
}
}
}

110
types/USMMessage.cs 100644
View File

@ -0,0 +1,110 @@
// /**
// * File: USMMessage.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 ln.snmp.asn1;
using System.Linq;
using ln.snmp.channel;
namespace ln.snmp.types
{
public class USMMessage : SnmpMessage
{
public SnmpV3AuthMethod AuthMethod { get; set; }
public SnmpV3PrivMethod PrivMethod { get; set; }
public Integer msgVersion { get; } = new Integer(3);
public MsgGlobalData msgGlobalData { get; set; }
public UsmSecurityParameters SecurityParameters { get; set; }
public Variable msgData { get; set; }
public USMMessage()
: base(SnmpVersion.V3)
{
msgGlobalData = new MsgGlobalData();
SecurityParameters = new UsmSecurityParameters();
msgData = new NullValue();
}
public USMMessage(ASN1Value asn)
:this()
{
Items = asn.Items.Select((x) => (Variable)x).ToArray();
}
public override Variable[] Items
{
get => new Variable[] {
msgVersion,
msgGlobalData,
new OctetString(((ASN1Value)SecurityParameters).AsByteArray),
msgData
};
set
{
msgGlobalData = new MsgGlobalData(value[1]);
SecurityParameters = new UsmSecurityParameters(new ASN1Value(value[2].Bytes));
msgData = value[3];
}
}
public override int MessageID
{
get => (int)msgGlobalData.msgID.LongValue;
set => msgGlobalData.msgID.LongValue = value;
}
public override void Add(Variable item)
{
throw new NotImplementedException();
}
public override void Remove(Variable item)
{
throw new NotImplementedException();
}
public class MsgGlobalData : AbstractSequence
{
public Integer msgID { get; set; }
public Integer msgMaxSize { get; set; }
public OctetString msgFlags { get; set; }
public Integer msgSecurityModel { get; set; }
public MsgGlobalData()
:base(new Identifier(IdentifierClass.UNIVERSAL,true,0x10))
{
msgID = new Integer((int)(DateTimeOffset.Now.ToUnixTimeSeconds()));
msgMaxSize = new Integer(65000);
msgFlags = new OctetString("\0");
msgSecurityModel = new Integer(3);
}
public MsgGlobalData(ASN1Value asn)
:this()
{
}
public override void Add(Variable item) => throw new NotImplementedException();
public override void Remove(Variable item) => throw new NotImplementedException();
public override Variable[] Items
{
get => new Variable[] { msgID,msgMaxSize,msgFlags,msgSecurityModel };
set
{
msgID = value[0] as Integer;
msgMaxSize = value[1] as Integer;
msgFlags = value[2] as OctetString;
msgSecurityModel = value[3] as Integer;
}
}
}
}
}

View File

@ -0,0 +1,69 @@
// /**
// * File: UsmSecurityParameters.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 ln.snmp.asn1;
using System.Linq;
namespace ln.snmp.types
{
public class UsmSecurityParameters : AbstractSequence
{
public OctetString msgAuthoritativeEngineID { get; set; }
public Integer msgAuthoritativeEngineBoots { get; set; }
public Integer msgAuthoritativeEngineTime { get; set; }
public OctetString msgUserName { get; set; }
public OctetString msgAuthenticationParameters { get; set; }
public OctetString msgPrivacyParameters { get; set; }
public UsmSecurityParameters()
:base(new Identifier(IdentifierClass.UNIVERSAL,true,0x10))
{
msgAuthoritativeEngineID = new OctetString();
msgAuthoritativeEngineBoots = new Integer();
msgAuthoritativeEngineTime = new Integer();
msgUserName = new OctetString();
msgAuthenticationParameters = new OctetString();
msgPrivacyParameters = new OctetString();
}
public UsmSecurityParameters(ASN1Value asn)
:base(asn.Identifier)
{
Items = asn.Items.Select((x) => (Variable)x).ToArray();
}
public override Variable[] Items
{
get => new Variable[] {
msgAuthoritativeEngineID,
msgAuthoritativeEngineBoots,
msgAuthoritativeEngineTime,
msgUserName,
msgAuthenticationParameters,
msgPrivacyParameters
};
set
{
msgAuthoritativeEngineID = value[0] as OctetString;
msgAuthoritativeEngineBoots = value[1] as Integer;
msgAuthoritativeEngineTime = value[2] as Integer;
msgUserName = value[3] as OctetString;
msgAuthenticationParameters = value[4] as OctetString;
msgPrivacyParameters = value[5] as OctetString;
}
}
public override void Add(Variable item) => throw new NotImplementedException();
public override void Remove(Variable item) => throw new NotImplementedException();
}
}

51
types/V3Packet.cs 100644
View File

@ -0,0 +1,51 @@
// /**
// * File: V3Packet.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.Runtime.Remoting.Messaging;
namespace ln.snmp.types
{
public class V3Packet : AbstractSequence
{
public Integer msgVersion { get; }
public Sequence msgGlobalData { get; }
public Integer msgID { get; }
public Integer msgMaxSize { get; }
public OctetString msgFlags { get; }
public Integer msgSecurityModel { get; }
public V3Packet()
:base(new Identifier(IdentifierClass.UNIVERSAL,true,0x10))
{
msgVersion = new Integer(3);
msgGlobalData = new Sequence();
msgID = new Integer(DateTimeOffset.Now.ToUnixTimeSeconds());
msgMaxSize = new Integer(65000);
msgSecurityModel = new Integer(3);
}
public override Variable[] Items
{
get => throw new NotImplementedException();
set => throw new NotImplementedException();
}
public override void Add(Variable item)
{
throw new NotImplementedException();
}
public override void Remove(Variable item)
{
throw new NotImplementedException();
}
}
}

View File

@ -9,6 +9,12 @@
// **/
using System;
using System.IO;
using ln.snmp.asn1;
using ln.logging;
using System.Collections.Generic;
using System.CodeDom;
using System.Reflection;
using System.Linq;
namespace ln.snmp.types
{
public abstract class Variable
@ -23,96 +29,110 @@ namespace ln.snmp.types
public abstract byte[] Bytes { get; set; }
public abstract object Value { get; set; }
public virtual void Write(Stream stream)
public void Dump()
{
byte[] payload = Bytes;
BasicEncodingRules.WriteIdentifier(stream,Identifier);
BasicEncodingRules.WriteLength(stream, payload.Length);
stream.Write(payload, 0, payload.Length);
Dump("");
}
public byte[] ToBytes()
public void Dump(string prefix)
{
MemoryStream memoryStream = new MemoryStream();
Write(memoryStream);
return memoryStream.ToArray();
}
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 Variable Read(byte[] bytes)
{
MemoryStream stream = new MemoryStream(bytes);
return Read(stream);
}
public static void Write(Stream stream,Variable variable)
{
variable.Write(stream);
}
public static Variable FromIdentifier(Identifier identifier)
{
if (identifier.IdentifierClass == IdentifierClass.UNIVERSAL)
if (this is AbstractSequence)
{
switch (identifier.Number)
AbstractSequence sequence = this as AbstractSequence;
Logging.Log(LogLevel.DEBUG, "{0}{1}", prefix, this.ToString());
foreach (Variable item in sequence.Items)
{
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();
if (item != null)
item.Dump(prefix + " ");
else
Logging.Log(LogLevel.DEBUG, "{0}NULL", prefix);
}
}
else if (identifier.IdentifierClass == IdentifierClass.CONTEXT)
else
{
switch (identifier.Number)
{
case 0x00:
return new GetRequest();
case 0x02:
return new GetResponse();
case 0x03:
return new SetRequest();
}
Logging.Log(LogLevel.DEBUG, "{0}{1} {2}", prefix, this.ToString(), BitConverter.ToString(this.Bytes));
}
else if (identifier.IdentifierClass == IdentifierClass.APPLICATION)
{
switch (identifier.Number)
{
case 0x01:
return new Counter32();
case 0x02:
return new Unsigned32();
case 0x06:
return new Counter64();
}
}
throw new NotSupportedException(String.Format("Unsupported ASN Type: {0}",identifier));
}
public static implicit operator ASN1Value(Variable variable)
{
ASN1Value value = new ASN1Value(variable.Identifier);
if (variable is AbstractSequence)
{
AbstractSequence sequence = variable as AbstractSequence;
foreach (Variable item in sequence.Items)
value.Add(item);
}
else
{
value.Bytes = variable.Bytes;
}
return value;
}
public static implicit operator Variable(ASN1Value value)
{
try
{
if (knownTypes.ContainsKey(value.Identifier))
{
Type type = knownTypes[value.Identifier];
//Logging.Log(LogLevel.DEBUGDETAIL, "ASN1Value->Variable: {0} -> {1}", value, type.Name);
Variable variable = Activator.CreateInstance(type,true) as Variable;
if (variable is AbstractSequence)
{
AbstractSequence sequence = variable as AbstractSequence;
sequence.Items = value.Items.Select((x) => (Variable)x).ToArray();
}
else
{
variable.Bytes = value.Bytes;
}
return variable;
}
throw new ArgumentException(String.Format("{0}",value.Identifier),nameof(value));
}
catch (Exception e)
{
Logging.Log(e);
throw e;
}
}
static Dictionary<Identifier, Type> knownTypes = new Dictionary<Identifier, Type>();
static bool __initialized__ = initialize();
static void registerKnownType<T>() where T:Variable, new()
{
T i = new T();
knownTypes.Add(i.Identifier, typeof(T));
}
static bool initialize()
{
registerKnownType<NullValue>();
registerKnownType<Boolean>();
registerKnownType<Integer>();
registerKnownType<OctetString>();
registerKnownType<Unsigned32>();
registerKnownType<Counter32>();
registerKnownType<Counter64>();
registerKnownType<Sequence>();
registerKnownType<ObjectIdentifier>();
registerKnownType<GetRequest>();
registerKnownType<GetNextRequest>();
registerKnownType<GetResponse>();
registerKnownType<GetBulkRequest>();
registerKnownType<Report>();
return true;
}
}
}