Index: Appender/SnmpTrapAppender.cs =================================================================== --- Appender/SnmpTrapAppender.cs (revision 0) +++ Appender/SnmpTrapAppender.cs (revision 0) @@ -0,0 +1,1059 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.Net; +using System.Net.Sockets; +using System.Text; + +using log4net.Layout; +using log4net.Core; +using log4net.Util; +using System.IO; +using System.Web; + +namespace log4net.Appender +{ + /// + /// Simple SNMP V1 Trap Appender Implementation + /// + public class SnmpTrapAppender : AppenderSkeleton + { + #region Public Instance Constructors + + /// + /// Initializes a new instance of the class. + /// + /// + /// The default constructor initializes all fields to their default values. + /// + public SnmpTrapAppender() + { + initDateTime = DateTime.Now; + } + + #endregion Public Instance Constructors + + #region Public Instance Properties + + /// + /// Gets or sets the IP address of the remote host or multicast group to which + /// the underlying should sent the logging event. + /// + /// + /// The IP address of the remote host or multicast group to which the logging event + /// will be sent. + /// + /// + /// + /// Multicast addresses are identified by IP class D addresses (in the range 224.0.0.0 to + /// 239.255.255.255). Multicast packets can pass across different networks through routers, so + /// it is possible to use multicasts in an Internet scenario as long as your network provider + /// supports multicasting. + /// + /// + /// Hosts that want to receive particular multicast messages must register their interest by joining + /// the multicast group. Multicast messages are not sent to networks where no host has joined + /// the multicast group. Class D IP addresses are used for multicast groups, to differentiate + /// them from normal host addresses, allowing nodes to easily detect if a message is of interest. + /// + /// + /// Static multicast addresses that are needed globally are assigned by IANA. A few examples are listed in the table below: + /// + /// + /// + /// + /// IP Address + /// Description + /// + /// + /// 224.0.0.1 + /// + /// + /// Sends a message to all system on the subnet. + /// + /// + /// + /// + /// 224.0.0.2 + /// + /// + /// Sends a message to all routers on the subnet. + /// + /// + /// + /// + /// 224.0.0.12 + /// + /// + /// The DHCP server answers messages on the IP address 224.0.0.12, but only on a subnet. + /// + /// + /// + /// + /// + /// + /// A complete list of actually reserved multicast addresses and their owners in the ranges + /// defined by RFC 3171 can be found at the IANA web site. + /// + /// + /// The address range 239.0.0.0 to 239.255.255.255 is reserved for administrative scope-relative + /// addresses. These addresses can be reused with other local groups. Routers are typically + /// configured with filters to prevent multicast traffic in this range from flowing outside + /// of the local network. + /// + /// + public IPAddress RemoteAddress + { + get { return m_remoteAddress; } + set { m_remoteAddress = value; } + } + + /// + /// Gets or sets the TCP port number of the remote host or multicast group to which + /// the underlying should sent the logging event. + /// + /// + /// An integer value in the range to + /// indicating the TCP port number of the remote host or multicast group to which the logging event + /// will be sent. + /// + /// + /// The underlying will send messages to this TCP port number + /// on the remote host or multicast group. + /// + /// The value specified is less than or greater than . + public int RemotePort + { + get { return m_remotePort; } + set + { + if (value < IPEndPoint.MinPort || value > IPEndPoint.MaxPort) + { + throw log4net.Util.SystemInfo.CreateArgumentOutOfRangeException("value", (object)value, + "The value specified is less than " + + IPEndPoint.MinPort.ToString(NumberFormatInfo.InvariantInfo) + + " or greater than " + + IPEndPoint.MaxPort.ToString(NumberFormatInfo.InvariantInfo) + "."); + } + else + { + m_remotePort = value; + } + } + } + + /// + /// Gets or sets the TCP port number from which the underlying will communicate. + /// + /// + /// An integer value in the range to + /// indicating the TCP port number from which the underlying will communicate. + /// + /// + /// + /// The underlying will bind to this port for sending messages. + /// + /// + /// Setting the value to 0 (the default) will cause the udp client not to bind to + /// a local port. + /// + /// + /// The value specified is less than or greater than . + public int LocalPort + { + get { return m_localPort; } + set + { + if (value != 0 && (value < IPEndPoint.MinPort || value > IPEndPoint.MaxPort)) + { + throw log4net.Util.SystemInfo.CreateArgumentOutOfRangeException("value", (object)value, + "The value specified is less than " + + IPEndPoint.MinPort.ToString(NumberFormatInfo.InvariantInfo) + + " or greater than " + + IPEndPoint.MaxPort.ToString(NumberFormatInfo.InvariantInfo) + "."); + } + else + { + m_localPort = value; + } + } + } + + /// + /// Gets or sets used to write the packets. + /// + /// + /// The used to write the packets. + /// + /// + /// + /// The used to write the packets. + /// + /// + public Encoding Encoding + { + get { return m_encoding; } + set { m_encoding = value; } + } + + /// + /// The OID for the enterprise you are sending a trap to + /// + public string EnterpriseOID + { + get { return enterpriseOID; } + set { enterpriseOID = value; } + } + + /// + /// The OID associated with a message variable added to the trap PDU + /// + public string ApplicationTrapOID + { + get { return applicationTrapOID; } + set { applicationTrapOID = value; } + } + + /// + /// Community String (password) for the remote listener + /// + public string CommunityString + { + get { return communityString; } + set { communityString = value; } + } + + /// + /// One of the generic SNMP Trap Types + /// + public GenericStatus GenericTrapType + { + get { return genericTrapType; } + set { genericTrapType = value; } + } + + /// + /// An Enterprise-Specific SNMP Trap Type (SpecificTrapType, SpecificTrapCode, SpecificCode, etc.) + /// + public int SpecificTrapType + { + get { return specificTrapType; } + set { specificTrapType = value; } + } + + #endregion Public Instance Properties + + #region Protected Instance Properties + + /// + /// Gets or sets the underlying . + /// + /// + /// The underlying . + /// + /// + /// creates a to send logging events + /// over a network. Classes deriving from can use this + /// property to get or set this . Use the underlying + /// returned from if you require access beyond that which + /// provides. + /// + protected UdpClient Client + { + get { return this.m_client; } + set { this.m_client = value; } + } + + /// + /// Gets or sets the cached remote endpoint to which the logging events should be sent. + /// + /// + /// The cached remote endpoint to which the logging events will be sent. + /// + /// + /// The method will initialize the remote endpoint + /// with the values of the and + /// properties. + /// + protected IPEndPoint RemoteEndPoint + { + get { return this.m_remoteEndPoint; } + set { this.m_remoteEndPoint = value; } + } + + #endregion Protected Instance Properties + + #region Implementation of IOptionHandler + + /// + /// Initialize the appender based on the options set. + /// + /// + /// + /// This is part of the delayed object + /// activation scheme. The method must + /// be called on this object after the configuration properties have + /// been set. Until is called this + /// object is in an undefined state and must not be used. + /// + /// + /// If any of the configuration properties are modified then + /// must be called again. + /// + /// + /// The appender will be ignored if no was specified or + /// an invalid remote or local TCP port number was specified. + /// + /// + /// The required property was not specified. + /// The TCP port number assigned to or is less than or greater than . + public override void ActivateOptions() + { + base.ActivateOptions(); + + if (this.RemoteAddress == null) + { + throw new ArgumentNullException("The required property 'Address' was not specified."); + } + else if (this.RemotePort < IPEndPoint.MinPort || this.RemotePort > IPEndPoint.MaxPort) + { + throw log4net.Util.SystemInfo.CreateArgumentOutOfRangeException("this.RemotePort", (object)this.RemotePort, + "The RemotePort is less than " + + IPEndPoint.MinPort.ToString(NumberFormatInfo.InvariantInfo) + + " or greater than " + + IPEndPoint.MaxPort.ToString(NumberFormatInfo.InvariantInfo) + "."); + } + else if (this.LocalPort != 0 && (this.LocalPort < IPEndPoint.MinPort || this.LocalPort > IPEndPoint.MaxPort)) + { + throw log4net.Util.SystemInfo.CreateArgumentOutOfRangeException("this.LocalPort", (object)this.LocalPort, + "The LocalPort is less than " + + IPEndPoint.MinPort.ToString(NumberFormatInfo.InvariantInfo) + + " or greater than " + + IPEndPoint.MaxPort.ToString(NumberFormatInfo.InvariantInfo) + "."); + } + else if (this.EnterpriseOID == null) + { + throw new ArgumentNullException("The required property 'EnterpriseOID' was not specified."); + } + else if (this.CommunityString == null) + { + throw new ArgumentNullException("The required property 'CommunityString' was not specified."); + } + else if (this.ApplicationTrapOID == null) + { + throw new ArgumentNullException("The required property 'ApplicationTrapOID' was not specified."); + } + else + { + this.RemoteEndPoint = new IPEndPoint(this.RemoteAddress, this.RemotePort); + this.InitializeClientConnection(); + } + } + + #endregion + + #region Override implementation of AppenderSkeleton + + /// + /// This method is called by the method. + /// + /// The event to log. + /// + /// + /// Sends the event using an SNMP trap. + /// + /// + /// Exceptions are passed to the . + /// + /// + protected override void Append(LoggingEvent loggingEvent) + { + try + { + SnmpTrapOptions options = new SnmpTrapOptions(this.GenericTrapType, this.SpecificTrapType, this.EnterpriseOID, + this.ApplicationTrapOID, this.CommunityString, this.GetUptimeTicks()); + + string message = RenderLoggingEvent(loggingEvent); + + List byteList = SnmpTrap.GetTrapSequence(message, options); + + this.Client.Send(byteList.ToArray(), byteList.Count, m_remoteEndPoint); + } + catch (Exception ex) + { + ErrorHandler.Error( + "Unable to send logging event to remote host " + + this.RemoteAddress.ToString() + + " on port " + + this.RemotePort + ".", + ex, + ErrorCode.WriteFailure); + } + } + + /// + /// This appender requires a to be set. + /// + /// true + /// + /// + /// This appender requires a to be set. + /// + /// + override protected bool RequiresLayout + { + get { return true; } + } + + /// + /// Closes the UDP connection and releases all resources associated with + /// this instance. + /// + /// + /// + /// Disables the underlying and releases all managed + /// and unmanaged resources associated with the . + /// + /// + override protected void OnClose() + { + base.OnClose(); + + if (this.Client != null) + { + this.Client.Close(); + this.Client = null; + } + } + + #endregion Override implementation of AppenderSkeleton + + #region Protected Instance Methods + + /// + /// Initializes the underlying connection. + /// + /// + /// + /// The underlying is initialized and binds to the + /// port number from which you intend to communicate. + /// + /// + /// Exceptions are passed to the . + /// + /// + protected virtual void InitializeClientConnection() + { + try + { + if (this.LocalPort == 0) + { + this.Client = new UdpClient(); + } + else + { + this.Client = new UdpClient(this.LocalPort); + } + } + catch (Exception ex) + { + ErrorHandler.Error( + "Could not initialize the UdpClient connection on port " + + this.LocalPort.ToString(NumberFormatInfo.InvariantInfo) + ".", + ex, + ErrorCode.GenericFailure); + + this.Client = null; + } + } + + #endregion Protected Instance Methods + + #region Private Instance Fields + + /// + /// The IP address of the remote host or multicast group to which + /// the logging event will be sent. + /// + private IPAddress m_remoteAddress; + + /// + /// The TCP port number of the remote host or multicast group to + /// which the logging event will be sent. + /// + private int m_remotePort; + + /// + /// The cached remote endpoint to which the logging events will be sent. + /// + private IPEndPoint m_remoteEndPoint; + + /// + /// The TCP port number from which the will communicate. + /// + private int m_localPort; + + /// + /// The instance that will be used for sending the + /// logging events. + /// + private UdpClient m_client; + + /// + /// The encoding to use for the packet. + /// + private Encoding m_encoding = Encoding.Default; + + private string enterpriseOID; + private GenericStatus genericTrapType; + private int specificTrapType; + private string communityString; + private string applicationTrapOID; + private DateTime initDateTime; + + #endregion Private Instance Fields + + #region Private Instance Methods + + /// + /// Get TimeTicks portion of Trap PDU. Based on the time this class was instantiated. + /// + /// + private long GetUptimeTicks() + { + return (DateTime.Now - initDateTime).Ticks; + + //if (UseAppPoolUptime) // if asp.net, get application pool uptime + //{ + // ProcessInfo processInfo = ProcessModelInfo.GetCurrentProcessInfo(); + // return (DateTime.Now - processInfo.StartTime).Ticks; + //} + //else // use time since boot-up + //{ + // // define a select query + // SelectQuery query = + // new SelectQuery("SELECT LastBootUpTime FROM Win32_OperatingSystem WHERE Primary='true'"); + + // // create a new management object searcher and pass it + // // the select query + // ManagementObjectSearcher searcher = + // new ManagementObjectSearcher(query); + + // // get the datetime value and set the local boot + // // time variable to contain that value + // foreach (ManagementObject mo in searcher.Get()) + // { + // dtBootTime = ManagementDateTimeConverter.ToDateTime(mo.Properties["LastBootUpTime"].Value.ToString()); + // return (DateTime.Now - dtBootTime).Ticks + // } + //} + } + + #endregion + } + + #region Snmp Trap Generation + + /// + /// Specific settings for an SNMP Trap + /// + public class SnmpTrapOptions + { + #region Public Properties + + /// + /// Typically GenericStatus.EnterpriseSpecific + /// + public GenericStatus SnmpGenericStatus { get; set; } + + /// + /// An Enterprise-Specific Status Type + /// + public int SnmpSpecificStatus { get; set; } + + /// + /// The OID for the enterprise you are sending a trap to + /// + public byte[] EnterpriseOID { get; set; } + + /// + /// The OID for your Application + /// + public byte[] ApplicationTrapOID { get; set; } + + /// + /// Community String (password) for the remote listener + /// + public byte[] CommunityString { get; set; } + + /// + /// Ticks since last trap, uptime in ticks, etc. + /// + public long TimeTicks { get; set; } + + #endregion + + #region Constructors + + /// + /// Instantiate an SnmpTrapOptions class for use with SnmpSendTrap.Send() + /// + /// i.e. GenericStatus.EnterpriseSpecific + /// The OID for the enterprise you are sending a trap to + /// The OID for your Application + /// Community String (password) for the remote listener + public SnmpTrapOptions(GenericStatus snmpGenericStatus, int snmpSpecificStatus, string enterpriseOID, string applicationTrapOID, string communityString, long timeTicks) + { + SnmpGenericStatus = snmpGenericStatus; + SnmpSpecificStatus = snmpSpecificStatus; + CommunityString = Encoding.Default.GetBytes(communityString); + EnterpriseOID = StringOidToByteArray(enterpriseOID); + ApplicationTrapOID = StringOidToByteArray(applicationTrapOID); + TimeTicks = timeTicks; + } + + #endregion + + #region OID Conversion + private static byte[] StringOidToByteArray(string oid) + { + string[] oidList = oid.Split('.'); + + if (oidList.Length < 2) + { + throw new ArgumentException(String.Format("Invalid OID string: {0}", oid)); + } + + ulong[] values = new ulong[oidList.Length]; + + for (int i = 0; i < oidList.Length; i++) + { + values[i] = Convert.ToUInt64(oidList[i]); + } + MemoryStream byteStream = new MemoryStream(); + byteStream.WriteByte((byte)(values[0] * 40 + values[1])); + + for (int i = 2; i < values.Length; i++) + { + EncodeValue(byteStream, values[i]); + } + + return byteStream.ToArray(); + } + + /// + /// Encode single OID value. + /// + /// Output stream + /// Source value + private static void EncodeValue(Stream stream, ulong value) + { + for (int i = (BitPrecision(value) - 1) / 7; i > 0; i--) + { + stream.WriteByte((byte)(0x80 | ((value >> (i * 7)) & 0x7f))); + } + + stream.WriteByte((byte)(value & 0x7f)); + } + + /// + /// Calculate how many bits is enough to hold ivalue. + /// + /// Source value + /// Number of bits + private static int BitPrecision(ulong value) + { + if (value == 0) + { + return 0; + } + + int l = 0, h = 8 * 4; // 4: sizeof(ulong) + while (h - l > 1) + { + int t = (int)(l + h) / 2; + if ((value >> t) != 0) + l = t; + else + h = t; + } + + return h; + } + + #endregion + } + + /// + /// Generates simple SNMP packet including Trap PDU + /// + static class SnmpTrap + { + // may be the result of the ASN.1 length encoding routine, however this has proven to be + // the most reliable out of all the c# snmp code I could review + private static int maxEncodableStringLength = 4000; + + #region SNMP Trap Generation + + /// + /// Generate SNMP Trap sequence including a message + /// + /// Your message + /// SnmpTrapOptions object + /// A generic list of bytes representing a complete snmp packet + public static List GetTrapSequence(string message, SnmpTrapOptions options) + { + List data = new List(); + + // build header + byte[] header = new byte[] { 0x02, 0x01, 0x00, ToByte(DataType.OctetString), Convert.ToByte(options.CommunityString.Length) }; + // { "IntegerType", "Length", "SNMP Version 1 == 0", "String Type", "Length", "CommunityName" + + data.AddRange(header); + data.AddRange(options.CommunityString); + + // add trap PDU + AddTrapPDU(data, message, options); + + // insert length-dependent bytes after generating sequence PDU, etc. + data.InsertRange(0, GetLengthInBytes(data.Count)); + data.Insert(0, ToByte(DataType.Sequence)); + + return data; + } + + #endregion + + #region Byte Conversion Routines + // does not appear to work w/ length > 190 + //private static List GetLengthInBytes(int length) + //{ + // List data = new List(); + // int len = length; + + // data.Add((byte)(len & 0xFF)); + + // len >>= 8; + // while (len != 0) + // { + // data.Add((byte)(len & 0xFF)); + // len >>= 8; + // } + + // if (length >= 0x80 || data.Count > 1) + // { + // data.Insert(0, (byte)(data.Count | 0x80)); + // } + + // return data; + //} + + // doesn't work at all + //private static List GetLengthInBytes(int length) + //{ + // byte[] lengthInBytes = BitConverter.GetBytes(length); + + // List data = new List(); + // for (int i = 3; i >= 0; i--) + // { + // if (lengthInBytes[i] != 0)// || buf.Length > 0) + // { + // data.Add(lengthInBytes[i]); + // } + // } + + // if (data.Count == 0) + // { + // // we are encoding a 0 value. Can't have a 0 byte length encoding + // data.Add((byte)0); + // } + + // // check for short/long form encoding + // if (data.Count != 1 && (data[0] & HIGH_BIT) != 0) + // { + // // long form + // byte encHeader = (byte)data.Count; + // encHeader = (byte)(encHeader | HIGH_BIT); + + // data.Insert(0, encHeader); + // } + + // return data; + //} + + // staight from ASN.1 implementation + private static List GetLengthInBytes(int length) + { + List lengthInBytes = new List(); + + if (length > 127) + { + if (length <= Byte.MaxValue) + { + lengthInBytes.Add(0x81); + lengthInBytes.Add(ToByte(length)); + } + else if (length <= UInt16.MaxValue) + { + lengthInBytes.Add(0x82); + lengthInBytes.Add(ToByte(length >> 8)); + lengthInBytes.Add(ToByte(length)); + } + else if (length <= 0xFFFFFF) // 24 bits + { + lengthInBytes.Add(0x83); + lengthInBytes.Add(ToByte(length >> 16)); + lengthInBytes.Add(ToByte(length >> 8)); + lengthInBytes.Add(ToByte(length)); + } + else // 32 bits (max) + { + lengthInBytes.Add(0x84); + lengthInBytes.Add(ToByte(length >> 24)); + lengthInBytes.Add(ToByte(length >> 16)); + lengthInBytes.Add(ToByte(length >> 8)); + lengthInBytes.Add(ToByte(length)); + } + } + else + { + lengthInBytes.Add(ToByte(length)); + } + + return lengthInBytes; + } + + // using same routine as signed integer, works up to long.MaxValue + private static List GetLengthAndDataBytes(long value, DataType dataType) + { + List data = new List(); + long val = value; + do + { + data.Insert(0, (byte)(val & 0xFF)); + val >>= 8; + } + while (val != 0); + + data.InsertRange(0, GetLengthInBytes(data.Count)); + data.Insert(0, ToByte(DataType.TimeTicks)); + + return data; + } + + private static byte ToByte(GenericStatus value) + { + return (byte)value; + } + + private static byte ToByte(DataType value) + { + return (byte)value; + } + + private static byte ToByte(int value) + { + return (byte)value; + } + + private static byte[] ToBytes(string data) + { + return Encoding.Default.GetBytes(data); + } + #endregion + + #region Trap PDU Generation + private static void AddTrapPDU(List data, string message, SnmpTrapOptions options) + { + List innerData = new List(); + + AddTrapSourceOID(innerData, options.EnterpriseOID); + AddTrapSourceIP(innerData); + AddTrapStatusGeneric(innerData, options.SnmpGenericStatus); + AddTrapStatusSpecific(innerData, ToByte(options.SnmpSpecificStatus)); + AddTrapTimeTicks(innerData, options.TimeTicks); + + // TODO: make extensible? Maybe not... appenders all seem to do the same thing, log a string + AddTrapVariables(innerData, message, options); + + innerData.InsertRange(0, GetLengthInBytes(innerData.Count)); + innerData.Insert(0, ToByte(DataType.TrapV1Pdu)); + + data.AddRange(innerData); + } + + private static void AddTrapSourceOID(List data, byte[] enterpriseOID) + { + data.Add(ToByte(DataType.ObjectIdentifier)); + data.AddRange(GetLengthInBytes(enterpriseOID.Length)); + data.AddRange(enterpriseOID); + } + + private static void AddTrapSourceIP(List data) + { + IPAddress[] ips = Dns.GetHostAddresses(Dns.GetHostName()); + data.Add(ToByte(DataType.IPAddress)); + data.Add((byte)4); + + if (ips.Length > 0) + data.AddRange(ips[0].GetAddressBytes()); + else + data.AddRange(new byte[4] { 0, 0, 0, 0 }); + } + + private static void AddTrapStatusGeneric(List data, GenericStatus genericStatus) + { + data.Add(ToByte(DataType.Integer32)); + data.Add((byte)1); + data.Add(ToByte(genericStatus)); + } + + private static void AddTrapStatusSpecific(List data, byte specificStatus) + { + data.Add(ToByte(DataType.Integer32)); + data.Add((byte)1); + data.Add(specificStatus); + } + + private static void AddTrapTimeTicks(List data, long timeTicks) + { + data.AddRange(GetLengthAndDataBytes(timeTicks, DataType.TimeTicks)); + } + + private static void AddTrapVariables(List data, string message, SnmpTrapOptions options) + { + List innerData = new List(); + + // using the ASN1 length encoding routine above, there appears to be a threshold where + // WireShark, TrapListener and SysEdge cannot decode the Trap PDU + if (message.Length > maxEncodableStringLength) + { + message = String.Format("{0}...", message.Substring(0, maxEncodableStringLength - 3)); + } + + AddTrapMessage(innerData, message, options.ApplicationTrapOID); + + innerData.InsertRange(0, GetLengthInBytes(innerData.Count)); + innerData.Insert(0, ToByte(DataType.Sequence)); + + data.AddRange(innerData); + } + + private static void AddTrapMessage(List data, string message, byte[] applicationTrapOID) + { + List innerData = new List(); + + innerData.Add(ToByte(DataType.ObjectIdentifier)); + innerData.AddRange(GetLengthInBytes(applicationTrapOID.Length)); + innerData.AddRange(applicationTrapOID); + + innerData.Add(ToByte(DataType.OctetString)); + innerData.AddRange(GetLengthInBytes(message.Length)); + innerData.AddRange(ToBytes(message)); + + innerData.InsertRange(0, GetLengthInBytes(innerData.Count)); + innerData.Insert(0, ToByte(DataType.Sequence)); + + data.AddRange(innerData); + } + #endregion + } + + #endregion + + #region Snmp/ASN.1 Enums + /// + /// The Generic SNMP Status of the Trap + /// + public enum GenericStatus + { + /// + /// 0 - The system is starting up for the first time + /// + ColdStart = 0, + + /// + /// 1 - The system has rebooted + /// + WarmStart = 1, + + /// + /// 2 - The link is down + /// + LinkDown = 2, + + /// + /// 3 - The link is up + /// + LinkUp = 3, + + /// + /// 4 - An authentication failure occured + /// + AuthenticationFailure = 4, + + /// + /// 5 + /// + EgpNeighborLoss = 5, + + /// + /// 6 + /// + EnterpriseSpecific = 6 + } + + /// + /// The ASN1 DataType of the variable element + /// + public enum DataType + { + /// + /// 0x02 - A single byte integer (0x00 - 0xFF) + /// + Integer32 = 0x02, + + /// + /// 0x03 - String of character information encoded in up to 255 bytes + /// + DisplayString = 0x03, + + /// + /// 0x04 - Stream of bytes up to 255 bytes long + /// + OctetString = 0x04, + + /// + /// 0x06 - An SNMP OID, which can be up to 255 bytes long + /// + ObjectIdentifier = 0x06, + + /// + /// 0x30 - A sequence of OID,Length,Data triplets where the maximum size can be up to 255 bytes + /// + Sequence = 0x30, + + /// + /// 0x40 - A 4 byte octet string representing an IP + /// + IPAddress = 0x40, + + /// + /// 0x43 - 1/100 seconds since some epoch as per MIB specification, 4 bytes long + /// + TimeTicks = 0x43, + + /// + /// 0x45 - Network Address (IP) and is 4 bytes long + /// + NetworkAddress = 0x45, + + /// + /// 0xa4 - Declaration of the main body of the trap + /// + TrapV1Pdu = 0xa4, + } + + #endregion +} \ No newline at end of file Index: log4net.vs2008.csproj =================================================================== --- log4net.vs2008.csproj (revision 934970) +++ log4net.vs2008.csproj (working copy) @@ -153,6 +153,7 @@ Code + Code