C Language Examples of IPv4 and IPv6 Raw Sockets for Linux
P. David Buchan
I have recently been investigating raw socket programming in C for linux and I decided to provide a collection of routines I have prepared.
Rather than use command-line arguments, each example has hard-coded values, so you need to modify each example to your preferences.
You must run these as root to obtain raw sockets.
IPv4
There are three subcategories depending on the Domain, Type, and Protocol arguments I chose to pass to socket(). There are other possible combinations.
1. sd = socket (AF_INET, SOCK_RAW, IPPROTO_RAW);
The kernel fills out layer 2 (data link) information (MAC addresses) for us.
2. sd = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL));
We provide layer 2 (data link) information. i.e., we specify ethernet frame header
with MAC addresses.
3. sd = socket (PF_PACKET, SOCK_DGRAM, htons (ETH_P_ALL));
We provide a "cooked" packet with destination MAC address in struct sockaddr_ll.
TCP, ICMP, and UDP examples are provided for each.
With IPv4 raw sockets you can edit all values within the IP header, and if you're using option 1 above, you specify that the IP header is included by using setsockopt() and the IP_HDRINCL flag. Or you can use options 2 or 3 above and send ethernet frames if you know the target node's MAC address (if it's local), or MAC address of the router the frames will be routed through.
To learn a link-local router or link-local node's MAC address, you must use the Address Resolution Protocol (ARP). I have included an example which sends an ARP request ethernet frame as well as an example that receives an ARP reply ethernet frame.
Some router discovery routines are also included.
Cases using sd = socket (AF_INET, SOCK_RAW, IPPROTO_RAW);
tcp4.c
icmp4.c
udp4.c
Cases using sd = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL));
tcp4_ll.c
icmp4_ll.c
udp4_ll.c
Cases using sd = socket (PF_PACKET, SOCK_DGRAM, htons (ETH_P_ALL));
tcp4_cooked.c
icmp4_cooked.c
udp4_cooked.c
Send an ARP request ethernet frame:
arp.c
Receive an ARP reply ethernet frame:
receive_arp.c
Send a router solicitation:
rs4.c
Send a router advertisement:
ra4.c
Receive a router advertisement:
receive_ra4.c
IPv6
In IPv6 there is no equivalent to using setsockopt() with the IP_HDRINCL flag (holy snap, that's annoying). Without doing something special, you can only change the hop limit and traffic class values in the IP header.
To change the hop limit you must use the ancillary data method. For traffic class you can use either the ancillary data method or a call to setsockopt() with option level IPPROTO_IPV6 and option name IPV6_TCLASS. Note that changes made to the properties of the socket with setsockopt() will remain in effect for all packets sent through the socket, whereas ancillary data is associated with a particular packet.
If we wish to have the ability to change any parameter in the IPv6 header, we need to have the source and destination MAC addresses available. In this case we have options 2 and 3 (above) available to us.
The Neighbor Discovery process is used to obtain the MAC address of a link-local target node, or MAC address of a link-local router the frames will be routed through. First we send a Neighbor Solicitation with our MAC address to the target node/router, and then it replies with a Neighbor Advertisement that contains its MAC address. The neighbor solicitation is sent to the target/router's solicited-node multicast address.
I have not provided any examples of extension headers.
For the transition to IPv6 from IPv4, a mechanism of tunneling IPv6 over IPv4 (6to4) has been established. I include some 6to4 examples as well.
Ancillary data method:
icmp6_ancillary1.c (changes 1 parameter)
icmp6_ancillary2.c (changes 2 parameters)
Send a neighbor solicitation:
ns.c
Send a neighbor advertisement (this doesn't respond to a solicitation, it just sends an advertisement for the joy of seeing it on Wireshark):
na.c
Receive a neighbor advertisement and extract lots of info including MAC address:
receive_ns.c
Send a router solicitation:
rs6.c
Send a router advertisement:
ra6.c
Receive a router advertisement:
receive_ra6.c
Cases using sd = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL));
tcp6_ll.c
icmp6_ll.c
udp6_ll.c
Cases using sd = socket (PF_PACKET, SOCK_DGRAM, htons (ETH_P_ALL));
tcp6_cooked.c
icmp6_cooked.c
udp6_cooked.c
Tunneling IPv6 over IPv4 (6to4):
tcp6_6to4.c
icmp6_6to4.c
udp6_6to4.c
January 10, 2012
pdbuchan@yahoo.com