]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2820 in SNORT/snort3 from ~MASHASAN/snort3:match_aux_ip to master
authorMasud Hasan (mashasan) <mashasan@cisco.com>
Tue, 27 Apr 2021 17:52:44 +0000 (17:52 +0000)
committerMasud Hasan (mashasan) <mashasan@cisco.com>
Tue, 27 Apr 2021 17:52:44 +0000 (17:52 +0000)
Squashed commit of the following:

commit 9bd621b4b6104b9e0699b664d53e7d134ee3c905
Author: Masud Hasan <mashasan@cisco.com>
Date:   Thu Mar 11 16:52:02 2021 -0500

    flow: Enhancing APIs to stash auxiliary IP

commit fe9fcb2eaf1a2af9ffcca1a46fd638f63ad78ff2
Author: Tom Peters <thopeter@cisco.com>
Date:   Mon Feb 15 16:02:13 2021 -0500

    http_inspect: IP reputation support

commit 173a34c1c6d897203c201dbd33802ec8befc24e3
Author: Masud Hasan <mashasan@cisco.com>
Date:   Tue Feb 9 10:30:21 2021 -0500

    flow: Adding stash API to save auxiliary IP

18 files changed:
src/codecs/misc/cd_user.cc
src/flow/flow_stash.cc
src/flow/flow_stash.h
src/flow/test/CMakeLists.txt
src/flow/test/flow_stash_test.cc
src/main/modules.cc
src/main/snort_config.h
src/network_inspectors/appid/appid_http_session.h
src/network_inspectors/reputation/reputation_config.h
src/network_inspectors/reputation/reputation_inspect.cc
src/network_inspectors/reputation/reputation_inspect.h
src/pub_sub/auxiliary_ip_event.h [new file with mode: 0644]
src/service_inspectors/http_inspect/http_msg_request.cc
src/service_inspectors/http_inspect/http_msg_request.h
src/sfip/sf_ip.cc
src/sfip/sf_ip.h
src/sfip/test/sf_ip_test.cc
src/stream/base/stream_module.cc

