mirror of
https://github.com/EmilHernvall/dnsguide.git
synced 2024-12-22 20:24:15 +07:00
Chapter 1 tweaks
This commit is contained in:
parent
1e0d2d67cb
commit
cf153a7847
146
chapter1.md
146
chapter1.md
@ -92,12 +92,12 @@ a lookup using the `dig` tool:
|
||||
|
||||
;; ANSWER SECTION:
|
||||
google.com. 204 IN A 172.217.18.142
|
||||
```
|
||||
|
||||
;; Query time: 0 msec
|
||||
;; SERVER: 192.168.1.1#53(192.168.1.1)
|
||||
;; WHEN: Wed Jul 06 13:24:19 CEST 2016
|
||||
;; MSG SIZE rcvd: 44
|
||||
```
|
||||
|
||||
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:
|
||||
@ -328,19 +328,18 @@ pub struct 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 {
|
||||
BytePacketBuffer {
|
||||
buf: [0; 512],
|
||||
pos: 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This gives us a fresh buffer for holding the packet contents, and a field for
|
||||
keeping track of where we are. When handling the reading of domain names later
|
||||
on, we'll need a way of reading and manipulating our buffer position:
|
||||
// When handling the reading of domain names, we'll need a way of
|
||||
// reading and manipulating our buffer position.
|
||||
|
||||
```rust
|
||||
fn pos(&self) -> usize {
|
||||
self.pos
|
||||
}
|
||||
@ -356,11 +355,8 @@ on, we'll need a way of reading and manipulating our buffer position:
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
Next up is a method for reading a single byte, and moving one step forward:
|
||||
|
||||
```rust
|
||||
// A method for reading a single byte, and moving one step forward
|
||||
fn read(&mut self) -> Result<u8> {
|
||||
if self.pos >= 512 {
|
||||
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)
|
||||
}
|
||||
```
|
||||
|
||||
We might also want to retrieve a byte at our current position without moving
|
||||
forward:
|
||||
// Methods for fetching data at a specified position, without modifying
|
||||
// the internal position
|
||||
|
||||
```rust
|
||||
fn get(&mut self, pos: usize) -> Result<u8> {
|
||||
if pos >= 512 {
|
||||
return Err(Error::new(ErrorKind::InvalidInput, "End of buffer"));
|
||||
}
|
||||
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]> {
|
||||
if start + len >= 512 {
|
||||
return Err(Error::new(ErrorKind::InvalidInput, "End of buffer"));
|
||||
}
|
||||
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>
|
||||
{
|
||||
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)
|
||||
}
|
||||
```
|
||||
|
||||
And then we get to the tricky part of correctly reading domain names, handling
|
||||
any jump we might encounter:
|
||||
|
||||
```rust
|
||||
// The tricky part: Reading domain names, taking labels into consideration.
|
||||
// Will take something like [3]www[6]google[3]com[0] and append
|
||||
// www.google.com to outstr.
|
||||
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.
|
||||
|
||||
```rust
|
||||
// Since we might encounter jumps, we'll keep track of our position
|
||||
// locally as opposed to using the position within the struct. This
|
||||
// allows us to move the shared position to a point past our current
|
||||
// qname, while keeping track of our progress on the current qname
|
||||
// using this variable.
|
||||
let mut pos = self.pos();
|
||||
```
|
||||
|
||||
We'll keep track of whether or not we've jumped for use later on
|
||||
|
||||
```rust
|
||||
// track whether or not we've jumped
|
||||
let mut jumped = false;
|
||||
```
|
||||
|
||||
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
|
||||
the end of the first iteration.
|
||||
|
||||
```rust
|
||||
// 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
|
||||
// the end of the first iteration.
|
||||
let mut delim = "";
|
||||
loop {
|
||||
```
|
||||
|
||||
We're at the beginning of a label, so our current position is the length byte.
|
||||
|
||||
```rust
|
||||
// At this point, we're always at the beginning of a label. Recall
|
||||
// that labels start with a length byte.
|
||||
let len = try!(self.get(pos));
|
||||
```
|
||||
|
||||
`len* is a two byte sequence, where the two highest bits of the first byte is
|
||||
set, represents a offset relative to the start of the buffer. We handle this
|
||||
by jumping to the offset, setting a flag to indicate that we shouldn't update
|
||||
the shared buffer position once done.
|
||||
|
||||
```rust
|
||||
// If len has the two most significant bit are set, it represents a jump to
|
||||
// some other offset in the packet:
|
||||
if (len & 0xC0) > 0 {
|
||||
```
|
||||
|
||||
When a jump is performed, we only modify the shared buffer position once, and avoid
|
||||
making the change later on.
|
||||
|
||||
```rust
|
||||
// Update the buffer position to a point past the current
|
||||
// label. We don't need to touch it any further.
|
||||
if !jumped {
|
||||
try!(self.seek(pos+2));
|
||||
}
|
||||
```
|
||||
|
||||
Read another byte, and calculate the jump offset:
|
||||
|
||||
```rust
|
||||
// Read another byte, calculate offset and perform the jump by
|
||||
// updating our local position variable
|
||||
let b2 = try!(self.get(pos+1)) as u16;
|
||||
let offset = (((len as u16) ^ 0xC0) << 8) | b2;
|
||||
pos = offset as usize;
|
||||
```
|
||||
|
||||
Indicate that a jump was performed.
|
||||
|
||||
```rust
|
||||
// Indicate that a jump was performed.
|
||||
jumped = true;
|
||||
```
|
||||
|
||||
Restart the loop and retry at the new position.
|
||||
|
||||
```rust
|
||||
continue;
|
||||
}
|
||||
```
|
||||
|
||||
Move a single byte forward to move past the length byte.
|
||||
|
||||
```rust
|
||||
// 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;
|
||||
```
|
||||
|
||||
Domain names are terminated by an empty label of length 0, so if the length is zero
|
||||
we're done.
|
||||
|
||||
```rust
|
||||
// Domain names are terminated by an empty label of length 0, so if the length is zero
|
||||
// we're done.
|
||||
if len == 0 {
|
||||
break;
|
||||
}
|
||||
```
|
||||
|
||||
Append the delimiter to our output buffer first.
|
||||
|
||||
```rust
|
||||
// Append the delimiter to our output buffer first.
|
||||
outstr.push_str(delim);
|
||||
```
|
||||
|
||||
Extract the actual ASCII bytes for this label and append them to the output buffer.
|
||||
// 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
|
||||
// Move forward the full length of the label.
|
||||
pos += len as usize;
|
||||
}
|
||||
```
|
||||
}
|
||||
|
||||
If a jump has been performed, we've already modified the buffer position state and
|
||||
shouldn't do so again.
|
||||
|
||||
```rust
|
||||
// If a jump has been performed, we've already modified the buffer position state and
|
||||
// shouldn't do so again.
|
||||
if !jumped {
|
||||
try!(self.seek(pos));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
} // End of read_qname
|
||||
```
|
||||
|
||||
Oh, and we're done:
|
||||
|
||||
```rust
|
||||
} // End of BytePacketBuffer
|
||||
```
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user