Packet.Net The high level design goals of Packet.Net are: - High performance. As little memory allocation/access and cpu usage as possible - Simpler, modular design - Clear and well documented api Packet.Net is a rewrite of SharpPcap's packet parsers. SharpPcap's packet parsers have a few shortcomings in their design. To understand what these are it is important to know more about SharpPcap's design. SharpPcap's packet parsing -------------------------- SharpPcap considers all packets to be of type 'Packet'. Packet types are subclassed, so a UdpPacket is an IpPacket which is an EthernetPacket which is a Packet. This is useful because a user can have a 'UdpPacket udp' and can access the source mac address via 'udp.SourceHwAddress', without having to jump through any hoops. As packets are received they are classified into their most specific type, first by looking at whether they are an EthernetPacket, checking if the EthernetPacket is an IpPacket and then if the IpPacket is a Udp or Tcp packet. At this time the most specific packet is created by passing in the byte stream, like TcpPacket tcp = new TcpPacket(packetBytes); SharpPcap performs lazy field parsing. Each packet field is extracted from the byte stream when requested. Some caching is performed in the TcpPacket class but in most cases the values are re-parsed by reading a number of bytes from a specific offset each time the class property is read. Shortcomings of SharpPcap's design ---------------------------------- Creating packets from values is cumbersome. Because a TcpPacket is an IpPacket which is an EthernetPacket, creating a TcpPacket means we need to somehow simultaniously create the TcpPacket, IpPacket and EthernetPacket. The most natural way to do this was to have the TcpPacket constructor take in the parameters that make up a TcpPacket in addition to an IpPacket. The IpPacket constructor follows the same rule, it takes in its unique parameters plus an EthernetPacket. One user reported that this hierarchy seems confusing because the encapsulation is usually thought of in the reverse order where an ethernet packet contains an ip packet which contains a tcp packet. Another issue of a more technical aspect is the internal method used to actually build the TcpPacket. Because packet bytes are contiguous the TcpPacket constructor has to allocate enough bytes for the IpPacket plus enough bytes for itself. The constructor then has to set its internal buffer to point to this newly allocated buffer, copy in the IpPacket's bytes and then set its own values. This code is complex and can be error prone. The same complexity exists in almost all of the value constructors. Shortcomings in SharpPcap's implementation ------------------------------------------ SharpPcap allows direct access to the header and content bytes of a packet. The Packet class, defined in Packet.cs, defines public accessors for retrieving the byte[] of the header and packet bytes, byte[] Bytes and byte[] Header. These routines do not take care to make the packets valid, ie. if the size of a TcpPacket changes the IpPacket length field is not updated to reflect the change. Design improvements over SharpPcap ---------------------------------- The inheritance order should be reversed. A user refers to the payload of an EthernetPacket to get an IpPacket and the IpPacket payload to get the TcpPacket. Reversing the encapsulation better matches how packets are parsed. Reversing the encapsulation also allows for modifying the type of packet without conflicting with the original class type for example when an IpPacket's payload is changed from a TcpPacket to a UdpPacket. With SharpPcap this is an impossible change because the packet instance is of type TcpPacket. There is no way to convert it to a UdpPacket without creating a new packet that is a copy of the original but with a its type altered. Eliminating the inheritance model of SharpPcap also makes packets easier to construct by value. In SharpPcap a TcpPacket required building an EthernetPacket and an IpPacket and passing both to a TcpPacket constructor that would discard their payloads and copy their headers into a byte[] that was allocated to fit the headers plus the tcp payload. In Packet.Net because each packet is separate a user is less confused by having to build both an IpPacket, that contains an EthernetPacket, and an EthernetPacket separately. Implementation improvements over SharpPcap ------------------------------------------ Packet.Net's Packet has a 'byte[] Bytes' get accessor retrieves packet bytes from the current packet as well as all sub packets. It does so using a fast mechanism in the case where memory is contiguous. Packet data will be contiguous unless the packet was constructed by values or had its payload altered. The contiguous fast case is the typical usage case as it reflects the condition when a packet is captured over the line by a capture library like SharpPcap and parsed using Packet.Net. In the case of non-contiguous memory a fallback mechanism is used that is slightly slower. Things kept the same as SharpPcap --------------------------------- Packet.Net does as much lazy field evaluation as possible. Values are read from memory only when requested by a call to the appropriate accessor. This reduces the number of memory reads in most cases and performs well even in the case when a user wants to retrieve each of the fields of a packet.