using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; namespace Unosquare.Swan.Networking { /// /// Represents a little SNMP client based on http://www.java2s.com/Code/CSharp/Network/SimpleSNMP.htm. /// public static class SnmpClient { private static readonly Byte[] DiscoverMessage = { 48, 41, 2, 1, 1, 4, 6, 112, 117, 98, 108, 105, 99, 160, 28, 2, 4, 111, 81, 45, 144, 2, 1, 0, 2, 1, 0, 48, 14, 48, 12, 6, 8, 43, 6, 1, 2, 1, 1, 1, 0, 5, 0, }; /// /// Discovers the specified SNMP time out. /// /// The SNMP time out. /// An array of network endpoint as an IP address and a port number. public static IPEndPoint[] Discover(Int32 snmpTimeOut = 6000) { List endpoints = new List(); Task[] tasks = { Task.Run(async () => { using (UdpClient udp = new UdpClient(IPAddress.Broadcast.AddressFamily)) { udp.EnableBroadcast = true; await udp.SendAsync( DiscoverMessage, DiscoverMessage.Length, new IPEndPoint(IPAddress.Broadcast, 161)); while (true) { try { Byte[] buffer = new Byte[udp.Client.ReceiveBufferSize]; EndPoint remote = new IPEndPoint(IPAddress.Any, 0); udp.Client.ReceiveFrom(buffer, ref remote); endpoints.Add(remote as IPEndPoint); } catch { break; } } #if NET452 udp.Close(); #endif } }), Task.Delay(snmpTimeOut), }; Task.WaitAny(tasks); return endpoints.ToArray(); } /// /// Gets the name of the public. /// /// The host. /// /// A string that contains the results of decoding the specified sequence /// of bytes ref=GetString". /// public static String GetPublicName(IPEndPoint host) => GetString(host, "1.3.6.1.2.1.1.5.0"); /// /// Gets the up-time. /// /// The host. /// The mibString. /// /// A time interval that represents a specified number of seconds, /// where the specification is accurate to the nearest millisecond. /// public static TimeSpan GetUptime(IPEndPoint host, String mibString = "1.3.6.1.2.1.1.3.0") { Byte[] response = Get(host, mibString); if(response[0] == 0xff) { return TimeSpan.Zero; } // If response, get the community name and MIB lengths Int16 commlength = Convert.ToInt16(response[6]); Int16 miblength = Convert.ToInt16(response[23 + commlength]); // Extract the MIB data from the SNMP response Int16 datalength = Convert.ToInt16(response[25 + commlength + miblength]); Int32 datastart = 26 + commlength + miblength; Int32 uptime = 0; while(datalength > 0) { uptime = (uptime << 8) + response[datastart++]; datalength--; } return TimeSpan.FromSeconds(uptime); } /// /// Gets the string. /// /// The host. /// The mibString. /// A that contains the results of decoding the specified sequence of bytes. public static String GetString(IPEndPoint host, String mibString) { Byte[] response = Get(host, mibString); if(response[0] == 0xff) { return String.Empty; } // If response, get the community name and MIB lengths Int16 commlength = Convert.ToInt16(response[6]); Int16 miblength = Convert.ToInt16(response[23 + commlength]); // Extract the MIB data from the SNMP response Int16 datalength = Convert.ToInt16(response[25 + commlength + miblength]); Int32 datastart = 26 + commlength + miblength; return Encoding.ASCII.GetString(response, datastart, datalength); } /// /// Gets the specified host. /// /// The host. /// The mibString. /// A byte array containing the results of encoding the specified set of characters. public static Byte[] Get(IPEndPoint host, String mibString) => Get("get", host, "public", mibString); /// /// Gets the specified request. /// /// The request. /// The host. /// The community. /// The mibString. /// A byte array containing the results of encoding the specified set of characters. public static Byte[] Get(String request, IPEndPoint host, String community, String mibString) { Byte[] packet = new Byte[1024]; Byte[] mib = new Byte[1024]; Int32 comlen = community.Length; String[] mibvals = mibString.Split('.'); Int32 miblen = mibvals.Length; Int32 cnt = 0; Int32 orgmiblen = miblen; Int32 pos = 0; // Convert the string MIB into a byte array of integer values // Unfortunately, values over 128 require multiple bytes // which also increases the MIB length for(Int32 i = 0; i < orgmiblen; i++) { Int32 temp = Convert.ToInt16(mibvals[i]); if(temp > 127) { mib[cnt] = Convert.ToByte(128 + temp / 128); mib[cnt + 1] = Convert.ToByte(temp - temp / 128 * 128); cnt += 2; miblen++; } else { mib[cnt] = Convert.ToByte(temp); cnt++; } } Int32 snmplen = 29 + comlen + miblen - 1; // The SNMP sequence start packet[pos++] = 0x30; // Sequence start packet[pos++] = Convert.ToByte(snmplen - 2); // sequence size // SNMP version packet[pos++] = 0x02; // Integer type packet[pos++] = 0x01; // length packet[pos++] = 0x00; // SNMP version 1 // Community name packet[pos++] = 0x04; // String type packet[pos++] = Convert.ToByte(comlen); // length // Convert community name to byte array Byte[] data = Encoding.ASCII.GetBytes(community); foreach(Byte t in data) { packet[pos++] = t; } // Add GetRequest or GetNextRequest value packet[pos++] = request == "get" ? (Byte)0xA0 : (Byte)0xA1; packet[pos++] = Convert.ToByte(20 + miblen - 1); // Size of total MIB // Request ID packet[pos++] = 0x02; // Integer type packet[pos++] = 0x04; // length packet[pos++] = 0x00; // SNMP request ID packet[pos++] = 0x00; packet[pos++] = 0x00; packet[pos++] = 0x01; // Error status packet[pos++] = 0x02; // Integer type packet[pos++] = 0x01; // length packet[pos++] = 0x00; // SNMP error status // Error index packet[pos++] = 0x02; // Integer type packet[pos++] = 0x01; // length packet[pos++] = 0x00; // SNMP error index // Start of variable bindings packet[pos++] = 0x30; // Start of variable bindings sequence packet[pos++] = Convert.ToByte(6 + miblen - 1); // Size of variable binding packet[pos++] = 0x30; // Start of first variable bindings sequence packet[pos++] = Convert.ToByte(6 + miblen - 1 - 2); // size packet[pos++] = 0x06; // Object type packet[pos++] = Convert.ToByte(miblen - 1); // length // Start of MIB packet[pos++] = 0x2b; // Place MIB array in packet for(Int32 i = 2; i < miblen; i++) { packet[pos++] = Convert.ToByte(mib[i]); } packet[pos++] = 0x05; // Null object value packet[pos] = 0x00; // Null // Send packet to destination SendPacket(host, packet, snmplen); return packet; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Codequalität", "IDE0067:Objekte verwerfen, bevor Bereich verloren geht", Justification = "")] private static void SendPacket(IPEndPoint host, Byte[] packet, Int32 length) { Socket sock = new Socket( AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); sock.SetSocketOption( SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 5000); EndPoint ep = (EndPoint)host; _ = sock.SendTo(packet, length, SocketFlags.None, host); // Receive response from packet try { _ = sock.ReceiveFrom(packet, ref ep); } catch(SocketException) { packet[0] = 0xff; } } } }