Stream, datagram, and raw sockets

Most networking applications communicate using stream (TCP) or datagram (UDP) sockets because they are easy to use: most of the networking details are handled by the socket implementation. For some specialized applications, especially network testing, stream and datagram sockets do not provide enough control over the frame contents. For example, with TCP sockets, the MAC source address is determined by the Ethernet driver, the IP source address and fragmentation fields are controlled by the IP implementation, and the TCP flags are controlled by the TCP implementation.

Raw sockets provide direct control over these fields and others as well. Unfortunately, raw sockets are harder to use: the programmer must explicitly assign every header field and deal with header layouts, byte swapping, and checksum calculation. The Raw Socket Toolkit (RST) is a C API which makes it easier to build, transmit, receive, and parse packets with raw sockets.

The RST way

RST provides three kinds of services:
Socket IO
provides access to raw sockets with a simple open/close/send/receive interface, similar to the C interface for low-level file I/O.
Packet Header
provides functions to build and parse packet headers, including byte swapping and checksum computation. Six protocols are supported: Ethernet, ARP, IP, ICMP, TCP, and UDP.
Utilities
provide ASCII/integer conversions for MAC and IP addresses, and retrieval of the MAC address, IP address, and IP mask for a local interface.

Unlike packet generation APIs like libnet, RST does no encapsulation of packet buffers. Instead, the packet buffers are created by the RST user and are always directly readable and writeable. Typically, most header fields are assigned using packetHeader initialization functions, and then a few fields are overwritten by the RST programmer.

RST documentation consists of this file, detailed API documentation for each function, and a series of executable examples, described below.

Installing RST

After copying and untar'ing the RST directory tree:
	cd rawSocketToolkit/
	make

Running the examples

In the next few sections are a variety of examples illustrating the use of RST. Each example consists of one or more short C programs, designed to be read, and then executed as root. The results are seen using Ethereal.

Each example is briefly described, followed by the shell command(s) used to execute it and the expected results.

If you wish to run the examples below, in a root window in directory rawSocketToolkit/bin type:

	./tapConfig.sh
This script creates two Ethernet taps: simulated Ethernet devices. With taps we can send and receive real network packets without having to set up a private network or risk sending damaging packets on a production network. Taps are extremely useful for tests and demonstrations. The first set of examples uses taps but can be understood without any knowledge of taps. The second set of examples explains tap operation. The third set of examples uses two taps to demonstrate packet forwarding through the kernel.

First examples

First invoke Ethereal and begin capture on the Ethernet interface tap1. Then cd to the examples directory, run the shell commands shown, and look to Ethereal for the expected results. Packet transmission involves the following steps:
  1. Initialize an rst_buf, R. R contains a pointer to a character buffer and pointers to the headers contained in R.
  2. Initialize the protocol headers in R. There is an initialization function for each of the supported protocols.
  3. Optionally override the default values for selected header fields.
  4. Call htonp ("host-to-network-protocol") to handle byte swaps and checksums.
  5. Send R using socketIO.
In the examples below,
generate.c
creates 3 packets: raw Ethernet, ICMP, and TCP, each with header fields unlikely to occur normally.

Shell commands
./generate tap1
Expected results
The first packet contains artificial MAC addresses, the second packet has an incorrect IP checksum, and the third packet has all 6 TCP flags set.
synFlood.c
mounts a TCP SYN flood, designed to disable a host by overflowing its TCP connection table.

Shell commands
./synFlood tap1 00:00:00:00:00:01 10.1.0.99 2000 5
Expected results
There will be 5 packets, identical except for the TCP source port. The source port will be 2000 in the first packet, 2001 in the second, etc.

Tap examples

The examples in the previous section used Ethernet taps, allowing packet generation without using any Ethernet hardware. This section focuses on the use of taps. A tap is a virtual ethernet device. Like a real Ethernet device, a tap can be given an IP address and mask, can be monitored with Ethereal, and can send and receive Ethernet packets with raw, stream, or datagram sockets.

