Skip to content

Commit 4e09fee

Browse files
committed
Topology, SNMP
1 parent 5eb7c66 commit 4e09fee

File tree

4 files changed

+127
-45
lines changed

4 files changed

+127
-45
lines changed

Protest/Front/topology.css

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,20 @@
2020
overflow-y: auto;
2121
}
2222

23+
.topology-interface-list {
24+
margin-top: 16px;
25+
}
26+
27+
.topology-interface-list > div {
28+
margin: 2px;
29+
padding: 4px;
30+
border-radius: 2px;
31+
}
32+
33+
.topology-interface-list > div:hover {
34+
background-color: var(--clr-highlight);
35+
}
36+
2337
.topology-sidebar-grid {
2438
display: grid;
2539

Protest/Front/topology.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,8 +345,10 @@ class Topology extends Window {
345345
}
346346
}
347347
else if (json.snmp) {
348-
const device = this.devices[json.snmp];
348+
const device = this.devices[json.snmp.file];
349349
if (device) {
350+
device.snmp = json.snmp;
351+
350352
device.element.icon.classList.remove("topology-loading");
351353
setTimeout(()=>{
352354
device.element.icon.style.fill = "#c0c0c0";
@@ -462,6 +464,18 @@ class Topology extends Window {
462464
ipLabel.style.gridArea = "3 / 2";
463465
ipLabel.textContent = initial.ip;
464466
grid.appendChild(ipLabel);
467+
468+
if (file in this.devices && this.devices[file].snmp) {
469+
const intList = document.createElement("div");
470+
intList.className = "topology-interface-list";
471+
this.sideBar.appendChild(intList);
472+
473+
for (let i=0; i<this.devices[file].snmp.localPortName.length; i++) {
474+
const interfaceBox = document.createElement("div");
475+
interfaceBox.textContent = this.devices[file].snmp.localPortName[i];
476+
intList.appendChild(interfaceBox);
477+
}
478+
}
465479
}
466480

467481
AdjustSvgSize() {

Protest/Protocols/Snmp.Polling.cs

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -246,39 +246,45 @@ public static IList<Variable> SnmpRequestV3(IPEndPoint endpoint, int timeout, To
246246
}
247247
}
248248

249-
public static Dictionary<string, string> ParseResponse(IList<Variable> result) {
249+
public static Dictionary<string, string>ParseResponse(IList<Variable> result, bool preserveOctet = false) {
250250
if (result is null || result.Count == 0) {
251251
return null;
252252
}
253253

254254
Dictionary<string, string> data = new Dictionary<string, string>();
255255

256256
for (int i = 0; i < result.Count; i++) {
257-
string value;
258-
if (result[i].Data.TypeCode == SnmpType.Null ||
259-
result[i].Data.TypeCode == SnmpType.NoSuchObject ||
260-
result[i].Data.TypeCode == SnmpType.NoSuchInstance) {
261-
continue;
257+
string value = ParseVariable(result[i], preserveOctet);
258+
if (value is null) continue;
259+
data.Add(result[i].Id.ToString(), value);
260+
}
261+
262+
return data;
263+
}
264+
265+
public static string ParseVariable(Variable variable, bool preserveOctet = false) {
266+
if (variable.Data.TypeCode == SnmpType.Null ||
267+
variable.Data.TypeCode == SnmpType.NoSuchObject ||
268+
variable.Data.TypeCode == SnmpType.NoSuchInstance) {
269+
return null;
270+
}
271+
else if (variable.Data.TypeCode == SnmpType.OctetString) {
272+
if (preserveOctet) {
273+
return variable.Data.ToString();
262274
}
263-
else if (result[i].Data.TypeCode == SnmpType.OctetString) {
264-
byte[] bytes = result[i].Data.ToBytes();
275+
else {
276+
byte[] bytes = variable.Data.ToBytes();
265277
for (int j = 0; j < bytes.Length; j++) {
266278
if (bytes[j] < 32) { bytes[j] = (byte)' '; }
267279
else if (bytes[j] > 126) { bytes[j] = (byte)' '; }
268280
}
269281

270-
value = Encoding.UTF8.GetString(bytes).Trim();
271-
}
272-
else {
273-
value = result[i].Data.ToString().Trim();
282+
return Encoding.UTF8.GetString(bytes).Trim();
274283
}
275-
276-
if (String.IsNullOrEmpty(value)) { continue; }
277-
278-
data.Add(result[i].Id.ToString(), value);
279284
}
280-
281-
return data;
285+
else {
286+
return variable.Data.ToString().Trim();
287+
}
282288
}
283289

284290
private static byte[] ParseResponseToBytes(IList<Variable> result) {

Protest/Tools/Topology.cs

Lines changed: 74 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
using System.Text.Json;
66
using System.Threading;
77
using System.Threading.Tasks;
8+
using Protest.Http;
89
using Protest.Protocols.Snmp;
910
using Lextm.SharpSnmpLib;
10-
using Protest.Http;
1111

1212
namespace Protest.Tools;
1313

@@ -89,19 +89,17 @@ internal static async void WebSocketHandler(HttpListenerContext ctx) {
8989
if (IPAddress.TryParse(ipString, out IPAddress ipAddress)) {
9090
await WsWriteText(ws, System.Text.Encoding.UTF8.GetBytes($"{{\"retrieve\":\"{candidates[i].filename}\"}}"));
9191

92-
Dictionary<string, string> local = Polling.ParseResponse(
93-
Polling.SnmpQuery(ipAddress, snmpProfile, [Oid.LLDP_LOCAL_SYS_DATA], Polling.SnmpOperation.Walk)
94-
);
92+
IList<Variable> rawLocal = Polling.SnmpQuery(ipAddress, snmpProfile, [Oid.LLDP_LOCAL_SYS_DATA], Polling.SnmpOperation.Walk);
93+
//Dictionary<string, string> local = Polling.ParseResponse(rawLocal, true);
9594

96-
Dictionary<string, string> remote = Polling.ParseResponse(
97-
Polling.SnmpQuery(ipAddress, snmpProfile, [Oid.LLDP_REMOTE_SYS_DATA], Polling.SnmpOperation.Walk)
98-
);
95+
IList<Variable> rawRemote = Polling.SnmpQuery(ipAddress, snmpProfile, [Oid.LLDP_REMOTE_SYS_DATA], Polling.SnmpOperation.Walk);
96+
//Dictionary<string, string> remote = Polling.ParseResponse(rawRemote, true);
9997

100-
if (local is null || local.Count == 0 || remote is null || remote.Count == 0) {
98+
if (rawLocal is null || rawLocal.Count == 0 || rawRemote is null || rawRemote.Count == 0) {
10199
await WsWriteText(ws, System.Text.Encoding.UTF8.GetBytes($"{{\"nosnmp\":\"{candidates[i].filename}\"}}"));
102100
}
103101
else {
104-
byte[] response = ComputeSnmpResponse(candidates[i].filename, local, remote);
102+
byte[] response = ComputeSnmpResponse(candidates[i].filename, rawLocal, rawRemote);
105103
await WsWriteText(ws, response);
106104
}
107105
}
@@ -120,60 +118,110 @@ internal static async void WebSocketHandler(HttpListenerContext ctx) {
120118
}
121119
}
122120

123-
private static byte[] ComputeSnmpResponse(string file, Dictionary<string, string> local, Dictionary<string, string> remote) {
124-
local.TryGetValue("1.0.8802.1.1.2.1.3.1.0", out string idSuptype);
125-
local.TryGetValue("1.0.8802.1.1.2.1.3.2.0", out string id);
126-
local.TryGetValue("1.0.8802.1.1.2.1.3.3.0", out string hostname);
127-
local.TryGetValue("1.0.8802.1.1.2.1.3.4.0", out string description);
121+
private static byte[] ComputeSnmpResponse(string file, IList<Variable> rawLocal, IList<Variable> rawRemote) {
122+
123+
Dictionary<string, Variable> local = new Dictionary<string, Variable>();
124+
for (int i = 0; i < rawLocal.Count; i++) {
125+
local.Add(rawLocal[i].Id.ToString(), rawLocal[i]);
126+
}
127+
128+
Dictionary<string, Variable> remote = new Dictionary<string, Variable>();
129+
for (int i = 0; i < rawRemote.Count; i++) {
130+
remote.Add(rawRemote[i].Id.ToString(), rawRemote[i]);
131+
}
132+
133+
local.TryGetValue("1.0.8802.1.1.2.1.3.1.0", out Variable localChassisIdSuptype);
134+
local.TryGetValue("1.0.8802.1.1.2.1.3.2.0", out Variable localChassisId);
135+
local.TryGetValue("1.0.8802.1.1.2.1.3.3.0", out Variable localHostname);
136+
local.TryGetValue("1.0.8802.1.1.2.1.3.4.0", out Variable localDescription);
128137

129138
List<(int, string)> localPortIdSuptype = new List<(int, string)>();
130139
List<(int, string)> localPortId = new List<(int, string)>();
140+
List<(int, string)> localPortName = new List<(int, string)>();
131141

132142
List<(int, string)> remoteChassisIdSuptype = new List<(int, string)>();
133143
List<(int, string)> remoteChassisId = new List<(int, string)>();
134144
List<(int, string)> remotePortIdSuptype = new List<(int, string)>();
135145
List<(int, string)> remotePortId = new List<(int, string)>();
136146
List<(int, string)> remoteSystemName = new List<(int, string)>();
137147

138-
foreach (KeyValuePair<string, string> pair in local) {
148+
foreach (KeyValuePair<string, Variable> pair in local) {
139149
if (!int.TryParse(pair.Key.Split('.')[^1], out int index)) continue;
140150

141151
if (pair.Key.StartsWith("1.0.8802.1.1.2.1.3.7.1.2")) {
142-
localPortIdSuptype.Add((index, pair.Value));
152+
localPortIdSuptype.Add((index, pair.Value.Data.ToString()));
143153
}
144154
else if (pair.Key.StartsWith("1.0.8802.1.1.2.1.3.7.1.3")) {
145-
localPortId.Add((index, pair.Value));
155+
localPortId.Add((index, pair.Value.Data.ToString()));
156+
}
157+
else if (pair.Key.StartsWith("1.0.8802.1.1.2.1.3.7.1.4")) {
158+
localPortName.Add((index, pair.Value.Data.ToString()));
146159
}
147160
}
148161

149-
foreach (KeyValuePair<string, string> pair in remote) {
162+
foreach (KeyValuePair<string, Variable> pair in remote) {
150163
if (!int.TryParse(pair.Key.Split('.')[^2], out int index)) continue;
151164

152165
if (pair.Key.StartsWith("1.0.8802.1.1.2.1.4.1.1.4")) {
153-
remoteChassisIdSuptype.Add((index, pair.Value));
166+
remoteChassisIdSuptype.Add((index, pair.Value.Data.ToString()));
154167
}
155168
else if (pair.Key.StartsWith("1.0.8802.1.1.2.1.4.1.1.5")) {
156-
remoteChassisId.Add((index, pair.Value));
169+
remoteChassisId.Add((index, pair.Value.Data.ToString()));
157170
}
158171
if (pair.Key.StartsWith("1.0.8802.1.1.2.1.4.1.1.6")) {
159-
remotePortIdSuptype.Add((index, pair.Value));
172+
remotePortIdSuptype.Add((index, pair.Value.Data.ToString()));
160173
}
161174
else if (pair.Key.StartsWith("1.0.8802.1.1.2.1.4.1.1.7")) {
162-
remotePortId.Add((index, pair.Value));
175+
remotePortId.Add((index, pair.Value.Data.ToString()));
163176
}
164177
else if (pair.Key.StartsWith("1.0.8802.1.1.2.1.4.1.1.9")) {
165-
remoteSystemName.Add((index, pair.Value));
178+
remoteSystemName.Add((index, pair.Value.Data.ToString()));
166179
}
167180
}
168181

169182
byte[] payload = JsonSerializer.SerializeToUtf8Bytes(new {
170-
switchInfo = new {
171-
localPortIdSuptype = localPortIdSuptype,
172-
localPortId = localPortId
183+
snmp = new {
184+
file = file,
185+
localChassisId = GetChassisId(localChassisIdSuptype.Data.ToString(), localChassisId.Data),
186+
localPortIdSuptype = localPortIdSuptype.Select(o=>o.Item2),
187+
localPortId = localPortId.Select(o=>o.Item2),
188+
localPortName = localPortName.Select(o=>o.Item2)
173189
}
174190
});
175191

176192
return payload;
177193
}
178194

195+
private static string GetChassisId(string subtype, ISnmpData value) {
196+
byte[] bytes = value.ToBytes();
197+
198+
switch (subtype) {
199+
case "4": //mac address
200+
if (bytes.Length - 2 == 6) {
201+
return $"{(bytes[2]).ToString("X2")}:{(bytes[3]).ToString("X2")}:{(bytes[4]).ToString("X2")}:{(bytes[5]).ToString("X2")}:{(bytes[6]).ToString("X2")}:{(bytes[7]).ToString("X2")}";
202+
}
203+
return value.ToString();
204+
205+
case "5": //network address
206+
if (bytes.Length - 2 == 4) {
207+
return $"{bytes[2]}.{bytes[3]}.{bytes[4]}.{bytes[5]}";
208+
}
209+
else if (bytes.Length - 2 == 16) {
210+
return $"""
211+
{bytes[2].ToString("x2")}){bytes[3].ToString("x2")}:
212+
{bytes[4].ToString("x2")}){bytes[5].ToString("x2")}:
213+
{bytes[6].ToString("x2")}){bytes[7].ToString("x2")}:
214+
{bytes[8].ToString("x2")}){bytes[9].ToString("x2")}:
215+
{bytes[10].ToString("x2")}){bytes[11].ToString("x2")}:
216+
{bytes[12].ToString("x2")}){bytes[13].ToString("x2")}:
217+
{bytes[14].ToString("x2")}){bytes[15].ToString("x2")}:
218+
{bytes[16].ToString("x2")}){bytes[17].ToString("x2")}
219+
""";
220+
}
221+
return value.ToString();
222+
223+
default: return value.ToString();
224+
}
225+
}
226+
179227
}

0 commit comments

Comments
 (0)