Rate this page

Send an arbitrary Ethernet frame using libpcap

Tested on

Debian (Lenny, Squeeze)
Ubuntu (Lucid)

Objective

To send an arbitrary Ethernet frame using libpcap

Background

Ethernet is a link layer protocol. Most networking programs interact with the network stack at the transport layer or above, so have no need to deal with Ethernet frames directly, but there are some circumstances where interaction at a lower level may be necessary. These include:

Scenario

Suppose that you wish to send an ARP request for a given IP address from a given Ethernet interface. You wish to use libpcap to perform the sending.

(ARP is the Address Resolution Protocol. It is used when a host needs to send a datagram to a given IP address, but does not know which MAC address corresponds to that IP address. It is described in RFC 826.)

Method

Overview

The method described here has five steps:

  1. Select the required EtherType.
  2. Construct the Ethernet frame.
  3. Obtain a PCAP descriptor by calling pcap_open_live.
  4. Send the Ethernet frame by calling pcap_inject.
  5. Close the PCAP descriptor by calling pcap_close.

The following header files are used:

Header Used by
<stdio.h> fprintf
<stdlib.h> exit
<pcap.h> pcap_open_live, pcap_inject, pcap_close, pcap_perror

Be aware that:

Programs that send raw packets, using this or any other method, are likely to require elevated privileges in order to run.

Select the required EtherType

The EtherType of an Ethernet frame specifies the type of payload that it contains. There are several sources from which EtherTypes can be obtained:

If you need an EtherType for experimental or private use then the values 0x88b5 and 0x88b6 have been reserved for that purpose.

Construct the Ethernet frame

Frames sent using libpcap must:

See the example program below for how this might be done in the specific case where you want to send an ARP request. Be aware that:

You will probably need to know the MAC address of the interface from which the packet will be sent. On Linux-based systems this can be obtained using the ioctl command SIOCGIFHWADDR. See the microHOWTO Get the MAC address of an Ethernet interface in C using SIOCGIFHWADDR for details.

As noted previously, libpcap does not provide guarantee that the link-layer header that is sent will be identical to the one that was provided.

Obtain a PCAP descriptor by calling pcap_open_live

To access a network interface via libpcap it is necessary to have an open packet capture descriptor. This is a pointer of type pcap_t* and can be obtained by calling pcap_open_live:

char pcap_errbuf[PCAP_ERRBUF_SIZE];
pcap_errbuf[0]='\0';
pcap_t* pcap=pcap_open_live(if_name,96,0,0,pcap_errbuf);
if (pcap_errbuf[0]!='\0') {
    fprintf(stderr,"%s",pcap_errbuf);
}
if (!pcap) {
    exit(1);
}

The first argument to pcap_open_live is the name of the interface from which the Ethernet frame is to be sent, for example eth0. (Remember that not all interfaces are suitable for sending Ethernet frames.)

The second, third and fourth arguments are the snapshot length, promiscuous mode flag and timeout. These control how packets are captured, and for the task in hand it is unimportant what values are used, but if you want to capture as well as send then you will need to ensure that they have been set appropriately (especially the snapshot length).

The last argument points to a buffer for returning error messages, which must be at least PCAP_ERRBUF_SIZE bytes long. As suggested on the pcap_open_live manpage, this has been set to the empty string before the function call then inspected afterwards in order to detect both warnings and errors.

Send the Ethernet frame by calling pcap_inject

Given a PCAP descriptor, frames can be sent by calling the function pcap_inject:

if (pcap_inject(pcap,&req,sizeof(req))==-1) {
    pcap_perror(pcap,0);
    pcap_close(pcap);
    exit(1);
}

The value returned by pcap_inject is the number of bytes sent, or -1 if there was an error. In the latter case a human-readable error message can be obtained using pcap_geterr or (as in this example) printed using pcap_perror.

Close the PCAP descriptor by calling pcap_close

The PCAP descriptor should be closed once it is no longer needed:

pcap_close(pcap)

Example program

The following example program constructs and sends an ARP request using the method described above:

send_arp.c

It can be compiled using the command:

gcc -lpcap -o send_arp send_arp.c

When invoked it takes two arguments, the name of the Ethernet interface and the (numeric) IP address to which the ARP request should be directed:

./send_arp eth0 192.168.0.83

Alternatives

Using an AF_PACKET socket

See: Send an arbitrary Ethernet frame using an AF_PACKET socket in C

On Linux-based systems an alternative way to send an Ethernet frame is to use an AF_PACKET socket. This has some advantages over the use of libpcap:

The main drawback of AF_PACKET sockets their lack of portability. They are specific to Linux (version 2.2 and later), and for this reason they are not recommended where the use of libpcap (or a raw socket) is a viable alternative.

Using a raw socket

See: Send an arbitrary IPv4 datagram using a raw socket in C

Raw sockets differ from packet sockets in that they operate at the network layer as opposed to the link layer. For this reason they are limited to network protocols for which raw socket support has been explicitly built into the network stack, but they also have a number of advantages which result from operating at a higher level of abstraction:

For these reasons, use of a raw socket is recommended unless you specifically need the extra functionality provided by working at the link layer.

Further reading