Rust DNS Lookups
A DNS lookup turns a name into one or more socket addresses. Rust exposes a DNS lookup through the ToSocketAddrs trait.
Turn a name into addresses
The call gives an iterator. More than one answer can come back:
let addrs = ("localhost", 8080).to_socket_addrs().unwrap();Print every answer
This program sorts the answers first. The order on screen then stays steady:
let mut addrs: Vec<_> = ("localhost", 8080).to_socket_addrs().unwrap().collect();
addrs.sort();
for addr in &addrs {
println!("{addr} loopback = {}", addr.ip().is_loopback());
}Count the answers
let count = ("localhost", 8080).to_socket_addrs().unwrap().count();
println!("answers for localhost = {count}");Connect using a name
connect takes the same forms. This client reaches a server on this machine, found by name:
let mut client = TcpStream::connect(format!("localhost:{}", port)).unwrap();
println!("peer is loopback = {}", client.peer_addr().unwrap().ip().is_loopback());A written address converts to itself
No lookup happens for a literal address. It just becomes a SocketAddr:
let lit = "127.0.0.1:9000".to_socket_addrs().unwrap().next().unwrap();
println!("literal gives itself = {}", lit == "127.0.0.1:9000".parse().unwrap());Example
use std::net::ToSocketAddrs;
fn main() {
let mut addrs: Vec<_> = ("localhost", 80).to_socket_addrs().unwrap().collect();
addrs.sort();
for addr in &addrs {
println!("{addr}");
}
println!("answers = {}", addrs.len());
println!("each is loopback = {}", addrs.iter().all(|a| a.ip().is_loopback()));
}Key points
- ToSocketAddrs: the trait that turns a name or a written address into socket addresses
- Use to_socket_addrs() on "localhost:8080" or ("localhost", 8080).
- Both forms give an iterator of answers
- One name can have several answers.
- An IPv4 answer and an IPv6 answer often arrive together
- connect and bind accept any ToSocketAddrs value.
- That is why names work inside those calls with no extra code
- A written address like "127.0.0.1:8080" needs no lookup.
- It converts into itself
In this example, one lookup does all the work. ("localhost", 80) becomes two socket addresses. One is IPv4. One is IPv6. The sort puts them in a steady order for printing. Both are loopback addresses, because localhost is this machine. A public name would answer with public addresses instead. A client then tries the answers in order until one connects.
Note
Your program never talks to a DNS server itself.
It asks the operating system.
The system uses its hosts file and its DNS settings.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
Why does to_socket_addrs() hand back an iterator, not a single address?