BlogHome

IPv4 to IPv6

2022-07-20

Why IPv6?

A 32-bit IPv4 address can create 232 addresses or ~4.3 billion addresses.

As more and more devices are connected to internet, IPv6 is the new standard to address the exhaustion of IPv4 addresses. And number of bytes to represent IPv6 is four times the size of IPv4: 16 bytes or 128-bit, allowing up to 2128 or ~3.4 x 1038 addresses.

Perspective

Lets bring 2128 to perspective.

  • If we gave out blocks of IP addresses the size of IPv4 every second on Earth then to exhaust IPv6 address space it will take 2.5 x 1021 Earth years1!
  • If we gave out the blocks of IP addresses the size of IPv4 every second to every one of the estimated 400 billion planets in the Milky Way galaxy3, then to exhaust IPv6 address space it will take 6.3 billion Earth years2!

It is an astronomical number and we never have to worry about running out of IP addresses again!

Carina Nebula

How to represent IPv6 addresses

16 bytes are separated by colon into 8 2-byte segments l:m:n:o:p:q:r:s.

Each 2-byte segment is represented by 4 hexadecimals xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx.

A hexadecimal is also called a nibble, a 4-bit thing. So each segment of IPv6 is a quad-nibble or quibble

IPv6 starts at 0000:0000:0000:0000:0000:0000:0000:0000 and ends at ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff

Shortened Representation

  1. Leading zeros can be ommitted.
    • a001:a002:a003:a004:a005:000f:002f:03af becomes a001:a002:a003:a004:a005:f:2f:3af
  2. Series of zero segments can be replaced by double colons ::
    • fa01:0000:0000:0000:0000:a012:b123:c456 becomes fa01::a012:b123:c456

IPv6 in URLs

Colon in URL is used to separate the schema, hence IPv6 with colons is wrapped in []. For example http://[beef::1]:8080

IPv4-Mapped IPv6 Address

IPv4 can be embedded into IPv6 address to represent an IPv4 node.

   |                80 bits               | 16 |      32 bits        |
   +--------------------------------------+--------------------------+
   |0000..............................0000|FFFF|    IPv4 address     |
   +--------------------------------------+----+---------------------+

So ::ffff:1.2.3.4 becomes 1.2.3.4.

IPv6 in Rust

Ipv6Addr Struct

Link to Playground

#![feature(ip)]

// Struct to represent IPv6 Address
use std::net::Ipv6Addr;

fn main() {
    // Create new IPv6 by passing each of the 8 segments in new
    let loopback_addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
    println!("Loopback address: {}", loopback_addr);

    let ipv4_mapped_addr = Ipv6Addr::new(0, 0, 0, 0, 0,
                                         0xffff, 0x7f00, 1);
    // Obtain IPv4 address
    // Requires nightly https://github.com/rust-lang/rust/issues/27709
    println!(
        "IPv4 mapped address: {:?}",
        ipv4_mapped_addr.to_ipv4_mapped()
    );

    // Get IPv6 segments or octets
    let address = Ipv6Addr::new(
        0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef,
    );
    println!("Segments [u16; 8]: {:?}", address.segments());
    println!("Octets [u8; 16]: {:?}", address.octets());
}

HTTP Server on IPv6 using Axum

use std::net::SocketAddr;

use axum::{response::IntoResponse, routing::get, Router, Server};

#[tokio::main]
async fn main() {
    let app = Router::new().route("/", get(index));

    // Loopback
    let addr: SocketAddr = "[::ffff:7f00:1]:8888".parse().unwrap();
    println!("Is Ipv6: {}", addr.is_ipv6());
    println!("Listening on http://{addr}");
    Server::bind(&addr)
        .serve(app.into_make_service())
        .await
        .unwrap();
}

async fn index() -> impl IntoResponse {
    "Hello from IPv6\n"
}

IPv6 using Curl

➜  ~ curl "http://[::ffff:127.0.0.1]:8888"
Hello from IPv6
➜  ~ curl "http://[::ffff:7f00:1]:8888"
Hello from IPv6

IPv6 in Firefox

Firefox IPv6 HTTP URL


[1]: ~2.5 x 1021 years = (2128-32 secs) / 60 / 60 / 24 / 365

[2]: ~6.3 billion years = (2128 / (232 x 400 x 109)) secs / 60 / 60 / 24 / 365