]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
bittorrent-dht: fix values decoding, as a list of peers
authorJason Ish <jason.ish@oisf.net>
Thu, 8 Sep 2022 16:42:15 +0000 (10:42 -0600)
committerVictor Julien <vjulien@oisf.net>
Fri, 28 Oct 2022 09:48:13 +0000 (11:48 +0200)
The "values" field is not a string, but instead peer information in
compact format. Decode this properly and then properly format in the
log.

rust/src/bittorrent_dht/logger.rs
rust/src/bittorrent_dht/parser.rs

index 283f10332335f8e4cd16f0e62ed593b0dc3a0bff..3145a956a36f8ebe85dd29fca9314a8e3c106ec5 100644 (file)
@@ -100,7 +100,10 @@ fn log_bittorrent_dht(
         if let Some(values) = &response.values {
             js.open_array("values")?;
             for value in values {
-                js.append_string(value)?;
+                js.start_object()?;
+                js.set_string("ip", &print_ip_addr(&value.ip))?;
+                js.set_uint("port", value.port.into())?;
+                js.close()?;
             }
             js.close()?;
         }
index cdb0db45dc4f8ff72a3c0cb8d4c1b19302e9db70..cc7c44a6364758ab91b7ef8f5aa680f7b80fd803 100644 (file)
@@ -52,7 +52,7 @@ pub struct BitTorrentDHTResponse {
     ///                           K(8) closest good nodes in routing table
     pub nodes: Option<Vec<Node>>,
     /// q = get_peers - list of compact peer infos
-    pub values: Option<Vec<String>>,
+    pub values: Option<Vec<Peer>>,
     /// q = get_peers - token key required for sender's future
     ///                 announce_peer query
     pub token: Option<Vec<u8>>,
@@ -73,6 +73,12 @@ pub struct Node {
     pub port: u16,
 }
 
+#[derive(Debug, Eq, PartialEq)]
+pub struct Peer {
+    pub ip: Vec<u8>,
+    pub port: u16,
+}
+
 /// Parse IPv4 node structures.
 pub fn parse_node(i: &[u8]) -> IResult<&[u8], Node> {
     let (i, id) = take(20usize)(i)?;
@@ -88,6 +94,22 @@ pub fn parse_node(i: &[u8]) -> IResult<&[u8], Node> {
     ))
 }
 
+fn parse_peer(i: &[u8]) -> IResult<&[u8], Peer> {
+    let (i, ip) = if i.len() < 18 {
+        take(4usize)(i)
+    } else {
+        take(16usize)(i)
+    }?;
+    let (i, port) = be_u16(i)?;
+    Ok((
+        i,
+        Peer {
+            ip: ip.to_vec(),
+            port,
+        },
+    ))
+}
+
 impl FromBencode for BitTorrentDHTRequest {
     // Try to parse with a `max_depth` of one.
     //
@@ -191,7 +213,7 @@ impl FromBencode for BitTorrentDHTResponse {
     {
         let mut id = None;
         let mut nodes = None;
-        let mut values = None;
+        let mut values = vec![];
         let mut token = None;
 
         let mut dict_dec = object.try_into_dictionary()?;
@@ -210,9 +232,14 @@ impl FromBencode for BitTorrentDHTResponse {
                     }
                 }
                 (b"values", value) => {
-                    values = Vec::decode_bencode_object(value)
-                        .context("values")
-                        .map(Some)?;
+                    if let Object::List(mut list) = value {
+                        while let Some(entry) = list.next_object()? {
+                            let (_, peer) =
+                                parse_peer(entry.try_into_bytes().context("values.entry")?)
+                                    .map_err(|_| Error::malformed_content("values.entry.peer"))?;
+                            values.push(peer);
+                        }
+                    }
                 }
                 (b"token", value) => {
                     token = value
@@ -229,7 +256,11 @@ impl FromBencode for BitTorrentDHTResponse {
         Ok(BitTorrentDHTResponse {
             id: id.to_vec(),
             nodes,
-            values,
+            values: if values.is_empty() {
+                None
+            } else {
+                Some(values)
+            },
             token,
         })
     }