mirror of
https://github.com/EmilHernvall/dnsguide.git
synced 2024-12-23 01:04:16 +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:
|
;; 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.
|
||||||
|
|
||||||
```rust
|
|
||||||
jumped = true;
|
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:
|
||||||
```rust
|
else {
|
||||||
|
// Move a single byte forward to move past the length byte.
|
||||||
pos += 1;
|
pos += 1;
|
||||||
```
|
|
||||||
|
|
||||||
Domain names are terminated by an empty label of length 0, so if the length is zero
|
// Domain names are terminated by an empty label of length 0, so if the length is zero
|
||||||
we're done.
|
// we're done.
|
||||||
|
|
||||||
```rust
|
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
```
|
|
||||||
|
|
||||||
Append the delimiter to our output buffer first.
|
// Append the delimiter to our output buffer first.
|
||||||
|
|
||||||
```rust
|
|
||||||
outstr.push_str(delim);
|
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));
|
let str_buffer = try!(self.get_range(pos, len as usize));
|
||||||
outstr.push_str(&String::from_utf8_lossy(str_buffer).to_lowercase());
|
outstr.push_str(&String::from_utf8_lossy(str_buffer).to_lowercase());
|
||||||
|
|
||||||
delim = ".";
|
delim = ".";
|
||||||
```
|
|
||||||
|
|
||||||
Move forward the full length of the label.
|
// Move forward the full length of the label.
|
||||||
|
|
||||||
```rust
|
|
||||||
pos += len as usize;
|
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
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user