I have updated how the header structure is represented in jnetpcap. Currently the header was simply described in native structures in 2 properties: offset and length. The offset is the offset into the overall packet buffer where the header starts and length property stored how many bytes long the header is. So offset + length pointed at the first byte past the header.
This simple structure did not take into account that some headers can have a slightly more complex structure. For example Ethernet2 frames are actually made up of a 8 byte preamble, then the 14 byte header, ethernet frame payload and a trailer at the end of the frame where last 4 bytes contain the CRC for the entire frame. Most NICs (Network Interface Cards) and OS kernels drop the preamble and trailer and the pcap user usually only sees the header and the payload.
I have expanded the native header "record" representation within the packet. The current structure takes into account the following structure:
+-------------------------------------------+ | prefix | header | gap | payload | postfix | +-------------------------------------------+
The header scanners calculate all of the above components. Of course, not all header utilize a prefix, a gap or a postfix. Most only utilize a header and payload component. Unused components are still there, but their length is set to zero.
The JHeader.State class has been enhanced to provide access to the new header properties. Also JHeader now provides accessor methods for each type of component and for convenience a data accessor method that retrieves the raw data as a byte[].
Specifically the following methods were added to JHeader class:
hasPrefix():boolean, getPrefixOffset():int,
getPrefixLength():int, getPrefix():byte[]
hasGap():boolean, getGapOffset():int,
getGapLength():int, getGap():byte[]
hasPayload():boolean, getPayloadffset():int,
getPayloadLength():int, getPayload():byte[]
hasPostfix():boolean, getPostfixOffset():int,
getPostfixLength():int, getPostfix():byte[]The scanning algorithm takes into account all the new header properties when calculating these values. For example a header that has a postfix such as some kind of padding at the end, will have its payload length calculated such that it not longer goes to the end of the entire packet, but only to the point where the padding starts.
Lets say that we have the following packet:
+------------------------------------------------------------------------------+ | preamble | ethernet | ip4 | udp | rtp | payload | rtp_padding | ethernet_crc | +------------------------------------------------------------------------------+ 0 8 22 42 50 62 162 163 167
There are 2 perspectives from which we can look at this packet. The first from a JPacket's point of view and the second from a header's point of view.
From packets point of view this is what it looks like:
+------------------------------------------------------------------------------+ | | ethernet | ip4 | udp | rtp | payload | unused packet part | +------------------------------------------------------------------------------+ 0 8 22 42 50 62 162 163 167
The packet only sees headers. Although the packet can access any part of the packet buffer, its has recorded information only about ethernet, ip4, upd rtp and payload headers (yes, payload.class is a normal header in jnetpcap). The remaining portions of the packet are only accessible using raw read methods that JPacket provides by extending JBuffer.
On the other hand, from individual header's perspective there is a lot more info. The diagram below shows the same packet from each header's point of view.
+------------------------------------------------------------------------------+
Eth => | preamble | ethernet | ethernet_payload | ethernet_crc |
+------------------------------------------------------------------------------+
Ip4 => | | ip4 | payload | |
+------------------------------------------------------------------------------+
Udp => | | udp | payload | |
+------------------------------------------------------------------------------+
Rtp => | | rtp | payload | rtp_padding | |
+------------------------------------------------------------------------------+
0 8 22 42 50 62 162 163 167
The packet structure looks a lot more complete. When you access ethernet header, you can use JHeader.getPrefix():byte[] to access the preamble. Ethernet's payload, at least from its perspective, is all the data the follows the ethernet header less then the crc trailer at the end. The payload in actuality is ip4 header, that from Ip4's perspecitve goes upto the end of ethernet's payload. Ip4's payload contains a udp datagram which has its own payload. Finally the Udp's payload contains an Rtp header that has its own payload and some padding to put the data on a 32-bit boundary (inline with Rtp specification).
All header's now provide convenience methods that provide offset and length of a header's prefix, a gap, payload and postfix. The Header's payload is not neccessarily the same payload that is recorded as a Payload header within the packet. The Packet's payload class, references the portion of the packet buffer, that has not been decoded as any other header. Its a catch-all header that assumes that its a payload of the last header. Therefore, the packet's payload header will reference exactly the same data as the last header within the packet which in our example's case is the rtp header's payload (bytes 62-162).
What does it all mean. From normal regular user's perspective, nothing. From a header definition developer, you now have the tools neccessary to correctly define boundaries of a given protocol, beside just the header itself. This was an issue upto now, since trailers had to be specifically handled within the header's decoder routine with some messy code. It is now very easy to define any of these additional header properties.
By default all of these properties are set to zero, and the payload length property is calculated by the scanner if it hasn't been defined to anything else. Therefore if a header doesn't use any of these extra properties, you just leave those properties out of your code and everything will be calculated for you. For example, this structral enhancement did not require any of the existing header definitions to be touched, although ethernet and 802.3 scanners may defined pre-ample and crc trailers on certain platforms. The new Rtp header definition is the only one so far that utilizes a posfix for padding its payload to a 32-bit boundary. I do not know of any protocols that use a gap (padding between the header and its payload).
For native header scanner functions, these new properties are set from native code in the "header_t" structure. In java the @HeaderLength and @Header annotations have been expanded to allow additional length getter methods to be defined. The @Header annotation now contains a new property called type. It takes an enum table constant HeaderLength.Type. There is a constant for each type of header padding.
Also the @Header annotation takes new parameters with static length. The new parameters are "prefix", "gap", "payload", "postfix", each takes an integer as a static length. For example to define a 8 byte preamble @Header(prefix = 8). You can define dynamic counter parts with @HeaderLength annotation, just like with the normal header length method. For example to define a dynamic method that determines the length of a postfix you would annotate the length getter method as follows: @HeaderLength(HeaderLength.Type.POSTFIX). This will cause your postfix length getter method to be called everytime a packet and this particular header is scanned.
Comments
Changes checked in. Also
Changes checked in. Also tagged the SVN tree before the checkin, just incase we need to revert the state to original header_t.
jnetpcap/tags/1.2/checkpoint-09-06-11
Sly Technologies, Inc.
R&D