Update examples with modernized code
This commit is contained in:
@@ -11,6 +11,8 @@ 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],
|
||||
@@ -18,22 +20,26 @@ impl BytePacketBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
/// Current position within buffer
|
||||
fn pos(&self) -> usize {
|
||||
self.pos
|
||||
}
|
||||
|
||||
/// Step the buffer position forward a specific number of steps
|
||||
fn step(&mut self, steps: usize) -> Result<()> {
|
||||
self.pos += steps;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Change the buffer position
|
||||
fn seek(&mut self, pos: usize) -> Result<()> {
|
||||
self.pos = pos;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Read a single byte and move the position one step forward
|
||||
fn read(&mut self) -> Result<u8> {
|
||||
if self.pos >= 512 {
|
||||
return Err("End of buffer".into());
|
||||
@@ -44,6 +50,7 @@ impl BytePacketBuffer {
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Get a single byte, without changing the buffer position
|
||||
fn get(&mut self, pos: usize) -> Result<u8> {
|
||||
if pos >= 512 {
|
||||
return Err("End of buffer".into());
|
||||
@@ -51,6 +58,7 @@ impl BytePacketBuffer {
|
||||
Ok(self.buf[pos])
|
||||
}
|
||||
|
||||
/// Get a range of bytes
|
||||
fn get_range(&mut self, start: usize, len: usize) -> Result<&[u8]> {
|
||||
if start + len >= 512 {
|
||||
return Err("End of buffer".into());
|
||||
@@ -58,12 +66,14 @@ impl BytePacketBuffer {
|
||||
Ok(&self.buf[start..start + len as usize])
|
||||
}
|
||||
|
||||
/// Read two bytes, stepping two steps forward
|
||||
fn read_u16(&mut self) -> Result<u16> {
|
||||
let res = ((self.read()? as u16) << 8) | (self.read()? as u16);
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Read four bytes, stepping four steps forward
|
||||
fn read_u32(&mut self) -> Result<u32> {
|
||||
let res = ((self.read()? as u32) << 24)
|
||||
| ((self.read()? as u32) << 16)
|
||||
@@ -73,13 +83,28 @@ impl BytePacketBuffer {
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Read a qname
|
||||
///
|
||||
/// 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. 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();
|
||||
let mut jumped = false;
|
||||
|
||||
let mut delim = "";
|
||||
// track whether or not we've jumped
|
||||
let mut jumped = false;
|
||||
let max_jumps = 5;
|
||||
let mut jumps_performed = 0;
|
||||
|
||||
// Our delimiter 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 {
|
||||
// Dns Packets are untrusted data, so we need to be paranoid. Someone
|
||||
// can craft a packet with a cycle in the jump instructions. This guards
|
||||
@@ -88,42 +113,56 @@ impl BytePacketBuffer {
|
||||
return Err(format!("Limit of {} jumps exceeded", max_jumps).into());
|
||||
}
|
||||
|
||||
// At this point, we're always at the beginning of a label. Recall
|
||||
// that labels start with a length byte.
|
||||
let len = self.get(pos)?;
|
||||
|
||||
// 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.
|
||||
// If len has the two most significant bit are set, it represents a
|
||||
// jump to some other offset in the packet:
|
||||
if (len & 0xC0) == 0xC0 {
|
||||
// When a jump is performed, we only modify the shared buffer
|
||||
// position once, and avoid making the change later on.
|
||||
// Update the buffer position to a point past the current
|
||||
// label. We don't need to touch it any further.
|
||||
if !jumped {
|
||||
self.seek(pos + 2)?;
|
||||
}
|
||||
|
||||
// Read another byte, calculate offset and perform the jump by
|
||||
// updating our local position variable
|
||||
let b2 = self.get(pos + 1)? as u16;
|
||||
let offset = (((len as u16) ^ 0xC0) << 8) | b2;
|
||||
pos = offset as usize;
|
||||
|
||||
// Indicate that a jump was performed.
|
||||
jumped = true;
|
||||
jumps_performed += 1;
|
||||
|
||||
continue;
|
||||
}
|
||||
// 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;
|
||||
|
||||
pos += 1;
|
||||
// Domain names are terminated by an empty label of length 0,
|
||||
// so if the length is zero we're done.
|
||||
if len == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
// Names are terminated by an empty label of length 0
|
||||
if len == 0 {
|
||||
break;
|
||||
// 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.
|
||||
let str_buffer = 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;
|
||||
}
|
||||
|
||||
outstr.push_str(delim);
|
||||
|
||||
let str_buffer = self.get_range(pos, len as usize)?;
|
||||
outstr.push_str(&String::from_utf8_lossy(str_buffer).to_lowercase());
|
||||
|
||||
delim = ".";
|
||||
|
||||
pos += len as usize;
|
||||
}
|
||||
|
||||
if !jumped {
|
||||
@@ -386,19 +425,19 @@ fn main() -> Result<()> {
|
||||
f.read(&mut buffer.buf)?;
|
||||
|
||||
let packet = DnsPacket::from_buffer(&mut buffer)?;
|
||||
println!("{:?}", packet.header);
|
||||
println!("{:#?}", packet.header);
|
||||
|
||||
for q in packet.questions {
|
||||
println!("{:?}", q);
|
||||
println!("{:#?}", q);
|
||||
}
|
||||
for rec in packet.answers {
|
||||
println!("{:?}", rec);
|
||||
println!("{:#?}", rec);
|
||||
}
|
||||
for rec in packet.authorities {
|
||||
println!("{:?}", rec);
|
||||
println!("{:#?}", rec);
|
||||
}
|
||||
for rec in packet.resources {
|
||||
println!("{:?}", rec);
|
||||
println!("{:#?}", rec);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user