//****************************************************************************************************** // Snmp.cs - Gbtc // // Copyright © 2020, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this // file except in compliance with the License. You may obtain a copy of the License at: // // http://opensource.org/licenses/MIT // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 09/10/2020 - J. Ritchie Carroll // Generated original version of source code. // //****************************************************************************************************** using System; using System.Collections.Generic; using System.Globalization; using System.Net; using System.Threading.Tasks; using GSF.Configuration; using GSF.Diagnostics; using GSF.Net.Snmp.Messaging; using GSF.Net.Snmp.Security; using GSF.Security.Cryptography; namespace GSF.Net.Snmp { /// /// Exposes simple SNMP functionality for GSF. /// public static class Snmp { /// /// Defines default IP end point for SNMP client agent. /// public const string DefaultIPEndPoint = "127.0.0.1:162"; /// /// Root GSF OID (1.3.6.1.4.1.56056). This is the private enterprise number defined for the Grid Protection Alliance. /// public static readonly ObjectIdentifier EnterpriseRoot = new ObjectIdentifier(OID.EnterpriseRoot); /// /// GSF SNMP engine ID (D3F30A26E61843918ED5ABD87E). /// public static readonly OctetString EngineID = new OctetString(ByteTool.Convert("D3F30A26E61843918ED5ABD87E")); /// /// Sends an integer based SNMP version 3 trap. /// /// Target OID. /// Notification value. public static void SendTrap(uint[] oid, int value) => SendTrapAsync(oid, value).Wait(); /// /// Sends a floating-point based SNMP version 3 trap. /// /// Target OID. /// Notification value. /// /// SNMP does not support floating point values via binary encoding, so value is encoded as a string. /// public static void SendTrap(uint[] oid, double value) => SendTrapAsync(oid, value).Wait(); /// /// Sends a string based SNMP version 3 trap. /// /// Target OID. /// Notification value. public static void SendTrap(uint[] oid, string value) => SendTrapAsync(oid, value).Wait(); /// /// Sends an SNMP version 3 trap. /// /// Target OID. /// Notification data. public static void SendTrap(uint[] oid, ISnmpData data) => SendTrapAsync(oid, data).Wait(); /// /// Sends an SNMP version 3 trap. /// /// Variables. public static void SendTrap(params Variable[] variables) => SendTrapAsync(variables).Wait(); /// /// Sends an integer based SNMP version 3 trap. /// /// Target OID. /// Notification value. public static Task SendTrapAsync(uint[] oid, int value) => SendTrapAsync(oid, new Integer32(value)); /// /// Sends a floating-point based SNMP version 3 trap. /// /// Target OID. /// Notification value. /// /// SNMP does not support floating point values via binary encoding, so value is encoded as a string. /// public static Task SendTrapAsync(uint[] oid, double value) => SendTrapAsync(oid, new OctetString(value.ToString(CultureInfo.InvariantCulture))); /// /// Sends a string based SNMP version 3 trap. /// /// Target OID. /// Notification value. public static Task SendTrapAsync(uint[] oid, string value) => SendTrapAsync(oid, new OctetString(value)); /// /// Sends an SNMP version 3 trap. /// /// Target OID. /// Notification data. public static Task SendTrapAsync(uint[] oid, ISnmpData data) => SendTrapAsync(new Variable(oid, data)); /// /// Sends an SNMP version 3 trap. /// /// Variables. public static async Task SendTrapAsync(params Variable[] variables) { await new TrapV2Message ( VersionCode.V3, Messenger.NextMessageId, Messenger.NextRequestId, s_community, EnterpriseRoot, (uint)Environment.TickCount / 10, new List(variables), s_privacyProvider, Messenger.MaxMessageSize, EngineID, 0, 0 ) .SendAsync(s_endPoint); } private static readonly OctetString s_community; private static readonly IPEndPoint s_endPoint; private static readonly DESPrivacyProvider s_privacyProvider; static Snmp() { try { // Get configured SNMP agent settings CategorizedSettingsElementCollection settings = ConfigurationFile.Current.Settings["snmpAgent"]; PasswordGenerator passwordGenerator = new PasswordGenerator(PasswordCharacterGroups); settings.Add("Community", "Eval(securityProvider.ApplicationName)", "Defines the SNMP agent community identifier for trap messages."); settings.Add("IPEndPoint", DefaultIPEndPoint, "Defines the SNMP agent target IP end point for trap messages."); settings.Add("AuthPhrase", passwordGenerator.GeneratePassword(16), "Defines the SNMP agent authentication phrase for trap messages."); settings.Add("EncryptKey", passwordGenerator.GeneratePassword(16), "Defines the SNMP agent encryption key for trap messages."); s_community = new OctetString(settings["Community"].ValueAs(nameof(GSF))); string endPoint = settings["IPEndPoint"].ValueAs(DefaultIPEndPoint); string[] parts = endPoint.Split(':'); if (parts.Length != 2) { parts = DefaultIPEndPoint.Split(':'); Logger.SwallowException(new Exception($"Configured SNMP agent IP end point \"{endPoint}\" format is invalid. Using default IP end point \"{DefaultIPEndPoint}\".")); } if (!IPAddress.TryParse(parts[0], out IPAddress address)) { address = IPAddress.Loopback; Logger.SwallowException(new Exception($"Configured SNMP agent IP end point \"{endPoint}\" address is invalid. Using loop-back address \"127.0.0.1\".")); } if (!ushort.TryParse(parts[1], out ushort port)) { port = 162; Logger.SwallowException(new Exception($"Configured SNMP agent IP end point \"{endPoint}\" port is invalid. Using default port \"162\".")); } s_endPoint = new IPEndPoint(address, port); string authPhrase = settings["AuthPhrase"].Value.PadRight(16, '#'); string encryptKey = settings["EncryptKey"].Value.PadRight(16, '#'); s_privacyProvider = new DESPrivacyProvider( new OctetString(encryptKey), new MD5AuthenticationProvider(new OctetString(authPhrase))); } catch (Exception ex) { Logger.SwallowException(new Exception($"Failed to load SNMP agent configuration: {ex.Message}", ex)); } } private static readonly IReadOnlyList PasswordCharacterGroups = new List() { new CharacterGroup { Characters = "abcdefghijklmnopqrstuvwxyz", MinOccurrence = 1 }, new CharacterGroup { Characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ", MinOccurrence = 1 }, new CharacterGroup { Characters = "0123456789", MinOccurrence = 1 }, }; } }