Преглед изворни кода

Introduce Opcodes

The DNS spec lists opcodes, which are used to specify which operation the request is for. For now, we only support the Query opcode, which is by far the most common one, but more are now technically possible as we no longer _assume_ Query (opcode #0).
Benjamin Sago пре 4 година
родитељ
комит
a8d2289b8e
3 измењених фајлова са 37 додато и 7 уклоњено
  1. 15 2
      dns/src/types.rs
  2. 19 2
      dns/src/wire.rs
  3. 3 3
      dns/tests/wire_parsing_tests.rs

+ 15 - 2
dns/src/types.rs

@@ -131,8 +131,8 @@ pub struct Flags {
     /// Whether this packet is a response packet.
     pub response: bool,
 
-    /// Number representing the operation being performed.
-    pub opcode: u8,
+    /// The operation being performed.
+    pub opcode: Opcode,
 
     /// In a response, whether the server is providing authoritative DNS responses.
     pub authoritative: bool,
@@ -158,6 +158,19 @@ pub struct Flags {
     pub error_code: Option<ErrorCode>,
 }
 
+/// A number representing the operation being performed.
+#[derive(PartialEq, Debug, Copy, Clone)]
+pub enum Opcode {
+
+    /// This request is a standard query, or this response is answering a
+    /// standard query.
+    Query,
+
+    /// Any other opcode. This can be from 1 to 15, as the opcode field is
+    /// four bits wide, and 0 is taken.
+    Other(u8),
+}
+
 
 /// A code indicating an error.
 #[derive(PartialEq, Debug, Copy, Clone)]

+ 19 - 2
dns/src/wire.rs

@@ -262,7 +262,8 @@ impl Flags {
         let mut                          bits  = 0b_0000_0000_0000_0000;
         if self.response               { bits += 0b_1000_0000_0000_0000; }
         match self.opcode {
-                                _ =>   { bits += 0b_0000_0000_0000_0000; }
+            Opcode::Query     =>       { bits += 0b_0000_0000_0000_0000; }
+            Opcode::Other(_)  =>       { unimplemented!(); }
         }
         if self.authoritative          { bits += 0b_0000_0100_0000_0000; }
         if self.truncated              { bits += 0b_0000_0010_0000_0000; }
@@ -281,7 +282,7 @@ impl Flags {
 
         Self {
             response:               has_bit(0b_1000_0000_0000_0000),
-            opcode:                 0,
+            opcode:                 Opcode::from_bits((bits.to_be_bytes()[0] & 0b_0111_1000) >> 3),
             authoritative:          has_bit(0b_0000_0100_0000_0000),
             truncated:              has_bit(0b_0000_0010_0000_0000),
             recursion_desired:      has_bit(0b_0000_0001_0000_0000),
@@ -294,6 +295,22 @@ impl Flags {
 }
 
 
+impl Opcode {
+
+    /// Extracts the opcode from this four-bit number, which should have been
+    /// extracted from the packet and shifted to be in the range 0–15.
+    fn from_bits(bits: u8) -> Self {
+        if bits == 0 {
+            Self::Query
+        }
+        else {
+            assert!(bits <= 15, "bits {:#08b} out of range", bits);
+            Self::Other(bits)
+        }
+    }
+}
+
+
 impl ErrorCode {
 
     /// Extracts the rcode from the last four bits of the flags field.

+ 3 - 3
dns/tests/wire_parsing_tests.rs

@@ -1,6 +1,6 @@
 use std::net::Ipv4Addr;
 
-use dns::{Response, Query, Answer, Labels, Flags, QClass, qtype};
+use dns::{Response, Query, Answer, Labels, Flags, Opcode, QClass, qtype};
 use dns::record::{Record, A, CNAME, OPT};
 
 
@@ -45,7 +45,7 @@ fn parse_response_standard() {
         transaction_id: 0x0dcd,
         flags: Flags {
             response: true,
-            opcode: 0,
+            opcode: Opcode::Query,
             authoritative: false,
             truncated: false,
             recursion_desired: true,
@@ -118,7 +118,7 @@ fn parse_response_with_mixed_string() {
         transaction_id: 0x069f,
         flags: Flags {
             response: true,
-            opcode: 0,
+            opcode: Opcode::Query,
             authoritative: false,
             truncated: false,
             recursion_desired: true,