index 520fc198198aa94c455b34bd10012eace5cde0fc..965fdc86012504b709dd81a8a05883000dbb44b6 100644 (file)
@@ -69,9 +69,8 @@ static void set_key(CodecData& codec, DecodeData& snort)
 {
     // FIXIT-L make configurable
     SfIp sip, dip;
-    sip.set("192.168.1.1");
-    dip.set("192.168.2.2");
-    snort.ip_api.set(sip, dip);
+    if ( sip.set("192.168.1.1") == SFIP_SUCCESS and dip.set("192.168.2.2") == SFIP_SUCCESS )
+        snort.ip_api.set(sip, dip);
 
     snort.sp = 12345;
     snort.dp = 54321;
index 677ce70df7ab6f137556c609e89b21fa232cac2c..2049650bb05b1323f7a40fb04a842259f5301426 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <cassert>
 
+#include "pub_sub/auxiliary_ip_event.h"
 #include "pub_sub/stash_events.h"
 
 using namespace snort;
@@ -38,7 +39,7 @@ FlowStash::~FlowStash()
 
 void FlowStash::reset()
 {
-    for(map<string, StashItem*>::iterator it = container.begin(); it != container.end(); ++it)
+    for(auto it = container.begin(); it != container.end(); ++it)
     {
         delete it->second;
     }
@@ -91,7 +92,7 @@ void FlowStash::store(const string& key, StashGenericObject* &val, StashItemType
     UNUSED(type);
 #endif
     auto item = new StashItem(val);
-    auto it_and_status = container.emplace(make_pair(key, item));
+    auto it_and_status = container.emplace(key, item);
 
     if (!it_and_status.second)
     {
@@ -139,7 +140,7 @@ void FlowStash::store(const string& key, T& val, StashItemType type)
     UNUSED(type);
 #endif
     auto item = new StashItem(val);
-    auto it_and_status = container.emplace(make_pair(key, item));
+    auto it_and_status = container.emplace(key, item);
 
     if (!it_and_status.second)
     {
@@ -151,3 +152,28 @@ void FlowStash::store(const string& key, T& val, StashItemType type)
     StashEvent e(item);
     DataBus::publish(key.c_str(), e);
 }
+
+bool FlowStash::store(const SfIp& ip, const SnortConfig* sc)
+{
+    if ( !sc )
+        sc = SnortConfig::get_conf();
+
+    if ( sc->max_aux_ip < 0 )
+        return false;
+
+    if ( sc->max_aux_ip > 0 )
+    {
+        for ( const auto& aip : aux_ip_fifo )
+            if ( aip == ip )
+                return false;
+
+        if ( aux_ip_fifo.size() == (unsigned)sc->max_aux_ip )
+            aux_ip_fifo.pop_back();
+
+        aux_ip_fifo.emplace_front(ip);
+    }
+
+    AuxiliaryIpEvent event(ip);
+    DataBus::publish(AUXILIARY_IP_EVENT, event);
+    return true;
+}
index 796e00efb7dc3a0993c9f0e92e802491cb9bb467..b24caf410a55487c8e5b8308f4384c50a9df853a 100644 (file)
 #ifndef FLOW_STASH_H
 #define FLOW_STASH_H
 
+#include <list>
 #include <map>
 #include <string>
+#include <unordered_map>
 
+#include "main/snort_config.h"
 #include "main/snort_types.h"
+#include "sfip/sf_ip.h"
 
 #include "stash_item.h"
 
@@ -46,8 +50,11 @@ public:
     void store(const std::string& key, std::string* val);
     void store(const std::string& key, StashGenericObject* val, bool publish = true);
 
+    bool store(const snort::SfIp&, const SnortConfig* sc = nullptr);
+
 private:
-    std::map<std::string, StashItem*> container;
+    std::list<snort::SfIp> aux_ip_fifo;
+    std::unordered_map<std::string, StashItem*> container;
 
     template<typename T>
     bool get(const std::string& key, T& val, StashItemType type);
index f199aea6e4a9ca5e34a612fbad4b88c99c9d8263..79dbbc9e7eb12c125a150754bad3191378f2ae06 100644 (file)
@@ -6,6 +6,7 @@ add_cpputest( deferred_trust_test
 
 add_cpputest( flow_stash_test
     SOURCES ../flow_stash.cc
+            ../../sfip/sf_ip.cc
 )
 
 add_cpputest( flow_control_test
index be8783565313ceec5ba46f2c0b6df297a35e5f3a..ee9e5faeeb610e0fb32966c0b578ef5ea839ccb1 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "flow/flow_stash.h"
 #include "pub_sub/stash_events.h"
+#include "utils/util.h"
 
 #include <CppUTest/CommandLineTestRunner.h>
 #include <CppUTest/TestHarness.h>
@@ -129,7 +130,23 @@ void DataBus::_publish(const char* key, DataEvent& e, Flow* f)
 }
 // end DataBus mock.
 
+static SnortConfig snort_conf;
 
+namespace snort
+{
+SnortConfig::SnortConfig(const SnortConfig* const) { }
+SnortConfig::~SnortConfig() = default;
+const SnortConfig* SnortConfig::get_conf() { return &snort_conf; }
+
+char* snort_strdup(const char* str)
+{
+    assert(str);
+    size_t n = strlen(str) + 1;
+    char* p = (char*)snort_alloc(n);
+    memcpy(p, str, n);
+    return p;
+}
+}
 
 TEST_GROUP(stash_tests)
 {
@@ -340,6 +357,41 @@ TEST(stash_tests, mixed_items)
     CHECK_EQUAL(test_object->get_object_type(), ((TestStashObject*)retrieved_object)->get_object_type());
 }
 
+TEST(stash_tests, store_ip)
+{
+    FlowStash stash;
+    SfIp ip;
+    CHECK(ip.set("1.1.1.1") == SFIP_SUCCESS);
+
+    // Disabled
+    snort_conf.max_aux_ip = -1;
+    CHECK_FALSE(stash.store(ip));
+
+    // Enabled without stashing, no duplicate IP checking
+    snort_conf.max_aux_ip = 0;
+    CHECK_TRUE(stash.store(ip));
+    CHECK_TRUE(stash.store(ip));
+
+    // Enabled with FIFO stashing, duplicate IP checking
+    snort_conf.max_aux_ip = 2;
+    CHECK_TRUE(stash.store(ip));
+    CHECK_FALSE(stash.store(ip));
+
+    SfIp ip2;
+    CHECK(ip2.set("1.1.1.2") == SFIP_SUCCESS);
+    CHECK_TRUE(stash.store(ip2));
+    CHECK_FALSE(stash.store(ip2));
+
+    SfIp ip3;
+    CHECK(ip3.set("1111::8888") == SFIP_SUCCESS);
+    CHECK_TRUE(stash.store(ip3));
+    CHECK_FALSE(stash.store(ip3));
+    CHECK_FALSE(stash.store(ip2));
+    CHECK_TRUE(stash.store(ip));
+    CHECK_FALSE(stash.store(ip));
+    CHECK_FALSE(stash.store(ip3));
+}
+
 int main(int argc, char** argv)
 {
     return CommandLineTestRunner::RunAllTests(argc, argv);
index 1a5a59c881a36ac0fa67309bb9b4f2a9a98548be..db8b8fe4e8a97be3b31b8b1894e3a73cf381725f 100644 (file)
@@ -1107,6 +1107,10 @@ static const Parameter inspection_params[] =
     { "mode", Parameter::PT_ENUM, "inline | inline-test", "inline-test",
       "set policy mode" },
 
+    { "max_aux_ip", Parameter::PT_INT, "-1:127", "16",
+      "maximum number of auxiliary IPs per flow to detect and save "
+      "(-1 = disable, 0 = detect but don't save, 1+ = save in FIFO manner)" },
+
     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
 };
 
@@ -1159,6 +1163,12 @@ bool InspectionModule::set(const char*, Value& v, SnortConfig* sc)
         }
     }
 
+    else if ( v.is("max_aux_ip") )
+    {
+        sc->max_aux_ip = v.get_int16();
+        return true;
+    }
+
     else
         return false;
 
index 6569c66f4e3f6ef36f49bf60cfb0527374d88fe1..7f471735241a77d5d33993f174a9a3e55527b85a 100644 (file)
@@ -393,6 +393,8 @@ public:
 
     uint16_t tunnel_mask = 0;
 
+    int16_t max_aux_ip = 16;
+
     // FIXIT-L this is temporary for legacy paf_max required only for HI;
     // it is not appropriate for multiple stream_tcp with different
     // paf_max; the HI splitter should pull from there
@@ -487,6 +489,9 @@ public:
     bool is_address_anomaly_check_enabled() const
     { return address_anomaly_check_enabled; }
 
+    bool aux_ip_is_enabled() const
+    { return max_aux_ip >= 0; }
+
     // mode related
     bool dump_config_mode() const
     { return dump_config_type > DUMP_CONFIG_NONE; }
index 78f9f261d4931a81650b3f54c45d456577c79894..cd79b28b8fb3939050b878d213c22559aa4bd317 100644 (file)
@@ -47,11 +47,11 @@ class HttpPatternMatchers;
 struct TunnelDest
 {
     snort::SfIp ip;
-    uint16_t port;
+    uint16_t port = 0;
     TunnelDest(const char* string_srcip, uint16_t tun_port)
     {
-        ip.set(string_srcip);
-        port = tun_port;
+        if ( ip.set(string_srcip) == SFIP_SUCCESS )
+            port = tun_port;
     }
 };
 
index d9ef9c1679cfc7c212534157043ac8f1e5001e44..f274471db02775c44140757e8a8a94c4a31298dc 100644 (file)
@@ -109,6 +109,9 @@ struct ReputationStats
     PegCount trusted;
     PegCount monitored;
     PegCount memory_allocated;
+    PegCount aux_ip_blocked;
+    PegCount aux_ip_trusted;
+    PegCount aux_ip_monitored;
 };
 
 extern const PegInfo reputation_peg_names[];
index 5a9214c4b1c7d97ea7e2c40be9c06e0f7c8f10b8..74ce5216f2a1c62416f7c4282df07c3e43bb0dd5 100644 (file)
@@ -33,7 +33,7 @@
 #include "packet_io/active.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
-
+#include "pub_sub/auxiliary_ip_event.h"
 
 #include "reputation_parse.h"
 
@@ -49,6 +49,9 @@ const PegInfo reputation_peg_names[] =
 { CountType::SUM, "trusted", "number of packets trusted" },
 { CountType::SUM, "monitored", "number of packets monitored" },
 { CountType::SUM, "memory_allocated", "total memory allocated" },
+{ CountType::SUM, "aux_ip_blocked", "number of auxiliary ip packets blocked" },
+{ CountType::SUM, "aux_ip_trusted", "number of auxiliary ip packets trusted" },
+{ CountType::SUM, "aux_ip_monitored", "number of auxiliary ip packets monitored" },
 { CountType::END, nullptr, nullptr }
 };
 
@@ -244,6 +247,73 @@ static IPdecision reputation_decision(ReputationConfig* config, Packet* p)
     return decision_final;
 }
 
