uint64_t expire_time = 0;
unsigned network_policy_id = 0;
+ struct timeval prev_packet_time = {0, 0};
+
unsigned inspection_policy_id = 0;
unsigned ips_policy_id = 0;
unsigned reload_id = 0;
#include "config.h"
#endif
+#include <sys/time.h>
+
#include <daq_common.h>
#include "flow_control.h"
#include "pub_sub/intrinsic_event_ids.h"
#include "pub_sub/packet_events.h"
#include "stream/stream.h"
+#include "utils/stats.h"
#include "utils/util.h"
#include "expect_cache.h"
return false;
}
+static void log_stale_packet(snort::Packet *p, snort::Flow *flow, bool drop_packet)
+{
+ char ts_flow[TIMEBUF_SIZE];
+ char ts_pkt[TIMEBUF_SIZE];
+ ts_print((const struct timeval *)&p->pkth->ts, ts_pkt);
+ ts_print((const struct timeval *)&flow->prev_packet_time, ts_flow);
+
+ if ( drop_packet )
+ PacketTracer::log("Flow: Dropping stale packet. current packet ts: %s < previous packet ts: %s.\n",
+ ts_pkt, ts_flow);
+ else
+ PacketTracer::log("Flow: Detected stale packet, dropping disabled. current packet ts: %s < previous packet ts: %s.\n",
+ ts_pkt, ts_flow);
+}
+
+static inline bool is_packet_stale(const Flow* flow, const Packet* p)
+{
+ return timercmp(&flow->prev_packet_time, &p->pkth->ts, >);
+}
+
+static void drop_stale_packet(snort::Packet *p, snort::Flow *flow)
+{
+ // This is a stale packet, ignore it.
+ p->active->set_drop_reason("snort");
+ p->active->drop_packet(p);
+ p->disable_inspect = true;
+ if ( PacketTracer::is_active() )
+ log_stale_packet(p, flow, true);
+}
+
bool FlowControl::process(PktType type, Packet* p, bool* new_flow)
{
if ( !get_proto_session[to_utype(type)] )
bool reversed = set_key(&key, p);
Flow* flow = cache->find(&key);
- if (flow)
+ if ( flow )
+ {
+ if ( !p->is_retry() and is_packet_stale(flow, p) )
+ {
+ flow->session->count_stale_packet();
+
+ if ( p->context->conf->drop_stale_packets() )
+ {
+ drop_stale_packet(p, flow);
+ return true;
+ }
+ else
+ {
+ if ( PacketTracer::is_active() )
+ log_stale_packet(p, flow, false);
+ }
+ }
+
flow = stale_flow_cleanup(cache, flow, p);
+ }
bool new_ha_flow = false;
if ( !flow )
unsigned news = 0;
flow->previous_ssn_state = flow->ssn_state;
+ flow->prev_packet_time = p->pkth->ts;
p->flow = flow;
p->disable_inspect = flow->is_inspection_disabled();
virtual uint8_t missing_in_reassembled(uint8_t /*dir*/) const { return SSN_MISSING_NONE; }
virtual bool set_packet_action_to_hold(snort::Packet*) { return false; }
+ virtual void count_stale_packet() { }
protected:
Session(snort::Flow* f) { flow = f; }
{ CountType::SUM, "created", module " session trackers created" }, \
{ CountType::SUM, "released", module " session trackers released" }, \
{ CountType::SUM, "timeouts", module " session timeouts" }, \
- { CountType::SUM, "prunes", module " session prunes" }
+ { CountType::SUM, "prunes", module " session prunes" }, \
+ { CountType::SUM, "stale_packets", module " stale packets" }
// See above. Add to end of stats array.
#define SESSION_STATS \
PegCount created; \
PegCount released; \
PegCount timeouts; \
- PegCount prunes
+ PegCount prunes; \
+ PegCount stale_packets
// Do not change the semantics of max. Max = the highest seen during the perf interval.
// To obtain max over the entire run, determine the maximum of reported max pegs.
void Flow::set_direction(Packet*) { }
void Flow::set_mpls_layer_per_dir(Packet*) { }
void packet_gettimeofday(struct timeval* ) { }
+SO_PUBLIC void ts_print(const struct timeval*, char*, bool) { }
time_t packet_time() { return 0; }
Flow* HighAvailabilityManager::import(Packet&, FlowKey&) { return nullptr; }
bool FlowCache::move_to_allowlist(snort::Flow*) { return true; }
uint64_t FlowCache::get_lru_flow_count(uint8_t) const { return 0; }
+SO_PUBLIC void snort::ts_print(const struct timeval*, char*, bool) { }
namespace snort
{
#ifdef SHELL
RUN_FLAG__SHELL = 0x02000000,
#endif
+ RUN_FLAG__DROP_STALE_PACKETS = 0x04000000,
};
enum OutputFlag
bool ip_frags_only() const
{ return (run_flags & RUN_FLAG__IP_FRAGS_ONLY) != 0; }
+ bool drop_stale_packets() const
+ { return (run_flags & RUN_FLAG__DROP_STALE_PACKETS) != 0; }
+
void clear_run_flags(RunFlag flag)
{ run_flags &= ~flag; }
{ "allowlist_cache", Parameter::PT_TABLE, allowlist_cache_params, nullptr, "configure allowlist cache" },
+ { "drop_stale_packets", Parameter::PT_BOOL, nullptr, "false",
+ "enable dropping of packets with stale timestamp" },
+
FLOW_TYPE_TABLE("ip_cache", "ip", ip_params),
FLOW_TYPE_TABLE("icmp_cache", "icmp", icmp_params),
FLOW_TYPE_TABLE("tcp_cache", "tcp", tcp_params),
else if ( !strcmp(fqn, "stream.udp_cache.idle_timeout") )
config.flow_cache_cfg.proto[to_utype(PktType::UDP)].nominal_timeout = v.get_uint32();
+ else if ( v.is("drop_stale_packets") )
+ {
+ config.drop_stale_packets = v.get_bool();
+ if (config.drop_stale_packets)
+ c->set_run_flags(RUN_FLAG__DROP_STALE_PACKETS);
+ else
+ c->clear_run_flags(RUN_FLAG__DROP_STALE_PACKETS);
+ return true;
+ }
else
{
assert(!strcmp(fqn, "stream.user_cache.idle_timeout"));
ConfigLogger::log_value("pruning_timeout", flow_cache_cfg.pruning_timeout);
ConfigLogger::log_value("prune_flows", flow_cache_cfg.prune_flows);
ConfigLogger::log_limit("require_3whs", hs_timeout, -1, hs_timeout < 0 ? hs_timeout : -1);
-
+ ConfigLogger::log_value("drop_stale_packets", drop_stale_packets ? "enabled" : "disabled");
+
for (int i = to_utype(PktType::IP); i < to_utype(PktType::PDU); ++i)
{
std::string tmp;
#endif
uint32_t held_packet_timeout = 1000; // in milliseconds
int hs_timeout = -1;
-
+ bool drop_stale_packets = false;
+
void show() const;
};
#define ICMP_SESSION_H
#include <sys/time.h>
+
#include "flow/session.h"
+#include "icmp_module.h"
+
class IcmpSession : public Session
{
public:
bool setup(snort::Packet*) override;
int process(snort::Packet*) override;
void clear() override;
-
+ void count_stale_packet() override
+ { icmpStats.stale_packets++; }
public:
uint32_t echo_count = 0;
struct timeval ssn_time = {};
struct Fragment;
struct FragEngine;
+extern THREAD_LOCAL IpStats ip_stats;
+
/* Only track a certain number of alerts per session */
#define MAX_FRAG_ALERTS 8
bool add_alert(snort::Packet*, uint32_t gid, uint32_t sid) override;
bool check_alerted(snort::Packet*, uint32_t gid, uint32_t sid) override;
+ void count_stale_packet() override
+ { ip_stats.stale_packets++; }
public:
FragTracker tracker = {};
};
-extern THREAD_LOCAL IpStats ip_stats;
-
#endif
void handle_data_segment(TcpSegmentDescriptor&, bool flush = true);
bool validate_packet_established_session(TcpSegmentDescriptor&);
+ void count_stale_packet() override
+ { tcpStats.stale_packets++; }
+
TcpStreamTracker client;
TcpStreamTracker server;
TcpStreamConfig* tcp_config = nullptr;
return 0;
}
+void UdpSession::count_stale_packet()
+{
+ udpStats.stale_packets++;
+}
#include "flow/session.h"
class SO_PUBLIC UdpSession : public Session
+
{
public:
UdpSession(snort::Flow*);
void update_direction(char dir, const snort::SfIp*, uint16_t port) override;
int process(snort::Packet*) override;
void clear() override;
+ void count_stale_packet() override;
-public:
+ public:
struct timeval ssn_time = {};
uint64_t payload_bytes_seen_client = 0;
uint64_t payload_bytes_seen_server = 0;
//--------------------------------------------------------------------------
// config_ignore_ports.cc author Josh Rosenbaum <jrosenba@cisco.com>
+#include <cstdint>
#include <sstream>
#include <vector>
#include <string>
#include "pps_dcerpc_server.h"
+#include <cstdint>
#include <algorithm>
#include <cstring>
//--------------------------------------------------------------------------
// pps_frag3_engine.cc author Josh Rosenbaum <jrosenba@cisco.com>
+#include <cstdint>
#include <sstream>
#include <vector>
//--------------------------------------------------------------------------
// pps_stream_tcp.cc author Josh Rosenbaum <jrosenba@cisco.com>
+#include <cstdint>
#include <sstream>
#include <vector>
#include <string>
// sid.
// Handle 2 cases: sid was read before/after gid.
+#include <cstdint>
#include <sstream>
#include <unordered_map>