/// <summary> /// Constructs for the given lower layer. /// </summary> /// <param name="lowerLayer">The lower layer for talking to this device.</param> /// <param name="oidLookup">The OID lookup table for the device.</param> /// <param name="osVersion">The SW version of the device.</param> /// <param name="model">The device's model name. Shall be the same name as used for the device name during OID database lookups.</param> /// <param name="options">The options to use.</param> public DeviceHandlerBase(ISnmpLowerLayer lowerLayer, IDeviceSpecificOidLookup oidLookup, SemVersion.SemanticVersion osVersion, string model, IQuerierOptions options) { if (lowerLayer == null) { throw new ArgumentNullException(nameof(lowerLayer), "lower layer is null when constructing a device handler"); } if (oidLookup == null) { throw new ArgumentNullException(nameof(oidLookup), "OID lookup table is null when constructing a device handler"); } if (osVersion == null) { throw new ArgumentNullException(nameof(osVersion), "OS version info is null when constructing a device handler"); } if (string.IsNullOrWhiteSpace(model)) { throw new ArgumentNullException(nameof(model), "Model name is null, empty or white-space-only when constructing a device handler"); } this.LowerLayer = lowerLayer; this.OidLookup = oidLookup; this.OsVersion = osVersion; this.Model = model; this.Options = options ?? throw new ArgumentNullException(nameof(options), "The options are null when constructing a device handler"); }
/// <summary> /// Construct for a lower layer and a cache data set (from which we return the non-volatile data). /// </summary> public VolatileFetchingWirelessPeerInfos(IWirelessPeerInfos wirelessPeerInfos, ISnmpLowerLayer lowerLayer) { this.lowerLayer = lowerLayer ?? throw new System.ArgumentNullException(nameof(lowerLayer), "lower layer is null"); this.underlyingWirelessPeerInfo = wirelessPeerInfos ?? throw new System.ArgumentNullException(nameof(wirelessPeerInfos), "underlying wireless peer info is null"); this.Details = wirelessPeerInfos.Details.Select(underlyingPeerInfo => new VolatileFetchingWirelessPeerInfo(underlyingPeerInfo, this.lowerLayer)).ToList(); }
/// <summary> /// Construct for a lower layer and a cache data set (from which we return the non-volatile data). /// </summary> public VolatileFetchingInterfaceDetails(IInterfaceDetails interfaceDetails, ISnmpLowerLayer lowerLayer) { this.lowerLayer = lowerLayer ?? throw new System.ArgumentNullException(nameof(lowerLayer), "lower layer is null"); this.underlyingInterfaceDetails = interfaceDetails ?? throw new System.ArgumentNullException(nameof(interfaceDetails), "underlying interface details is null"); this.Details = interfaceDetails.Details.Select(underlyingInterfaceDetail => new VolatileFetchingInterfaceDetail(underlyingInterfaceDetail, this.lowerLayer)).ToList(); }
/// <summary> /// Gets the device handler of the given handler class name via reflection. /// </summary> /// <param name="handlerClassName">The class name of the device handler to get.</param> /// <param name="lowerLayer">The lower layer for talking to this device.</param> /// <param name="oidTable">The OID lookup table for the device.</param> /// <param name="osVersion">The SW version of the device.</param> /// <param name="model">The device's model name. Shall be the same name as used for the device name during OID database lookups.</param> /// <param name="options">The options to use.</param> /// <returns>The generated device handler.</returns> protected IDeviceHandler GetHandlerViaReflection(string handlerClassName, ISnmpLowerLayer lowerLayer, IDeviceSpecificOidLookup oidTable, SemanticVersion osVersion, string model, IQuerierOptions options) { var type = Type.GetType($"SnmpAbstraction.{handlerClassName}"); if (type == null) { var ex = new HamnetSnmpException($"{lowerLayer.Address} ({model} v {osVersion}): Cannot find a DeviceHandler implementation of name '{handlerClassName}'", lowerLayer.Address?.ToString()); this.CollectException("Missing handler class name", ex); throw ex; } object myObject = null; try { myObject = Activator.CreateInstance(type, lowerLayer, oidTable, osVersion, model, options); } catch (Exception ex) { this.CollectException($"Instantiate handler class '{type.FullName}'", ex); throw new HamnetSnmpException($"{lowerLayer.Address} ({model} v {osVersion}): Exception while instantiating DeviceHandler of name '{handlerClassName}': {ex.Message}", ex, lowerLayer.Address?.ToString()); } IDeviceHandler castedHandler = myObject as IDeviceHandler; if (castedHandler == null) { var ex = new HamnetSnmpException($"{lowerLayer.Address} ({model} v {osVersion}): Instantiating DeviceHandler of name '{handlerClassName}' is NOT an IDeviceHandler", lowerLayer.Address?.ToString()); this.CollectException($"Cast handler class '{type.FullName}' to IDeviceHandler", ex); throw ex; } return(castedHandler); }
/// <summary> /// Creates a new querier using the given lower layer and options. /// </summary> /// <param name="lowerLayer">The IP address of the device to query.</param> /// <param name="options">The options for the query.</param> /// <returns>An <see cref="IHamnetQuerier" /> that talks to the given address.</returns> internal IHamnetQuerier Create(ISnmpLowerLayer lowerLayer, IQuerierOptions options) { if (lowerLayer == null) { throw new ArgumentNullException(nameof(lowerLayer), "lowerLayer is null"); } IHamnetQuerier querier = null; if (options.EnableCaching) { querier = new CachingHamnetQuerier(lowerLayer, options); } else { var detector = new DeviceDetector(lowerLayer); IDeviceHandler handler = detector.Detect(options); if (handler == null) { var errorInfo = $"Cannot obtain a feasible device handler for device '{lowerLayer.Address}'"; log.Error(errorInfo); throw new HamnetSnmpException(errorInfo, lowerLayer.Address?.ToString()); } querier = new HamnetQuerier(handler, lowerLayer.Options); } return(querier); }
/// <summary> /// Queries the given OIDs and returns the value as string or null if the OID is not available. /// </summary> /// <param name="lowerLayer">The lower layer engine to extend.</param> /// <param name="oid">The OID to query.</param> /// <param name="what">Descriptive text what is being queried. Used for debug/error output</param> /// <param name="encoding">If not null, will try to detect whether the string is a hex string and then use the given encoding to decode it.</param> /// <returns>The OID's value as string or null if the OID is not available.</returns> public static string QueryAsString(this ISnmpLowerLayer lowerLayer, Oid oid, string what, Encoding encoding = null) { VbCollection result = lowerLayer.Query(oid); var retVal = result[oid]?.Value?.ToString(); if (retVal == null) { log.Warn($"Querying '{what}' from '{lowerLayer.Address}' as string returned null"); } if ((encoding != null) && (retVal.Length > 0)) { bool couldBeHexString = true; for (int i = 2; i < retVal.Length; i += 3) { if (retVal[i] != ' ') { couldBeHexString = false; break; } } if (couldBeHexString) { retVal = encoding.GetString(retVal.HexStringToByteArray(' ')); } } return(retVal); }
/// <inheritdoc /> public override IDeviceHandler CreateHandler(ISnmpLowerLayer lowerLayer, IQuerierOptions options) { string osVersionString = null; // try #1: In IEEE SNMP tree try { osVersionString = lowerLayer.QueryAsString(OsVersionOid, "MikroTik RouterOS Version String #1"); } catch (SnmpException ex) { this.CollectException("MtikSnmp: Getting version string", ex); osVersionString = null; } catch (HamnetSnmpException ex) { this.CollectException("MtikSnmp: Getting version string", ex); osVersionString = null; } // try #2: Withing MikroTik enterprise tree if (string.IsNullOrWhiteSpace(osVersionString)) { osVersionString = lowerLayer.QueryAsString(OsVersionOid2, "MikroTik RouterOS Version String #2"); } // Example: "RouterOS 6.45.3 (stable) on RB711-5Hn-MMCX" Match match = OsVersionExtractionRegex.Match(osVersionString); SemanticVersion osVersion = match.Success ? match.Groups[1].Value.ToSemanticVersion() : null; var model = lowerLayer.SystemData.Description.Replace(RouterOsDetectionString, string.Empty).Trim(); log.Info($"Detected device '{lowerLayer.Address}' as MikroTik '{model}' v '{osVersion}'"); DeviceVersion deviceVersion; IDeviceSpecificOidLookup oidTable = this.ObtainOidTable(model.Trim(), osVersion, out deviceVersion, lowerLayer.Address); if (string.IsNullOrWhiteSpace(deviceVersion.HandlerClassName)) { try { return(new MikrotikSnmpDeviceHandler(lowerLayer, oidTable, osVersion, model, options)); } catch (Exception ex) { this.CollectException("MtikSnmp: OID table lookup", ex); // we want to catch and nest the exception here as the APIs involved are not able to append the infomration for which // device (i.e. IP address) the exception is for throw new HamnetSnmpException($"Failed to create MikroTik handler for device '{lowerLayer.Address}': {ex.Message}", ex, lowerLayer.Address?.ToString()); } } else { return(this.GetHandlerViaReflection(deviceVersion.HandlerClassName, lowerLayer, oidTable, osVersion, model, options)); } }
/// <summary> /// Construct for the given device address and query duration. /// </summary> /// <param name="lowerSnmpLayer">The communication layer to use for talking to the device.</param> /// <param name="queryDuration">The duration of the query.</param> protected LazyHamnetSnmpQuerierResultBase(ISnmpLowerLayer lowerSnmpLayer, TimeSpan queryDuration) : this(lowerSnmpLayer, queryDuration, lowerSnmpLayer.SystemData?.DeviceModel) { if (lowerSnmpLayer == null) { throw new ArgumentNullException(nameof(lowerSnmpLayer), "The handle to the lower layer interface is null"); } this.LowerSnmpLayer = lowerSnmpLayer; }
/// <summary> /// Construct for the given device address and query duration. /// </summary> /// <param name="lowerSnmpLayer">The communication layer to use for talking to the device.</param> /// <param name="queryDuration">The duration of the query.</param> /// <param name="deviceModel">The model and version of the device.</param> protected LazyHamnetSnmpQuerierResultBase(ISnmpLowerLayer lowerSnmpLayer, TimeSpan queryDuration, string deviceModel) : base(lowerSnmpLayer.Address, deviceModel, queryDuration) { if (lowerSnmpLayer == null) { throw new ArgumentNullException(nameof(lowerSnmpLayer), "The handle to the lower layer interface is null"); } this.LowerSnmpLayer = lowerSnmpLayer; }
/// <summary> /// Construct taking the lower layer to use for lazy-querying the data. /// </summary> /// <param name="lowerSnmpLayer">The communication layer to use for talking to the device.</param> /// <param name="oidLookup">The OID lookup table for the device.</param> /// <param name="macAddress">The MAC address of the peer (serves as index in OIDs for MikroTik devices).</param> /// <param name="interfaceId">The ID of the interface (i.e. the value to append to interface-specific OIDs).</param> /// <param name="isAccessPoint">Value indicating whether the device proving the peer info is an access point or a client.</param> /// <param name="numberOfClients">The number of clients that are connected to this AP when in AP mode. null if not an AP or not available.</param> public LazyLoadingAlixWirelessPeerInfo( ISnmpLowerLayer lowerSnmpLayer, IDeviceSpecificOidLookup oidLookup, string macAddress, int?interfaceId, bool?isAccessPoint, int?numberOfClients) : base(lowerSnmpLayer, oidLookup, macAddress, interfaceId, isAccessPoint, numberOfClients) { }
/// <inheritdoc /> public virtual IDeviceHandler CreateHandler(ISnmpLowerLayer lowerLayer, IQuerierOptions options) { if (this.circularCreateHandler++ > 1) { var ex = new InvalidOperationException($"Internal Error: DetectableDevice {this.GetType().Name} seems to neither implement CreateHandler(ISnmpLowerLayer lowerLayer, IQuerierOptions options) nor CreateHandler(IpAddress address, IQuerierOptions options)"); this.CollectException("CreateHandler(ISnmpLowerLayer, IQuerierOptions) circular call", ex); throw ex; } return(this.CreateHandler(lowerLayer.Address, options)); }
/// <summary> /// Queries the given OIDs and returns the value as OID or null if the OID is not available. /// </summary> /// <param name="lowerLayer">The lower layer engine to extend.</param> /// <param name="oid">The OID to query.</param> /// <param name="what">Descriptive text what is being queried. Used for debug/error output</param> /// <returns>The OID's value as OID or null if the OID is not available.</returns> public static Oid QueryAsOid(this ISnmpLowerLayer lowerLayer, Oid oid, string what) { VbCollection result = lowerLayer.Query(oid); var retVal = result[oid]?.Value as Oid; if (retVal == null) { log.Warn($"Querying '{what}' from '{lowerLayer.Address}' as OID returned null"); } return(retVal); }
/// <summary> /// Queries the given OIDs and returns the value as string or null if the OID is not available. /// </summary> /// <param name="lowerLayer">The lower layer engine to extend.</param> /// <param name="oid">The OID to query.</param> /// <param name="what">Descriptive text what is being queried. Used for debug/error output</param> /// <returns>The OID's value as int or <see cref="int.MinValue" /> if the OID is not available.</returns> public static int QueryAsInt(this ISnmpLowerLayer lowerLayer, Oid oid, string what) { VbCollection result = lowerLayer.Query(oid); int retVal = int.MinValue; if (!(result[oid]?.Value?.TryToInt(out retVal) ?? false)) { log.Warn($"Querying '{what}' from '{lowerLayer.Address}' as string returned null"); } return(retVal); }
/// <summary> /// Queries the given OIDs and returns the value as <see cref="TimeSpan" /> or null if the OID is not available. /// </summary> /// <param name="lowerLayer">The lower layer engine to extend.</param> /// <param name="oid">The OID to query.</param> /// <param name="what">Descriptive text what is being queried. Used for debug/error output</param> /// <returns>The OID's value as <see cref="TimeSpan" /> or null if the OID is not available or cannot be parsed as <see cref="TimeSpan" />.</returns> public static TimeSpan?QueryAsTimeSpan(this ISnmpLowerLayer lowerLayer, Oid oid, string what) { VbCollection result = lowerLayer.Query(oid); var retVal = result[oid]?.Value as TimeTicks; if (retVal == null) { log.Warn($"Querying '{what}' from '{lowerLayer.Address}' as TimeTicks returned null"); return(null); } return(TimeSpan.FromMilliseconds(retVal.Milliseconds)); }
/// <summary> /// Construct taking the lower layer to use for lazy-querying the data. /// </summary> /// <param name="lowerSnmpLayer">The communication layer to use for talking to the device.</param> /// <param name="oidLookup">The OID lookup table for the device.</param> /// <param name="macAddress">The MAC address of the peer (serves as index in OIDs for MikroTik devices).</param> /// <param name="interfaceId">The ID of the interface (i.e. the value to append to interface-specific OIDs).</param> /// <param name="isAccessPoint">Value indicating whether the device proving the peer info is an access point or a client.</param> /// <param name="numberOfClients">The number of clients that are connected to this AP when in AP mode. null if not an AP or not available.</param> protected LazyLoadingGenericWirelessPeerInfo( ISnmpLowerLayer lowerSnmpLayer, IDeviceSpecificOidLookup oidLookup, string macAddress, int?interfaceId, bool?isAccessPoint, int?numberOfClients) : base(lowerSnmpLayer) { this.OidLookup = oidLookup; this.PeerMac = macAddress; this.InterfaceId = interfaceId; this.IsAccessPoint = isAccessPoint; this.NumberOfClients = numberOfClients; }
/// <summary> /// Construct taking the lower layer to use for lazy-querying the data. /// </summary> /// <param name="lowerSnmpLayer">The communication layer to use for talking to the device.</param> /// <param name="oidLookup">The OID lookup table for the device.</param> /// <param name="peerIndex">The peer's index (to use in SNMP get).</param> /// <param name="numberOfClients">The number of clients that are connected to this AP when in AP mode. null if not an AP or not available.</param> public LazyLoadingUbiquitiAirFiberWirelessPeerInfo( ISnmpLowerLayer lowerSnmpLayer, IDeviceSpecificOidLookup oidLookup, int peerIndex, int?numberOfClients) : base( lowerSnmpLayer, oidLookup, null, null, // For UBNT there's no way to find which wireless interface this peer belongs to. null, numberOfClients) { this.peerIndex = peerIndex; }
/// <summary> /// Construct taking the lower layer to use for lazy-querying the data. /// </summary> /// <param name="lowerSnmpLayer">The communication layer to use for talking to the device.</param> /// <param name="oidLookup">The OID lookup table for the device.</param> /// <param name="interfaceId">The interface ID (to use in SNMP get).</param> /// <param name="peerWalkCollection">The collection generated by the walk operation that triggered creation of this peer info.</param> /// <param name="numberOfClients">The number of clients that are connected to this AP when in AP mode. null if not an AP or not available.</param> public LazyLoadingUbiquitiAirOs4WirelessPeerInfo( ISnmpLowerLayer lowerSnmpLayer, IDeviceSpecificOidLookup oidLookup, int interfaceId, VbCollection peerWalkCollection, int?numberOfClients) : base( lowerSnmpLayer, oidLookup, null, interfaceId, null, numberOfClients) { this.walkCollection = peerWalkCollection; }
/// <summary> /// Construct taking the lower layer to use for lazy-querying the data. /// </summary> /// <param name="lowerSnmpLayer">The communication layer to use for talking to the device.</param> /// <param name="oidLookup">The OID lookup table for the device.</param> /// <param name="macAddress">The MAC address of the peer (serves as index in OIDs for MikroTik devices).</param> /// <param name="peerIndex">The peer's index (to use in SNMP get).</param> /// <param name="isAccessPoint">Value indicating whether the device proving the peer info is an access point or a client.</param> /// <param name="numberOfClients">The number of clients that are connected to this AP when in AP mode. null if not an AP or not available.</param> public LazyLoadingUbiquitiAirOs6plusWirelessPeerInfo( ISnmpLowerLayer lowerSnmpLayer, IDeviceSpecificOidLookup oidLookup, string macAddress, int peerIndex, bool?isAccessPoint, int?numberOfClients) : base( lowerSnmpLayer, oidLookup, macAddress, null, // For UBNT there's no way to find which wireless interface this peer belongs to. isAccessPoint, numberOfClients) { this.peerIndex = peerIndex; }
/// <inheritdoc /> public override bool IsApplicableSnmp(ISnmpLowerLayer snmpLowerLayer, IQuerierOptions options) { var description = snmpLowerLayer?.SystemData?.Description; if (string.IsNullOrWhiteSpace(description)) { var info = $"Description in system data of device '{snmpLowerLayer.Address}' is null, empty or white-space-only: Assuming the device is not a Ubiquiti device"; log.Warn(info); this.CollectException("UbntSnmp: No device description", new HamnetSnmpException(info)); return(false); } if (!description.Contains(PossiblyUbiquitiDetectionDescriptionString)) { var info = $"Description in system data of device '{snmpLowerLayer.Address}' doesn't contain string '{PossiblyUbiquitiDetectionDescriptionString}': Assuming the device is not a Ubiquiti device"; log.Info(info); this.CollectException("UbntSnmp: No UBNT-like string in device description", new HamnetSnmpException(info)); return(false); } var ubntManufacturer = snmpLowerLayer?.DoWalk(UbntManufacturerDetectionOid); if ((ubntManufacturer == null) || (ubntManufacturer.Count == 0)) { var info = $"UBNT Manufacturer ID string of device '{snmpLowerLayer.Address}' is null or empty: The device could still be AirFiber"; log.Warn(info); this.CollectException("UbntSnmp: No UBNT manufacturer detection OID", new HamnetSnmpException(info)); return(this.DetectAirFiber(snmpLowerLayer)); } var manufacturer = ubntManufacturer.FirstOrDefault(m => m.Value.ToString().Contains(UbiquitiManufactorerDetectionString)); if (manufacturer == null) { var info = $"UBNT Manufacturer ID string of device '{snmpLowerLayer.Address}' doesn't contain string '{UbiquitiManufactorerDetectionString}': Assuming the device is not a Ubiquiti device"; log.Info(info); this.CollectException("UbntSnmp: No UBNT manufacturer", new HamnetSnmpException(info)); return(false); } this.detectionId = manufacturer.Oid[manufacturer.Oid.Length - 1]; log.Info($"Device '{snmpLowerLayer.Address}' seems to be a Ubiquiti device (detection ID {this.detectionId})"); return(true); }
/// <summary> /// Constructs for the given lower layer. /// </summary> /// <param name="lowerLayer">The lower layer for talking to this device.</param> /// <param name="oidLookup">The OID lookup table for the device.</param> /// <param name="osVersion">The SW version of the device.</param> /// <param name="model">The device's model name. Shall be the same name as used for the device name during OID database lookups.</param> /// <param name="options">The options to use.</param> public AlixDeviceHandler(ISnmpLowerLayer lowerLayer, IDeviceSpecificOidLookup oidLookup, SemanticVersion osVersion, string model, IQuerierOptions options) : base(lowerLayer, oidLookup, osVersion, model, options) { if ((options.AllowedApis & this.SupportedApi) == 0) { throw new ArgumentOutOfRangeException(nameof(options), $"This device handler doesn't support any of the APIs allowed by the IQuerierOptions (allowed: {options.AllowedApis}, supported {this.SupportedApi})."); } LazyLoadingDeviceSystemData llsd = lowerLayer.SystemData as LazyLoadingDeviceSystemData; if (llsd != null) { if (oidLookup.TryGetValue(RetrievableValuesEnum.RxSignalStrengthCh0AppendMacAndInterfaceId, out DeviceSpecificOid oid0) && !oid0.Oid.IsNull) { // for ALIX/H4L devices we currently only support RSSI querying llsd.SupportedFeatures = DeviceSupportedFeatures.Rssi; } } }
/// <summary> /// Queries the given OIDs and returns the value as string or null if the OID is not available. /// </summary> /// <param name="lowerLayer">The lower layer engine to extend.</param> /// <param name="oids">The OIDs list to query.</param> /// <param name="what">Descriptive text what is being queried. Used for debug/error output</param> /// <returns>The OID's value as int or or <see cref="int.MinValue" /> if the OID is not available.</returns> public static Dictionary <Oid, int> QueryAsInt(this ISnmpLowerLayer lowerLayer, IEnumerable <Oid> oids, string what) { if (oids == null) { throw new ArgumentNullException(nameof(oids), "The array of oids to query is null"); } VbCollection queryResult = lowerLayer.Query(oids); return(queryResult.ToDictionary(qr => qr.Oid, qr => { int retVal = int.MinValue; if (!(qr.Value?.TryToInt(out retVal) ?? false)) { log.Warn($"Querying '{what}' from '{lowerLayer.Address}' as Dictionary<Oid, int>: Conversion to int returned null for response '{qr}'"); } return retVal; })); }
/// <summary> /// Detects an AirFiber device which does not really provide any manufacturer ID or similar /// </summary> /// <param name="snmpLowerLayer">The lower communication layer to user.</param> /// <returns><c>true</c> if an AirFiber device has been detected and the class fields have been set accordingly.</returns> private bool DetectAirFiber(ISnmpLowerLayer snmpLowerLayer) { var mibInfo41112 = snmpLowerLayer.DoWalk(AirFiberDetectionWalkRootOid); if (mibInfo41112.Count == 0) { // it's also not an AirFiber device log.Info($"Reading of OS version of device '{snmpLowerLayer.Address}' via AirFiber OID {AirFiberDetectionWalkRootOid} didn't reveal anything: Assuming the device is not an Ubiquiti AirFiber device"); return(false); } // never seen AirFiber returning more than one var firstValue = mibInfo41112.First(); this.osDetectedVersion = firstValue.Value.ToString(); this.detectionId = firstValue.Oid.Last(); this.detectedModel = AirFiberFakeModelString; return(true); }
/// <inheritdoc /> public override bool IsApplicableSnmp(ISnmpLowerLayer snmpLowerLayer, IQuerierOptions options) { var description = snmpLowerLayer?.SystemData?.Description; if (string.IsNullOrWhiteSpace(description)) { var info = $"Description in system data of device '{snmpLowerLayer.Address}' is null, empty or white-space-only: Assuming the device is not a MikroTik device"; this.CollectException("AlixSnmp: No device description", new HamnetSnmpException(info)); log.Warn(info); return(false); } if (!AlixDetectionStrings.Any(ds => description.Contains(ds, StringComparison.InvariantCultureIgnoreCase))) { var info = $"Description in system data of device '{snmpLowerLayer.Address}' doesn't contain any of the strings string '{string.Join(", ", AlixDetectionStrings)}': Assuming the device is not an ALIX device"; this.CollectException("AlixSnmp: No ALIX-like string in device description", new HamnetSnmpException(info)); log.Info(info); return(false); } log.Info($"Device '{snmpLowerLayer.Address}' seems to be an ALIX device"); return(true); }
/// <inheritdoc /> public override IDeviceHandler CreateHandler(ISnmpLowerLayer lowerLayer, IQuerierOptions options) { string osVersionString = "0.0.0"; // Example: "..." Match match = OsVersionExtractionRegex.Match(osVersionString); SemanticVersion osVersion = osVersionString.ToSemanticVersion(); // match.Success ? match.Groups[1].Value.ToSemanticVersion() : null; var model = lowerLayer.SystemData.Description; //lowerLayer.SystemData.Description.Replace(RouterOsDetectionString, string.Empty).Trim(); log.Info($"Detected device '{lowerLayer.Address}' as ALIX '{model}' v '{osVersion}'"); DeviceVersion deviceVersion; IDeviceSpecificOidLookup oidTable = this.ObtainOidTable(model.Trim(), osVersion, out deviceVersion, lowerLayer.Address); if (string.IsNullOrWhiteSpace(deviceVersion.HandlerClassName)) { try { return(new AlixDeviceHandler(lowerLayer, oidTable, osVersion, model, options)); } catch (Exception ex) { this.CollectException("AlixSnmp: OID table lookup", ex); // we want to catch and nest the exception here as the APIs involved are not able to append the infomration for which // device (i.e. IP address) the exception is for throw new HamnetSnmpException($"Failed to create ALIX handler for device '{lowerLayer.Address}': {ex.Message}", ex, lowerLayer?.Address?.ToString()); } } else { return(this.GetHandlerViaReflection(deviceVersion.HandlerClassName, lowerLayer, oidTable, osVersion, model, options)); } }
/// <inheritdoc /> public override bool IsApplicableSnmp(ISnmpLowerLayer snmpLowerLayer, IQuerierOptions options) { var description = snmpLowerLayer?.SystemData?.Description; if (string.IsNullOrWhiteSpace(description)) { var info = $"Description in system data of device '{snmpLowerLayer.Address}' is null, empty or white-space-only: Assuming the device is not a MikroTik device"; log.Warn(info); this.CollectException("MtikSnmp: No device description", new HamnetSnmpException(info)); return(false); } if (!description.Contains(RouterOsDetectionString)) { var info = $"Description in system data of device '{snmpLowerLayer.Address}' doesn't contain string '{RouterOsDetectionString}': Assuming the device is not a MikroTik device"; log.Info(info); this.CollectException("MtikSnmp: No Router-OS-like string in device description", new HamnetSnmpException(info)); return(false); } log.Info($"Device '{snmpLowerLayer.Address}' seems to be a MikroTik device"); return(true); }
/// <inheritdoc /> protected override IWirelessPeerInfos RetrieveWirelessPeerInfos(ISnmpLowerLayer lowerLayer, IDeviceSpecificOidLookup oidLookup) { return(new LazyLoadingAlixWirelessPeerInfos(this.LowerLayer, this.OidLookup)); }
/// <inheritdoc /> protected override IInterfaceDetails RetrieveDeviceInterfaceDetails(ISnmpLowerLayer lowerLayer, IDeviceSpecificOidLookup oidLookup) { return(new LazyLoadingAlixInterfaceDetails(this.LowerLayer, this.OidLookup)); }
/// <summary> /// Allows deriving class to retrieve and return their implementation of <see cref="IWirelessPeerInfos" />. /// </summary> /// <param name="lowerLayer">The lower layer for talking to this device.</param> /// <param name="oidLookup">The OID lookup table for the device.</param> /// <returns>The retrieved interface details.</returns> protected abstract IWirelessPeerInfos RetrieveWirelessPeerInfos(ISnmpLowerLayer lowerLayer, IDeviceSpecificOidLookup oidLookup);
/// <summary> /// Constructs for the given lower layer. /// </summary> /// <param name="lowerLayer">The lower layer for talking to this device.</param> /// <param name="oidLookup">The OID lookup table for the device.</param> /// <param name="osVersion">The SW version of the device.</param> /// <param name="model">The device's model name. Shall be the same name as used for the device name during OID database lookups.</param> /// <param name="options">The options to use.</param> public GenericDeviceHandler(ISnmpLowerLayer lowerLayer, IDeviceSpecificOidLookup oidLookup, SemanticVersion osVersion, string model, IQuerierOptions options) : base(lowerLayer, oidLookup, osVersion, model, options) { }
/// <summary> /// Allows deriving class to retrieve and return their implementation of <see cref="IInterfaceDetails" />. /// </summary> /// <param name="lowerLayer">The lower layer for talking to this device.</param> /// <param name="oidLookup">The OID lookup table for the device.</param> /// <returns>The retrieved interface details.</returns> protected abstract IInterfaceDetails RetrieveDeviceInterfaceDetails(ISnmpLowerLayer lowerLayer, IDeviceSpecificOidLookup oidLookup);