+static void snort_reputation_aux_ip(ReputationConfig* config, Packet* p, const SfIp* ip)
+{
+    if (!config->ip_list)
+        return;
+
+    uint32_t ingress_intf = 0;
+    uint32_t egress_intf = 0;
+
+    if (p->pkth)
+    {
+        ingress_intf = p->pkth->ingress_index;
+        if (p->pkth->egress_index < 0)
+            egress_intf = ingress_intf;
+        else
+            egress_intf = p->pkth->egress_index;
+    }
+
+    IPrepInfo* result = reputation_lookup(config, ip);
+    if (result)
+    {
+        IPdecision decision = get_reputation(config, result, &p->iplist_id, ingress_intf,
+            egress_intf);
+
+        if (decision == BLOCKED)
+        {
+            if (p->flow)
+                p->flow->flags.reputation_blocklist = true;
+
+            // Prior to IPRep logging, IPS policy must be set to the default policy,
+            set_ips_policy(SnortConfig::get_conf(), 0);
+
+            DetectionEngine::queue_event(GID_REPUTATION, REPUTATION_EVENT_BLOCKLIST_DST);
+            p->active->drop_packet(p, true);
+
+            // disable all preproc analysis and detection for this packet
+            DetectionEngine::disable_all(p);
+            p->active->block_session(p, true);
+            p->active->set_drop_reason("reputation");
+            reputationstats.aux_ip_blocked++;
+            if (PacketTracer::is_active())
+            {
+                char ip_str[INET6_ADDRSTRLEN];
+                sfip_ntop(ip, ip_str, sizeof(ip_str));
+                PacketTracer::log("Reputation: packet blocked for auxiliary ip %s, drop\n",
+                    ip_str);
+            }
+        }
+        else if (decision == MONITORED)
+        {
+            if (p->flow)
+                p->flow->flags.reputation_monitor = true;
+
+            DetectionEngine::queue_event(GID_REPUTATION, REPUTATION_EVENT_MONITOR_DST);
+            reputationstats.aux_ip_monitored++;
+        }
+        else if (decision == TRUSTED)
+        {
+            if (p->flow)
+                p->flow->flags.reputation_allowlist = true;
+
+            DetectionEngine::queue_event(GID_REPUTATION, REPUTATION_EVENT_ALLOWLIST_DST);
+            p->active->trust_session(p, true);
+            reputationstats.aux_ip_trusted++;
+        }
+    }
+}
+
 static void snort_reputation(ReputationConfig* config, Packet* p)
 {
     IPdecision decision;
@@ -371,6 +441,23 @@ static const char* to_string(IPdecision ipd)
     }
 }
 
