Part 2: IPv6 Addresses 128-bit Addressing, Notation, Special Addresses & IPv4-Mapped IPv6

 

Chapter 58 – Part 2: IPv6 Addresses
128-bit Addressing, Notation, Special Addresses & IPv4-Mapped IPv6
Topic
IPv6 Addressing
Level
Beginner to Intermediate
Part
2 of 5

Why IPv6?

IPv4 provides ~4.3 billion addresses. That sounds like a lot, but with billions of smartphones, IoT devices, and servers, the world ran out of IPv4 addresses. IPv6 was designed to fix this — it uses 128-bit addresses, giving us 2128 addresses. That is approximately 340 undecillion (340 × 1036) addresses — enough for every grain of sand on Earth to have its own address, many times over.

The principles of IPv6 addressing are similar to IPv4 — there is still a network part and a host part, and there are still special addresses like loopback and wildcard. The main differences are the size (128 bits vs 32 bits) and the notation used to write addresses.

Key Terms:

IPv6 128-bit Address Hexadecimal Notation Compressed Notation Format Prefix Loopback ::1 Wildcard :: IPv4-mapped IPv6 ::FFFF AF_INET6 in6addr_any in6addr_loopback

1. IPv6 Address Format

An IPv6 address is 128 bits long. It is written as eight groups of four hexadecimal digits, separated by colons:

128 bits total = 8 groups × 16 bits each
F000
16 bits
0000
16 bits
0000
16 bits
0000
16 bits
0000
16 bits
0000
16 bits
000A
16 bits
0001
16 bits
Full: F000:0000:0000:0000:0000:0000:000A:0001  |  Simplified: F000::A:1

Each group is written in hexadecimal. Leading zeros within a group can be dropped (so 000A becomes A). Consecutive groups of all zeros can be replaced with :: (double colon). The example above becomes F000::A:1.

Important rule: The :: shortcut can only appear once in an address. If it appeared more than once, it would be ambiguous — the reader would not know how many zero groups each :: replaces.

2. IPv6 Address Compression Rules
Full Address After Dropping Leading Zeros After :: Compression
F000:0000:0000:0000:0000:0000:000A:0001 F000:0:0:0:0:0:A:1 F000::A:1
0000:0000:0000:0000:0000:0000:0000:0001 0:0:0:0:0:0:0:1 ::1 (loopback)
0000:0000:0000:0000:0000:0000:0000:0000 0:0:0:0:0:0:0:0 :: (wildcard)
2001:0DB8:0000:0000:0008:0800:200C:417A 2001:DB8:0:0:8:800:200C:417A 2001:DB8::8:800:200C:417A

3. Special IPv6 Addresses
Address C Constant IPv4 Equivalent Meaning
::1 in6addr_loopback 127.0.0.1 Loopback — packets stay on the local host
:: in6addr_any 0.0.0.0 Wildcard — bind to all interfaces

::1 is 127 zero bits followed by a single 1-bit — the IPv6 loopback address. :: is all 128 bits set to zero — the IPv6 wildcard address.

4. IPv4-Mapped IPv6 Addresses

During the transition from IPv4 to IPv6, many hosts still only support IPv4. IPv6 provides a special mechanism called IPv4-mapped IPv6 addresses so that IPv6 applications can communicate with IPv4-only hosts.

80 bits — all zeros FFFF
16 bits
IPv4 Address
32 bits
0000 0000 0000 0000 0000 FFFF 204.152 189.116
Written as: ::FFFF:204.152.189.116

The format is: 80 zero bits, followed by 16 bits of FFFF, followed by the 32-bit IPv4 address written in dotted-decimal notation. When writing it as a string, the IPv4 portion is kept in dotted-decimal rather than being converted to hex — this makes it easier to read.

Why Is This Useful?

An IPv6 server socket (AF_INET6) can receive connections from IPv4 clients when the OS maps the client’s IPv4 address into IPv4-mapped IPv6 format automatically. This allows a single server to handle both IPv4 and IPv6 clients without running two separate server sockets.

5. Coding Example – IPv6 Server Socket

Creating an IPv6 TCP server uses AF_INET6 and struct sockaddr_in6:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>

#define PORT 8080

