Browse Source

Stop treating some NAPTR fields as UTF-8

Because NAPTR is one of the few (possibly the only?) response type that contains both arbitrary strings and length-encoded DNS labels, the ANSI sample output still manage to contain UTF-8, rather than being pure ASCII, which will need to be changed when domains get encoded properly.

Also, the regex field is now just printed as a quoted string, rather than having its own special slashy representation.
Benjamin Sago 3 years ago
parent
commit
fab09a7b62

+ 15 - 21
dns/src/record/naptr.rs

@@ -23,14 +23,14 @@ pub struct NAPTR {
 
     /// A set of characters that control the rewriting and interpretation of
     /// the other fields.
-    pub flags: String,
+    pub flags: Box<[u8]>,
 
     /// The service parameters applicable to this delegation path.
-    pub service: String,
+    pub service: Box<[u8]>,
 
     /// A regular expression that gets applied to a string in order to
     /// construct the next domain name to look up using the DDDS algorithm.
-    pub regex: String,
+    pub regex: Box<[u8]>,
 
     /// The replacement domain name as part of the DDDS algorithm.
     pub replacement: Labels,
@@ -53,31 +53,25 @@ impl Wire for NAPTR {
         let flags_length = c.read_u8()?;
         trace!("Parsed flags length -> {:?}", flags_length);
 
-        let mut flags_buffer = vec![0_u8; usize::from(flags_length)];
-        c.read_exact(&mut flags_buffer)?;
-
-        let flags = String::from_utf8_lossy(&flags_buffer).to_string();
-        trace!("Parsed flags -> {:?}", flags);
+        let mut flags = vec![0_u8; usize::from(flags_length)].into_boxed_slice();
+        c.read_exact(&mut flags)?;
+        trace!("Parsed flags -> {:?}", String::from_utf8_lossy(&flags));
 
         // service
         let service_length = c.read_u8()?;
         trace!("Parsed service length -> {:?}", service_length);
 
-        let mut service_buffer = vec![0_u8; usize::from(service_length)];
-        c.read_exact(&mut service_buffer)?;
-
-        let service = String::from_utf8_lossy(&service_buffer).to_string();
-        trace!("Parsed service -> {:?}", service);
+        let mut service = vec![0_u8; usize::from(service_length)].into_boxed_slice();
+        c.read_exact(&mut service)?;
+        trace!("Parsed service -> {:?}", String::from_utf8_lossy(&service));
 
         // regex
         let regex_length = c.read_u8()?;
         trace!("Parsed regex length -> {:?}", regex_length);
 
-        let mut regex_buffer = vec![0_u8; usize::from(regex_length)];
-        c.read_exact(&mut regex_buffer)?;
-
-        let regex = String::from_utf8_lossy(&regex_buffer).to_string();
-        trace!("Parsed regex -> {:?}", regex);
+        let mut regex = vec![0_u8; usize::from(regex_length)].into_boxed_slice();
+        c.read_exact(&mut regex)?;
+        trace!("Parsed regex -> {:?}", String::from_utf8_lossy(&regex));
 
         // replacement
         let (replacement, replacement_length) = c.read_labels()?;
@@ -123,9 +117,9 @@ mod test {
                    NAPTR {
                        order: 5,
                        preference: 10,
-                       flags: "s".into(),
-                       service: "SRV".into(),
-                       regex: "\\d\\d:\\d\\d:\\d\\d".into(),
+                       flags: Box::new(*b"s"),
+                       service: Box::new(*b"SRV"),
+                       regex: Box::new(*b"\\d\\d:\\d\\d:\\d\\d"),
                        replacement: Labels::encode("srv-example.lookup.dog").unwrap(),
                    });
     }

+ 7 - 7
src/output.rs

@@ -228,12 +228,12 @@ impl TextFormat {
                 format!("{} {:?}", mx.preference, mx.exchange.to_string())
             }
             Record::NAPTR(naptr) => {
-                format!("{} {} {} {:?} /{}/ {:?}",
+                format!("{} {} {} {} {} {:?}",
                     naptr.order,
                     naptr.preference,
-                    naptr.flags,
-                    naptr.service,
-                    naptr.regex,
+                    Ascii(&naptr.flags),
+                    Ascii(&naptr.service),
+                    Ascii(&naptr.regex),
                     naptr.replacement.to_string(),
                 )
             }
@@ -520,9 +520,9 @@ fn json_record_data(record: Record) -> JsonValue {
         Record::NAPTR(naptr) => {
             object! {
                 "order": naptr.order,
-                "flags": naptr.flags,
-                "service": naptr.service,
-                "regex": naptr.regex,
+                "flags": String::from_utf8_lossy(&naptr.flags).to_string(),
+                "service": String::from_utf8_lossy(&naptr.service).to_string(),
+                "regex": String::from_utf8_lossy(&naptr.regex).to_string(),
                 "replacement": naptr.replacement.to_string(),
             }
         }

+ 32 - 0
xtests/madns/naptr-records.toml

@@ -16,6 +16,22 @@ stderr = { empty = true }
 status = 0
 tags = [ "naptr", "madns" ]
 
+[[cmd]]
+name = "Running with ‘utf8.naptr.example’ escapes characters in the NAPTR"
+shell = "dog --colour=always ${MADNS_ARGS:[email protected]:5301 --tcp} NAPTR utf8.naptr.invalid"
+stdout = { file = "outputs/utf8.naptr.invalid.ansitxt" }
+stderr = { empty = true }
+status = 0
+tags = [ "naptr", "madns", "chars" ]
+
+[[cmd]]
+name = "Running with ‘bad-utf8.naptr.example’ escapes characters in the NAPTR and does not crash"
+shell = "dog --colour=always ${MADNS_ARGS:[email protected]:5301 --tcp} NAPTR bad-utf8.naptr.invalid"
+stdout = { file = "outputs/bad-utf8.naptr.invalid.ansitxt" }
+stderr = { empty = true }
+status = 0
+tags = [ "naptr", "madns", "chars" ]
+
 
 # NAPTR record successes (JSON)
 
@@ -27,6 +43,22 @@ stderr = { empty = true }
 status = 0
 tags = [ "naptr", "madns", "json" ]
 
+[[cmd]]
+name = "Running with ‘utf8.naptr.example --json’ interprets the response as UTF-8"
+shell = "dog --colour=always ${MADNS_ARGS:[email protected]:5301 --tcp} NAPTR utf8.naptr.invalid --json | jq"
+stdout = { file = "outputs/utf8.naptr.invalid.json" }
+stderr = { empty = true }
+status = 0
+tags = [ "naptr", "madns", "chars", "json" ]
+
+[[cmd]]
+name = "Running with ‘bad-utf8.naptr.example --json’ uses UTF-8 replacement characters"
+shell = "dog --colour=always ${MADNS_ARGS:[email protected]:5301 --tcp} NAPTR bad-utf8.naptr.invalid --json | jq"
+stdout = { file = "outputs/bad-utf8.naptr.invalid.json" }
+stderr = { empty = true }
+status = 0
+tags = [ "naptr", "madns", "chars", "json" ]
+
 
 # NAPTR record invalid packets
 

+ 1 - 1
xtests/madns/outputs/bad-regex.naptr.example.ansitxt

@@ -1 +1 @@
-NAPTR bad-regex.naptr.example. 10m00s   5 10 s "SRV" /(((((((((((((((((((((((((/ "srv.example."
+NAPTR bad-regex.naptr.example. 10m00s   5 10 "s" "SRV" "(((((((((((((((((((((((((" "srv.example."

+ 1 - 0
xtests/madns/outputs/bad-utf8.naptr.invalid.ansitxt

@@ -0,0 +1 @@
+NAPTR bad-utf8.naptr.invalid. 10m00s   5 10 "\208\208\160\255" "\208\208\160\255" "\208\208\160\255" "�Р�."

+ 30 - 0
xtests/madns/outputs/bad-utf8.naptr.invalid.json

@@ -0,0 +1,30 @@
+{
+  "responses": [
+    {
+      "queries": [
+        {
+          "name": "bad-utf8.naptr.invalid.",
+          "class": "IN",
+          "type": "NAPTR"
+        }
+      ],
+      "answers": [
+        {
+          "name": "bad-utf8.naptr.invalid.",
+          "class": "IN",
+          "ttl": 600,
+          "type": "NAPTR",
+          "data": {
+            "order": 5,
+            "flags": "�Р�",
+            "service": "�Р�",
+            "regex": "�Р�",
+            "replacement": "�Р�."
+          }
+        }
+      ],
+      "authorities": [],
+      "additionals": []
+    }
+  ]
+}

+ 1 - 1
xtests/madns/outputs/naptr.example.ansitxt

@@ -1 +1 @@
-NAPTR naptr.example. 10m00s   5 10 s "SRV" /\d\d:\d\d:\d\d/ "srv.example."
+NAPTR naptr.example. 10m00s   5 10 "s" "SRV" "\\d\\d:\\d\\d:\\d\\d" "srv.example."

+ 1 - 0
xtests/madns/outputs/utf8.naptr.invalid.ansitxt

@@ -0,0 +1 @@
+NAPTR utf8.naptr.invalid. 10m00s   5 10 "\240\159\140\180" "\240\159\140\180" "\240\159\140\180" "🌴."

+ 30 - 0
xtests/madns/outputs/utf8.naptr.invalid.json

@@ -0,0 +1,30 @@
+{
+  "responses": [
+    {
+      "queries": [
+        {
+          "name": "utf8.naptr.invalid.",
+          "class": "IN",
+          "type": "NAPTR"
+        }
+      ],
+      "answers": [
+        {
+          "name": "utf8.naptr.invalid.",
+          "class": "IN",
+          "ttl": 600,
+          "type": "NAPTR",
+          "data": {
+            "order": 5,
+            "flags": "🌴",
+            "service": "🌴",
+            "regex": "🌴",
+            "replacement": "🌴."
+          }
+        }
+      ],
+      "authorities": [],
+      "additionals": []
+    }
+  ]
+}