]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
http: logs content range 3810/head
authorPhilippe Antoine <contact@catenacyber.fr>
Thu, 4 Apr 2019 18:37:29 +0000 (20:37 +0200)
committerVictor Julien <victor@inliniac.net>
Fri, 19 Apr 2019 05:34:39 +0000 (07:34 +0200)
Fixes #2485

src/app-layer-htp-file.c
src/app-layer-htp-file.h
src/app-layer-htp.c
src/output-json-file.c
src/output-json-http.c
src/util-file.c
src/util-file.h

index 2018452ef51d016eb7d912d417f3c04a53239b02..ce5599381e9269b348af2bc280202dd1389c58b8 100644 (file)
@@ -150,6 +150,111 @@ end:
     SCReturnInt(retval);
 }
 
+/**
+ * Performs parsing of the content-range value
+ *
+ * @param[in] rawvalue
+ * @param[out] range
+ *
+ * @return HTP_OK on success, HTP_ERROR on failure.
+ */
+int HTPParseContentRange(bstr * rawvalue, HtpContentRange *range)
+{
+    unsigned char *data = bstr_ptr(rawvalue);
+    size_t len = bstr_len(rawvalue);
+    size_t pos = 0;
+    size_t last_pos;
+
+    // skip spaces and units
+    while (pos < len && data[pos] == ' ')
+        pos++;
+    while (pos < len && data[pos] != ' ')
+        pos++;
+    while (pos < len && data[pos] == ' ')
+        pos++;
+
+    // initialize to unseen
+    range->start = -1;
+    range->end = -1;
+    range->size = -1;
+
+    if (pos == len) {
+        // missing data
+        return -1;
+    }
+
+    if (data[pos] == '*') {
+        // case with size only
+        if (len < pos + 1 || data[pos+1] != '/') {
+            range->size = -1;
+            return -1;
+        }
+        pos += 2;
+        range->size = bstr_util_mem_to_pint(data + pos, len - pos, 10, &last_pos);
+    } else {
+        // case with start and end
+        range->start = bstr_util_mem_to_pint(data + pos, len - pos, 10, &last_pos);
+        pos += last_pos;
+        if (len < pos || data[pos] != '-') {
+            return -1;
+        }
+        pos++;
+        range->end = bstr_util_mem_to_pint(data + pos, len - pos, 10, &last_pos);
+        pos += last_pos;
+        if (len < pos || data[pos] != '/') {
+            return -1;
+        }
+        pos++;
+        if (data[pos] != '*') {
+            // case with size
+            range->size = bstr_util_mem_to_pint(data + pos, len - pos, 10, &last_pos);
+        }
+    }
+
+    return 0;
+}
+
+/**
+ *  \brief Sets range for a file
+ *
+ *  \param s http state
+ *  \param rawvalue raw header value
+ *
+ *  \retval 0 ok
+ *  \retval -1 error
+ *  \retval -2 error parsing
+ *  \retval -3 error negative end in range
+ */
+int HTPFileSetRange(HtpState *s, bstr *rawvalue)
+{
+    SCEnter();
+
+    if (s == NULL) {
+        SCReturnInt(-1);
+    }
+
+    FileContainer * files = s->files_tc;
+    if (files == NULL) {
+        SCLogDebug("no files in state");
+        SCReturnInt(-1);
+    }
+
+    HtpContentRange crparsed;
+    if (HTPParseContentRange(rawvalue, &crparsed) != 0) {
+        SCLogDebug("parsing range failed");
+        SCReturnInt(-2);
+    }
+    if (crparsed.end <= 0) {
+        SCLogDebug("negative end in range");
+        SCReturnInt(-3);
+    }
+    int retval = FileSetRange(files, crparsed.start, crparsed.end);
+    if (retval == -1) {
+        SCLogDebug("set range failed");
+    }
+    SCReturnInt(retval);
+}
+
 /**
  *  \brief Store a chunk of data in the flow
  *
index 1f0bfb60556f172e78a09d718045c85f3f30c9cb..3e6bdc1fb923d221748f5b845903631a69ba68b2 100644 (file)
 #ifndef __APP_LAYER_HTP_FILE_H__
 #define __APP_LAYER_HTP_FILE_H__
 
+typedef struct HtpContentRange_ {
+    int64_t start;
+    int64_t end;
+    int64_t size;
+} HtpContentRange;
+
 int HTPFileOpen(HtpState *, const uint8_t *, uint16_t, const uint8_t *, uint32_t, uint64_t, uint8_t);
+int HTPParseContentRange(bstr * rawvalue, HtpContentRange *range);
+int HTPFileSetRange(HtpState *, bstr *rawvalue);
 int HTPFileStoreChunk(HtpState *, const uint8_t *, uint32_t, uint8_t);
 int HTPFileClose(HtpState *, const uint8_t *, uint32_t, uint8_t, uint8_t);
 
index d01f420fd769a35169046fdf4da7ee19f11c3707..5c7a5ad50d915c8f18f82c4de9f9f5fa7c4b14d1 100644 (file)
@@ -1633,6 +1633,11 @@ static int HtpResponseBodyHandle(HtpState *hstate, HtpTxUserData *htud,
                 htud->tcflags |= HTP_FILENAME_SET;
                 htud->tcflags &= ~HTP_DONTSTORE;
             }
+            //set range if present
+            htp_header_t *h_content_range = htp_table_get_c(tx->response_headers, "content-range");
+            if (h_content_range != NULL) {
+                HTPFileSetRange(hstate, h_content_range->value);
+            }
         }
     }
     else
index 09d3510ba4dff613cd2502ec2b622a2e2e5d6040..3283a2f3106aa5510b253bdc26e250edfb0f17df 100644 (file)
@@ -217,6 +217,10 @@ json_t *JsonBuildFileInfoRecord(const Packet *p, const File *ff,
         json_object_set_new(fjs, "file_id", json_integer(ff->file_store_id));
     }
     json_object_set_new(fjs, "size", json_integer(FileTrackedSize(ff)));
+    if (ff->end > 0) {
+        json_object_set_new(fjs, "start", json_integer(ff->start));
+        json_object_set_new(fjs, "end", json_integer(ff->end));
+    }
     json_object_set_new(fjs, "tx_id", json_integer(ff->txid));
 
     /* xff header */
index f167b27b4cdf38bcead13c743ee5f2e9b94ee7f0..aebdd72521d99d052a9747e78dfb9ee96ab450a9 100644 (file)
@@ -40,6 +40,7 @@
 
 #include "output.h"
 #include "app-layer-htp.h"
+#include "app-layer-htp-file.h"
 #include "app-layer-htp-xff.h"
 #include "app-layer.h"
 #include "app-layer-parser.h"
@@ -261,6 +262,26 @@ static void JsonHttpLogJSONBasic(json_t *js, htp_tx_t *tx)
                 *p = '\0';
             json_object_set_new(js, "http_content_type", SCJsonString(string));
         }
+        htp_header_t *h_content_range = htp_table_get_c(tx->response_headers, "content-range");
+        if (h_content_range != NULL) {
+            const size_t size = bstr_len(h_content_range->value) * 2 + 1;
+            char string[size];
+            BytesToStringBuffer(bstr_ptr(h_content_range->value), bstr_len(h_content_range->value), string, size);
+            json_t *crjs = json_object();
+            if (crjs != NULL) {
+                json_object_set_new(crjs, "raw", SCJsonString(string));
+                HtpContentRange crparsed;
+                if (HTPParseContentRange(h_content_range->value, &crparsed) == 0) {
+                    if (crparsed.start >= 0)
+                        json_object_set_new(crjs, "start", json_integer(crparsed.start));
+                    if (crparsed.end >= 0)
+                        json_object_set_new(crjs, "end", json_integer(crparsed.end));
+                    if (crparsed.size >= 0)
+                        json_object_set_new(crjs, "size", json_integer(crparsed.size));
+                }
+                json_object_set_new(js, "content_range", crjs);
+            }
+        }
     }
 }
 
index d3fd235ab02936f12db1b59bfed17bdd6a6cbd9b..f322970e72a52f2d319375c1b22f60c21592fd37 100644 (file)
@@ -738,6 +738,28 @@ int FileAppendGAPById(FileContainer *ffc, uint32_t track_id,
     SCReturnInt(-1);
 }
 
+/**
+ *  \brief Sets the offset range for a file.
+ *
+ *  \param ffc the container
+ *  \param start start offset
+ *  \param end end offset
+ *
+ *  \retval  0 ok
+ *  \retval -1 error
+ */
+int FileSetRange(FileContainer *ffc, uint64_t start, uint64_t end)
+{
+    SCEnter();
+
+    if (ffc == NULL || ffc->tail == NULL) {
+        SCReturnInt(-1);
+    }
+    ffc->tail->start = start;
+    ffc->tail->end = end;
+    SCReturnInt(0);
+}
+
 /**
  *  \brief Open a new File
  *
index 4f67e73d3f99512773103b7068302577e15b918a..01bff145b2af4354daf1892e977e519a25ecc42a 100644 (file)
@@ -89,6 +89,8 @@ typedef struct File_ {
                                      *   flag is set */
     uint64_t content_stored;
     uint64_t size;
+    uint64_t start;
+    uint64_t end;
 
     uint32_t *sid; /* signature id of a rule that triggered the filestore event */
     uint32_t sid_cnt;
@@ -169,6 +171,18 @@ int FileAppendDataById(FileContainer *, uint32_t track_id,
 int FileAppendGAPById(FileContainer *ffc, uint32_t track_id,
         const uint8_t *data, uint32_t data_len);
 
+/**
+ *  \brief Sets the offset range for a file.
+ *
+ *  \param ffc the container
+ *  \param start start offset
+ *  \param end end offset
+ *
+ *  \retval 0 ok
+ *  \retval -1 error
+ */
+int FileSetRange(FileContainer *, uint64_t start, uint64_t end);
+
 /**
  *  \brief Tag a file for storing
  *