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,116 +176,89 @@ 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); // With a socket ready, we can go ahead and read a packet. This will
// block until one is received.
let mut req_buffer = BytePacketBuffer::new();
// The `recv_from` function will write the data into the provided buffer,
// and return the length of the data read as well as the source address.
// We're not interested in the length, but we need to keep track of the
// source in order to send our reply later on.
let (_, src) = socket.recv_from(&mut req_buffer.buf)?;
// Next, `DnsPacket::from_buffer` is used to parse the raw bytes into
// a `DnsPacket`.
let request = DnsPacket::from_buffer(&mut req_buffer)?;
// Create and initialize the response packet
let mut packet = DnsPacket::new();
packet.header.id = request.header.id;
packet.header.recursion_desired = true;
packet.header.recursion_available = true;
packet.header.response = true;
// Being mindful of how unreliable input data from arbitrary senders can be, we
// need make sure that a question is actually present. If not, we return `FORMERR`
// to indicate that the sender made something wrong.
if request.questions.is_empty() {
packet.header.rescode = ResultCode::FORMERR;
}
// Usually a question will be present, though.
else {
let question = &request.questions[0];
println!("Received query: {:?}", question);
// Since all is set up and as expected, the query can be forwarded to the
// target server. There's always the possibility that the query will
// fail, in which case the `SERVFAIL` response code is set to indicate
// as much to the client. If rather everything goes as planned, the
// question and response records as copied into our response packet.
if let Ok(result) = lookup(&question.name, question.qtype) {
packet.questions.push(question.clone());
packet.header.rescode = result.header.rescode;
for rec in result.answers {
println!("Answer: {:?}", rec);
packet.answers.push(rec);
}
for rec in result.authorities {
println!("Authority: {:?}", rec);
packet.authorities.push(rec);
}
for rec in result.resources {
println!("Resource: {:?}", rec);
packet.resources.push(rec);
}
} else {
packet.header.rescode = ResultCode::SERVFAIL;
}
}
// The only thing remaining is to encode our response and send it off!
let mut res_buffer = BytePacketBuffer::new();
packet.write(&mut res_buffer)?;
let len = res_buffer.pos();
let data = res_buffer.get_range(0, len)?;
socket.send_to(data, src)?;
Ok(())
}
fn main() -> Result<()> {
// Bind an UDP socket on port 2053 // Bind an UDP socket on port 2053
let socket = UdpSocket::bind(("0.0.0.0", 2053))?; let socket = UdpSocket::bind(("0.0.0.0", 2053))?;
// For now, queries are handled sequentially, so an infinite loop for servicing // For now, queries are handled sequentially, so an infinite loop for servicing
// requests is initiated. // requests is initiated.
loop { loop {
match handle_query(&socket) {
// With a socket ready, we can go ahead and read a packet. This will Ok(_) => {},
// block until one is received. Err(e) => eprintln!("An error occured: {}", e),
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 raw bytes are simply returned, and if not it'll abort by restarting the
// loop and waiting for the next request. The `recv_from` function will write the
// data into the provided buffer, and return the length of the data read as well
// as the source address. We're not interested in the length, but we need to keep
// track of the source in order to send our reply later on.
// 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.
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
let mut packet = DnsPacket::new();
packet.header.id = request.header.id;
packet.header.recursion_desired = true;
packet.header.recursion_available = true;
packet.header.response = true;
// Being mindful of how unreliable input data from arbitrary senders can be, we
// need make sure that a question is actually present. If not, we return `FORMERR`
// to indicate that the sender made something wrong.
if request.questions.is_empty() {
packet.header.rescode = ResultCode::FORMERR;
} }
// Usually a question will be present, though.
else {
let question = &request.questions[0];
println!("Received query: {:?}", question);
// Since all is set up and as expected, the query can be forwarded to the target
// server. There's always the possibility that the query will fail, in which case
// the `SERVFAIL` response code is set to indicate as much to the client. If
// rather everything goes as planned, the question and response records as copied
// into our response packet.
if let Ok(result) = lookup(&question.name, question.qtype, server) {
packet.questions.push(question.clone());
packet.header.rescode = result.header.rescode;
for rec in result.answers {
println!("Answer: {:?}", rec);
packet.answers.push(rec);
}
for rec in result.authorities {
println!("Authority: {:?}", rec);
packet.authorities.push(rec);
}
for rec in result.resources {
println!("Resource: {:?}", rec);
packet.resources.push(rec);
}
} else {
packet.header.rescode = ResultCode::SERVFAIL;
}
}
// The only thing remaining is to encode our response and send it off!
let mut res_buffer = BytePacketBuffer::new();
match packet.write(&mut res_buffer) {
Ok(_) => {}
Err(e) => {
println!("Failed to encode UDP response packet: {:?}", e);
continue;
}
};
let len = res_buffer.pos();
let data = match 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) {
Ok(_) => {}
Err(e) => {
println!("Failed to send response buffer: {:?}", e);
continue;
}
};
} }
} }
``` ```

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,114 +714,88 @@ 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); // With a socket ready, we can go ahead and read a packet. This will
// block until one is received.
let mut req_buffer = BytePacketBuffer::new();
// The `recv_from` function will write the data into the provided buffer,
// and return the length of the data read as well as the source address.
// We're not interested in the length, but we need to keep track of the
// source in order to send our reply later on.
let (_, src) = socket.recv_from(&mut req_buffer.buf)?;
// Next, `DnsPacket::from_buffer` is used to parse the raw bytes into
// a `DnsPacket`.
let request = DnsPacket::from_buffer(&mut req_buffer)?;
// Create and initialize the response packet
let mut packet = DnsPacket::new();
packet.header.id = request.header.id;
packet.header.recursion_desired = true;
packet.header.recursion_available = true;
packet.header.response = true;
// Being mindful of how unreliable input data from arbitrary senders can be, we
// need make sure that a question is actually present. If not, we return `FORMERR`
// to indicate that the sender made something wrong.
if request.questions.is_empty() {
packet.header.rescode = ResultCode::FORMERR;
}
// Usually a question will be present, though.
else {
let question = &request.questions[0];
println!("Received query: {:?}", question);
// Since all is set up and as expected, the query can be forwarded to the
// target server. There's always the possibility that the query will
// fail, in which case the `SERVFAIL` response code is set to indicate
// as much to the client. If rather everything goes as planned, the
// question and response records as copied into our response packet.
if let Ok(result) = lookup(&question.name, question.qtype) {
packet.questions.push(question.clone());
packet.header.rescode = result.header.rescode;
for rec in result.answers {
println!("Answer: {:?}", rec);
packet.answers.push(rec);
}
for rec in result.authorities {
println!("Authority: {:?}", rec);
packet.authorities.push(rec);
}
for rec in result.resources {
println!("Resource: {:?}", rec);
packet.resources.push(rec);
}
} else {
packet.header.rescode = ResultCode::SERVFAIL;
}
}
// The only thing remaining is to encode our response and send it off!
let mut res_buffer = BytePacketBuffer::new();
packet.write(&mut res_buffer)?;
let len = res_buffer.pos();
let data = res_buffer.get_range(0, len)?;
socket.send_to(data, src)?;
Ok(())
}
fn main() -> Result<()> {
// Bind an UDP socket on port 2053 // Bind an UDP socket on port 2053
let socket = UdpSocket::bind(("0.0.0.0", 2053))?; let socket = UdpSocket::bind(("0.0.0.0", 2053))?;
// For now, queries are handled sequentially, so an infinite loop for servicing // For now, queries are handled sequentially, so an infinite loop for servicing
// requests is initiated. // requests is initiated.
loop { loop {
// With a socket ready, we can go ahead and read a packet. This will match handle_query(&socket) {
// block until one is received. Ok(_) => {},
let mut req_buffer = BytePacketBuffer::new(); Err(e) => eprintln!("An error occured: {}", e),
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 raw bytes are simply returned, and if not it'll abort by restarting the
// loop and waiting for the next request. The `recv_from` function will write the
// data into the provided buffer, and return the length of the data read as well
// as the source address. We're not interested in the length, but we need to keep
// track of the source in order to send our reply later on.
// 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.
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
let mut packet = DnsPacket::new();
packet.header.id = request.header.id;
packet.header.recursion_desired = true;
packet.header.recursion_available = true;
packet.header.response = true;
// Being mindful of how unreliable input data from arbitrary senders can be, we
// need make sure that a question is actually present. If not, we return `FORMERR`
// to indicate that the sender made something wrong.
if request.questions.is_empty() {
packet.header.rescode = ResultCode::FORMERR;
} }
// Usually a question will be present, though.
else {
let question = &request.questions[0];
println!("Received query: {:?}", question);
// Since all is set up and as expected, the query can be forwarded to the target
// server. There's always the possibility that the query will fail, in which case
// the `SERVFAIL` response code is set to indicate as much to the client. If
// rather everything goes as planned, the question and response records as copied
// into our response packet.
if let Ok(result) = lookup(&question.name, question.qtype, server) {
packet.questions.push(question.clone());
packet.header.rescode = result.header.rescode;
for rec in result.answers {
println!("Answer: {:?}", rec);
packet.answers.push(rec);
}
for rec in result.authorities {
println!("Authority: {:?}", rec);
packet.authorities.push(rec);
}
for rec in result.resources {
println!("Resource: {:?}", rec);
packet.resources.push(rec);
}
} else {
packet.header.rescode = ResultCode::SERVFAIL;
}
}
// The only thing remaining is to encode our response and send it off!
let mut res_buffer = BytePacketBuffer::new();
match packet.write(&mut res_buffer) {
Ok(_) => {}
Err(e) => {
println!("Failed to encode UDP response packet: {:?}", e);
continue;
}
};
let len = res_buffer.pos();
let data = match 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) {
Ok(_) => {}
Err(e) => {
println!("Failed to send response buffer: {:?}", e);
continue;
}
};
} }
} }

