I’m interning at Linux Kernel in project nftables, it filters network traffic, soon I’ll blog about it, promise; and recently had to work with code that deals with IPv6.
Probably we’ve all heard about IP addresses, everything connected to the internet has this identifier. IP is the internet protocol that tries to send messages to IP addresses, it runs in Network Layer (L3) in the core of the internet.
There are two well known versions of IP, v4 and v6. Nowadays most of the internet traffic is based on the v4, what might change in the near (maybe not so near) future.
The main reason to replace v4 is the number of addresses, there are only 32 bits (~4 billion addresses) available. A few decades ago this number was huge, almost unimaginable, but the game has changed and the last address was sold to an Internet Service Provider (ISP) a few years ago.
NATs are used to make a single IP address identify multiple hosts; probably in your home only the ISP modem has a unique IP address, the computers, cellphones and other devices all have a local IP 192.168.x.y – you can use ifconfig in a terminal window to check your network board’s (probably named eth0) IP. However, many people don’t like NATs for many reasons, but this belongs to another discussion.
Now, IPv6 reserves 128 bits (~a lot) to source and destination address, every grain of sand on Earth can have its own IP address, how long will it last? Moreover, the decades of experience with v4 were used to improve IP in many ways. Take a look at both headers and how different they are:
It’s important to notice that v4 header has variable length, options may be sent in it, what slows processing. For IPv6 the header has a fixed length of 40 bytes, no options allowed in the base header; however, options are an useful feature, so v6 still has them but they’re sent in extension headers.
The ‘Next Header’ field in the v6 defines which header follows the current one, that’s how extension headers are sent. In the last header this field contains the upper layer protocol (TCP, UDP etc.) that is used, similar to v4 ‘Protocol’ field.
Sometimes it is necessary know which protocol an IPv6 packet uses, somewhere in Netfilter subsystem in the Kernel ipv6_find_hdr() is used for that. I was given the task to analyze if ipv6_skip_exthdr() can be used instead, because it’s simpler and faster. These functions are used by nftables to process every IPv6 packet, and to test them I had to create IPv6 packets, with extension headers. Now comes Scapy.
Scapy is a packet manipulation program, it has its own shell but it’s possible to use it with Python. Creating IPv6 packets with it is very simple, will just show it, since a code sample speaks for a thousand words. The following sends a message over TCP and IPv6:
from scapy.all import * base = IPv6() base.dst = '::1' # ::1 is localhost in IPv6 base.src = '::1' prot = TCP(sport=1234, dport=1234, flags='S') # Attributes can be defined in initialization data = Raw(load="Important message!") packet = base / prot / data # '/' encapsulates the messages packet.show2() # Displays the fields in the packet send(packet)
You can add as many extension headers to a v6 packet you want, just initialize and encapsulate them before sending:
... ext = IPv6ExtHdrRouting(addresses=["::1", "::1"]) packet = base / ext / prot / data ...
With it I was able to test the functions with different kinds of IPv6 packets. The values used in the packets don’t mean anything, just needed to test how the extension headers are skipped 🙂
Scapy seems very useful to manipulate packets in different layers, and it’s easy to use, looking forward to explore it in future tasks. Thank you for reading!