/*!
* Unlink and free an ANR node or the oldest node, if ANR is empty
- * behavior is undefined if t->usrfree is set
+ * behavior is undefined if either t->anrfree or t->usrfree is set
*
* t XHash table pointer
*
++*num_freed;
}
- return (t->mc.memcap > t->mc.memused) ? XHASH_OK : XHASH_PENDING;
+ return (t->mc.memcap >= t->mc.memused) ? XHASH_OK : XHASH_PENDING;
}
/*!
{ return t->overhead_blocks; }
// Get the amount of space required to allocate a new node in the xhash t.
-inline size_t xhash_required_mem(XHash *t)
-{ return sizeof(XHashNode) + t->pad + t->keysize + t->datasize; }
+constexpr size_t xhash_required_mem(XHash *t)
+{ return sizeof(XHashNode) + t->pad + t->keysize + t->datasize + sizeof(long); }
SO_PUBLIC int xhash_free_anr_lru(XHash* t);
SO_PUBLIC void* xhash_mru(XHash* t);
bool AppIdServiceState::prune(size_t max_memory, size_t num_items)
{
- bool done = false;
if ( service_state_cache )
- done = service_state_cache->prune(max_memory, num_items);
- return done;
+ return service_state_cache->prune(max_memory, num_items);
+ return true;
}
return (result == XHASH_OK);
}
else
- {
- return false;
- }
+ return true;
}
void PerfMonitor::tterm()
using namespace snort;
-THREAD_LOCAL SimpleStats spstats;
+THREAD_LOCAL PsPegStats spstats;
THREAD_LOCAL ProfileStats psPerfStats;
static void make_port_scan_info(Packet* p, PS_PROTO* proto)
if ( p->packet_flags & PKT_REBUILT_STREAM )
return;
- ++spstats.total_packets;
+ ++spstats.packets;
PS_PKT ps_pkt(p);
ps_detect(&ps_pkt);
#include "utils/stats.h"
#include "ps_inspect.h"
+#include "ps_pegs.h"
using namespace snort;
PADDING_GUARD_END
static THREAD_LOCAL XHash* portscan_hash = nullptr;
+extern THREAD_LOCAL PsPegStats spstats;
PS_PKT::PS_PKT(Packet* p)
{
unsigned ps_node_size()
{ return sizeof(PS_HASH_KEY) + sizeof(PS_TRACKER); }
-void ps_init_hash(unsigned long memcap)
+bool ps_init_hash(unsigned long memcap)
{
if ( portscan_hash )
- return;
+ {
+ bool need_pruning = (memcap < portscan_hash->mc.memused);
+ portscan_hash->mc.memcap = memcap;
+ return need_pruning;
+ }
int rows = memcap / ps_node_size();
if ( !portscan_hash )
FatalError("Failed to initialize portscan hash table.\n");
+
+ return false;
+}
+
+bool ps_prune_hash(unsigned work_limit)
+{
+ if ( !portscan_hash )
+ return true;
+
+ unsigned num_pruned = 0;
+ int result = xhash_free_overallocations(portscan_hash, work_limit, &num_pruned);
+ spstats.reload_prunes += num_pruned;
+ return result != XHASH_PENDING;
}
void ps_reset()
if ( ht )
return ht;
+ auto prev_count = portscan_hash->count;
if ( xhash_add(portscan_hash, (void*)key, nullptr) != XHASH_OK )
return nullptr;
+ ++spstats.trackers;
+ if ( prev_count == portscan_hash->count )
+ ++spstats.alloc_prunes;
+
ht = (PS_TRACKER*)xhash_mru(portscan_hash);
if ( ht )
void ps_reset();
unsigned ps_node_size();
-void ps_init_hash(unsigned long);
+bool ps_init_hash(unsigned long);
+bool ps_prune_hash(unsigned);
int ps_detect(PS_PKT*);
#endif
#include "ps_module.h"
#include "log/messages.h"
+#include "main/snort.h"
#include <cassert>
{ return &psPerfStats; }
const PegInfo* PortScanModule::get_pegs() const
-{ return simple_pegs; }
+{ return ps_module_pegs; }
PegCount* PortScanModule::get_counts() const
{ return (PegCount*)&spstats; }
return true;
}
-bool PortScanModule::end(const char* fqn, int, SnortConfig*)
+bool PortScanModule::end(const char* fqn, int, SnortConfig* sc)
{
- if (strcmp(fqn, "port_scan") == 0)
+ if ( strcmp(fqn, "port_scan") == 0 )
{
- static size_t saved_memcap = 0;
-
- if (saved_memcap != 0 )
- {
- if (config->memcap != saved_memcap)
- {
- ReloadError("Changing port_scan.memcap requires a restart\n");
- }
- }
- else
- {
- saved_memcap = config->memcap;
- }
+ ps_rrt.memcap = config->memcap;
+ if ( Snort::is_reloading() )
+ sc->register_reload_resource_tuner(ps_rrt);
}
-
return true;
}
config = nullptr;
return tmp;
}
-
#define PS_MODULE_H
#include "framework/module.h"
+#include "main/snort_config.h"
#include "ps_detect.h"
+#include "ps_pegs.h"
#define PS_NAME "port_scan"
#define PS_HELP "detect various ip, icmp, tcp, and udp port or protocol scans"
"open port"
//-------------------------------------------------------------------------
+// Reload resource tuning
+//-------------------------------------------------------------------------
+
+class PortScanReloadTuner : public snort::ReloadResourceTuner
+{
+public:
+ bool tinit() override
+ { return ps_init_hash(memcap); }
+
+ bool tune_idle_context() override
+ { return ps_prune_hash(max_work_idle); }
+
+ bool tune_packet_context() override
+ { return ps_prune_hash(max_work); }
-extern THREAD_LOCAL SimpleStats spstats;
+ size_t memcap = 0;
+};
+
+//-------------------------------------------------------------------------
+
+extern THREAD_LOCAL PsPegStats spstats;
extern THREAD_LOCAL snort::ProfileStats psPerfStats;
struct PortscanConfig;
private:
PS_ALERT_CONF* get_alert_conf(const char* fqn);
-
-private:
PortscanConfig* config;
+ PortScanReloadTuner ps_rrt;
};
#endif
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 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.
+//--------------------------------------------------------------------------
+
+// ps_pegs.h author Masud Hasan <mashasan@cisco.com>
+
+#ifndef PS_PEGS_H
+#define PS_PEGS_H
+
+#include "framework/counts.h"
+#include "main/snort_types.h"
+
+static const PegInfo ps_module_pegs[] =
+{
+ { CountType::SUM, "packets", "number of packets processed by port scan" },
+ { CountType::SUM, "trackers", "number of trackers allocated by port scan" },
+ { CountType::SUM, "alloc_prunes", "number of trackers pruned on allocation of new tracking" },
+ { CountType::SUM, "reload_prunes", "number of trackers pruned on reload due to reduced memcap" },
+ { CountType::END, nullptr, nullptr },
+};
+
+struct PsPegStats
+{
+ PegCount packets;
+ PegCount trackers;
+ PegCount alloc_prunes;
+ PegCount reload_prunes;
+};
+
+#endif