Unlike a real Ethernet device, a tap has no underlying network hardware. Instead a tap has a character device closely associated with the network device. This character device takes the place of the Ethernet hardware. If you write buffer B to the character device, B will arrive through the network device. From the kernel's point of view, it will seem that B has just arrived on an Ethernet card. To work properly, B must contain a complete frame, including at least an Ethernet header. Similarly, if you send a frame to the network device, reading from the character device will yield the frame, including all the headers.

Taps are extremely useful for testing and demonstrations. For example, you can test software designed for a multihomed machine on a machine with a single Ethernet card or even with no network hardware at all.

The Raw Socket Toolkit works well with taps, for generating frames to send to the network device or to write to the character device, and parsing frames received on the network device or read from the character device.

In the examples below, packets are read and parsed. In RST, packet reception involves the following steps:

  1. Create a character buffer C.
  2. Read a character C buffer using socketIO.
  3. Initialize an rst_buf, containing a pointer to C.
  4. Invoke ntohp (network-to-host-protocol) to parse the headers and to handle byte swaps.
  5. Process the packet header fields as needed.
sendOne.c
sends a frame to the network side of a tap and then reads that frame from the character device.

Shell commands
./sendOne tap1
Expected results
Ethereal will display a single Ethernet packet with protocol 0x9000.
The sendOne application will write to stdout:
read. length: 60 protocol: 0x9000
receiveOne.c
writes a frame to the character device and then reads the frame from the network device.

Shell commands
./receiveOne tap1
Expected results
Ethereal will display a single Ethernet packet with protocol 0x9000.
The receiveOne application will write to stdout:
read. length: 60 protocol: 0x9000
echoRequest.c
writes an ICMP echo request to the char device. The packet is sufficiently realistic to stimulate an echo reply from the local host, observable with Ethereal.

Shell commands
./echoRequest tap1 10.1.0.99
Expected results
Ethereal will display the echo request written to the char side of the tap by the echoRequest application, followed by the echo reply sent to the network side of the tap by the ICMP code in the Linux kernel.

Forwarding examples

For the second set of examples, invoke Ethereal twice, with one instance capturing on tap1 and the other capturing on tap2.
forward.c
writes an IP packet to the character side of one tap, which is forwarded by the kernel and sent to the network side of another tap.

To get a raw packet forwarded by the kernel requires careful attention to detail. For packet P arriving on tap1 to be forwarded by the kernel and sent out on tap2:

  1. Forwarding must be enabled in the Linux kernel. This is done by tapConfig.sh.
  2. P's destination MAC address must be the same as tap1's MAC address.
  3. P's destination IP address must be on the same subnet as tap2.
  4. P's destination IP address must not be on the same as tap2's.
  5. P's destination IP address must appear in the ARP cache. This is done in tapConfig.sh by creating static ARP entries for IP addresses 10.1.0.99 and 10.2.0.99.
  6. There must be no firewall rules blocking P. On many Linux hosts, firewall rules are installed during reboot. The firewall rules may be cleared by invoking clearFirewall.sh in the bin directory.

Shell commands
./forward tap1 10.1.0.99 10.2.0.99
Expected results
On tap1, Ethereal will display the packet written to the char side of the tap by the forward application. On tap2, Ethereal will display the packet sent to the network side of tap2 by the IP forwarding code in the Linux kernel.
ipOptions.c
writes an IP packet to the character side of one tap, which is forwarded by the kernel and sent to the network side of another tap. In this example, however, the packet carries the IP Record Route option. With this option, each time the packet is forwarded, the IP address of the outgoing interface is added to the IP options portion of the packet.

Shell commands
./ipOptions tap1 10.1.0.99 10.2.0.99
Expected results
On tap1, Ethereal will display the packet written to the char side of the tap by the forward application. On tap2, Ethereal will display the packet sent to the network side of tap2 by the IP forwarding code in the Linux kernel.