IPv4 to IPv6
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!
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
- Leading zeros can be ommitted.
a001:a002:a003:a004:a005:000f:002f:03af
becomesa001:a002:a003:a004:a005:f:2f:3af
- Series of zero segments can be replaced by double colons
::
fa01:0000:0000:0000:0000:a012:b123:c456
becomesfa01::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
#![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
[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