Chapter 1 tweaks

This commit is contained in:
Emil Hernvall 2018-03-15 14:16:22 +01:00
parent 1e0d2d67cb
commit cf153a7847

View File

@ -92,12 +92,12 @@ a lookup using the `dig` tool:
;; ANSWER SECTION: ;; ANSWER SECTION:
google.com. 204 IN A 172.217.18.142 google.com. 204 IN A 172.217.18.142
```
;; Query time: 0 msec ;; Query time: 0 msec
;; SERVER: 192.168.1.1#53(192.168.1.1) ;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Wed Jul 06 13:24:19 CEST 2016 ;; WHEN: Wed Jul 06 13:24:19 CEST 2016
;; MSG SIZE rcvd: 44 ;; MSG SIZE rcvd: 44
```
We're using the `+noedns` flag to make sure we stick to the original format. We're using the `+noedns` flag to make sure we stick to the original format.
There are a few things of note in the output above: There are a few things of note in the output above:
@ -328,19 +328,18 @@ pub struct BytePacketBuffer {
impl BytePacketBuffer { impl BytePacketBuffer {
// This gives us a fresh buffer for holding the packet contents, and a field for
// keeping track of where we are.
pub fn new() -> BytePacketBuffer { pub fn new() -> BytePacketBuffer {
BytePacketBuffer { BytePacketBuffer {
buf: [0; 512], buf: [0; 512],
pos: 0 pos: 0
} }
} }
```
This gives us a fresh buffer for holding the packet contents, and a field for // When handling the reading of domain names, we'll need a way of
keeping track of where we are. When handling the reading of domain names later // reading and manipulating our buffer position.
on, we'll need a way of reading and manipulating our buffer position:
```rust
fn pos(&self) -> usize { fn pos(&self) -> usize {
self.pos self.pos
} }
@ -356,11 +355,8 @@ on, we'll need a way of reading and manipulating our buffer position:
Ok(()) Ok(())
} }
```
Next up is a method for reading a single byte, and moving one step forward: // A method for reading a single byte, and moving one step forward
```rust
fn read(&mut self) -> Result<u8> { fn read(&mut self) -> Result<u8> {
if self.pos >= 512 { if self.pos >= 512 {
return Err(Error::new(ErrorKind::InvalidInput, "End of buffer")); return Err(Error::new(ErrorKind::InvalidInput, "End of buffer"));
@ -370,34 +366,27 @@ Next up is a method for reading a single byte, and moving one step forward:
Ok(res) Ok(res)
} }
```
We might also want to retrieve a byte at our current position without moving // Methods for fetching data at a specified position, without modifying
forward: // the internal position
```rust
fn get(&mut self, pos: usize) -> Result<u8> { fn get(&mut self, pos: usize) -> Result<u8> {
if pos >= 512 { if pos >= 512 {
return Err(Error::new(ErrorKind::InvalidInput, "End of buffer")); return Err(Error::new(ErrorKind::InvalidInput, "End of buffer"));
} }
Ok(self.buf[pos]) Ok(self.buf[pos])
} }
```
Sometimes we want to get a full range of the buffer:
```rust
fn get_range(&mut self, start: usize, len: usize) -> Result<&[u8]> { fn get_range(&mut self, start: usize, len: usize) -> Result<&[u8]> {
if start + len >= 512 { if start + len >= 512 {
return Err(Error::new(ErrorKind::InvalidInput, "End of buffer")); return Err(Error::new(ErrorKind::InvalidInput, "End of buffer"));
} }
Ok(&self.buf[start..start+len as usize]) Ok(&self.buf[start..start+len as usize])
} }
```
In many cases we'll want to read a two-byte integer or a four-byte integer: // Methods for reading a u16 and u32 from the buffer, while stepping
// forward 2 or 4 bytes
```rust
fn read_u16(&mut self) -> Result<u16> fn read_u16(&mut self) -> Result<u16>
{ {
let res = ((try!(self.read()) as u16) << 8) | let res = ((try!(self.read()) as u16) << 8) |
@ -415,135 +404,86 @@ In many cases we'll want to read a two-byte integer or a four-byte integer:
Ok(res) Ok(res)
} }
```
And then we get to the tricky part of correctly reading domain names, handling // The tricky part: Reading domain names, taking labels into consideration.
any jump we might encounter: // Will take something like [3]www[6]google[3]com[0] and append
// www.google.com to outstr.
```rust
fn read_qname(&mut self, outstr: &mut String) -> Result<()> fn read_qname(&mut self, outstr: &mut String) -> Result<()>
{ {
``` // Since we might encounter jumps, we'll keep track of our position
// locally as opposed to using the position within the struct. This
Since we might encounter jumps, we'll keep track of our position // allows us to move the shared position to a point past our current
locally as opposed to using the position within the struct. // qname, while keeping track of our progress on the current qname
// using this variable.
```rust
let mut pos = self.pos(); let mut pos = self.pos();
```
We'll keep track of whether or not we've jumped for use later on // track whether or not we've jumped
```rust
let mut jumped = false; let mut jumped = false;
```
Our delimeter which we append for each label. Since we don't want a dot at the // Our delimeter which we append for each label. Since we don't want a dot at the
beginning of the domain name we'll leave it empty for now and set it to "." at // beginning of the domain name we'll leave it empty for now and set it to "." at
the end of the first iteration. // the end of the first iteration.
```rust
let mut delim = ""; let mut delim = "";
loop { loop {
``` // At this point, we're always at the beginning of a label. Recall
// that labels start with a length byte.
We're at the beginning of a label, so our current position is the length byte.
```rust
let len = try!(self.get(pos)); let len = try!(self.get(pos));
```
`len* is a two byte sequence, where the two highest bits of the first byte is // If len has the two most significant bit are set, it represents a jump to
set, represents a offset relative to the start of the buffer. We handle this // some other offset in the packet:
by jumping to the offset, setting a flag to indicate that we shouldn't update
the shared buffer position once done.
```rust
if (len & 0xC0) > 0 { if (len & 0xC0) > 0 {
``` // Update the buffer position to a point past the current
// label. We don't need to touch it any further.
When a jump is performed, we only modify the shared buffer position once, and avoid
making the change later on.
```rust
if !jumped { if !jumped {
try!(self.seek(pos+2)); try!(self.seek(pos+2));
} }
```
Read another byte, and calculate the jump offset: // Read another byte, calculate offset and perform the jump by
// updating our local position variable
```rust
let b2 = try!(self.get(pos+1)) as u16; let b2 = try!(self.get(pos+1)) as u16;
let offset = (((len as u16) ^ 0xC0) << 8) | b2; let offset = (((len as u16) ^ 0xC0) << 8) | b2;
pos = offset as usize; pos = offset as usize;
```
Indicate that a jump was performed. // Indicate that a jump was performed.
jumped = true;
```rust
jumped = true;
```
Restart the loop and retry at the new position.
```rust
continue;
} }
```
Move a single byte forward to move past the length byte. // The base scenario, where we're reading a single label and
// appending it to the output:
else {
// Move a single byte forward to move past the length byte.
pos += 1;
```rust // Domain names are terminated by an empty label of length 0, so if the length is zero
pos += 1; // we're done.
``` if len == 0 {
break;
}
Domain names are terminated by an empty label of length 0, so if the length is zero // Append the delimiter to our output buffer first.
we're done. outstr.push_str(delim);
```rust // Extract the actual ASCII bytes for this label and append them to the output buffer.
if len == 0 {
break; let str_buffer = try!(self.get_range(pos, len as usize));
outstr.push_str(&String::from_utf8_lossy(str_buffer).to_lowercase());
delim = ".";
// Move forward the full length of the label.
pos += len as usize;
} }
```
Append the delimiter to our output buffer first.
```rust
outstr.push_str(delim);
```
Extract the actual ASCII bytes for this label and append them to the output buffer.
```rust
let str_buffer = try!(self.get_range(pos, len as usize));
outstr.push_str(&String::from_utf8_lossy(str_buffer).to_lowercase());
delim = ".";
```
Move forward the full length of the label.
```rust
pos += len as usize;
} }
```
If a jump has been performed, we've already modified the buffer position state and // If a jump has been performed, we've already modified the buffer position state and
shouldn't do so again. // shouldn't do so again.
```rust
if !jumped { if !jumped {
try!(self.seek(pos)); try!(self.seek(pos));
} }
Ok(()) Ok(())
} // End of read_qname } // End of read_qname
```
Oh, and we're done:
```rust
} // End of BytePacketBuffer } // End of BytePacketBuffer
``` ```