]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2729 in SNORT/snort3 from ~MIALTIZE/snort3:compound_codec to...
authorMichael Altizer (mialtize) <mialtize@cisco.com>
Tue, 9 Mar 2021 03:01:53 +0000 (03:01 +0000)
committerMichael Altizer (mialtize) <mialtize@cisco.com>
Tue, 9 Mar 2021 03:01:53 +0000 (03:01 +0000)
Squashed commit of the following:

commit d38e1757de753e33fbd7eb86fdd47e7005367ba4
Author: Michael Altizer <mialtize@cisco.com>
Date:   Mon Mar 8 17:32:42 2021 -0500

    snort_config: Clean up and annotate command line config merge process

commit 7ddcab755604935be48973c78b17ca70a1dc3eb4
Author: Michael Altizer <mialtize@cisco.com>
Date:   Tue Mar 2 15:30:14 2021 -0500

    protocols: Add peg count for decodes that exceeded the max layers

    Also, make sure that the alert for doing so only triggers once per
    packet being decoded.

commit 4dbd0f9718ee3160864c760632dc8e4611101899
Author: Michael Altizer <mialtize@cisco.com>
Date:   Tue Feb 2 18:25:29 2021 -0500

    protocols: Add initial support for multilayer compound codecs

commit 6903a09c81e02f8dce04becc393edc26c1ce3b48
Author: Michael Altizer <mialtize@cisco.com>
Date:   Mon Feb 1 12:29:19 2021 -0500

    protocols: Consistently encapsulate exported protocol headers in the snort namespace

commit e4f056d9fb416c0aaab573f6fa8d81c8f58367d1
Author: Michael Altizer <mialtize@cisco.com>
Date:   Wed Jan 27 13:24:22 2021 -0500

    log: Base logging the Ethernet header on proto bits rather than DLT

commit d80dc65860f76d1f28e8c93dc832d66d65169e3e
Author: Michael Altizer <mialtize@cisco.com>
Date:   Mon Jan 11 20:43:46 2021 -0500

    main: Fix accumulating and printing codec stats at run time

16 files changed:
src/codecs/link/cd_mpls.cc
src/framework/codec.h
src/log/log_text.cc
src/main/analyzer_command.cc
src/main/snort.cc
src/main/snort_config.cc
src/main/snort_config.h
src/parser/parser.cc
src/protocols/eapol.h
src/protocols/linux_sll.h
src/protocols/packet_manager.cc
src/protocols/packet_manager.h
src/protocols/teredo.h
src/protocols/token_ring.h
src/target_based/snort_protocols.cc
src/target_based/snort_protocols.h

