Team LiB
Previous Section Next Section

11.3. Advanced libnet Functions

In addition to the functionality we have already discussed, the libnet library also contains functionality for more specialized tasks, including the ability to extract raw packet data or packet headers, as well as the functionality to handle multiple libnet contexts for creating multiple packets.

11.3.1. Accessing Raw Packet Data

For some situations it is necessary to be able to access either raw packet data or the raw packet header from within libnet. This can be useful, from a debugging standpoint, for handcrafting packets and for assembling truly unusual data packets.

libnet provides functions for "culling" the packet data from a libnet context, and for culling an individual packet header from a context and protocol tag. These functions are available only if the libnet injection type was one of LIBNET_LINK_ADV, LIBNET_RAW4_ADV, or LIBNET_RAW6_ADV. These functions are as follows:

int libnet_adv_cull_packet (libnet_t *l, u_int8_t **packet, u_int32_t *packet_s);

int libnet_adv_cull_header (libnet_t *l, libnet_ptag_t ptag, u_int8_t **header,
                  u_int32_t *header_s);

Both functions return 1 on success and -1 on failure, and you can query the errors using libnet_geterror(). For each function, the packet or header in network byte order and the size of the data returned are pointed to by the pointers supplied to the functions.

As noted earlier, culling a packet can be useful for debugging purposes, but it also gives you control over the format of the data to be sent out, which can can allow you to create protocol types not yet supported by libnet or to create unusual packets. For example, I have used this functionality to create packets for the Microsoft Teredo protocol that is included in Windows XP updates and is outlined at This technology uses IPv6 packets encapsulated within UDP over IPv4 packets to bypass Network Address Translation (NAT) controls implemented by common home cable/DSL gateways. Using packet culling, it is possible to create an appropriate IPv6 packet, and then use this packet data as the payload for an appropriate UDP packet for the transport layer.

The other main use for packet culling is to manipulate the packet assembled by libnet. Therefore, libnet supplies the functionality to write a culled packet to the wire using the libnet_adv_write_link() function as follows:

int libnet_adv_write_link (libnet_t *l, u_int8_t *packet, u_int32_t packet_s)

This function returns the number of bytes written, or -1 on error. libnet_geterror( ) can tell you what the error was. In addition to writing the packet, you should free the memory associated with the culled packet with libnet_adv_free_packet( ) as follows:

void libnet_adv_free_packet (libnet_t *l, u_int8_t *packet)

11.3.2. Context Queues

If you want to send multiple packets, possibly through different interfaces, you have a couple of options. You can handle each libnet context and send the packet individually, or you can use context queues to create a series of packets, and send them out in an organized fashion.

Context queues are a very useful mechanism for handling multiple-context situations. It is easy to create a context queue: just push a context onto the queue using libnet_cq_add( ) as follows:

int libnet_cq_add (libnet_t *l, char *label)

This function returns 1 on success and -1 on failure, with libnet_geterror() telling you why. Each context and identifier label must be unique, as they are identifiers for returning libnet contexts from the queue using libnet_cq_find_by_label() as follows:

libnet_t* libnet_cq_find_by_label (char *label)

To look up labels for contexts on the queue, use libnet_cq_getlabel( ) as follows:

int8_t* libnet_cq_getlabel (libnet_t *l)

Contexts can be iterated using libnet_cq_head( ) to return the first item in the queue and prevent additional items from being added to the queue; libnet_cq_next() to return the next item in the queue; libnet_cq_last() to see if the context is the last in the queue; or libnet_cq_size() to track the queue size. Do this manually as follows:

libnet_t* l;
for (l = libnet_cq_head( ); libnet_cq_last( ); l = libnet_cq_next( ))

Or you can do this using the provided for_each_context_in_cq() macro.

You can remove contexts from the queue either by the libnet context:

libnet_t* libnet_cq_remove (libnet_t *l)

or by using the label provided when adding the context to the queue:

libnet_t* libnet_cq_remove_by_label (char *label)

In both cases, the function returns NULL on failure, or a pointer to the libnet context that was removed.

Finally, you can use the libnet_cq_destroy( ) function to destroy the context queue, and you can use libnet_destroy() to free all resources used by contexts on the queue.

    Team LiB
    Previous Section Next Section