+class AuxiliaryIpRepHandler : public DataHandler
+{
+public:
+    AuxiliaryIpRepHandler(ReputationConfig& rc) : DataHandler(REPUTATION_NAME), conf(rc) { }
+    void handle(DataEvent&, Flow*) override;
+
+private:
+    ReputationConfig& conf;
+};
+
+void AuxiliaryIpRepHandler::handle(DataEvent& event, Flow*)
+{
+    Profile profile(reputation_perf_stats);
+    snort_reputation_aux_ip(&conf, DetectionEngine::get_current_packet(),
+        static_cast<AuxiliaryIpEvent*>(&event)->get_ip());
+}
+
 //-------------------------------------------------------------------------
 // class stuff
 //-------------------------------------------------------------------------
@@ -421,6 +508,12 @@ void Reputation::eval(Packet* p)
     ++reputationstats.packets;
 }
 
+bool Reputation::configure(SnortConfig* sc)
+{
+    DataBus::subscribe_global( AUXILIARY_IP_EVENT, new AuxiliaryIpRepHandler(config), sc );
+    return true;
+}
+
 //-------------------------------------------------------------------------
 // api stuff
 //-------------------------------------------------------------------------
index 52ef957f3b2a46883b28a81e8179cb00c8496ced..85d6e6c8d619b65f6f5db10246a8794cac2b2bb4 100644 (file)
@@ -30,6 +30,7 @@ public:
 
     void show(const snort::SnortConfig*) const override;
     void eval(snort::Packet*) override;