View File

@ -832,84 +832,63 @@ fn recursive_lookup(qname: &str, qtype: QueryType) -> Result<DnsPacket> {
} }
} }
fn handle_query(socket: &UdpSocket) -> Result<()> {
let mut req_buffer = BytePacketBuffer::new();
let (_, src) = socket.recv_from(&mut req_buffer.buf)?;
let request = DnsPacket::from_buffer(&mut req_buffer)?;
let mut packet = DnsPacket::new();
packet.header.id = request.header.id;
packet.header.recursion_desired = true;
packet.header.recursion_available = true;
packet.header.response = true;
if request.questions.is_empty() {
packet.header.rescode = ResultCode::FORMERR;
} else {
let question = &request.questions[0];
println!("Received query: {:?}", question);
if let Ok(result) = recursive_lookup(&question.name, question.qtype) {
packet.questions.push(question.clone());
packet.header.rescode = result.header.rescode;
for rec in result.answers {
println!("Answer: {:?}", rec);
packet.answers.push(rec);
}
for rec in result.authorities {
println!("Authority: {:?}", rec);
packet.authorities.push(rec);
}
for rec in result.resources {
println!("Resource: {:?}", rec);
packet.resources.push(rec);
}
} else {
packet.header.rescode = ResultCode::SERVFAIL;
}
}
let mut res_buffer = BytePacketBuffer::new();
packet.write(&mut res_buffer)?;
let len = res_buffer.pos();
let data = res_buffer.get_range(0, len)?;
socket.send_to(data, src)?;
Ok(())
}
fn main() -> Result<()> { fn main() -> Result<()> {
let socket = UdpSocket::bind(("0.0.0.0", 2053))?; let socket = UdpSocket::bind(("0.0.0.0", 2053))?;
loop { loop {
let mut req_buffer = BytePacketBuffer::new(); match handle_query(&socket) {
let (_, src) = match socket.recv_from(&mut req_buffer.buf) { Ok(_) => {},
Ok(x) => x, Err(e) => eprintln!("An error occured: {}", e),
Err(e) => {
println!("Failed to read from UDP socket: {:?}", e);
continue;
}
};
let request = match 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();
packet.header.id = request.header.id;
packet.header.recursion_desired = true;
packet.header.recursion_available = true;
packet.header.response = true;
if request.questions.is_empty() {
packet.header.rescode = ResultCode::FORMERR;
} else {
let question = &request.questions[0];
println!("Received query: {:?}", question);
if let Ok(result) = recursive_lookup(&question.name, question.qtype) {
packet.questions.push(question.clone());
packet.header.rescode = result.header.rescode;
for rec in result.answers {
println!("Answer: {:?}", rec);
packet.answers.push(rec);
}
for rec in result.authorities {
println!("Authority: {:?}", rec);
packet.authorities.push(rec);
}
for rec in result.resources {
println!("Resource: {:?}", rec);
packet.resources.push(rec);
}
} else {
packet.header.rescode = ResultCode::SERVFAIL;
}
} }
let mut res_buffer = BytePacketBuffer::new();
match packet.write(&mut res_buffer) {
Ok(_) => {}
Err(e) => {
println!("Failed to encode UDP response packet: {:?}", e);
continue;
}
};
let len = res_buffer.pos();
let data = match 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) {
Ok(_) => {}
Err(e) => {
println!("Failed to send response buffer: {:?}", e);
continue;
}
};
} }
} }