Packet Filtering in the SNMP Remote Monitor

The Simple Network Management Protocol (SNMP) was designed for managing complex, multivendor internetworks. Bill examines its remote-network monitoring facilities, while Steve Witten adds details on the abstract-syntax notation, an OSI language for defining the formats of SNMP packets.


November 01, 1994
URL:http://www.drdobbs.com/architecture-and-design/packet-filtering-in-the-snmp-remote-moni/184409347

Figure 1


Copyright © 1994, Dr. Dobb's Journal

Figure 2


Copyright © 1994, Dr. Dobb's Journal

Figure 2


Copyright © 1994, Dr. Dobb's Journal

Figure 3


Copyright © 1994, Dr. Dobb's Journal

Figure 3


Copyright © 1994, Dr. Dobb's Journal

Figure 1


Copyright © 1994, Dr. Dobb's Journal

Figure 2


Copyright © 1994, Dr. Dobb's Journal

Figure 3


Copyright © 1994, Dr. Dobb's Journal

NOV94: Packet Filtering in the SNMP Remote Monitor

Packet Filtering in the SNMP Remote Monitor

Controlling remote monitors on a LAN

William Stallings

William is president of Comp-Comm Consulting of Brewster, MA. This article is based on his recent book, SNMP, SNMPv2, and CMIP: The Practical Guide to Network Management Standards (Addison-Wesley, 1993). He can be reached at [email protected].


The Simple Network Management Protocol (SNMP) architecture was designed for managing complex, multivendor internetworks. To achieve this, a few managers and numerous agents scattered throughout the network must communicate. Each agent uses its own management-information database (MIB) of managed objects to observe or manipulate the local data available to a manager.

The remote-network monitoring (RMON) MIB, defined as part of the SNMP framework, provides a tool that an SNMP or SNMPv2 manager can use to control a remote monitor of a local-area network. The RMON specification is primarily a definition of a data structure containing management information. The effect, however, is to define standard network-monitoring functions and interfaces for communicating between SNMP-based management consoles and remote monitors. In general terms, the RMON capability provides an efficient way of monitoring LAN behavior, while reducing the burden on both other agents and management stations; see Figure 1.

The accompanying text box entitled, "Abstract Syntax Notation One (ASN.1)" gives details on defining the communication formats between agents and managers.

The key to using RMON is the ability to define "channels"--subsets of the stream of packets on a LAN. By combining various filters, a channel can be configured to observe a variety of packets. For example, a monitor can be configured to count all packets of a certain size or all packets with a given source address.

To use RMON effectively, the person responsible for configuring the remote monitor must understand the underlying filter and channel logic used in setting it up. In this article, I'll examine this filter and channel logic.

The RMON MIB contains variables that can be used to configure a monitor to observe selected packets on a particular LAN. The basic building blocks are a data filter and a status filter. The data filter allows the monitor to screen observed packets based on whether or not a portion of the packet matches a certain bit pattern. The status filter allows the monitor to screen observed packets on the basis of their status (valid, CRC error, and so on). These filters can be combined using logical AND and OR operations to form a complex test to be applied to incoming packets. The stream of packets that pass the test is referred to as a "channel," and a count of such packets is maintained. The channel can be configured to generate an alert if a packet passes through the channel when it is in an enabled state. Finally, the packets passing through a channel can be captured in a buffer. The logic defined for a single channel is quite complex. This gives the user enormous flexibility in defining the stream of packets to be counted.

Filter Logic

At the lowest level of the filter logic, a single data or status filter defines characteristics of a packet. First, consider the logic for defining packet characteristics using the variables input (the incoming portion of a packet to be filtered), filterPktData (the bit pattern to be tested for), filterpktDataMask (the relevant bits to be tested for), and filterPktDataNotMask (which indicates whether to test for a match or a mismatch). For the purposes of this discussion, the logical operators AND, OR, NOT, XOR, EQUAL, and NOT-EQUAL are represented by the symbols o, +, --, _, =, and _, respectively.

Suppose that initially, you simply want to test the input against a bit pattern for a match. This could be used to screen for packets with a specific source address, for example. In the expression in Example 1(a), you would take the bit-wise exclusive-OR of input and filterPktData. The result has a 1 bit only in those positions where input and filterPktData differ. Thus, if the result is all 0s, there's an exact match. Alternatively, you may wish to test for a mismatch. For example, suppose a LAN consists of a number of workstations and a server. A mismatch test could be used to screen for all packets that did not have the server as a source. The test for a mismatch would be just the opposite of the test for a match; see Example 1(b). A 1 bit in the result indicates a mismatch.

