I was hoping to create a packet crafting application for no particular reason, but had to leave it unfinished for a while. You’ll see why. If nothing else, the project should be educational to anyone learning about the networking layers, protocols and packet crafting tools.
In networking theory TCP/IP packets are usually discussed as a logical structure, with clearly defined header and payload sections, and we visualise those blocks travelling across the Internet (or network) and through the OSI layers. The OSI model, I argue, is actually descriptive rather than prescriptive: Think of it as an assembly line for packets, starting at the application layer and ending at the hardware layer. Each layer adds something specific to the packet.
One of the first things we come across in network programming is ‘sockets’. Basically the socket is a data structure with a file handle that’s created to ensure data is piped to the network interface in the correct format – a network-enabled application should write an IP address, port number, TCP state and payload as variables, the variables should then be strung together into a sequence of bytes, becoming the TCP/UDP packet. The operating system might append a source IP address. The packet is then passed to the network interface. A Python script I created last year shows this at work nicely.
The first line of interest creates an Internet stream (usually TCP) socket:
s = socket(AF_INET, SOCK_STREAM)
The next lines dump the variables serverHost, serverPort and raw_input to the socket:
Anyone running a packet capture would see the bytecode for these variables leaving the network interface in that order. Also important to note is the ‘s.recv(1024)’ line in the script, as this creates a 1024-byte socket buffer for incoming data. An incoming payload larger than 1024 bytes might cause a buffer overflow.
To demonstrate this further, I’ve added a feature to my little C# packet crafting application that enables users compare the bytecode being sent with the captured packet in Wireshark.
The simplest form of packet is the UDP datagram. Since there is no session control or handshake, there are just three variables: destination address, port number and payload. The UDP header has fewer fields and is smaller, thereby reducing the overhead of processing each packet. This is why it’s useful in case where a load of packets are going one-way, and where large numbers of them are redundant packets – video streaming, for example. A person doesn’t need to receive every UDP packets being streamed in order to get decent quality video or audio.
TCP socket programming is slightly more complex, as the program must establish a session with the server prior to sending a payload. This is handled by the operating system at the session/transport layer.
The Hardware Layer
So far the code worked for creating TCP/IP packets by writing to buffers. Data from the buffers are sent in sequence to the network interface, which prefixes the TCP/IP packets with an Ethernet header. It becomes an ‘Ethernet frame’. Because Ethernet works mainly at the hardware layer, we can’t manipulate this directly using C#. There is a NetworkInterface library, but it’s used for reading the status of a network interface.
So what’s needed is a driver that provides an API to the hardware layer, and something like this is provided by Pcap.Net. A few alternatives are available, and I might create my own drivers later in C/C++, if there’s a demand for it.
To use the Pcap.Net libraries, download the binaries from the project page. It will include a collection of DLL files that are referenced in Visual Studio (make sure the Copy Local property is set as ‘True’ for each). From this we require PcapDotNet.Base, PcapDotNet.Core, PcapDotNet.Packets and PcapDotNet.Ethernet.
It does cause ambiguity problems if the System.Net and the PcapDotNet libraries are both used, so the full namespaces must be defined at certain points in the code.
I ran into problems at this point. As far as I can tell, my program constructs the Ethernet headers but doesn’t write them to the outgoing TCP/IP packets because the native Client.Send() already does this. Since I had already coded most the program before including the Pcap.Net library, it needs a rewrite to use it throughout.