Clean up error handling in chapter 4 and 5

This commit is contained in:
Emil Hernvall 2020-06-18 02:03:56 +02:00
parent f815075ae4
commit 45cbfa59f7
4 changed files with 215 additions and 282 deletions

View File

@ -144,7 +144,10 @@ a separate function. This is for the most part the same code as we had in our
`main` function in the previous chapter. `main` function in the previous chapter.
```rust ```rust
fn lookup(qname: &str, qtype: QueryType, server: (&str, u16)) -> Result<DnsPacket> { fn lookup(qname: &str, qtype: QueryType) -> Result<DnsPacket> {
// Forward queries to Google's public DNS
let server = ("8.8.8.8", 53);
let socket = UdpSocket::bind(("0.0.0.0", 43210))?; let socket = UdpSocket::bind(("0.0.0.0", 43210))?;
let mut packet = DnsPacket::new(); let mut packet = DnsPacket::new();
@ -165,6 +168,7 @@ fn lookup(qname: &str, qtype: QueryType, server: (&str, u16)) -> Result<DnsPacke
DnsPacket::from_buffer(&mut res_buffer) DnsPacket::from_buffer(&mut res_buffer)
} }
``` ```
### Implementing our first server ### Implementing our first server
@ -172,45 +176,21 @@ fn lookup(qname: &str, qtype: QueryType, server: (&str, u16)) -> Result<DnsPacke
Now we'll write our server code. First, we need get some things in order. Now we'll write our server code. First, we need get some things in order.
```rust ```rust
fn main() -> Result<()> { /// Handle a single incoming packet
// Forward queries to Google's public DNS fn handle_query(socket: &UdpSocket) -> Result<()> {
let server = ("8.8.8.8", 53);
// Bind an UDP socket on port 2053
let socket = UdpSocket::bind(("0.0.0.0", 2053))?;
// For now, queries are handled sequentially, so an infinite loop for servicing
// requests is initiated.
loop {
// With a socket ready, we can go ahead and read a packet. This will // With a socket ready, we can go ahead and read a packet. This will
// block until one is received. // block until one is received.
let mut req_buffer = BytePacketBuffer::new(); let mut req_buffer = BytePacketBuffer::new();
let (_, src) = match socket.recv_from(&mut req_buffer.buf) {
Ok(x) => x,
Err(e) => {
println!("Failed to read from UDP socket: {:?}", e);
continue;
}
};
// Here we use match to safely unwrap the `Result`. If everything's as expected, // The `recv_from` function will write the data into the provided buffer,
// the raw bytes are simply returned, and if not it'll abort by restarting the // and return the length of the data read as well as the source address.
// loop and waiting for the next request. The `recv_from` function will write the // We're not interested in the length, but we need to keep track of the
// data into the provided buffer, and return the length of the data read as well // source in order to send our reply later on.
// as the source address. We're not interested in the length, but we need to keep let (_, src) = socket.recv_from(&mut req_buffer.buf)?;
// track of the source in order to send our reply later on.
// Next, `DnsPacket::from_buffer` is used to parse the raw bytes into // Next, `DnsPacket::from_buffer` is used to parse the raw bytes into
// a `DnsPacket`. It uses the same error handling idiom as the previous statement. // a `DnsPacket`.
let request = DnsPacket::from_buffer(&mut req_buffer)?;
let request = match DnsPacket::from_buffer(&mut req_buffer) {
Ok(x) => x,
Err(e) => {
println!("Failed to parse UDP query packet: {:?}", e);
continue;
}
};
// Create and initialize the response packet // Create and initialize the response packet
let mut packet = DnsPacket::new(); let mut packet = DnsPacket::new();
@ -230,12 +210,12 @@ fn main() -> Result<()> {
let question = &request.questions[0]; let question = &request.questions[0];
println!("Received query: {:?}", question); println!("Received query: {:?}", question);
// Since all is set up and as expected, the query can be forwarded to the target // Since all is set up and as expected, the query can be forwarded to the
// server. There's always the possibility that the query will fail, in which case // target server. There's always the possibility that the query will
// the `SERVFAIL` response code is set to indicate as much to the client. If // fail, in which case the `SERVFAIL` response code is set to indicate
// rather everything goes as planned, the question and response records as copied // as much to the client. If rather everything goes as planned, the
// into our response packet. // question and response records as copied into our response packet.
if let Ok(result) = lookup(&question.name, question.qtype, server) { if let Ok(result) = lookup(&question.name, question.qtype) {
packet.questions.push(question.clone()); packet.questions.push(question.clone());
packet.header.rescode = result.header.rescode; packet.header.rescode = result.header.rescode;
@ -258,30 +238,27 @@ fn main() -> Result<()> {
// The only thing remaining is to encode our response and send it off! // The only thing remaining is to encode our response and send it off!
let mut res_buffer = BytePacketBuffer::new(); let mut res_buffer = BytePacketBuffer::new();
match packet.write(&mut res_buffer) { packet.write(&mut res_buffer)?;
Ok(_) => {}
Err(e) => {
println!("Failed to encode UDP response packet: {:?}", e);
continue;
}
};
let len = res_buffer.pos(); let len = res_buffer.pos();
let data = match res_buffer.get_range(0, len) { let data = res_buffer.get_range(0, len)?;
Ok(x) => x,
Err(e) => {
println!("Failed to retrieve response buffer: {:?}", e);
continue;
}
};
match socket.send_to(data, src) { socket.send_to(data, src)?;
Ok(_) => {}
Err(e) => { Ok(())
println!("Failed to send response buffer: {:?}", e); }
continue;
fn main() -> Result<()> {
// Bind an UDP socket on port 2053
let socket = UdpSocket::bind(("0.0.0.0", 2053))?;
// For now, queries are handled sequentially, so an infinite loop for servicing
// requests is initiated.
loop {
match handle_query(&socket) {
Ok(_) => {},
Err(e) => eprintln!("An error occured: {}", e),
} }
};
} }
} }
``` ```

View File

@ -222,7 +222,7 @@ impl DnsPacket {
/// However, not all name servers are as that nice. In certain cases there won't /// However, not all name servers are as that nice. In certain cases there won't
/// be any A records in the additional section, and we'll have to perform *another* /// be any A records in the additional section, and we'll have to perform *another*
/// lookup in the midst of our first. For this, we introduce a method for /// lookup in the midst of our first. For this, we introduce a method for
returning the hostname of an appropriate name server. /// returning the hostname of an appropriate name server.
pub fn get_unresolved_ns(&self, qname: &str) -> Option<String> { pub fn get_unresolved_ns(&self, qname: &str) -> Option<String> {
// Get an iterator over the nameservers in the authorities section // Get an iterator over the nameservers in the authorities section
self.get_ns(qname) self.get_ns(qname)
@ -299,11 +299,11 @@ fn recursive_lookup(qname: &str, qtype: QueryType) -> Result<DnsPacket> {
### Trying out recursive lookup ### Trying out recursive lookup
The only thing remaining is to change our main function to use The only thing remaining is to change our `handle_query` function to use
`recursive_lookup`: `recursive_lookup`:
```rust ```rust
fn main() -> Result<()> { fn handle_query(socket: &UdpSocket) -> Result<()> {
- snip - - snip -

View File

@ -689,7 +689,10 @@ impl DnsPacket {
} }
} }
fn lookup(qname: &str, qtype: QueryType, server: (&str, u16)) -> Result<DnsPacket> { fn lookup(qname: &str, qtype: QueryType) -> Result<DnsPacket> {
// Forward queries to Google's public DNS
let server = ("8.8.8.8", 53);
let socket = UdpSocket::bind(("0.0.0.0", 43210))?; let socket = UdpSocket::bind(("0.0.0.0", 43210))?;
let mut packet = DnsPacket::new(); let mut packet = DnsPacket::new();
@ -711,44 +714,21 @@ fn lookup(qname: &str, qtype: QueryType, server: (&str, u16)) -> Result<DnsPacke
DnsPacket::from_buffer(&mut res_buffer) DnsPacket::from_buffer(&mut res_buffer)
} }
fn main() -> Result<()> { /// Handle a single incoming packet
// Forward queries to Google's public DNS fn handle_query(socket: &UdpSocket) -> Result<()> {
let server = ("8.8.8.8", 53);
// Bind an UDP socket on port 2053
let socket = UdpSocket::bind(("0.0.0.0", 2053))?;
// For now, queries are handled sequentially, so an infinite loop for servicing
// requests is initiated.
loop {
// With a socket ready, we can go ahead and read a packet. This will // With a socket ready, we can go ahead and read a packet. This will
// block until one is received. // block until one is received.
let mut req_buffer = BytePacketBuffer::new(); let mut req_buffer = BytePacketBuffer::new();
let (_, src) = match socket.recv_from(&mut req_buffer.buf) {
Ok(x) => x,
Err(e) => {
println!("Failed to read from UDP socket: {:?}", e);
continue;
}
};
// Here we use match to safely unwrap the `Result`. If everything's as expected, // The `recv_from` function will write the data into the provided buffer,
// the raw bytes are simply returned, and if not it'll abort by restarting the // and return the length of the data read as well as the source address.
// loop and waiting for the next request. The `recv_from` function will write the // We're not interested in the length, but we need to keep track of the
// data into the provided buffer, and return the length of the data read as well // source in order to send our reply later on.
// as the source address. We're not interested in the length, but we need to keep let (_, src) = socket.recv_from(&mut req_buffer.buf)?;
// track of the source in order to send our reply later on.
// Next, `DnsPacket::from_buffer` is used to parse the raw bytes into // Next, `DnsPacket::from_buffer` is used to parse the raw bytes into
// a `DnsPacket`. It uses the same error handling idiom as the previous statement. // a `DnsPacket`.
let request = DnsPacket::from_buffer(&mut req_buffer)?;
let request = match DnsPacket::from_buffer(&mut req_buffer) {
Ok(x) => x,
Err(e) => {
println!("Failed to parse UDP query packet: {:?}", e);
continue;
}
};
// Create and initialize the response packet // Create and initialize the response packet
let mut packet = DnsPacket::new(); let mut packet = DnsPacket::new();
@ -768,12 +748,12 @@ fn main() -> Result<()> {
let question = &request.questions[0]; let question = &request.questions[0];
println!("Received query: {:?}", question); println!("Received query: {:?}", question);
// Since all is set up and as expected, the query can be forwarded to the target // Since all is set up and as expected, the query can be forwarded to the
// server. There's always the possibility that the query will fail, in which case // target server. There's always the possibility that the query will
// the `SERVFAIL` response code is set to indicate as much to the client. If // fail, in which case the `SERVFAIL` response code is set to indicate
// rather everything goes as planned, the question and response records as copied // as much to the client. If rather everything goes as planned, the
// into our response packet. // question and response records as copied into our response packet.
if let Ok(result) = lookup(&question.name, question.qtype, server) { if let Ok(result) = lookup(&question.name, question.qtype) {
packet.questions.push(question.clone()); packet.questions.push(question.clone());
packet.header.rescode = result.header.rescode; packet.header.rescode = result.header.rescode;
@ -796,29 +776,26 @@ fn main() -> Result<()> {
// The only thing remaining is to encode our response and send it off! // The only thing remaining is to encode our response and send it off!
let mut res_buffer = BytePacketBuffer::new(); let mut res_buffer = BytePacketBuffer::new();
match packet.write(&mut res_buffer) { packet.write(&mut res_buffer)?;
Ok(_) => {}
Err(e) => {
println!("Failed to encode UDP response packet: {:?}", e);
continue;
}
};
let len = res_buffer.pos(); let len = res_buffer.pos();
let data = match res_buffer.get_range(0, len) { let data = res_buffer.get_range(0, len)?;
Ok(x) => x,
Err(e) => {
println!("Failed to retrieve response buffer: {:?}", e);
continue;
}
};
match socket.send_to(data, src) { socket.send_to(data, src)?;
Ok(_) => {}
Err(e) => { Ok(())
println!("Failed to send response buffer: {:?}", e); }
continue;
fn main() -> Result<()> {
// Bind an UDP socket on port 2053
let socket = UdpSocket::bind(("0.0.0.0", 2053))?;
// For now, queries are handled sequentially, so an infinite loop for servicing
// requests is initiated.
loop {
match handle_query(&socket) {
Ok(_) => {},
Err(e) => eprintln!("An error occured: {}", e),
} }
};
} }
} }

View File

@ -832,26 +832,11 @@ fn recursive_lookup(qname: &str, qtype: QueryType) -> Result<DnsPacket> {
} }
} }
fn main() -> Result<()> { fn handle_query(socket: &UdpSocket) -> Result<()> {
let socket = UdpSocket::bind(("0.0.0.0", 2053))?;
loop {
let mut req_buffer = BytePacketBuffer::new(); let mut req_buffer = BytePacketBuffer::new();
let (_, src) = match socket.recv_from(&mut req_buffer.buf) { let (_, src) = socket.recv_from(&mut req_buffer.buf)?;
Ok(x) => x,
Err(e) => {
println!("Failed to read from UDP socket: {:?}", e);
continue;
}
};
let request = match DnsPacket::from_buffer(&mut req_buffer) { let request = DnsPacket::from_buffer(&mut req_buffer)?;
Ok(x) => x,
Err(e) => {
println!("Failed to parse UDP query packet: {:?}", e);
continue;
}
};
let mut packet = DnsPacket::new(); let mut packet = DnsPacket::new();
packet.header.id = request.header.id; packet.header.id = request.header.id;
@ -887,29 +872,23 @@ fn main() -> Result<()> {
} }
let mut res_buffer = BytePacketBuffer::new(); let mut res_buffer = BytePacketBuffer::new();
match packet.write(&mut res_buffer) { packet.write(&mut res_buffer)?;
Ok(_) => {}
Err(e) => {
println!("Failed to encode UDP response packet: {:?}", e);
continue;
}
};
let len = res_buffer.pos(); let len = res_buffer.pos();
let data = match res_buffer.get_range(0, len) { let data = res_buffer.get_range(0, len)?;
Ok(x) => x,
Err(e) => {
println!("Failed to retrieve response buffer: {:?}", e);
continue;
}
};
match socket.send_to(data, src) { socket.send_to(data, src)?;
Ok(_) => {}
Err(e) => { Ok(())
println!("Failed to send response buffer: {:?}", e); }
continue;
fn main() -> Result<()> {
let socket = UdpSocket::bind(("0.0.0.0", 2053))?;
loop {
match handle_query(&socket) {
Ok(_) => {},
Err(e) => eprintln!("An error occured: {}", e),
} }
};
} }
} }