int main() {
    int server_fd;
    struct sockaddr_in6 addr6;
    char addr_str[INET6_ADDRSTRLEN];

    /* Create an IPv6 TCP socket */
    server_fd = socket(AF_INET6, SOCK_STREAM, 0);
    if (server_fd == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    /* Fill in IPv6 address structure */
    memset(&addr6, 0, sizeof(addr6));
    addr6.sin6_family = AF_INET6;
    addr6.sin6_port   = htons(PORT);

    /*
     * in6addr_any is the IPv6 wildcard address (::)
     * Accepts connections on all interfaces for both IPv4 and IPv6
     * when IPV6_V6ONLY socket option is 0 (default on Linux).
     */
    addr6.sin6_addr = in6addr_any;
    /* OR use loopback: addr6.sin6_addr = in6addr_loopback; */

    if (bind(server_fd,
             (struct sockaddr *)&addr6, sizeof(addr6)) == -1) {
        perror("bind");
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    printf("IPv6 server bound to port %d\n", PORT);
    listen(server_fd, 5);

    /* ... accept() loop goes here ... */

    close(server_fd);
    return 0;
}

Address Conversion: inet_pton / inet_ntop

Unlike IPv4 where we used inet_addr(), for both IPv4 and IPv6 the modern functions are inet_pton() (text to binary) and inet_ntop() (binary to text):

#include <stdio.h>
#include <arpa/inet.h>

int main() {
    struct in6_addr addr6;
    char text[INET6_ADDRSTRLEN];
    const char *ipv6_str  = "F000::A:1";
    const char *ipv4mapped = "::FFFF:204.152.189.116";

    /* Convert text to binary */
    if (inet_pton(AF_INET6, ipv6_str, &addr6) == 1) {
        printf("Conversion OK\n");
    }

    /* Convert binary back to text */
    if (inet_ntop(AF_INET6, &addr6, text, sizeof(text)) != NULL) {
        printf("Address: %s\n", text);
    }

    /* Convert an IPv4-mapped address */
    if (inet_pton(AF_INET6, ipv4mapped, &addr6) == 1) {
        inet_ntop(AF_INET6, &addr6, text, sizeof(text));
        printf("IPv4-mapped: %s\n", text);
    }

    return 0;
}

Key difference from IPv4: Use AF_INET for IPv4 addresses and AF_INET6 for IPv6 addresses with these functions.

Interview Questions – IPv6 Addressing
Q1. What is the size of an IPv6 address and how is it written?IPv6 addresses are 128 bits wide, written as eight groups of four hexadecimal digits separated by colons. Example: 2001:0DB8:0000:0000:0008:0800:200C:417A. Two compression shortcuts exist: leading zeros in a group can be dropped, and one sequence of consecutive all-zero groups can be replaced with ::.

Q2. What is the IPv6 loopback address and how does it compare to IPv4’s?The IPv6 loopback address is ::1 (127 zero bits followed by a single 1-bit). It is the equivalent of IPv4’s 127.0.0.1. In C, it is available as the constant in6addr_loopback for use with struct sockaddr_in6. Like IPv4 loopback, packets sent to ::1 never leave the host.

Q3. Why can the :: notation appear only once in an IPv6 address?The :: notation replaces one or more consecutive groups of zeros. If it appeared more than once, the address would be ambiguous — it would be impossible to determine how many zero groups each :: represents. For example, ::1::1 could mean many different addresses, so it is invalid.

Q4. What is an IPv4-mapped IPv6 address and when is it used?An IPv4-mapped IPv6 address represents an IPv4 address within IPv6 format. It consists of 80 zero bits, then 16 bits of FFFF, then the 32-bit IPv4 address. Written as ::FFFF:w.x.y.z. It allows IPv6-capable applications to communicate with IPv4-only hosts. On Linux, an IPv6 server socket bound to in6addr_any can automatically receive connections from IPv4 clients presented in this form.

Q5. What functions should you use in C to convert IPv6 addresses between text and binary?Use inet_pton(AF_INET6, text_str, &in6_addr) to convert a text IPv6 address to binary (network byte order). Use inet_ntop(AF_INET6, &in6_addr, buf, buf_size) to convert binary back to text. These functions work for both IPv4 (AF_INET) and IPv6 (AF_INET6). The older inet_addr() and inet_ntoa() only work for IPv4.

Q6. What socket address structure is used for IPv6 in C?For IPv6, use struct sockaddr_in6 (defined in <netinet/in.h>). Key fields: sin6_family (set to AF_INET6), sin6_port (port in network byte order via htons()), and sin6_addr (the 128-bit address of type struct in6_addr). For wildcard, assign in6addr_any; for loopback, assign in6addr_loopback.

Q7. What is the significance of the format prefix in an IPv6 address?The first few bits of an IPv6 address form the format prefix, which identifies the address type (unicast, multicast, link-local, etc.). For example, addresses beginning with FE80:: are link-local addresses. This prefix-based type identification replaces the class-based (Class A/B/C) system used in early IPv4 design, providing a more flexible and extensible addressing architecture.

Continue Learning

Next: Transport Layer — Port Numbers, how TCP/UDP identify applications.

Part 3: Port Numbers → ← Part 1: IPv4

Leave a Reply

Your email address will not be published. Required fields are marked *