diff --git a/chapter4.md b/chapter4.md index 388b266..bd851d4 100644 --- a/chapter4.md +++ b/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 { +fn lookup(qname: &str, qtype: QueryType) -> Result { + // 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 Result 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; - } - }; } } ``` diff --git a/chapter5.md b/chapter5.md index 7023cf4..b85a3f9 100644 --- a/chapter5.md +++ b/chapter5.md @@ -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 { // 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 { ### 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 - diff --git a/examples/sample4.rs b/examples/sample4.rs index 0f928cd..b446362 100644 --- a/examples/sample4.rs +++ b/examples/sample4.rs @@ -689,7 +689,10 @@ impl DnsPacket { } } -fn lookup(qname: &str, qtype: QueryType, server: (&str, u16)) -> Result { +fn lookup(qname: &str, qtype: QueryType) -> Result { + // 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 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; - } - }; } } diff --git a/examples/sample5.rs b/examples/sample5.rs index 354d4bd..fe3fd49 100644 --- a/examples/sample5.rs +++ b/examples/sample5.rs @@ -832,84 +832,63 @@ fn recursive_lookup(qname: &str, qtype: QueryType) -> Result { } } +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; - } - }; } }