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?