The preceding tests assume that all bits in the input are relevant. There may, however, be some "don't-care" bits irrelevant to the filter. For example, you may wish to test for packets with any multicast destination address. Typically, a multicast address is indicated by one bit in the address field; the remaining bits are irrelevant to such a test. The variable filterPktDataMask is introduced to account for "don't-care" bits. This variable has a 1 bit in each relevant position and 0 bits in irrelevant positions. The tests can be modified; see Example 1(c).

The XOR operation produces a result that has a 1 bit in every position where there is a mismatch. The AND operation produces a result with a 1 bit in every relevant position where there is a mismatch. If all of the resulting bits are 0, then there is an exact match on the relevant bits; if any of the resulting bits is 1, there is a mismatch on the relevant bits.

Finally, you may wish to test for an input that matches in certain relevant bit positions and mismatches in others. For example, you could screen for all packets that had a particular host as a destination (exact match of the DA field) and did not come from the server (mismatch on the SA field). To enable these more complex tests to be performed, use filterPktDataNotMask, where:

For convenience, assume the definition in Example 2(a). Incorporating filterPktDataNotMask into the test for a match gives Example 2(b).

The test for a mismatch is slightly more complex. If all of the bits of filterPktDataNotMask are 0 bits, then no mismatch test is needed. By the same token, if all bits of filterPktDataNotMask are 1 bits, then no match test is needed. However, in this case, filterPktDataNotMask is all 0s, and the match test automatically passes relevant_bits_differento0=0. Therefore, the test for mismatch is as in Example 2(c).

The logic for the filter test is summarized in Figure 2. If an incoming packet is to be tested for a bit pattern in a portion of the packet, located at a distance filterPktDataOffset from the start of the packet, the following tests will be performed:

A packet passes this filter if and only if it passes all three tests.

Why use the filter test? Consider that you might want to accept all Ethernet packets that have a destination address of "A5"h but do not have a source address of "BB"h. The first 48 bits of the Ethernet packet constitute the destination address and the next 48 bits, the source address. Example 3 implements the test. The variable filterPktDataOffset indicates that the pattern matching should start with the first bit of the packet; filter PktData indicates that the pattern of interest consists of "A5"h in the first 48 bits and "BB"h in the second 48 bits; filter PktDataMask indicates that the first 96 bits are relevant; and filterPktDataNotMask indicates that the test is for a match on the first 48 bits and a mismatch on the second 48 bits.

The logic for the status filter has the same structure as that for the data filter; see Figure 2. For the status filter, the reported status of the packet is converted into a bit pattern. Each error-status condition has a unique integer value, corresponding to a bit position in the status-bit pattern. To generate the bit pattern, each error value is raised to a power of 2 and the results are added. If there are no error conditions, the status-bit pattern is all 0s. An Ethernet interface, for example, has the error values defined in Table 1. Therefore, an Ethernet fragment would have the status value of 6(21+22).

Channel Definition

A channel is defined by a set of filters. For each observed packet and each channel, the packet is passed through each of the filters defined for that channel. The way these filters are combined to determine whether a packet is accepted for a channel depends on the value of an object associated with the channel (channelAcceptType), which has the syntax INTEGER {acceptMatched(1), acceptFailed(2)}.

If the value of this object is acceptMatched(1), packets will be accepted for this channel if they pass both the packet-data and packet-status matches of at least one associated filter. If the value of this object is acceptFailed(2), packets will be accepted to this channel only if they fail either the packet-data match or the packet-status match of every associated filter.

Figure 3 illustrates the logic by which filters are combined for a channel whose accept type is acceptMatched. A filter is passed if both the data filter and the status filter are passed; otherwise, that filter has failed. If you define a pass as a logical 1 and a fail as a logical 0, then the result for a single filter is the AND of the data filter and status filter for that filter. The overall result for a channel is then the OR of all the filters. Thus, a packet is accepted for a channel if it passes at least one associated filter pair for that channel.

If the accept type for a channel is acceptFailed, then the complement of the function just described is used. That is, a packet is accepted for a channel only if it fails every filter pair for that channel. This would be represented in Figure 3 by placing a NOT gate after the OR gate.

Channel Operation