+    bool configure(snort::SnortConfig*) override;
 
 private:
     ReputationConfig config;
diff --git a/src/pub_sub/auxiliary_ip_event.h b/src/pub_sub/auxiliary_ip_event.h
new file mode 100644 (file)
index 0000000..66293da
--- /dev/null
@@ -0,0 +1,40 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2021-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// auxiliary_ip_event.h author Masud Hasan <mashasan@cisco.com>
+
+#ifndef AUXILIARY_IP_EVENT_H
+#define AUXILIARY_IP_EVENT_H
+
+#include "framework/data_bus.h"
+#include "sfip/sf_ip.h"
+
+#define AUXILIARY_IP_EVENT "auxiliary_ip_event"
+
+class AuxiliaryIpEvent : public snort::DataEvent
+{
+public:
+   AuxiliaryIpEvent(const snort::SfIp& aux_ip) : ip(aux_ip) { }
+
+   const snort::SfIp* get_ip()
+   { return &ip; }
+
+private:
+   const snort::SfIp& ip;
+};
+
+#endif
index 2e04914f47a0f74ccd47ef66a684409e61bb4708..c14f8eafcfcb42d1ac1140070170eb5bd12cf44a 100644 (file)
 #include "http_api.h"
 #include "http_common.h"
 #include "http_enum.h"
+#include "http_test_manager.h"
 
 using namespace HttpCommon;
 using namespace HttpEnums;
 using namespace snort;
+using namespace std;
 
 HttpMsgRequest::HttpMsgRequest(const uint8_t* buffer, const uint16_t buf_size,
     HttpFlowData* session_data_, SourceId source_id_, bool buf_owner, Flow* flow_,
@@ -317,6 +319,47 @@ void HttpMsgRequest::publish()
         session_data->ssl_search_abandoned = true;
         DataBus::publish(SSL_SEARCH_ABANDONED, DetectionEngine::get_current_packet());
     }
+
+    if (SnortConfig::get_conf()->aux_ip_is_enabled())
+    {
+        string aux_ip_str = get_aux_ip();
+
+        if (!aux_ip_str.empty())
+        {
+            SfIp aux_ip;
+            if (parse_ip_from_uri(aux_ip_str, aux_ip))
+                flow->stash->store(aux_ip);
+        }
+    }
+}
+
+string HttpMsgRequest::get_aux_ip()
+{
+    string ip_str;
+
+    if (!uri)
+        return ip_str;
+
+    const Field& auth = uri->get_authority();
+
+    if (!(auth.length() > 0) or auth.start() == nullptr)
+        return ip_str;
+
+    // The following rules out most host values that are not IP addresses before we
+    // waste resources on them. The subscriber must do more careful validation. IPv4
+    // must begin with a digit while IPv6 within a URI must begin with a '['.
+    if (((auth.start()[0] >= '0') && (auth.start()[0] <= '9')) ||
+        (auth.start()[0] == '['))
+    {
+        const Field& host = uri->get_host();
+        if (host.length() > 0)
+        {
+            ip_str = string((const char*)host.start(), (size_t)host.length());
+            return ip_str;
+        }
+    }
+
+    return ip_str;
 }
 
 #ifdef REG_TEST
