Skip to content

Commit 52653bf

Browse files
Add Sample app, fix error in encoding, add SHA224 (#3)
* Sample app * Ensured proper length calculation and that header is written first * Small decode optimization for Counter64 * SHA224 + a lot of tests * Added changelog
1 parent a21aeac commit 52653bf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+2224
-329
lines changed

CHANGES.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
0.9.7
1+
0.9.8-wmo1
2+
* Added SHA224 authentication
3+
* Fixed a bug in null-object encoding
4+
* Added more tests and performance improvements.
5+
0.9.7-wmo1
26
* Changed target framework to .NET 9
37
* Added span-based API's to many of the types encode and decode functions
48
* Added tests and benchmarking capabilities

SampleApp/HighLevelClient.cs

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
using Microsoft.Extensions.Logging;
2+
using SnmpSharpNet;
3+
4+
namespace SampleApp;
5+
6+
public class HighLevelSnmpClient(UdpTarget target, IAgentParameters parameters, ILogger? logger)
7+
{
8+
private const int SnmpTimeout = 4000;
9+
10+
public AsnType QuerySingleValueAsync(Oid oid)
11+
{
12+
var pdu = new Pdu(PduType.Get)
13+
{
14+
RequestId = Random.Shared.Next()
15+
};
16+
17+
pdu.VbList.Add(oid);
18+
19+
SnmpPacket? result;
20+
try
21+
{
22+
result = target.Request(pdu, parameters);
23+
if (result == null)
24+
{
25+
logger?.LogWarning("Unintelligible SNMP packet returned from {Address}", target.Address);
26+
throw new IOException($"Unrecognized SNMP packet received from {target.Address}");
27+
}
28+
}
29+
catch (Exception e)
30+
{
31+
Log(pdu, e);
32+
logger?.LogDebug("SNMP Get request failed for {Oid} on {Address}: {Exception}", oid, target.Address, e);
33+
throw new TimeoutException();
34+
}
35+
36+
// ErrorStatus other than 0 is an error returned by
37+
// the Agent - see SnmpConstants for error definitions
38+
if (result.Pdu.ErrorStatus != 0)
39+
{
40+
// agent reported an error with the request
41+
logger?.LogWarning("Error in SNMP Get reply. Error {Status} index {Index}", result.Pdu.ErrorStatus,
42+
result.Pdu.ErrorIndex);
43+
throw new IOException($"SNMP error: {result.Pdu.ErrorStatus} ({result.Pdu.ErrorIndex})");
44+
}
45+
46+
Log(pdu, result);
47+
48+
return result.Pdu.VbList.Single().Value!;
49+
}
50+
51+
public Vb[] QueryMultipleValues(params IEnumerable<Oid> oids)
52+
{
53+
var pdu = new Pdu(PduType.Get)
54+
{
55+
RequestId = Random.Shared.Next()
56+
};
57+
foreach (var oid in oids)
58+
{
59+
pdu.VbList.Add(oid);
60+
}
61+
62+
SnmpPacket? result;
63+
var start = DateTime.UtcNow;
64+
try
65+
{
66+
result = target.Request(pdu, parameters);
67+
if (result == null)
68+
{
69+
logger?.LogWarning("Unintelligible SNMP packet returned from {Address}", target.Address);
70+
throw new IOException($"Unrecognized SNMP packet received from {target.Address}");
71+
}
72+
}
73+
catch (OperationCanceledException ex)
74+
{
75+
Log(pdu, ex);
76+
logger?.LogWarning(
77+
"SnmpClient.QueryMultipleValuesAsync was cancelled. CancellationToken.IsCancellationRequested = {CancellationState}",
78+
false);
79+
var end = DateTime.UtcNow - start;
80+
if (end.TotalMilliseconds >= SnmpTimeout)
81+
{
82+
throw new TimeoutException();
83+
}
84+
85+
throw;
86+
}
87+
catch (Exception e)
88+
{
89+
Log(pdu, e);
90+
logger?.LogDebug("SNMP Get multiple requests failed for {{ {PDU} }} on {Address}: {ErrorMessage}", pdu,
91+
target.Address,
92+
e);
93+
throw new TimeoutException();
94+
}
95+
96+
// ErrorStatus other than 0 is an error returned by
97+
// the Agent - see SnmpConstants for error definitions
98+
if (result.Pdu.ErrorStatus != 0)
99+
{
100+
// agent reported an error with the request
101+
// However, in some case we get answers, but one of the values in the returned array is wrong.
102+
// Any errors in the returned values are handled by the caller of this function.
103+
104+
logger?.LogWarning("Error in SNMP Get reply. Error {ErrorStatus} index {ErrorIndex}",
105+
result.Pdu.ErrorStatus, result.Pdu.ErrorIndex);
106+
}
107+
108+
Log(pdu, result);
109+
110+
return result.Pdu.VbList.ToArray();
111+
}
112+
113+
private void Log(Pdu pdu, Exception exception)
114+
{
115+
logger?.LogDebug("SNMP Error for {address}: {ErrorMessage}: {PDU}", target.Address, exception.Message, pdu);
116+
}
117+
118+
private void Log(Pdu pdu, SnmpPacket snmpPacket)
119+
{
120+
logger?.LogDebug("SNMP Response for {address}: {Status}:\nRequest: {PDU}\nResponse:{Packet}", target.Address,
121+
snmpPacket.Pdu.ErrorStatus == 0 ? "Good" : "Bad", pdu, snmpPacket);
122+
}
123+
124+
public IDictionary<Oid, AsnType?> WalkTree(Oid oid)
125+
{
126+
var treeData = new Dictionary<Oid, AsnType?>();
127+
var rootOid = oid;
128+
var lastOid = (Oid)rootOid.Clone();
129+
130+
var pdu = new Pdu(PduType.GetBulk)
131+
{
132+
NonRepeaters = 0,
133+
MaxRepetitions = 30
134+
};
135+
136+
// Loop through results
137+
while (lastOid is not null)
138+
{
139+
pdu.RequestId = Random.Shared.Next();
140+
pdu.VbList.Clear();
141+
pdu.VbList.Add(lastOid);
142+
143+
// Make SNMP request
144+
SnmpPacket? result;
145+
try
146+
{
147+
result = target.Request(pdu, parameters);
148+
}
149+
catch (Exception e)
150+
{
151+
logger?.LogDebug("SNMP request failed for {Root} on {Address}: {ErrorMessage}", rootOid, target.Address,
152+
e.Message);
153+
throw;
154+
}
155+
156+
// If result is null then agent didn't reply or we couldn't parse the reply.
157+
if (result == null)
158+
{
159+
logger?.LogWarning("No response received from SNMP agent.");
160+
break;
161+
}
162+
163+
// ErrorStatus other then 0 is an error returned by
164+
// the Agent - see SnmpConstants for error definitions
165+
if (result.Pdu.ErrorStatus != 0)
166+
{
167+
// agent reported an error with the request
168+
logger?.LogWarning("Error in SNMP reply. Error {ErrorStatus} index {ErrorIndex}",
169+
result.Pdu.ErrorStatus, result.Pdu.ErrorIndex);
170+
break;
171+
}
172+
173+
// Walk through returned variable bindings
174+
foreach (var vb in result.Pdu.VbList)
175+
{
176+
// Check that retrieved Oid is "child" of the root OID
177+
if (rootOid.IsRootOf(vb.Oid!))
178+
{
179+
treeData[vb.Oid!] = vb.Value;
180+
181+
// Done?
182+
lastOid = vb.Value!.Type == SnmpConstants.SMI_ENDOFMIBVIEW
183+
? null
184+
: vb.Oid;
185+
}
186+
else
187+
{
188+
lastOid = null;
189+
}
190+
}
191+
}
192+
193+
return treeData;
194+
}
195+
}

SampleApp/Program.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// See https://aka.ms/new-console-template for more information
2+
3+
using System.Net;
4+
using Microsoft.Extensions.Logging;
5+
using SampleApp;
6+
using SnmpSharpNet;
7+
8+
var factory = LoggerFactory.Create(conf => conf.AddConsole().SetMinimumLevel(LogLevel.Debug));
9+
var logger = factory.CreateLogger<HighLevelSnmpClient>();
10+
using var target = new UdpTarget(IPAddress.Parse(args[0]), 161, 2000, 1);
11+
var parameters = new AgentParameters(SnmpVersion.Ver2, new OctetString("public"));
12+
var client = new HighLevelSnmpClient(target, parameters, logger);
13+
var result = client.WalkTree(new Oid("1"));
14+
foreach (var pair in result)
15+
{
16+
Console.WriteLine($"{pair.Key} => {pair.Value}");
17+
}

SampleApp/SampleApp.csproj

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net9.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<ProjectReference Include="..\src\SnmpSharpNet.csproj"/>
12+
</ItemGroup>
13+
14+
<ItemGroup>
15+
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.1" />
16+
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.1" />
17+
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.1" />
18+
</ItemGroup>
19+
20+
</Project>

benchmark/SnmpSharpNet.Benchmarks/Security/AuthenticationBenchmarks.cs

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,24 @@ namespace SnmpSharpNet.Tests.AuthenticationTests;
66
[MemoryDiagnoser]
77
public class AuthenticationBenchmarks
88
{
9-
private AuthenticationMD5 _md5;
10-
private AuthenticationSHA1 _sha1;
11-
private AuthenticationSHA256 _sha256;
12-
private AuthenticationSHA384 _sha384;
13-
private AuthenticationSHA512 _sha512;
14-
private byte[] _password;
15-
private byte[] _engineId;
9+
private AuthenticationMD5? _md5;
10+
private AuthenticationSHA1? _sha1;
11+
private AuthenticationSHA256? _sha256;
12+
private AuthenticationSHA384? _sha384;
13+
private AuthenticationSHA512? _sha512;
14+
private byte[]? _password;
15+
private byte[]? _engineId;
16+
private AuthenticationSHA224? _sha224;
1617

17-
[Params(11, 111, 1111)] public int passwordSize { get; set; }
18+
[Params(111)] public int passwordSize { get; set; }
1819

1920
[GlobalSetup]
2021
public void PasswordToKeyIsConsistent()
2122
{
2223
_md5 = new AuthenticationMD5();
2324
_sha1 = new AuthenticationSHA1();
2425
_sha256 = new AuthenticationSHA256();
26+
_sha224 = new AuthenticationSHA224();
2527
_sha384 = new AuthenticationSHA384();
2628
_sha512 = new AuthenticationSHA512();
2729

@@ -30,18 +32,21 @@ public void PasswordToKeyIsConsistent()
3032
_engineId = [0x80, 0x00, 0x13, 0x70, 0x02, 0x01];
3133
}
3234

33-
[Benchmark(Baseline = true)]
34-
public byte[] MD5() => _md5.PasswordToKey(_password, _engineId);
35+
// [Benchmark(Baseline = true)]
36+
// public byte[] MD5() => _md5!.PasswordToKey(_password, _engineId);
37+
//
38+
// [Benchmark]
39+
// public byte[] SHA1() => _sha1.PasswordToKey(_password, _engineId);
3540

3641
[Benchmark]
37-
public byte[] SHA1() => _sha1.PasswordToKey(_password, _engineId);
38-
39-
[Benchmark]
40-
public byte[] SHA256() => _sha256.PasswordToKey(_password, _engineId);
41-
42-
[Benchmark]
43-
public byte[] SHA384() => _sha384.PasswordToKey(_password, _engineId);
44-
45-
[Benchmark]
46-
public byte[] SHA512() => _sha512.PasswordToKey(_password, _engineId);
42+
public byte[] SHA224() => _sha224!.PasswordToKey(_password!, _engineId!);
43+
//
44+
// [Benchmark]
45+
// public byte[] SHA256() => _sha256.PasswordToKey(_password, _engineId);
46+
//
47+
// [Benchmark]
48+
// public byte[] SHA384() => _sha384.PasswordToKey(_password, _engineId);
49+
//
50+
// [Benchmark]
51+
// public byte[] SHA512() => _sha512.PasswordToKey(_password, _engineId);
4752
}

0 commit comments

Comments
 (0)