Networking with the Standard Library
IP Addresses
An IP address uniquely identifies a network interface on an Internet Protocol network. Rust models IP addresses in std::net using Ipv4Addr (32-bit), Ipv6Addr (128-bit), and the version-agnostic enum IpAddr (IpAddr::V4(Ipv4Addr) or IpAddr::V6(Ipv6Addr)), all of which are lightweight Copy value types.
Ipv4Addr (4 octets = 32 bits):
192 . 168 . 1 . 10 ---> [u8; 4] = [192, 168, 1, 10] (u32 = 0xC0A8010A)
Ipv6Addr (8 hextets = 128 bits):
2001:0db8::8a2e:0370:7334 ---> [u16; 8] or [u8; 16] (u128)
Constructing Ipv4Addr, Ipv6Addr, and IpAddr
Standard well-known addresses are available as associated const items on Ipv4Addr and Ipv6Addr:
| Constant | Value | Meaning |
|---|---|---|
Ipv4Addr::LOCALHOST |
127.0.0.1 |
IPv4 loopback address (local host only). |
Ipv4Addr::UNSPECIFIED |
0.0.0.0 |
Wildcard bind address (all local IPv4 interfaces). |
Ipv4Addr::BROADCAST |
255.255.255.255 |
Local network broadcast address. |
Ipv6Addr::LOCALHOST |
::1 |
IPv6 loopback address. |
Ipv6Addr::UNSPECIFIED |
:: |
Wildcard bind address (all local IPv6 interfaces). |
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
fn main() {
// 1. From octets or segments (compile-time const fn)
const LOCAL_DNS: Ipv4Addr = Ipv4Addr::new(192, 168, 1, 1);
const DOC_IPV6: Ipv6Addr = Ipv6Addr::new(0x2001, 0x0db8, 0, 0, 0, 0, 0, 1);
// 2. From raw integer representations (network byte order / big-endian)
let from_u32 = Ipv4Addr::from_bits(0x7F00_0001);
assert_eq!(from_u32, Ipv4Addr::LOCALHOST);
// 3. Parsing strings via FromStr (.parse())
let parsed_v4: IpAddr = "10.0.0.42".parse().unwrap();
let parsed_v6: IpAddr = "fe80::1ff:fe23:4567:890a".parse().unwrap();
println!("LOCAL_DNS: {} (octets: {:?})", LOCAL_DNS, LOCAL_DNS.octets());
println!("DOC_IPV6: {}", DOC_IPV6);
println!("Parsed: v4={}, v6={}", parsed_v4.is_ipv4(), parsed_v6.is_ipv6());
}
LOCAL_DNS: 192.168.1.1 (octets: [192, 168, 1, 1])
DOC_IPV6: 2001:db8::1
Parsed: v4=true, v6=true
Classification and Inspection Methods
Both IpAddr and the version-specific structs provide classification methods to validate security boundaries (for example, rejecting SSRF requests targeting loopback or private RFC 1918 networks):
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
fn classify(ip: IpAddr) {
println!(
"{:<18} -> loopback: {:<5} unspecified: {:<5} multicast: {}",
ip.to_string(),
ip.is_loopback(),
ip.is_unspecified(),
ip.is_multicast()
);
}
fn main() {
classify(IpAddr::V4(Ipv4Addr::LOCALHOST));
classify(IpAddr::V4(Ipv4Addr::UNSPECIFIED));
classify(IpAddr::V4(Ipv4Addr::new(224, 0, 0, 1)));
let private_v4 = Ipv4Addr::new(10, 24, 0, 5);
println!("10.24.0.5 is_private: {}", private_v4.is_private());
// IPv4-mapped IPv6 addresses (::ffff:a.b.c.d)
let mapped: Ipv6Addr = "::ffff:192.0.2.128".parse().unwrap();
println!(
"{} -> to_ipv4_mapped(): {:?}",
mapped,
mapped.to_ipv4_mapped()
);
}
127.0.0.1 -> loopback: true unspecified: false multicast: false
0.0.0.0 -> loopback: false unspecified: true multicast: false
224.0.0.1 -> loopback: false unspecified: false multicast: true
10.24.0.5 is_private: true
::ffff:192.0.2.128 -> to_ipv4_mapped(): Some(192.0.2.128)