]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
rust/ftp: add parser for active mode port handling
authorJeff Lucovsky <jeff@lucovsky.org>
Wed, 28 Aug 2019 22:55:00 +0000 (18:55 -0400)
committerVictor Julien <victor@inliniac.net>
Thu, 19 Sep 2019 10:40:35 +0000 (12:40 +0200)
rust/src/ftp/mod.rs

index 7c6c31005078c4f92c8535826f0d10d3901e24ab..289876b7de0a3003a2721050433f0c3e7fd36019 100644 (file)
@@ -18,6 +18,7 @@
 extern crate nom;
 
 use nom::digit;
+use nom::types::CompleteByteSlice;
 use std::str;
 use std;
 use std::str::FromStr;
@@ -38,6 +39,27 @@ named!(getu16<u16>,
     )
 );
 
+named!(parse_digits<CompleteByteSlice, &[u8]>,
+    map!(take_while!(nom::is_digit), |b| b.0));
+
+named!(parse_u16<CompleteByteSlice, u16>,
+    map_res!(map_res!(parse_digits, str::from_utf8), u16::from_str));
+
+// PORT 192,168,0,13,234,10
+named!(pub ftp_active_port<CompleteByteSlice, u16>,
+       do_parse!(
+            tag!("PORT") >>
+            ws!(digit) >> tag!(",") >> digit >> tag!(",") >>
+            digit >> tag!(",") >> digit >> tag!(",") >>
+            part1: verify!(parse_u16, |v| v <= std::u8::MAX as u16) >>
+            tag!(",") >>
+            part2: verify!(parse_u16, |v| v <= std::u8::MAX as u16) >>
+            (
+                part1 * 256 + part2
+            )
+        )
+);
+
 // 227 Entering Passive Mode (212,27,32,66,221,243).
 named!(pub ftp_pasv_response<u16>,
        do_parse!(
@@ -56,13 +78,31 @@ named!(pub ftp_pasv_response<u16>,
 );
 
 
+#[no_mangle]
+pub extern "C" fn rs_ftp_active_port(input: *const u8, len: u32) -> u16 {
+    let buf = CompleteByteSlice(build_slice!(input, len as usize));
+    match ftp_active_port(buf) {
+        Ok((_, dport)) => {
+            return dport;
+        },
+        Err(nom::Err::Incomplete(_)) => {
+            SCLogDebug!("port incomplete: '{:?}'", buf);
+        },
+        Err(_) => {
+            SCLogDebug!("port error on '{:?}'", buf);
+        },
+    }
+    return 0;
+}
+
+
 #[no_mangle]
 pub extern "C" fn rs_ftp_pasv_response(input: *const u8, len: u32) -> u16 {
     let buf = unsafe{std::slice::from_raw_parts(input, len as usize)};
     match ftp_pasv_response(buf) {
         Ok((_, dport)) => {
             return dport;
-        }
+        },
         Err(nom::Err::Incomplete(_)) => {
             let buf = unsafe{std::slice::from_raw_parts(input, len as usize)};
             SCLogDebug!("pasv incomplete: '{:?}'", String::from_utf8_lossy(buf));
@@ -88,6 +128,38 @@ named!(pub ftp_epsv_response<u16>,
         )
 );
 
+// EPRT |2|2a01:e34:ee97:b130:8c3e:45ea:5ac6:e301|41813|
+named!(pub ftp_active_eprt<u16>,
+       do_parse!(
+            tag!("EPRT") >>
+            take_until_and_consume!("|") >>
+            take_until_and_consume!("|") >>
+            take_until_and_consume!("|") >>
+            port: getu16 >>
+            tag!("|") >>
+            (
+                port
+            )
+        )
+);
+
+#[no_mangle]
+pub extern "C" fn rs_ftp_active_eprt(input: *const u8, len: u32) -> u16 {
+    let buf = build_slice!(input, len as usize);
+    match ftp_active_eprt(buf) {
+        Ok((_, dport)) => {
+            return dport;
+        },
+        Err(nom::Err::Incomplete(_)) => {
+            SCLogDebug!("eprt incomplete: '{:?}'", String::from_utf8_lossy(buf));
+        },
+        Err(_) => {
+            SCLogDebug!("epsv incomplete: '{:?}'", String::from_utf8_lossy(buf));
+        },
+
+    }
+    return 0;
+}
 #[no_mangle]
 pub extern "C" fn rs_ftp_epsv_response(input: *const u8, len: u32) -> u16 {
     let buf = unsafe{std::slice::from_raw_parts(input, len as usize)};
@@ -118,6 +190,18 @@ mod test {
         assert_eq!(port, Ok((&b""[..], 56819)));
     }
 
+    #[test]
+    fn test_active_eprt_valid() {
+        let port = ftp_active_eprt("EPRT |2|2a01:e34:ee97:b130:8c3e:45ea:5ac6:e301|41813|".as_bytes());
+        assert_eq!(port, Ok((&b""[..], 41813)));
+    }
+
+    #[test]
+    fn test_active_port_valid() {
+        let port = ftp_active_port(CompleteByteSlice("PORT 192,168,0,13,234,10".as_bytes()));
+        assert_eq!(port, Ok((CompleteByteSlice(&b""[..]), 59914)));
+    }
+
     // A port that is too large for a u16.
     #[test]
     fn test_pasv_response_too_large() {
@@ -127,4 +211,19 @@ mod test {
         let port = ftp_pasv_response("227 Entering Passive Mode (212,27,32,66,255,65535).".as_bytes());
         assert!(port.is_err());
     }
+
+    #[test]
+    fn test_active_eprt_too_large() {
+        let port = ftp_active_eprt("EPRT |2|2a01:e34:ee97:b130:8c3e:45ea:5ac6:e301|81813|".as_bytes());
+        assert!(port.is_err());
+    }
+
+    #[test]
+    fn test_active_port_too_large() {
+        let port = ftp_active_port(CompleteByteSlice("PORT 212,27,32,66,257,243".as_bytes()));
+        assert!(port.is_err());
+
+        let port = ftp_active_port(CompleteByteSlice("PORT 212,27,32,66,255,65535".as_bytes()));
+        assert!(port.is_err());
+    }
 }