mirror of
https://github.com/EmilHernvall/dnsguide.git
synced 2024-12-22 20:24:15 +07:00
Clean up error handling in chapter 4 and 5
This commit is contained in:
parent
f815075ae4
commit
45cbfa59f7
183
chapter4.md
183
chapter4.md
@ -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.
|
||||
|
||||
```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 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)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### 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.
|
||||
|
||||
```rust
|
||||
fn main() -> Result<()> {
|
||||
// Forward queries to Google's public DNS
|
||||
let server = ("8.8.8.8", 53);
|
||||
/// Handle a single incoming packet
|
||||
fn handle_query(socket: &UdpSocket) -> Result<()> {
|
||||
// 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
|
||||
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
|
||||
// block until one is received.
|
||||
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;
|
||||
match handle_query(&socket) {
|
||||
Ok(_) => {},
|
||||
Err(e) => eprintln!("An error occured: {}", e),
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -222,7 +222,7 @@ impl DnsPacket {
|
||||
/// 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*
|
||||
/// 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> {
|
||||
// Get an iterator over the nameservers in the authorities section
|
||||
self.get_ns(qname)
|
||||
@ -299,11 +299,11 @@ fn recursive_lookup(qname: &str, qtype: QueryType) -> Result<DnsPacket> {
|
||||
|
||||
### 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`:
|
||||
|
||||
```rust
|
||||
fn main() -> Result<()> {
|
||||
fn handle_query(socket: &UdpSocket) -> Result<()> {
|
||||
|
||||
- snip -
|
||||
|
||||
|
@ -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 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)
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
// Forward queries to Google's public DNS
|
||||
let server = ("8.8.8.8", 53);
|
||||
/// Handle a single incoming packet
|
||||
fn handle_query(socket: &UdpSocket) -> Result<()> {
|
||||
// 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
|
||||
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
|
||||
// block until one is received.
|
||||
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;
|
||||
match handle_query(&socket) {
|
||||
Ok(_) => {},
|
||||
Err(e) => eprintln!("An error occured: {}", e),
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -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<()> {
|
||||
let socket = UdpSocket::bind(("0.0.0.0", 2053))?;
|
||||
|
||||
loop {
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
match handle_query(&socket) {
|
||||
Ok(_) => {},
|
||||
Err(e) => eprintln!("An error occured: {}", e),
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user