index 72def1ec4c5ad6fef686aba939e4009a075078fe..e35d1a09e361ad9dbb422565dbddc646e71d7291 100644 (file)
@@ -45,6 +45,7 @@ public:
     const Field& get_method() { return method; }
     const Field& get_uri();
     const Field& get_uri_norm_classic();
+    std::string get_aux_ip();
     HttpUri* get_http_uri() { return uri; }
     ParameterMap& get_query_params();
     ParameterMap& get_body_params();
index 2700fcd4ba51d3a85acc7e2a75b4f3cc36bb9149..363738e64f9c96ecfb537c0bdd1501eaaaa72c25 100644 (file)
@@ -27,7 +27,6 @@
 
 #include "sf_ip.h"
 
-#include <cassert>
 #include <cmath> // For ceil
 
 #include "main/thread.h"
 
 using namespace snort;
 
-/* Support function */
-// note that an ip6 address may have a trailing dotted quad form
-// but that it always has at least 2 ':'s; furthermore there is
-// no valid ip4 format (including mask) with 2 ':'s
-// we don't have to figure out if the format is entirely legal
-// we just have to be able to tell correct formats apart
-static inline int sfip_str_to_fam(const char* str)
-{
-    const char* s;
-    assert(str);
-    s = strchr(str, (int)':');
-    if ( s && strchr(s+1, (int)':') )
-        return AF_INET6;
-    if ( strchr(str, (int)'.') )
-        return AF_INET;
-    return AF_UNSPEC;
-}
-
 /* Masks off 'val' bits from the IP contained within 'ip' */
 inline int SfIp::cidr_mask(int val)
 {
index 06a32d7c9e15a647c206c14e39c4190746c2e915..f41cdba78ef662a062ad7b2c90bf83a50c49d41a 100644 (file)
@@ -25,6 +25,8 @@
 #include <arpa/inet.h>
 #include <sys/socket.h>
 
+#include <cassert>
+#include <cstring>
 #include <sstream>
 
 #include "main/snort_types.h"
@@ -34,6 +36,9 @@ namespace snort
 {
 using SfIpString = char[INET6_ADDRSTRLEN];
 
+// INET6_ADDRSTRLEN without IPv4-mapped IPv6
+#define MAX_INET6_STRLEN_NO_IPV4_MAP 40
+
 struct SfCidr;
 
 struct SO_PUBLIC SfIp
@@ -460,6 +465,72 @@ inline bool SfIp::operator==(const SfIp& ip2) const
 
 /* End of member function definitions */
 
+/* Support functions */
+// note that an ip6 address may have a trailing dotted quad form
+// but that it always has at least 2 ':'s; furthermore there is
+// no valid ip4 format (including mask) with 2 ':'s
+// we don't have to figure out if the format is entirely legal
+// we just have to be able to tell correct formats apart
+static inline int sfip_str_to_fam(const char* str)
+{
+    const char* s;
+    assert(str);
+    s = strchr(str, (int)':');
+    if ( s && strchr(s+1, (int)':') )
+        return AF_INET6;
+    if ( strchr(str, (int)'.') )
+        return AF_INET;
+    return AF_UNSPEC;
+}
+
+static inline bool parse_ip_from_uri(std::string& ip_str, SfIp& ip)
+{
+    auto host_start = ip_str.find("://");
+    if ( host_start != std::string::npos )
+    {
+        host_start += 3;
+        if ( host_start >= ip_str.size() )
+            return false;
+    }
+    else
+        host_start = 0;
+
+    auto host_end = host_start;
+    int family = sfip_str_to_fam(ip_str.c_str() + host_start);
+
+    if ( family == AF_INET )
+    {
+        while ( host_end < ip_str.size() and ip_str[host_end] != ':' and ip_str[host_end] != '/' )
+            ++host_end;
+    }
+    else if ( family == AF_INET6 )
+    {
+        if ( ip_str[host_start] == '[' )
+        {
+            ++host_start;
+            ++host_end;
+        }
+        while ( host_end < ip_str.size() and ip_str[host_end] != ']' and ip_str[host_end] != '/')
+            ++host_end;
+    }
+    else
+        return false;
+
+    if ( host_end <= host_start or (host_end - host_start) > MAX_INET6_STRLEN_NO_IPV4_MAP )
+        return false;
+
+    if ( host_start != 0 or host_end != ip_str.size() )
+    {
+        const std::string host_str = ip_str.substr(host_start, host_end - host_start);
+        if ( ip.set(host_str.c_str()) != SFIP_SUCCESS )
+            return false;
+    }
+    else if ( ip.set(ip_str.c_str()) != SFIP_SUCCESS )
+        return false;
+
+    return true;
+}
+
 SO_PUBLIC const char* sfip_ntop(const SfIp* ip, char* buf, int bufsize);
 
 inline std::ostream& operator<<(std::ostream& os, const SfIp* addr)
index cb4d02215f0d560a59f5d034202e2a1f6bb274e1..738afdbb03253a898fb447bf9657c3a8767b7fd4 100644 (file)
@@ -409,3 +409,22 @@ TEST_CASE("sfip copy", "[sfip]")
     for ( unsigned i = 0; i < NUM_TESTS; ++i )
         CHECK(CopyCheck(i) == 1);
 }
+
+TEST_CASE("uri parsing", "[sfip]")
+{
+    std::string ip_str;
+    SfIp ip;
+
+    // Validity of IP strings: empty, large, protocol, port, path
+    CHECK(parse_ip_from_uri(ip_str, ip) == false);
+    ip_str = "1111:2222:3333:4444:5555:6666:7777:8888:9999";
+    CHECK(parse_ip_from_uri(ip_str, ip) == false);
+    ip_str = "http://";
+    CHECK(parse_ip_from_uri(ip_str, ip) == false);
+    ip_str = "http://1.2.3.4:80";
+    CHECK(parse_ip_from_uri(ip_str, ip));
+    ip_str = "https://1.2.3.5/about.html";
+    CHECK(parse_ip_from_uri(ip_str, ip));
+    ip_str = "[1111::2222]/about.html";
+    CHECK(parse_ip_from_uri(ip_str, ip));
+}
index 2057995322b400bbaa05a6aa63a3cf27fbd8a656..fc75c8a756a0f4dca127c0824f3c2f1f7b344922 100644 (file)
@@ -70,17 +70,17 @@ static const Parameter s_params[] =
 {
 #ifdef REG_TEST
     { "footprint", Parameter::PT_INT, "0:max32", "0",
-        "use zero for production, non-zero for testing at given size (for TCP and user)" },
+      "use zero for production, non-zero for testing at given size (for TCP and user)" },
 #endif
 
     { "ip_frags_only", Parameter::PT_BOOL, nullptr, "false",
-            "don't process non-frag flows" },
+      "don't process non-frag flows" },
 
     { "max_flows", Parameter::PT_INT, "2:max32", "476288",
-                "maximum simultaneous flows tracked before pruning" },
+      "maximum simultaneous flows tracked before pruning" },
 
     { "pruning_timeout", Parameter::PT_INT, "1:max32", "30",
-                    "minimum inactive time before being eligible for pruning" },
+      "minimum inactive time before being eligible for pruning" },
 
     { "held_packet_timeout", Parameter::PT_INT, "1:max32", "1000",
       "timeout in milliseconds for held packets" },
@@ -334,6 +334,7 @@ bool StreamUnloadReloadResourceManager::tune_resources(unsigned work_limit)
 void StreamModuleConfig::show() const
 {
     ConfigLogger::log_value("max_flows", flow_cache_cfg.max_flows);
+    ConfigLogger::log_value("max_aux_ip", SnortConfig::get_conf()->max_aux_ip);
     ConfigLogger::log_value("pruning_timeout", flow_cache_cfg.pruning_timeout);
 
     for (int i = to_utype(PktType::IP); i < to_utype(PktType::MAX); ++i)