The value of channelAcceptType and the set of filters for a channel determine whether a given packet is accepted for a channel or not. If the packet is accepted, then the counter channelMatches is incremented. Several additional controls are associated with the channel: channelDataControl, which determines whether the channel is on or off; channelEventStatus, which indicates whether the channel is enabled to generate an event when a packet is matched; and channelEventIndex, which specifies an associated event.

When channelDataControl has the value off, then, for this channel, no events may be generated as the result of packet acceptance, and no packets may be buffered. If channelDataControl has the value on, then these related actions are possible.

Figure 4 summarizes the channel logic. If channelDataControl is on, then an event will be generated if: 1. an event is defined for this channel in channelEventIndex; and 2. channelEventStatus has the value eventReady or eventAlwaysReady. If the event status is eventReady, then each time an event is generated, the event status is changed to eventFired. It then takes a positive action on the part of the management station to reenable the channel. This mechanism can therefore be used to control the flow of events from a channel to a management station. If the management station is not concerned about flow control, it may set the event status to eventAlwaysReady, where it will remain until explicitly changed.

Summary

The packet-filtering facility of RMON provides a powerful tool for the remote monitoring of LANs. It enables a monitor to be configured to count and buffer packets that pass or fail an elaborate series of tests. This facility is the key to successful remote-network monitoring.

Abstract Syntax Notation One (ASN.1)

Steve Witten

Steve, a software engineer for Hewlett-Packard, specializes in network testing and measurement. You can contact him at [email protected].

SNMP protocol and MIB are formally defined using an abstract syntax. This allowed SNMP's authors to define data and data structures without regard to differences in machine representations. This abstract syntax is an OSI language called "abstract syntax notation one" (ASN.1). It is used for defining the formats of the packets exchanged by the agent and manager in the SNMP protocol and is also the means for defining the managed objects.

ASN.1 is a formal language defined in terms of a grammar. The language itself is defined in ISO #8824. The management framework defined by the SNMP protocol, the SMI, and the MIB use only a subset of ASN.1's capabilities. While the general principles of abstract syntax are good, many of the bells and whistles lead to unnecessary complexity. This minimalist approach is taken to facilitate the simplicity of agents.

Listings One through Three show an MIB, using a fictitious enterprise called SNMP Motors. Listing One is an ASN.1 module that contains global information for all MIB modules. Listing Two, another ASN.1 module, contains the definitions of specific MIB objects. Finally, Listing Three illustrates manageable objects.

Once data structures can be described in a machine-independent fashion, there must be an unambiguous way of transmitting those structures over the network. This is the job of the transfer-syntax notation. Obviously, you could have several transfer-syntax notations for an abstract syntax, but only one abstract-syntax/transfer-syntax pair has been defined in OSI. The basic encoding rule (BER) embodies the transfer syntax. The BER is simply a recursive algorithm that can produce a compact octet encoding for any ASN.1 value.

At the top level, the BER describes how to encode a single ASN.1 type. This may be a simple type such as an Integer, or an arbitrarily complex type. The key to applying the BER is understanding that the most complex ASN.1 type is nothing more than several simpler ASN.1 types. Continuing the decomposition, an ASN.1 simple type (such as an Integer) is encoded.

Using the BER, each ASN.1 type is encoded as three fields: a tag field, which indicates the ASN.1 type; a length field, which indicates the size of the ASN.1 value encoding which follows; and a value field, which is the ASN.1 value encoding.

Each field is of variable length. Because ASN.1 may be used to define arbitrarily complex types, the BER must be able to support arbitrarily complex encodings.

It is important to note how the BER views an octet. Each octet consists of eight bits. BER numbers the high-order (most significant) bit as bit 8 and the low-order (least significant) bit as bit 1. It's critical that this view be applied consistently because different machine architectures use different ordering rules.

Figure 1 RMON description.

Figure 2 Logic for the filter test.

Figure 3 Logic by which filters are combined for a channel whose accept type is acceptMatched.

Figure 4: Logic for channel filter.

procedure packet_data_match;
begin
  if (result = 1 and channelAcceptType = acceptMatched) or
     (result = 0 and channelAcceptType = acceptFailed)
  then begin
     channelMatches := channelMatches + 1;
     if channelDataControl = on
     then begin
             if (channelEventStatus _ eventFired) and
                (channelEventIndex _ 0) then generate_event;
             if (channelEventStatus = eventReady) then 
                  channelEventStatus := eventFired
             end;
      end;
end;

Example 1: Testing the input against a bit pattern for a match.

(a) (input XOR filterPktData) = 0 --> match

