Static Packet Construction with C
Anyone with even a cursory interest in networks needs to dig below the high level socket libraries to learn how networks operate by constructing packets headers and all and letting them loose on the network. Unfortunately, almost all of today’s low level network code makes use of antiquated data structures, frivolously casts character buffers to user defined types, is littered with pointer arithmetic, and relies heavily on the C preprocessor. Although I’m not a C++ purest who believes that C is the root of all evil, C does seem to have an iron grip on areas of system programming when languages such as C++ may provide advantages. Thus, almost all popular open source tools developed at this level, including network scanners, exploits, sniffers, and the like, are written in C using many of the same unsafe, unreadable coding practices.
Instead of continuing this legacy of requiring C in low level network code, you can leverage C++’s powers to take the “hack” out of hacking and move towards writing more readable, safer tools. In this article, I use C++ s to facilitate packet construction and show timberland how this can be used to write generic routines to support low level networking primitives.
My main focus is on developing a set of building blocks from which you can construct packets of arbitrary complexity. One of the more frustrating aspects of dealing with packet headers is handling addresses. With addresses come the headaches of byte ordering, converting from user readable character strings to their respective byte representation, and manipulating those utterly confusing C address structs. While any good C++ networking library contains an address class and you don’t want to reinvent the wheel, my needs are particular. I want to use addresses as part of a protocol header. For example, consider this struct that defines an Ethernet packet header:
If ethernetaddr is the class representing an Ethernet address, it is imperative that ethernetaddr’s memory footprint be only the 6 bytes representing the address. Any additional member variables interfere with the layout of the protocol header. Also, the byte representation of the address should be stored internally in network byte order, a timberland s the packet should look on the wire. While this isn’t important for Ethernet addresses, it often comes into play with IPv4 addresses. It is important to ensure that the byte ordering is consistent across all accessors and mutators.
Here, I use two address classes ethernetaddr (10 timberland /100 mb Ethernet) and ipaddr (IPv4) that handle conversion to/from user readable strings, bitwise operations, comparison operations, and mathematical operations. Listing timberland 1 is the class declaration for ipaddr. (Listing 2 demonstrates ipaddr in action.) The ethernetaddr class has similar functionality.
Templates and Packet Construction
Given a library of predefined protocol headers, you want to be able to piece them together anyway you like to construct valid, layered network packets. For example, say you want to construct an Ethernet ARP packet in memory, the protocol headers should be nested as follows:Again, the C style approach is to declare a buffer of the correct size, then dynamically pack it by casting header structs to appropriate offsets within the buffer. Why not let the C++ mechanism construct the memory layout? For example, consider these two structs: