]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #1046 in SNORT/snort3 from nhttp93 to master
authorTom Peters (thopeter) <thopeter@cisco.com>
Wed, 18 Oct 2017 17:50:56 +0000 (13:50 -0400)
committerTom Peters (thopeter) <thopeter@cisco.com>
Wed, 18 Oct 2017 17:50:56 +0000 (13:50 -0400)
Squashed commit of the following:

commit 8964af3ce07990e4f30562a64ddc4ba0bc9303d7
Author: Tom Peters <thopeter@cisco.com>
Date:   Tue Oct 10 12:10:01 2017 -0400

    http_inspect: true IP enhancements

doc/http_inspect.txt
src/service_inspectors/http_inspect/http_api.cc
src/service_inspectors/http_inspect/http_enum.h
src/service_inspectors/http_inspect/http_inspect.cc
src/service_inspectors/http_inspect/http_msg_header.cc
src/service_inspectors/http_inspect/http_msg_header.h
src/service_inspectors/http_inspect/http_msg_section.cc
src/service_inspectors/http_inspect/ips_http.cc
src/service_inspectors/http_inspect/ips_http.h

index 6b93a9dfa6bab0cc7330ba1d68ef43ff1a3086b3..2d19e472f5bdcaaa74e85d33eb6f7baa416604ed 100644 (file)
@@ -403,6 +403,13 @@ will be concatenated into a comma-separated list.
 Normalization for http_cookie is the same URI-style normalization applied
 to http_header when no specific header is specified.
 
+===== http_true_ip
+
+This provides the original IP address of the client sending the request as
+it was stored by a proxy in the request message headers. Specifically it
+is the last IP address listed in the X-Forwarded-For or True-Client-IP
+header. If both headers are present the former is used.
+
 ===== http_client_body
 
 This is the body of a request message such as POST or PUT. Normalization
index 849e0f75cbda5785fab531cfe3c3bc30a0351515..0b18d384d37c387966d09f1da962e3a8fbe2075e 100644 (file)
@@ -50,6 +50,7 @@ const char* HttpApi::classic_buffer_names[] =
     "http_stat_code",
     "http_stat_msg",
     "http_trailer",
+    "http_true_ip",
     "http_uri",
     "http_version",
     nullptr
@@ -97,6 +98,7 @@ extern const BaseApi* ips_http_raw_uri;
 extern const BaseApi* ips_http_stat_code;
 extern const BaseApi* ips_http_stat_msg;
 extern const BaseApi* ips_http_trailer;
+extern const BaseApi* ips_http_true_ip;
 extern const BaseApi* ips_http_uri;
 extern const BaseApi* ips_http_version;
 
@@ -121,6 +123,7 @@ const BaseApi* sin_http[] =
     ips_http_stat_code,
     ips_http_stat_msg,
     ips_http_trailer,
+    ips_http_true_ip,
     ips_http_uri,
     ips_http_version,
     nullptr
index a62b51926226010422e58b91990a73da1b05de96..3f31f3148f7f5f9c20e10bfe037672526fd85869 100644 (file)
@@ -56,8 +56,8 @@ enum SectionType { SEC_DISCARD = -19, SEC_ABORT = -18, SEC__NOT_COMPUTE=-14, SEC
 enum HTTP_BUFFER { HTTP_BUFFER_CLIENT_BODY = 1, HTTP_BUFFER_COOKIE, HTTP_BUFFER_HEADER,
     HTTP_BUFFER_METHOD, HTTP_BUFFER_RAW_BODY, HTTP_BUFFER_RAW_COOKIE, HTTP_BUFFER_RAW_HEADER,
     HTTP_BUFFER_RAW_REQUEST, HTTP_BUFFER_RAW_STATUS, HTTP_BUFFER_RAW_TRAILER, HTTP_BUFFER_RAW_URI,
-    HTTP_BUFFER_STAT_CODE, HTTP_BUFFER_STAT_MSG, HTTP_BUFFER_TRAILER, HTTP_BUFFER_URI,
-    HTTP_BUFFER_VERSION, HTTP_BUFFER_MAX };
+    HTTP_BUFFER_STAT_CODE, HTTP_BUFFER_STAT_MSG, HTTP_BUFFER_TRAILER, HTTP_BUFFER_TRUE_IP,
+    HTTP_BUFFER_URI, HTTP_BUFFER_VERSION, HTTP_BUFFER_MAX };
 
 // Peg counts
 // This enum must remain synchronized with HttpModule::peg_names[] in http_tables.cc
index a8335e3bc35f3e8060a1010e6eb3b03920f9e61c..f0d3fad95ec92b25bae81d54d269b5a9c659a4b9 100644 (file)
@@ -175,7 +175,7 @@ int HttpInspect::get_xtra_trueip(Flow* flow, uint8_t** buf, uint32_t* len, uint3
     HttpMsgHeader* const req_header = transaction->get_header(SRC_CLIENT);
     if (req_header == nullptr)
         return 0;
-    const Field& true_ip = req_header->get_true_ip();
+    const Field& true_ip = req_header->get_true_ip_addr();
     if (true_ip.length() <= 0)
         return 0;
 
index 5cb474efac075295ef81549d242301125f6c4d34..31f01620fbdc96ed78c1ee4b8706aedc9fd1d646 100644 (file)
@@ -76,33 +76,51 @@ const Field& HttpMsgHeader::get_true_ip()
         }
     }
 
-    // This is potentially a comma-separated list of IP addresses. Just take the first one in
-    // the list. Since this is a normalized header field any whitespace will be an actual space.
-    uint8_t* addr_str = new uint8_t[header_to_use->length()+1];
+    // This is potentially a comma-separated list of IP addresses. Take the last one in the list.
+    // Since this is a normalized header field any whitespace will be an actual space.
     int32_t length;
     for (length = 0; length < header_to_use->length(); length++)
     {
-        if (is_sp_comma[header_to_use->start()[length]])
+        if (is_sp_comma[header_to_use->start()[header_to_use->length() - length - 1]])
             break;
-        addr_str[length] = header_to_use->start()[length];
     }
-    addr_str[length] = '\0';
+
+    true_ip.set(length, header_to_use->start() + (header_to_use->length() - length));
+    return true_ip;
+}
+
+const Field& HttpMsgHeader::get_true_ip_addr()
+{
+    if (true_ip_addr.length() != STAT_NOT_COMPUTE)
+        return true_ip_addr;
+
+    const Field& true_ip = get_true_ip();
+    if (true_ip.length() <= 0)
+    {
+        true_ip_addr.set(STAT_NOT_PRESENT);
+        return true_ip_addr;
+    }
+
+    // Need a temporary copy so we can add null termination
+    uint8_t* addr_str = new uint8_t[true_ip.length()+1];
+    memcpy(addr_str, true_ip.start(), true_ip.length());
+    addr_str[true_ip.length()] = '\0';
 
     SfIp tmp_sfip;
     const SfIpRet status = tmp_sfip.set((char*)addr_str);
     delete[] addr_str;
     if (status != SFIP_SUCCESS)
     {
-        true_ip.set(STAT_PROBLEMATIC);
+        true_ip_addr.set(STAT_PROBLEMATIC);
     }
     else
     {
         const size_t addr_length = (tmp_sfip.is_ip6() ? 4 : 1);
         uint32_t* const addr_buf = new uint32_t[addr_length];
         memcpy(addr_buf, tmp_sfip.get_ptr(), addr_length * sizeof(uint32_t));
-        true_ip.set(addr_length * sizeof(uint32_t), (uint8_t*)addr_buf, true);
+        true_ip_addr.set(addr_length * sizeof(uint32_t), (uint8_t*)addr_buf, true);
     }
-    return true_ip;
+    return true_ip_addr;
 }
 
 void HttpMsgHeader::gen_events()
@@ -490,6 +508,11 @@ void HttpMsgHeader::print_section(FILE* output)
         HttpApi::classic_buffer_names[HTTP_BUFFER_COOKIE-1]);
     get_classic_buffer(HTTP_BUFFER_HEADER, 0, 0).print(output,
         HttpApi::classic_buffer_names[HTTP_BUFFER_HEADER-1]);
+    if (source_id == SRC_CLIENT)
+    {
+        get_classic_buffer(HTTP_BUFFER_TRUE_IP, 0, 0).print(output,
+            HttpApi::classic_buffer_names[HTTP_BUFFER_TRUE_IP-1]);
+    }
     get_classic_buffer(HTTP_BUFFER_RAW_COOKIE, 0, 0).print(output,
         HttpApi::classic_buffer_names[HTTP_BUFFER_RAW_COOKIE-1]);
     get_classic_buffer(HTTP_BUFFER_RAW_HEADER, 0, 0).print(output,
index 0733485d5716baa28db0c7372151c711c0789cc7..f1fbdecfc343dd34edb245a98db4be9874f246bd 100644 (file)
@@ -42,6 +42,7 @@ public:
     void gen_events() override;
     void publish() override;
     const Field& get_true_ip();
+    const Field& get_true_ip_addr();
 
 private:
     // Dummy configurations to support MIME processing
@@ -57,6 +58,7 @@ private:
     bool detection_section = true;
 
     Field true_ip;
+    Field true_ip_addr;
 
 #ifdef REG_TEST
     void print_section(FILE* output) override;
index 07bb17dc587f4d3e17b4dd347e24a4a712c33f97..cd965d30b90d023e09bfbfadc26a8b92381acf26 100644 (file)
@@ -191,6 +191,11 @@ const Field& HttpMsgSection::get_classic_buffer(unsigned id, uint64_t sub_id, ui
         HttpMsgStatus* status = transaction->get_status();
         return (status != nullptr) ? status->get_reason_phrase() : Field::FIELD_NULL;
       }
+    case HTTP_BUFFER_TRUE_IP:
+      {
+        HttpMsgHeader* header = transaction->get_header(SRC_CLIENT);
+        return (header != nullptr) ? header->get_true_ip() : Field::FIELD_NULL;
+      }
     case HTTP_BUFFER_URI:
     case HTTP_BUFFER_RAW_URI:
       {
index fadd23fe3eb2cbe8c475bacb515eec83f58c9f0c..13c529cfa74916b5847690c397844442331cc3b2 100644 (file)
@@ -54,6 +54,7 @@ bool HttpCursorModule::begin(const char*, int, SnortConfig*)
     case HTTP_BUFFER_RAW_URI:
     case HTTP_BUFFER_STAT_CODE:
     case HTTP_BUFFER_STAT_MSG:
+    case HTTP_BUFFER_TRUE_IP:
     case HTTP_BUFFER_URI:
     case HTTP_BUFFER_VERSION:
         inspect_section = IS_DETECTION;
@@ -931,6 +932,55 @@ static const IpsApi trailer_api =
     nullptr
 };
 
+//-------------------------------------------------------------------------
+// http_true_ip
+//-------------------------------------------------------------------------
+
+static const Parameter http_true_ip_params[] =
+{
+    { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "parts of this rule examine HTTP message body" },
+    { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "parts of this rule examine HTTP message trailers" },
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+#undef IPS_OPT
+#define IPS_OPT "http_true_ip"
+#undef IPS_HELP
+#define IPS_HELP "rule option to set the detection cursor to the final client IP address"
+
+static Module* true_ip_mod_ctor()
+{
+    return new HttpCursorModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_TRUE_IP, CAT_SET_OTHER,
+        PSI_TRUE_IP, http_true_ip_params);
+}
+
+static const IpsApi true_ip_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        true_ip_mod_ctor,
+        HttpCursorModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpIpsOption::opt_ctor,
+    HttpIpsOption::opt_dtor,
+    nullptr
+};
+
 //-------------------------------------------------------------------------
 // http_uri
 //-------------------------------------------------------------------------
@@ -1061,6 +1111,7 @@ const BaseApi* ips_http_raw_uri = &raw_uri_api.base;
 const BaseApi* ips_http_stat_code = &stat_code_api.base;
 const BaseApi* ips_http_stat_msg = &stat_msg_api.base;
 const BaseApi* ips_http_trailer = &trailer_api.base;
+const BaseApi* ips_http_true_ip = &true_ip_api.base;
 const BaseApi* ips_http_uri = &uri_api.base;
 const BaseApi* ips_http_version = &version_api.base;
 
index 498b4e6dc86a28a3d897cde5e3b1e58225ac6a3a..1b00b80531c28f7d3f9cf7561bd2658580bb45d5 100644 (file)
@@ -30,7 +30,7 @@
 
 enum PsIdx { PSI_CLIENT_BODY, PSI_COOKIE, PSI_HEADER, PSI_METHOD, PSI_RAW_BODY, PSI_RAW_COOKIE,
     PSI_RAW_HEADER, PSI_RAW_REQUEST, PSI_RAW_STATUS, PSI_RAW_TRAILER, PSI_RAW_URI, PSI_STAT_CODE,
-    PSI_STAT_MSG, PSI_TRAILER, PSI_URI, PSI_VERSION, PSI_MAX };
+    PSI_STAT_MSG, PSI_TRAILER, PSI_TRUE_IP, PSI_URI, PSI_VERSION, PSI_MAX };
 
 class HttpCursorModule : public Module
 {