(b) (input XOR filterPktData) (does not equal) 0 --> mismatch

(c) ((input XOR filterPktData) (and) filterPktDataMask) = 
      0 --> match on relevant bits 
    ((input XOR filterPktData) (and) filterPktDataMask) (does not equal) 
      0 --> mismatch on relevant bits

Table 1: Ethernet-interface error values.

     Bit   Error

     0     Packet is longer than 1518 octets.
     1     Packet is shorter than 64 octets.
     2     Packet experienced a CRC or
           alignment error.

Example 2: Assuming the definition in (a), incorporating filterPktDataNotMask into the test for a match, you end up with (b). Test for a mismatch is shown in (c).

(a) relevant_bits_different = 
      (input XOR filterPktData) (and) filterPktDataMask

(b) (relevant_bits_different (and) filterPktDataNotMask') = 
      0 --> successful match

(c) ((relevant_bits_different (and) filterPktDataNotMask) (does not equal) 0) + 
      (filterPktDataNotMask = 0) --> successful mismatch

Example 3: Launching a filter test.

filterPktDataOffset   = 0
filterPktData         = "00 00 00 00 00 A5 00 00 00 00 00 BB"h
filterPktDataMask     = "FF FF FF FF FF FF FF FF FF FF FF FF"h
filterPktDataNotMask  = "00 00 00 00 00 00 FF FF FF FF FF FF"h

Listing One


SNMP-motors-MIB DEFINITIONS ::= BEGIN
IMPORTS
    enterprises
        FROM RFC1155-SMI;
SNMP-motors OBJECT IDENTIFIER ::= { enterprises 9999 }
expr        OBJECT IDENTIFIER ::= { SNMP-motors 2 }
END


Listing Two


SNMP-motors-car-MIB DEFINITIONS ::= BEGIN
IMPORTS
    SNMP-motors
        FROM SNMP-motors-MIB;
IMPORTS
    OBJECT TYPE, ObjectName, NetworkAddress,
    IpAddress, Counter, Gauge, TimeTicks, Opaque
        FROM RFC1155-SMI;
car OBJECT IDENTIFIER ::= { SNMP-motors 3 }
-- this is a comment
-- Implementation of the car group is mandatory
-- for all SNMP-motors cars.
-- ( the rest of the SNMP-motors-car-MIB module )
END


Listing Three


carName OBJECT TYPE
    SYNTAX DisplayString (SIZE (0..64))
    ACCESS read-only
    STATUS mandatory
    DESCRIPTION
        "A textual name of the car."
    ::= { car 1 }
carLength OBJECT TYPE
    SYNTAX INTEGER (0..100)
    ACCESS read-only
    STATUS mandatory
    DESCRIPTION
        "The length of the car in feet."
    ::= { car 2 }
carPassengers OBJECT TYPE
    SYNTAX INTEGER (0..4)
    ACCESS read-only
    STATUS mandatory
    DESCRIPTION
        "The number of passengers in the car."
    ::= { car 3 }
carPassengerTable OBJECT TYPE
    SYNTAX SEQUENCE OF CarPassengerEntry
    ACCESS not-accessible
    STATUS mandatory
    DESCRIPTION
        "A table describing each passenger."
    ::= { car 4 }
carPassengerEntry OBJECT TYPE
    SYNTAX SEQUENCE OF CarPassengerEntry
    ACCESS not-accessible
    STATUS mandatory
    DESCRIPTION
        "A entry table describing each passenger."
    ::= { carPassengerTable 1 }
CarPassengerEntry ::= SEQUENCE {
    carPindex
        INTEGER,
    carPname
        DisplayString,
    carPstatus
        INTEGER
}
carPindex OBJECT TYPE
    SYNTAX INTEGER (1..4)
    ACCESS read-only
    STATUS mandatory
    DESCRIPTION
        "Index for each passenger which ranges from               
                  1 to the value of carPassengers."
    ::= { carPassengerEntry 1 }
carPname OBJECT TYPE
    SYNTAX DisplayString (SIZE (0..64))
    ACCESS read-write
    STATUS mandatory
    DESCRIPTION
        "The name of the passenger."
    ::= { carPassengerEntry 2 }
carPstatus OBJECT TYPE
    SYNTAX INTEGER { other(1),driver(2) }
    ACCESS read-write
    STATUS mandatory
    DESCRIPTION
        "The status of the passenger."
    ::= { carPassengerEntry 3 }

Copyright © 1994, Dr. Dobb's Journal

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.