index 22a0c97bafa9c132c9a5645d62bd91145ca2ea25..45fd02e1dacb07c061ce4080148d52dc425b3621 100644 (file)
@@ -38,7 +38,7 @@ namespace
 {
 enum MplsPayloadType : uint8_t
 {
-    // Entries must align with mpls_payload_type enum parameter in mpls_params
+    // Entries must align with payload_type enum parameter in mpls_params
     MPLS_PAYLOADTYPE_AUTODETECT = 0,
     MPLS_PAYLOADTYPE_ETHERNET,
     MPLS_PAYLOADTYPE_IPV4,
index 75a72c8d20dbee9c901f1cf15710f56557d863f5..c3481561d9fece3ef0fd36c929a0bd46acaf72b3 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "framework/base_api.h"
 #include "framework/decode_data.h"
+#include "protocols/layer.h"
 #include "utils/cpp_macros.h"
 
 struct TextLog;
@@ -55,7 +56,6 @@ struct ICMPHdr;
 }
 
 class Flow;
-struct Layer;
 
 // Used by root codecs to add their DLT to their HELP string
 #define ADD_DLT(help, x) help " (DLT " STRINGIFY_MX(x) ")"
@@ -112,26 +112,36 @@ constexpr uint16_t CODEC_IP6_EXT_OOO = 0x0400;
 constexpr uint16_t CODEC_IP6_BAD_OPT = 0x0800;
 
 constexpr uint16_t CODEC_ETHER_NEXT = 0x1000;
+constexpr uint16_t CODEC_COMPOUND = 0x2000;
+constexpr uint16_t CODEC_LAYERS_EXCEEDED = 0x400;
 
 constexpr uint16_t CODEC_IPOPT_FLAGS = (CODEC_IPOPT_RR_SEEN |
     CODEC_IPOPT_RTRALT_SEEN | CODEC_IPOPT_LEN_THREE);
 
 struct SnortConfig;
 
+constexpr uint8_t COMPOUND_LAYERS_MAX = 8;
+
+struct CompoundLayer
+{
+    Layer layer;
+    uint32_t proto_bits;
+};
+
 struct CodecData
 {
     const SnortConfig* conf;
 
     /* This section will get reset before every decode() function call */
-    ProtocolId next_prot_id;      /* protocol type of the next layer */
-    uint16_t lyr_len = 0;           /* The length of the valid part layer */
-    uint16_t invalid_bytes = 0;     /* the length of the INVALID part of this layer */
+    ProtocolId next_prot_id;        /* protocol type of the next layer */
+    uint16_t lyr_len = 0;           /* length of the valid portion of this layer */
+    uint16_t invalid_bytes = 0;     /* length of the INVALID part of this layer */
+    uint32_t proto_bits = 0;        /* protocols contained within this packet
+                                        -- will be propogated to Snort++ Packet struct*/
 
     /* Reset before each decode of packet begins */
 
     /*  Codec specific fields.  These fields are only relevant to codecs. */
-    uint32_t proto_bits = 0;    /* protocols contained within this packet
-                                 -- will be propogated to Snort++ Packet struct*/
     uint16_t codec_flags = 0;   /* flags used while decoding */
     uint8_t ip_layer_cnt = 0;
 
@@ -140,6 +150,9 @@ struct CodecData
     IpProtocol ip6_csum_proto = IpProtocol::IP;   /* Used for IPv6 checksums */
     bool tunnel_bypass = false;
 
+    CompoundLayer compound_layers[COMPOUND_LAYERS_MAX]{};
+    uint8_t compound_layer_cnt = 0;
+
     CodecData(const SnortConfig* sc, ProtocolId init_prot) : conf(sc), next_prot_id(init_prot)
     { }
 
index 9ff4c4ac420c786c060396e01ce57dfd3498f717..abc64c50026b58228e8c7f5a04978e7ec0f3024f 100644 (file)
@@ -150,7 +150,7 @@ void Log2ndHeader(TextLog* log, Packet* p)
     if ( !p or !p->num_layers )
         return;
 
-    if ( SFDAQ::get_base_protocol() == DLT_EN10MB )
+    if ( p->is_eth() )
         LogEthHeader(log, p);
 
     else if ( SnortConfig::log_verbose() )
index 1afa76eb8a5880d856fab2a6fd5378fd3aff7103..4f5fa5b07a620c0818ef177dd59a6350a13565ae 100644 (file)
@@ -28,6 +28,7 @@
 #include "framework/module.h"
 #include "log/messages.h"
 #include "managers/module_manager.h"
+#include "protocols/packet_manager.h"
 #include "target_based/host_attributes.h"
 #include "utils/stats.h"
 
@@ -77,10 +78,10 @@ bool ACRotate::execute(Analyzer& analyzer, void**)
 
 bool ACGetStats::execute(Analyzer&, void**)
 {
-
     // FIXIT-P This incurs locking on all threads to retrieve stats.  It
     // could be reimplemented to optimize for large thread counts by
     // retrieving stats in the command and accumulating in the main thread.
+    PacketManager::accumulate();
     ModuleManager::accumulate();
     return true;
 }
index bd3b901e9c55a4cdaa404b7dcb69e918c16c8d14..71fa28bdbc20a1a9b168f3a1475fd4177ca1f61a 100644 (file)
@@ -152,10 +152,7 @@ void Snort::init(int argc, char** argv)
     parser_init();
     SnortConfig* sc = ParseSnortConf(snort_cmd_line_conf);
 
-    /* Merge the command line and config file confs to take care of
-     * command line overriding config file.
-     * Set the global snort_conf that will be used during run time */
-    sc->merge(snort_cmd_line_conf);
+    /* Set the global snort_conf that will be used during run time */
     SnortConfig::set_conf(sc);
 
     // This call must be immediately after "SnortConfig::set_conf(sc)"
@@ -460,7 +457,6 @@ SnortConfig* Snort::get_reload_config(const char* fname, const char* plugin_path
 
     parser_init();
     SnortConfig* sc = ParseSnortConf(snort_cmd_line_conf, fname, false);
-    sc->merge(snort_cmd_line_conf);
 
     if ( get_parse_errors() || ModuleManager::get_errors() || !sc->verify() )
     {
index 3b2fbfb05ab00f01f3b69620de978b87b8df6869..d0e6a76d25cedbc12d076ca686042dba4bc7b121 100644 (file)
@@ -336,113 +336,120 @@ void SnortConfig::clone(const SnortConfig* const conf)
 }
 
 // merge in everything from the command line config
-void SnortConfig::merge(SnortConfig* cmd_line)
+void SnortConfig::merge(const SnortConfig* cmd_line_conf)
 {
-    if ( !cmd_line->log_dir.empty() )
-        log_dir = cmd_line->log_dir;
+    // -D / -H / -Q / -r / -T / -x / --alert-before-pass / --create-pidfile / --enable-inline-test / --mem-check /
+    // --nolock-pidfile / --pause / --pcap-file / --pcap-dir / --pcap-list / --pcap-show / --pedantic / --piglet /
+    // --shell / --show-file-codes
+    run_flags |= cmd_line_conf->run_flags;
 
-    if ( log_dir.empty() )
-        log_dir = DEFAULT_LOG_DIR;
-
-    run_prefix = cmd_line->run_prefix;
-    id_offset = cmd_line->id_offset;
-    id_subdir = cmd_line->id_subdir;
-    id_zero = cmd_line->id_zero;
-
-    /* Used because of a potential chroot */
-    orig_log_dir = log_dir;
-    event_log_id = cmd_line->event_log_id;
+    // -A / -C / -d / -e / -f / -O / -U / -X / -y / --nostamps
+    output_flags |= cmd_line_conf->output_flags;
 
-    run_flags |= cmd_line->run_flags;
-    output_flags |= cmd_line->output_flags;
+    // -B
+    if (cmd_line_conf->obfuscation_net.get_family() != 0)
+        memcpy(&obfuscation_net, &cmd_line_conf->obfuscation_net, sizeof(obfuscation_net));
 
-    include_path = cmd_line->include_path;
-    stdin_rules = cmd_line->stdin_rules;
+    // -g
+    if (cmd_line_conf->group_id != -1)
+        group_id = cmd_line_conf->group_id;
 
-    // only set by cmd_line to override other conf output settings
-    output = cmd_line->output;
+    // -G / --logid
+    event_log_id = cmd_line_conf->event_log_id;
 
-    /* Merge checksum flags.  If command line modified them, use from the
-     * command line, else just use from config_file. */
+    // -i / -s / --daq / --daq-batch-size / --daq-dir / --daq-list / --daq-mode / --daq-var / --snaplen
+    daq_config->overlay(cmd_line_conf->daq_config);
 
-    int cl_chk = cmd_line->policy_map->get_network_policy()->checksum_eval;
-    int cl_drop = cmd_line->policy_map->get_network_policy()->checksum_drop;
-
-    NetworkPolicy* nw_policy = nullptr;
-
-    for ( unsigned idx = 0; idx < policy_map->network_policy_count(); ++idx )
+    // -k (only configures eval, not drop)
+    int cl_chk = cmd_line_conf->policy_map->get_network_policy()->checksum_eval;
+    if (!(cl_chk & CHECKSUM_FLAG__DEF))
     {
-        nw_policy = policy_map->get_network_policy(idx);
-
-        if ( !(cl_chk & CHECKSUM_FLAG__DEF) )
-            nw_policy->checksum_eval = cl_chk;
-
-        if ( !(cl_drop & CHECKSUM_FLAG__DEF) )
-            nw_policy->checksum_drop = cl_drop;
+        for (unsigned idx = 0; idx < policy_map->network_policy_count(); ++idx)
+        {
+            NetworkPolicy* nw_policy = policy_map->get_network_policy(idx);
+            if (!(cl_chk & CHECKSUM_FLAG__DEF))
+                nw_policy->checksum_eval = cl_chk;
+        }
     }
 
-    /* FIXIT-L do these belong in network policy? */
-    if (cmd_line->num_layers != 0)
-        num_layers = cmd_line->num_layers;
-
-    if (cmd_line->max_ip6_extensions != 0)
-        max_ip6_extensions = cmd_line->max_ip6_extensions;
-
-    if (cmd_line->max_ip_layers != 0)
-        max_ip_layers = cmd_line->max_ip_layers;
+    // -l
+    if ( !cmd_line_conf->log_dir.empty() )
+        log_dir = cmd_line_conf->log_dir;
 
-    if (cmd_line->obfuscation_net.get_family() != 0)
-        memcpy(&obfuscation_net, &cmd_line->obfuscation_net, sizeof(obfuscation_net));
+    // -L (output is only set by cmd_line_conf to override other conf output settings)
+    output = cmd_line_conf->output;
 
-    if (cmd_line->homenet.get_family() != 0)
-        memcpy(&homenet, &cmd_line->homenet, sizeof(homenet));
+    // -m
+    if (cmd_line_conf->file_mask != 0)
+        file_mask = cmd_line_conf->file_mask;
 
-    if ( !cmd_line->bpf_file.empty() )
-        bpf_file = cmd_line->bpf_file;
+    // -n
+    if (cmd_line_conf->pkt_cnt != 0)
+        pkt_cnt = cmd_line_conf->pkt_cnt;
 
-    if ( !cmd_line->bpf_filter.empty() )
-        bpf_filter = cmd_line->bpf_filter;
+    // -t
+    if (!cmd_line_conf->chroot_dir.empty())
+        chroot_dir = cmd_line_conf->chroot_dir;
 
-    if (cmd_line->pkt_cnt != 0)
-        pkt_cnt = cmd_line->pkt_cnt;
+    // -u
+    if (cmd_line_conf->user_id != -1)
+        user_id = cmd_line_conf->user_id;
 
-    if (cmd_line->pkt_skip != 0)
-        pkt_skip = cmd_line->pkt_skip;
+    // --bpf
+    if (!cmd_line_conf->bpf_filter.empty())
+        bpf_filter = cmd_line_conf->bpf_filter;
 
-    if (cmd_line->pkt_pause_cnt != 0)
-        pkt_pause_cnt = cmd_line->pkt_pause_cnt;
+    // --dirty-pig
+    if (cmd_line_conf->dirty_pig)
+        dirty_pig = cmd_line_conf->dirty_pig;
 
-    if (cmd_line->group_id != -1)
-        group_id = cmd_line->group_id;
+    // --id-offset
+    id_offset = cmd_line_conf->id_offset;
+    // --id-subdir
+    id_subdir = cmd_line_conf->id_subdir;
+    // --id-zero
+    id_zero = cmd_line_conf->id_zero;
 
-    if (cmd_line->user_id != -1)
-        user_id = cmd_line->user_id;
+    // --include-path
+    include_path = cmd_line_conf->include_path;
 
-    /* Only configurable on command line */
-    if (cmd_line->file_mask != 0)
-        file_mask = cmd_line->file_mask;
+    // --metadata-filter
+    if (!cmd_line_conf->metadata_filter.empty())
+        metadata_filter = cmd_line_conf->metadata_filter;
 
-    if ( !cmd_line->chroot_dir.empty() )
-        chroot_dir = cmd_line->chroot_dir;
+    // --pause-after-n
+    if (cmd_line_conf->pkt_pause_cnt != 0)
+        pkt_pause_cnt = cmd_line_conf->pkt_pause_cnt;
 
-    if ( cmd_line->dirty_pig )
-        dirty_pig = cmd_line->dirty_pig;
+    // --process-all-events
+    if (cmd_line_conf->run_flags & RUN_FLAG__PROCESS_ALL_EVENTS)
+        event_queue_config->process_all_events = 1;
 
-    if ( !cmd_line->metadata_filter.empty() )
-        metadata_filter = cmd_line->metadata_filter;
+    // --run-prefix
+    run_prefix = cmd_line_conf->run_prefix;
 
-    daq_config->overlay(cmd_line->daq_config);
+    // --skip
+    if (cmd_line_conf->pkt_skip != 0)
+        pkt_skip = cmd_line_conf->pkt_skip;
 
-    if (cmd_line->run_flags & RUN_FLAG__PROCESS_ALL_EVENTS)
-        event_queue_config->process_all_events = 1;
+    // --stdin-rules
+    stdin_rules = cmd_line_conf->stdin_rules;
 
 #ifdef SHELL
-    if ( cmd_line->remote_control_port )
-        remote_control_port = cmd_line->remote_control_port;
-    else if ( !cmd_line->remote_control_socket.empty() )
-        remote_control_socket = cmd_line->remote_control_socket;
+    // -j
+    if (cmd_line_conf->remote_control_port)
+        remote_control_port = cmd_line_conf->remote_control_port;
+    // --control-socket
+    else if (!cmd_line_conf->remote_control_socket.empty())
+        remote_control_socket = cmd_line_conf->remote_control_socket;
 #endif
 
+    // Finalize the log directory, save a copy in case we need to chroot
+    if ( log_dir.empty() )
+        log_dir = DEFAULT_LOG_DIR;
+    orig_log_dir = log_dir;
+
+    // Initialize the slotted state memory for threads
     assert(!state);
     num_slots = offload_threads + ThreadConfig::get_instance_max();
     state = new std::vector<void*>[num_slots];
index efa8345039cdc8954e7e4f0e64f0d1531ecb4745..24a2a9e70b1f1405fe0ca21783ac1929d0a08492 100644 (file)
@@ -202,7 +202,7 @@ public:
     void post_setup();
     bool verify() const;
 
-    void merge(SnortConfig*);
+    void merge(const SnortConfig*);
     void clone(const SnortConfig* const);
 
 private:
index 315a43feab30fb81988af53121b6e1bf73b05306..71c5ea18bef75b54aa03855695b7d21058a22fc0 100644 (file)
@@ -313,14 +313,15 @@ void parser_term(SnortConfig*)
     ruleIndexMap = nullptr;
 }
 
-SnortConfig* ParseSnortConf(const SnortConfig* boot_conf, const char* fname, bool is_fatal)
+SnortConfig* ParseSnortConf(const SnortConfig* cmd_line_conf, const char* fname, bool is_fatal)
 {
-    SnortConfig* sc = new SnortConfig(SnortConfig::get_conf()->proto_ref);
+    const SnortConfig* current_conf = SnortConfig::get_conf();
+    SnortConfig* sc = new SnortConfig(current_conf->proto_ref);
 
-    sc->run_flags = boot_conf->run_flags;
-    sc->output_flags = boot_conf->output_flags;
-    sc->tweaks = boot_conf->tweaks;
-    sc->dump_config_type = boot_conf->dump_config_type;
+    sc->run_flags = cmd_line_conf->run_flags;
+    sc->output_flags = cmd_line_conf->output_flags;
+    sc->tweaks = cmd_line_conf->tweaks;
+    sc->dump_config_type = cmd_line_conf->dump_config_type;
 
     if ( !fname )
         fname = get_snort_conf();
@@ -339,7 +340,7 @@ SnortConfig* ParseSnortConf(const SnortConfig* boot_conf, const char* fname, boo
     sc->detection_filter_config = DetectionFilterConfigNew();
 
     // get overrides from cmd line
-    Shell* sh = boot_conf->policy_map->get_shell();
+    Shell* sh = cmd_line_conf->policy_map->get_shell();
     sc->policy_map->get_shell()->set_overrides(sh);
 
     if ( *fname )
@@ -349,8 +350,8 @@ SnortConfig* ParseSnortConf(const SnortConfig* boot_conf, const char* fname, boo
     }
 
     bool parse_file_failed = false;
-    auto output = SnortConfig::get_conf()->create_config_output();
-    bool is_top = SnortConfig::get_conf()->dump_config_type == DUMP_CONFIG_JSON_TOP;
+    auto output = current_conf->create_config_output();
+    bool is_top = current_conf->dump_config_type == DUMP_CONFIG_JSON_TOP;
     for ( unsigned i = 0; true; i++ )
     {
         sh = sc->policy_map->get_shell(i);
@@ -375,6 +376,9 @@ SnortConfig* ParseSnortConf(const SnortConfig* boot_conf, const char* fname, boo
     if ( !parse_file_failed )
         set_default_policy(sc);
 
+    // Merge in any overrides from the command line
+    sc->merge(cmd_line_conf);
+
     return sc;
 }
 
index 54ea71d435c910f6cbe7ab0d174d85402633461e..9c1945eb3f41af16ec9b1d7a37319f1a31f4ac4e 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef PROTOCOLS_EAPOL_H
 #define PROTOCOLS_EAPOL_H
 
+namespace snort
+{
 namespace eapol
 {
 struct EtherEapol
@@ -80,7 +82,8 @@ struct EapolKey
 #define EAP_TYPE_OTP        0x05
 #define EAP_TYPE_GTC        0x06
 #define EAP_TYPE_TLS        0x0d
-}
+} // namespace eapol
+} // namespace snort
 
 #endif /* EAPOL_H */
 
index d673a29c48946a80ad07a21cf448d71db38914a9..e877c4e72b80af2e5100f1d0592704aba721ba35 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef PROTOCOLS_LINUX_SLL_H
 #define PROTOCOLS_LINUX_SLL_H
 
+namespace snort
+{
 namespace linux_sll
 {
 /* 'Linux cooked captures' data
@@ -39,7 +41,7 @@ struct SLLHdr
 };
 
 /*
- * ssl_pkttype values.
+ * sll_pkttype values.
  */
 
 #define LINUX_SLL_HOST          0
@@ -48,11 +50,12 @@ struct SLLHdr
 #define LINUX_SLL_OTHERHOST     3
 #define LINUX_SLL_OUTGOING      4
 
-/* ssl protocol values */
+/* sll protocol values */
 
 #define LINUX_SLL_P_802_3       0x0001  /* Novell 802.3 frames without 802.2 LLC header */
 #define LINUX_SLL_P_802_2       0x0004  /* 802.2 frames (not D/I/X Ethernet) */
-} // namespace ssl
+} // namespace linux_sll
+} // namespace snort
 
 #endif /* LINUX_SLL_H */
 
index 8142f1aecf71c2e30eeae08fca78afac3d8d3f74..7fd5fd503a8674320137db36ccd66ca1595b7e83 100644 (file)
@@ -63,7 +63,8 @@ const std::array<const char*, PacketManager::stat_offset> PacketManager::stat_na
     {
         "total",
         "other",
-        "discards"
+        "discards",
+        "depth_exceeded"
     }
 };
 
@@ -85,17 +86,38 @@ void PacketManager::thread_term()
 // Private helper functions
 //-------------------------------------------------------------------------
 
-static inline void push_layer(Packet* p,
-    ProtocolId prot_id,
-    const uint8_t* hdr_start,
-    uint32_t len)
+inline bool PacketManager::push_layer(Packet* p, CodecData& codec_data, ProtocolId prot_id,
+    const uint8_t* hdr_start, uint32_t len)
 {
-    // We check to ensure num_layer < MAX_LAYERS before this function call
+    if ( p->num_layers == CodecManager::get_max_layers() )
+    {
+        if (!(codec_data.codec_flags & CODEC_LAYERS_EXCEEDED))
+        {
+            codec_data.codec_flags |= CODEC_LAYERS_EXCEEDED;
+            DetectionEngine::queue_event(GID_DECODE, DECODE_TOO_MANY_LAYERS);
+            s_stats[depth_exceeded]++;
+        }
+        return false;
+    }
+
     Layer& lyr = p->layers[p->num_layers++];
     lyr.prot_id = prot_id;
     lyr.start = hdr_start;
     lyr.length = (uint16_t)len;
 //    lyr.invalid_bits = p->byte_skip;  -- currently unused
+
+    return true;
+}
+
+inline Codec* PacketManager::get_layer_codec(const Layer& lyr, int idx)
+{
+    ProtocolIndex mapped_prot;
+    // prot_id == ProtocolId::FINISHED_DECODE is a special case for root codecs not registering a protocol ID
+    if (idx == 0 && (lyr.prot_id == CodecManager::grinder_id || lyr.prot_id == ProtocolId::FINISHED_DECODE))
+        mapped_prot = CodecManager::grinder;
+    else
+        mapped_prot = CodecManager::s_proto_map[to_utype(lyr.prot_id)];
+    return CodecManager::s_protocols[mapped_prot];
 }
 
 void PacketManager::pop_teredo(Packet* p, RawData& raw)
@@ -114,6 +136,56 @@ void PacketManager::pop_teredo(Packet* p, RawData& raw)
     raw.len += lyr_len;
 }
 
+void PacketManager::handle_decode_failure(Packet* p, RawData& raw, const CodecData& codec_data,
+    const DecodeData& unsure_encap_ptrs, ProtocolId prev_prot_id)
+{
+    if (codec_data.codec_flags & CODEC_UNSURE_ENCAP)
+    {
+        p->ptrs = unsure_encap_ptrs;
+
+        switch (p->layers[p->num_layers - 1].prot_id)
+        {
+            case ProtocolId::ESP:
+                // Hardcoding ESP because we trust iff the layer
+                // immediately preceding the fail is ESP.
+                p->ptrs.decode_flags |= DECODE_PKT_TRUST;
+                break;
+
+            case ProtocolId::TEREDO:
+                // if we just decoded teredo and the next
+                // layer fails, we made a mistake. Therefore,
+                // remove this bit.
+                pop_teredo(p, raw);
+                break;
+            default:
+                break;
+        }
+        return;
+    }
+
+    if ( (p->num_layers > 0) && (p->layers[p->num_layers - 1].prot_id == ProtocolId::TEREDO) &&
+        (prev_prot_id == ProtocolId::IPV6) )
+    {
+        pop_teredo(p, raw);
+    }
+
+    // if the codec exists, it failed
+    if (CodecManager::s_proto_map[to_utype(prev_prot_id)])
+    {
+        s_stats[discards]++;
+    }
+    else
+    {
+        s_stats[other_codecs]++;
+
+        if ( (to_utype(ProtocolId::MIN_UNASSIGNED_IP_PROTO) <= to_utype(prev_prot_id)) &&
+                (to_utype(prev_prot_id) <= std::numeric_limits<uint8_t>::max()) )
+        {
+            DetectionEngine::queue_event(GID_DECODE, DECODE_IP_UNASSIGNED_PROTO);
+        }
+    }
+}
+
 static inline bool payload_offset_from_daq_mismatch(const uint8_t* pkt, const RawData& raw)
 {
     const DAQ_PktDecodeData_t* pdd =
@@ -153,7 +225,7 @@ void PacketManager::decode(
     RawData raw(p->daq_msg, pkt, pktlen);
     CodecData codec_data(p->context->conf, ProtocolId::FINISHED_DECODE);
 
-    if ( cooked )
+    if (cooked)
         codec_data.codec_flags |= CODEC_STREAM_REBUILT;
 
     // initialize all Packet information
@@ -170,20 +242,82 @@ void PacketManager::decode(
     // loop until the protocol id is no longer valid
     while (CodecManager::s_protocols[mapped_prot]->decode(raw, codec_data, p->ptrs))
     {
-        debug_logf(decode_trace, nullptr, "Codec %s (protocol_id: %hu) "
-            "ip header starts at: %p, length is %d\n",
+        debug_logf(decode_trace, nullptr,
+            "Codec %s (0x%0*hx) starts at %u, length is %hu\n",
             CodecManager::s_protocols[mapped_prot]->get_name(),
-            static_cast<uint16_t>(codec_data.next_prot_id), pkt, codec_data.lyr_len);
+            (static_cast<uint16_t>(prev_prot_id) < 0xFF) ? 2 : 4,
+            static_cast<uint16_t>(prev_prot_id),
+            pktlen - raw.len, codec_data.lyr_len);
+
+        if (codec_data.codec_flags & CODEC_COMPOUND)
+        {
+            for (int idx = 0; idx < codec_data.compound_layer_cnt; idx++)
+            {
+                CompoundLayer* clyr = &codec_data.compound_layers[idx];
+
+                // If this was an IP layer, stash the next protocol in the Packet for later
+                if (clyr->proto_bits & (PROTO_BIT__IP | PROTO_BIT__IP6_EXT) &&
+                    idx + 1 < codec_data.compound_layer_cnt)
+                {
+                    CompoundLayer* nclyr = &codec_data.compound_layers[idx + 1];
+                    p->ip_proto_next = convert_protocolid_to_ipprotocol(nclyr->layer.prot_id);
+                }
+                p->proto_bits |= clyr->proto_bits;
+
+                // If we have reached the MAX_LAYERS, we keep decoding
+                // but no longer keep track of the layers.
+                if (!push_layer(p, codec_data, clyr->layer.prot_id, clyr->layer.start, clyr->layer.length))
+                    continue;
+
+                // Cache the index of the vlan layer for quick access.
+                if (clyr->proto_bits == PROTO_BIT__VLAN)
+                    p->vlan_idx = p->num_layers - 1;
+            }
+            codec_data.codec_flags &= ~CODEC_COMPOUND;
+        }
+        else
+        {
+            // If this was an IP layer, stash the next protocol in the Packet for later
+            if (codec_data.proto_bits & (PROTO_BIT__IP | PROTO_BIT__IP6_EXT))
+            {
+                // FIXIT-M refactor when ip_proto's become an array
+                if (p->is_fragment())
+                {
+                    if (prev_prot_id == ProtocolId::FRAGMENT)
+                    {
+                        const ip::IP6Frag* const fragh = reinterpret_cast<const ip::IP6Frag*>(raw.data);
+                        p->ip_proto_next = fragh->next();
+                    }
+                    else
+                        p->ip_proto_next = p->ptrs.ip_api.get_ip4h()->proto();
+                }
+                else
+                {
+                    if (codec_data.next_prot_id != ProtocolId::FINISHED_DECODE)
+                        p->ip_proto_next = convert_protocolid_to_ipprotocol(codec_data.next_prot_id);
+                }
+            }
+
+            // If we have reached the MAX_LAYERS, we keep decoding
+            // but no longer keep track of the layers.
+            if (push_layer(p, codec_data, prev_prot_id, raw.data, codec_data.lyr_len))
+            {
+                // Cache the index of the vlan layer for quick access.
+                if (codec_data.proto_bits == PROTO_BIT__VLAN)
+                    p->vlan_idx = p->num_layers - 1;
+            }
+        }
 
-        if ( codec_data.tunnel_bypass )
+        if (codec_data.tunnel_bypass)
         {
             p->active->set_tunnel_bypass();
             codec_data.tunnel_bypass = false;
         }
 
-        if ( codec_data.codec_flags & CODEC_ETHER_NEXT )
+        // Sanity check the next protocol ID is a valid ethertype
+        if (codec_data.codec_flags & CODEC_ETHER_NEXT)
         {
-            if ( codec_data.next_prot_id < ProtocolId::ETHERTYPE_MINIMUM )
+            if (codec_data.next_prot_id < ProtocolId::ETHERTYPE_MINIMUM)
             {
                 DetectionEngine::queue_event(GID_DECODE, DECODE_BAD_ETHER_TYPE);
                 break;
@@ -202,125 +336,39 @@ void PacketManager::decode(
             codec_data.codec_flags &= ~CODEC_SAVE_LAYER;
             unsure_encap_ptrs = p->ptrs;
         }
-        else
-        {
+        else if (codec_data.codec_flags & CODEC_UNSURE_ENCAP)
             codec_data.codec_flags &= ~CODEC_UNSURE_ENCAP;
-        }
-
-        if (codec_data.proto_bits & (PROTO_BIT__IP | PROTO_BIT__IP6_EXT))
-        {
-            // FIXIT-M refactor when ip_proto's become an array
-            if ( p->is_fragment() )
-            {
-                if ( prev_prot_id == ProtocolId::FRAGMENT )
-                {
-                    const ip::IP6Frag* const fragh =
-                        reinterpret_cast<const ip::IP6Frag*>(raw.data);
-                    p->ip_proto_next = fragh->next();
-                }
-                else
-                {
-                    p->ip_proto_next = p->ptrs.ip_api.get_ip4h()->proto();
-                }
-            }
-            else
-            {
-                if(codec_data.next_prot_id != ProtocolId::FINISHED_DECODE)
-                    p->ip_proto_next = convert_protocolid_to_ipprotocol(codec_data.next_prot_id);
-            }
-        }
-
-        // If we have reached the MAX_LAYERS, we keep decoding
-        // but no longer keep track of the layers.
-        if ( p->num_layers == CodecManager::max_layers )
-            DetectionEngine::queue_event(GID_DECODE, DECODE_TOO_MANY_LAYERS);
-        else
-        {
-            push_layer(p, prev_prot_id, raw.data, codec_data.lyr_len);
-
-            // Cache the index of the vlan layer for quick access.
-            if ( codec_data.proto_bits == PROTO_BIT__VLAN )
-                p->vlan_idx = p->num_layers-1;
-        }
 
         // internal statistics and record keeping
         s_stats[mapped_prot + stat_offset]++; // add correct decode for previous layer
         mapped_prot = CodecManager::s_proto_map[to_utype(codec_data.next_prot_id)];
         prev_prot_id = codec_data.next_prot_id;
 
-        // set for next call
+        // Shrink the buffer of undecoded data
         const uint16_t curr_lyr_len = codec_data.lyr_len + codec_data.invalid_bytes;
         assert(curr_lyr_len <= raw.len);
         raw.len -= curr_lyr_len;
         raw.data += curr_lyr_len;
+
         p->proto_bits |= codec_data.proto_bits;
+
+        // Reset the volatile part of the codec data for the next codec to decode into
         codec_data.next_prot_id = ProtocolId::FINISHED_DECODE;
         codec_data.lyr_len = 0;
         codec_data.invalid_bytes = 0;
         codec_data.proto_bits = 0;
     }
 
-    debug_logf(decode_trace, nullptr, "Codec %s (protocol_id: %hu) ip header"
-        " starts at: %p, length is %lu\n",
-        CodecManager::s_protocols[mapped_prot]->get_name(),
-        static_cast<uint16_t>(prev_prot_id), pkt, (unsigned long)codec_data.lyr_len);
+    debug_logf(decode_trace, nullptr, "Payload starts at %u, length is %u\n", pktlen - raw.len, raw.len);
 
-    if ( p->num_layers > 0 )
+    if (p->num_layers > 0)
         s_stats[mapped_prot + stat_offset]++;
 
     // if the final protocol ID is not the default codec, a Codec failed
-    if (prev_prot_id != ProtocolId::FINISHED_DECODE or p->num_layers == 0 )
-    {
-        if (codec_data.codec_flags & CODEC_UNSURE_ENCAP)
-        {
-            p->ptrs = unsure_encap_ptrs;
+    if (prev_prot_id != ProtocolId::FINISHED_DECODE || p->num_layers == 0 )
+        handle_decode_failure(p, raw, codec_data, unsure_encap_ptrs, prev_prot_id);
 
-            switch (p->layers[p->num_layers-1].prot_id)
-            {
-            case ProtocolId::ESP:
-                // Hardcoding ESP because we trust iff the layer
-                // immediately preceding the fail is ESP.
-                p->ptrs.decode_flags |= DECODE_PKT_TRUST;
-                break;
-
-            case ProtocolId::TEREDO:
-                // if we just decoded teredo and the next
-                // layer fails, we made a mistake. Therefore,
-                // remove this bit.
-                pop_teredo(p, raw);
-                break;
-            default:
-                ;
-            } /* switch */
-        }
-        else
-        {
-            if ( (p->num_layers > 0) &&
-                (p->layers[p->num_layers-1].prot_id == ProtocolId::TEREDO) &&
-                (prev_prot_id == ProtocolId::IPV6) )
-            {
-                pop_teredo(p, raw);
-            }
-
-            // if the codec exists, it failed
-            if (CodecManager::s_proto_map[to_utype(prev_prot_id)])
-            {
-                s_stats[discards]++;
-            }
-            else
-            {
-                s_stats[other_codecs]++;
-
-                if ( (to_utype(ProtocolId::MIN_UNASSIGNED_IP_PROTO) <= to_utype(prev_prot_id)) &&
-                    (to_utype(prev_prot_id) <= std::numeric_limits<uint8_t>::max()) )
-                {
-                    DetectionEngine::queue_event(GID_DECODE, DECODE_IP_UNASSIGNED_PROTO);
-                }
-            }
-        }
-    }
-
-    if ( payload_offset_from_daq_mismatch(pkt, raw) )
+    if (payload_offset_from_daq_mismatch(pkt, raw))
         p->active->set_tunnel_bypass();
 
     // set any final Packet fields
@@ -328,7 +376,7 @@ void PacketManager::decode(
     p->dsize = (uint16_t)raw.len;
     p->proto_bits |= codec_data.proto_bits;
 
-    if ( !p->proto_bits )
+    if (!p->proto_bits)
         p->proto_bits = PROTO_BIT__OTHER;
 }
 
@@ -419,12 +467,9 @@ bool PacketManager::encode(const Packet* p,
         for (int i = outer_layer; i > inner_layer; --i)
         {
             const Layer& l = lyrs[i];
-            ProtocolIndex mapped_prot =
-                i ? CodecManager::s_proto_map[to_utype(l.prot_id)] : CodecManager::grinder;
-            if (!CodecManager::s_protocols[mapped_prot]->encode(l.start, l.length, enc, buf, p->flow))
-            {
+            Codec* cd = get_layer_codec(l, i);
+            if (!cd->encode(l.start, l.length, enc, buf, p->flow))
                 return false;
-            }
         }
         outer_layer = inner_layer;
         // inner_layer is set in 'layer::set_inner_ip_api'
@@ -436,13 +481,9 @@ bool PacketManager::encode(const Packet* p,
     for (int i = outer_layer; i >= 0; --i)
     {
         const Layer& l = lyrs[i];
-        ProtocolIndex mapped_prot =
-            i ? CodecManager::s_proto_map[to_utype(l.prot_id)] : CodecManager::grinder;
-
-        if (!CodecManager::s_protocols[mapped_prot]->encode(l.start, l.length, enc, buf, p->flow))
-        {
+        Codec* cd = get_layer_codec(l, i);
+        if (!cd->encode(l.start, l.length, enc, buf, p->flow))
             return false;
-        }
     }
 
     return true;
@@ -719,7 +760,7 @@ int PacketManager::encode_format(
     init_daq_pkthdr(p, c, phdr, opaque);
 
     // copy raw packet data to clone
-    Layer* lyr = (Layer*)p->layers + num_layers - 1;
+    Layer* lyr = &p->layers[num_layers - 1];
     int len = lyr->start - p->pkt + lyr->length;
     memcpy((void*)c->pkt, p->pkt, len);
 
@@ -729,7 +770,7 @@ int PacketManager::encode_format(
     for ( int i = 0; i < num_layers; i++ )
     {
         const uint8_t* b = c->pkt + (p->layers[i].start - p->pkt); // == c->pkt + p->layers[i].len
-        lyr = c->layers + i;
+        lyr = &c->layers[i];
 
         lyr->prot_id = p->layers[i].prot_id;
         lyr->length = p->layers[i].length;
@@ -737,16 +778,13 @@ int PacketManager::encode_format(
 
         // NOTE: this must always go from outer to inner
         //       to ensure a valid ip header
-        ProtocolIndex mapped_prot =
-            i ? CodecManager::s_proto_map[to_utype(lyr->prot_id)] : CodecManager::grinder;
-
-        CodecManager::s_protocols[mapped_prot]->format(
-            reverse, const_cast<uint8_t*>(lyr->start), c->ptrs);
+        Codec* cd = get_layer_codec(*lyr, i);
+        cd->format(reverse, const_cast<uint8_t*>(lyr->start), c->ptrs);
     }
 
     if ( update_ip4_len )
     {
-        lyr = (Layer*)c->layers + num_layers - 1;
+        lyr = &c->layers[num_layers - 1];
         ip::IP4Hdr* ip4h = reinterpret_cast<ip::IP4Hdr*>(const_cast<uint8_t*>(lyr->start));
         lyr->length = ip::IP4_HEADER_LEN;
         ip4h->set_ip_len(ip::IP4_HEADER_LEN);
@@ -818,11 +856,8 @@ void PacketManager::encode_update(Packet* p)
         for (int i = outer_layer; i > inner_layer; --i)
         {
             const Layer& l = lyr[i];
-            ProtocolIndex mapped_prot = i ?
-                CodecManager::s_proto_map[to_utype(l.prot_id)] : CodecManager::grinder;
-
-            CodecManager::s_protocols[mapped_prot]->update(
-                tmp_api, flags, const_cast<uint8_t*>(l.start), l.length, len);
+            Codec* cd = get_layer_codec(l, i);
+            cd->update(tmp_api, flags, const_cast<uint8_t*>(l.start), l.length, len);
         }
         outer_layer = inner_layer;
         // inner_layer is set in 'layer::set_inner_ip_api'
@@ -870,7 +905,7 @@ void PacketManager::dump_stats()
     std::vector<const char*> pkt_names;
 
     // zero out the default codecs
-    g_stats[3] = 0;
+    g_stats[stat_offset] = 0;
     g_stats[CodecManager::s_proto_map[to_utype(ProtocolId::FINISHED_DECODE)] + stat_offset] = 0;
 
     for (unsigned int i = 0; i < stat_names.size(); i++)
@@ -913,20 +948,24 @@ void PacketManager::log_protocols(TextLog* const text_log,
 
     if (num_layers != 0)
     {
-        // Grinder is not in the layer array
-        Codec* cd = CodecManager::s_protocols[CodecManager::grinder];
-
-        TextLog_Print(text_log, "%-.6s(DLT):  ", cd->get_name());
-        cd->log(text_log, lyr[0].start, lyr[0].length);
+        int i = 0;
+        // Special case for root codecs not registering a protocol ID
+        if (lyr[0].prot_id == CodecManager::grinder_id || lyr[0].prot_id == ProtocolId::FINISHED_DECODE)
+        {
+            Codec* cd = CodecManager::s_protocols[CodecManager::grinder];
+            TextLog_Print(text_log, "%s(DLT):  ", cd->get_name());
+            cd->log(text_log, lyr[0].start, lyr[0].length);
+            i++;
+        }
 
-        for (int i = 1; i < num_layers; i++)
+        for (; i < num_layers; i++)
         {
             const auto protocol = to_utype(lyr[i].prot_id);
             const uint8_t codec_offset =  CodecManager::s_proto_map[protocol];
-            cd = CodecManager::s_protocols[codec_offset];
+            Codec* cd = CodecManager::s_protocols[codec_offset];
 
             TextLog_NewLine(text_log);
-            TextLog_Print(text_log, "%-.*s", 6, cd->get_name());
+            TextLog_Print(text_log, "%s", cd->get_name());
 
             if (protocol <= 0xFF)
                 TextLog_Print(text_log, "(0x%02x)", protocol);
index c9b395ddcb5ef205cc2f4f9f9254f59190772bd0..27e85c552a5bc3d52539ec92c8d7b03978238135 100644 (file)
@@ -134,11 +134,13 @@ public:
     static ProtocolIndex proto_idx(ProtocolId prot_id)
     { return CodecManager::s_proto_map[to_utype(prot_id)]; }
 
-private:
-    // The only time we should accumulate is when CodecManager tells us too
-    friend void CodecManager::thread_term();
     static void accumulate();
+
+private:
+    static bool push_layer(Packet*, CodecData&, ProtocolId, const uint8_t* hdr_start, uint32_t len);
+    static Codec* get_layer_codec(const Layer&, int idx);
     static void pop_teredo(Packet*, RawData&);
+    static void handle_decode_failure(Packet*, RawData&, const CodecData&, const DecodeData&, ProtocolId);
 
     static bool encode(const Packet*, EncodeFlags,
         uint8_t lyr_start, IpProtocol next_prot, Buffer& buf);
@@ -148,7 +150,8 @@ private:
     static const uint8_t total_processed = 0;
     static const uint8_t other_codecs = 1;
     static const uint8_t discards = 2;
-    static const uint8_t stat_offset = 3;
+    static const uint8_t depth_exceeded = 3;
+    static const uint8_t stat_offset = 4;
 
     // declared in header so it can access s_protocols
     static THREAD_LOCAL std::array<PegCount, stat_offset +
index a65f5d11fc4f30dda581e7a2df2298c8a065f2ba..ce9665c2d7c4cbb0d53fbe1113df3a127c64045f 100644 (file)
@@ -22,6 +22,8 @@
 
 #include <cstdint>
 
+namespace snort
+{
 namespace teredo
 {
 constexpr uint16_t TEREDO_PORT = 3544;
@@ -34,6 +36,7 @@ constexpr uint16_t MIN_HDR_LEN = 2;
 inline bool is_teredo_port(uint16_t port)
 { return port == TEREDO_PORT; }
 } // namespace teredo
+} // namespace snort
 
 #endif
 
index 93d6759dd67baaea9e87688ee9ab26057e585034..b435c76f3c8f0b83cd57e7ee722b912aa84a28bf 100644 (file)
@@ -24,6 +24,8 @@
 
 #include "protocols/protocol_ids.h"
 
+namespace snort
+{
 namespace token_ring
 {
 /* LLC structure */
@@ -98,6 +100,7 @@ inline const Trh_mr* get_trhmr(const Trh_llc* llc)
     return nullptr;
 }
 } // namespace token_ring
+} // namespace snort
 
 #endif
 
index 6b120188ca5b20bed69ac3d7ace2aaadc5fce3e0..3de53910cc5fd9b171e9d0096b84b13193fe47f0 100644 (file)
 using namespace snort;
 using namespace std;
 
-SnortProtocolId ProtocolReference::get_count()
+SnortProtocolId ProtocolReference::get_count() const
 { return protocol_number; }
 
-const char* ProtocolReference::get_name(SnortProtocolId id)
+const char* ProtocolReference::get_name(SnortProtocolId id) const
 {
     if ( id >= id_map.size() )
         id = 0;
@@ -86,7 +86,7 @@ SnortProtocolId ProtocolReference::add(const char* protocol)
     return snort_protocol_id;
 }
 
-SnortProtocolId ProtocolReference::find(const char* protocol)
+SnortProtocolId ProtocolReference::find(const char* protocol) const
 {
     auto protocol_ref = ref_table.find(protocol);
     if ( protocol_ref != ref_table.end() )
@@ -95,7 +95,7 @@ SnortProtocolId ProtocolReference::find(const char* protocol)
     return UNKNOWN_PROTOCOL_ID;
 }
 
-void ProtocolReference::init(ProtocolReference* old_proto_ref)
+void ProtocolReference::init(const ProtocolReference* old_proto_ref)
 {
     if ( !old_proto_ref )
     {
@@ -109,7 +109,7 @@ void ProtocolReference::init(ProtocolReference* old_proto_ref)
     }
     else
     {
-        for(SnortProtocolId id = 0; id < old_proto_ref->get_count(); id++)
+        for (SnortProtocolId id = 0; id < old_proto_ref->get_count(); id++)
             add(old_proto_ref->get_name(id));
     }
 }
index 74c1d3836df83beed8805f6c841754d1ed9bbb1f..4cb40859217a0b0efad4da8ef24028f0e697410f 100644 (file)
@@ -70,13 +70,13 @@ public:
     ProtocolReference(const ProtocolReference&)  = delete;
     ProtocolReference& operator=(const ProtocolReference&)  = delete;
 
-    SnortProtocolId get_count();
+    SnortProtocolId get_count() const;
 
-    const char* get_name(SnortProtocolId id);
+    const char* get_name(SnortProtocolId id) const;
     const char* get_name_sorted(SnortProtocolId id);
 
     SnortProtocolId add(const char* protocol);
-    SnortProtocolId find(const char* protocol);
+    SnortProtocolId find(const char* protocol) const;
 
     bool operator()(SnortProtocolId a, SnortProtocolId b);
 
@@ -87,7 +87,7 @@ private:
 
     SnortProtocolId protocol_number = 0;
 
-    void init(ProtocolReference* old_proto_ref);
+    void init(const ProtocolReference* old_proto_ref);
 };
 }
 #endif