]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #3683: Cip appid support on snort3
authorSreeja Athirkandathil Narayanan (sathirka) <sathirka@cisco.com>
Tue, 10 Jan 2023 15:27:09 +0000 (15:27 +0000)
committerSreeja Athirkandathil Narayanan (sathirka) <sathirka@cisco.com>
Tue, 10 Jan 2023 15:27:09 +0000 (15:27 +0000)
Merge in SNORT/snort3 from ~SUBALU/snort3:Cip_Appid to master

Squashed commit of the following:

commit 4de25c9be46823b572bc9a40365966eb587ad4a4
Author: suriya <subalu@cisco.com>
Date:   Mon Dec 19 17:51:22 2022 +0530

    appid: add support for cip service, client and payload detection

20 files changed:
src/network_inspectors/appid/CMakeLists.txt
src/network_inspectors/appid/appid_api.cc
src/network_inspectors/appid/appid_cip_event_handler.cc [new file with mode: 0644]
src/network_inspectors/appid/appid_cip_event_handler.h [new file with mode: 0644]
src/network_inspectors/appid/appid_config.cc
src/network_inspectors/appid/appid_config.h
src/network_inspectors/appid/appid_inspector.cc
src/network_inspectors/appid/application_ids.h
src/network_inspectors/appid/detector_plugins/cip_patterns.cc [new file with mode: 0644]
src/network_inspectors/appid/detector_plugins/cip_patterns.h [new file with mode: 0644]
src/network_inspectors/appid/detector_plugins/test/detector_sip_test.cc
src/network_inspectors/appid/detector_plugins/test/http_url_patterns_test.cc
src/network_inspectors/appid/lua_detector_api.cc
src/network_inspectors/appid/service_plugins/test/service_plugin_mock.h
src/network_inspectors/appid/test/appid_discovery_test.cc
src/network_inspectors/appid/test/appid_mock_definitions.h
src/network_inspectors/appid/test/service_state_test.cc
src/network_inspectors/appid/test/tp_lib_handler_test.cc
src/pub_sub/cip_events.cc
src/pub_sub/cip_events.h

index 894aa910ac8e8e702f372b35ec2a328d7db1a397..6d2afd949cd768777d54f8e5d0974a0b2caaacf9 100644 (file)
@@ -105,6 +105,8 @@ set ( SP_APPID_SOURCES
 )
 
 set ( DP_APPID_SOURCES
+    detector_plugins/cip_patterns.cc
+    detector_plugins/cip_patterns.h
     detector_plugins/detector_dns.cc
     detector_plugins/detector_dns.h
     detector_plugins/detector_imap.cc
@@ -144,6 +146,8 @@ set ( APPID_SOURCES
     appid_app_descriptor.h
     appid_config.cc
     appid_config.h
+    appid_cip_event_handler.cc
+    appid_cip_event_handler.h
     appid_data_decrypt_event_handler.h
     appid_debug.cc
     appid_debug.h
index 9e6a367adfc0160f7dd63f861ec5bc72c2cc7129..f06316261361bbaaad384091b0109fd757cdffd5 100644 (file)
@@ -261,7 +261,8 @@ bool AppIdApi::is_inspection_needed(const Inspector& inspector) const
 
     SnortProtocolId id = inspector.get_service();
     const AppIdConfig& config = appid_inspector->get_ctxt().config;
-    if (id == config.snort_proto_ids[PROTO_INDEX_HTTP2] or id == config.snort_proto_ids[PROTO_INDEX_SSH])
+    if (id == config.snort_proto_ids[PROTO_INDEX_HTTP2] or id == config.snort_proto_ids[PROTO_INDEX_SSH]
+           or id == config.snort_proto_ids[PROTO_INDEX_CIP])
         return true;
 
     return false;
diff --git a/src/network_inspectors/appid/appid_cip_event_handler.cc b/src/network_inspectors/appid/appid_cip_event_handler.cc
new file mode 100644 (file)
index 0000000..9ef7c54
--- /dev/null
@@ -0,0 +1,107 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2023-2023 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.
+// --------------------------------------------------------------------------------
+// appid_cip_event_handler.cc author Suriya Balu <subalu@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "appid_cip_event_handler.h"
+#include "detector_plugins/cip_patterns.h"
+#include "appid_debug.h"
+
+using namespace snort;
+
+void CipEventHandler::client_handler(AppIdSession& asd)
+{
+    asd.set_client_id(APP_ID_CIP);
+    asd.set_client_detected();
+    asd.client_inferred_service_id = APP_ID_CIP;
+}
+
+void CipEventHandler::service_handler(const Packet& p, AppIdSession& asd)
+{
+    int16_t group;
+    uint16_t port;
+    const SfIp* ip;
+
+    if (p.is_from_client())
+    {
+        ip = p.ptrs.ip_api.get_dst();
+        port = p.ptrs.dp;
+        group = p.get_egress_group();
+    }
+    else
+    {
+        ip = p.ptrs.ip_api.get_src();
+        port = p.ptrs.sp;
+        group = p.get_ingress_group();
+    }
+
+    asd.set_server_info(*ip, port, group);
+    asd.set_service_id(APP_ID_CIP, asd.get_odp_ctxt());
+    asd.set_service_detected();        
+}
+
+void CipEventHandler::handle(DataEvent& event, Flow* flow)
+{
+    if (!flow)
+        return;
+
+    AppIdSession* asd = appid_api.get_appid_session(*flow);
+
+    if (!asd)
+        return;
+
+    if (!pkt_thread_odp_ctxt or (asd->get_odp_ctxt_version() != pkt_thread_odp_ctxt->get_version()))
+        return; 
+
+    if (!asd->get_session_flags(APPID_SESSION_DISCOVER_APP | APPID_SESSION_SPECIAL_MONITORED))
+        return;
+
+    CipEvent& cip_event = (CipEvent&)event;
+    const CipEventData* event_data = cip_event.get_event_data();
+
+    if (!event_data)
+        return;
+
+    const Packet* p = cip_event.get_packet();
+    assert(p);
+
+    AppidChangeBits change_bits;
+    client_handler(*asd);
+    service_handler(*p, *asd);
+    AppId payload_id = asd->get_odp_ctxt().get_cip_matchers().get_cip_payload_id(event_data);
+    asd->set_payload_id(payload_id);
+    asd->set_ss_application_ids(APP_ID_CIP, APP_ID_CIP, payload_id, APP_ID_NONE, APP_ID_NONE, change_bits);
+   
+    if (change_bits[APPID_PAYLOAD_BIT] and appidDebug->is_enabled())
+    {
+        appidDebug->activate(flow, asd, inspector.get_ctxt().config.log_all_sessions);
+        if (appidDebug->is_active())
+        {
+            const char* app_name_service = asd->get_odp_ctxt().get_app_info_mgr().get_app_name(APP_ID_CIP);
+            const char* app_name_payload = asd->get_odp_ctxt().get_app_info_mgr().get_app_name(payload_id);
+            LogMessage("AppIdDbg %s CIP event handler service %s (%d) and payload %s (%d) are detected\n",
+                appidDebug->get_debug_session(), app_name_service, APP_ID_CIP, app_name_payload, payload_id);
+        }
+    }
+
+    asd->publish_appid_event(change_bits, *p);
+}
diff --git a/src/network_inspectors/appid/appid_cip_event_handler.h b/src/network_inspectors/appid/appid_cip_event_handler.h
new file mode 100644 (file)
index 0000000..5e21199
--- /dev/null
@@ -0,0 +1,44 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2023-2023 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.
+// --------------------------------------------------------------------------------
+// appid_cip_event_handler.h author Suriya Balu <subalu@cisco.com>
+
+#ifndef APPID_CIP_EVENT_HANDLER_H
+#define APPID_CIP_EVENT_HANDLER_H
+
+#include "pub_sub/cip_events.h"
+#include "appid_detector.h"
+#include "appid_inspector.h"
+
+class CipEventHandler : public snort::DataHandler
+{
+public:
+    CipEventHandler(AppIdInspector& inspector) :
+        DataHandler(MOD_NAME), inspector(inspector)
+    { }
+
+    void handle(snort::DataEvent&, snort::Flow*) override;
+
+private:
+    void client_handler(AppIdSession&);
+    void service_handler(const snort::Packet&, AppIdSession&);
+
+    AppIdInspector& inspector;
+};
+
+#endif //APPID_CIP_EVENT_HANDLER_H
index 7af81f52bdebea695199ee0d37ecda46102bdd1e..f51ee69b5cf83bf21fab4724b0d983c724eca5b9 100644 (file)
@@ -63,6 +63,7 @@ static void map_app_names_to_snort_ids(SnortConfig* sc, AppIdConfig& config)
     config.snort_proto_ids[PROTO_INDEX_TFTP] = sc->proto_ref->add("tftp");
     config.snort_proto_ids[PROTO_INDEX_SIP] = sc->proto_ref->add("sip");
     config.snort_proto_ids[PROTO_INDEX_SSH] = sc->proto_ref->add("ssh");
+    config.snort_proto_ids[PROTO_INDEX_CIP] = sc->proto_ref->add("cip");
 }
 
 AppIdConfig::~AppIdConfig()
index a0ec848fcf49087e2bba67575d65057bc287ceb8..ddd8539a4141e2bbc341310b359e53c316c69e2a 100644 (file)
@@ -31,6 +31,7 @@
 #include "app_info_table.h"
 #include "client_plugins/client_discovery.h"
 #include "client_plugins/eve_ca_patterns.h"
+#include "detector_plugins/cip_patterns.h"
 #include "detector_plugins/dns_patterns.h"
 #include "detector_plugins/http_url_patterns.h"
 #include "detector_plugins/sip_patterns.h"
@@ -63,6 +64,7 @@ enum SnortProtoIdIndex
     PROTO_INDEX_TFTP,
     PROTO_INDEX_SIP,
     PROTO_INDEX_SSH,
+    PROTO_INDEX_CIP,
 
     PROTO_INDEX_MAX
 };
@@ -188,6 +190,11 @@ public:
         return length_cache.add(key, val);
     }
 
+    CipPatternMatchers& get_cip_matchers()
+    {
+        return cip_matchers;
+    }
+
     DnsPatternMatchers& get_dns_matchers()
     {
         return dns_matchers;
@@ -244,6 +251,7 @@ private:
     HostPortCache host_port_cache;
     HostPortCache first_pkt_cache;
     LengthCache length_cache;
+    CipPatternMatchers cip_matchers;
     DnsPatternMatchers dns_matchers;
     HttpPatternMatchers http_matchers;
     EveCaPatternMatchers eve_ca_matchers;
index ba24f89f9318b0ff1d7fe518329ac2fa1171db32..df5cd3372617c98512be8de235e57912982f0149 100644 (file)
@@ -36,6 +36,7 @@
 #include "pub_sub/appid_event_ids.h"
 #include "pub_sub/intrinsic_event_ids.h"
 
+#include "appid_cip_event_handler.h"
 #include "appid_data_decrypt_event_handler.h"
 #include "appid_dcerpc_event_handler.h"
 #include "appid_debug.h"
@@ -128,6 +129,7 @@ bool AppIdInspector::configure(SnortConfig* sc)
     DataBus::subscribe_global(sip_pub_key, SipEventIds::DIALOG, new SipEventHandler(*this), *sc);
     DataBus::subscribe_global(dce_tcp_pub_key, DceTcpEventIds::EXP_SESSION, new DceExpSsnEventHandler(), *sc);
     DataBus::subscribe_global(ssh_pub_key, SshEventIds::STATE_CHANGE, new SshEventHandler(), *sc);
+    DataBus::subscribe_global(cip_pub_key, CipEventIds::DATA, new CipEventHandler(*this), *sc);
     DataBus::subscribe_global(external_pub_key, ExternalEventIds::DATA_DECRYPT, new DataDecryptEventHandler(), *sc);
 
     DataBus::subscribe_global(external_pub_key, ExternalEventIds::EVE_PROCESS,
index c9223a05afc15a03d92fff8909e2246a161a9040..d77b712154cac0110d726a284367fd70bdb7d091 100644 (file)
@@ -1017,6 +1017,10 @@ enum ApplicationIds : AppId
     APP_ID_SMB_VERSION_3                  = 4647,
     APP_ID_HTTP3                          = 4667,
     APP_ID_SMB_OVER_QUIC                  = 4668,
+    APP_ID_ENIP                           = 5001,
+    APP_ID_CIP                            = 5002,
+    APP_ID_CIP_UNKNOWN                    = 5003,
+    APP_ID_CIP_MALFORMED                  = 5005,
 #ifdef REG_TEST
     APP_ID_DNS_OVER_TLS                   = 4615,
     APP_ID_REGTEST                        = 10000,
diff --git a/src/network_inspectors/appid/detector_plugins/cip_patterns.cc b/src/network_inspectors/appid/detector_plugins/cip_patterns.cc
new file mode 100644 (file)
index 0000000..26e9862
--- /dev/null
@@ -0,0 +1,356 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2023-2023 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.
+// --------------------------------------------------------------------------------
+// cip_patterns.cc author Suriya Balu <subalu@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cip_patterns.h"
+#include "service_inspectors/cip/cip.h"              
+#include "utils/util.h"
+
+using namespace snort;
+
+void CipPatternMatchers::cip_add_enip_command(AppId app_id, uint16_t command_id)
+{
+    EnipCommandList* pattern = (EnipCommandList*)snort_calloc(sizeof(EnipCommandList));
+    if (!pattern)
+    {
+        return;
+    }
+
+    pattern->data.app_id = app_id;
+    pattern->data.command_id = command_id;
+
+    pattern->next = enip_command_list;
+    enip_command_list = pattern;
+}
+
+void CipPatternMatchers::cip_add_path(AppId app_id, uint32_t class_id, uint8_t service_id)
+{
+    CipPathList* pattern = (CipPathList*)snort_calloc(sizeof(CipPathList));
+    if (!pattern)
+    {
+        return;
+    }
+
+    pattern->data.app_id = app_id;
+    pattern->data.class_id = class_id;
+    pattern->data.service_id = service_id;
+
+    pattern->next = path_list;
+    path_list = pattern;
+}
+
+void CipPatternMatchers::cip_add_set_attribute(AppId app_id, uint32_t class_id, bool is_class_instance, 
+    uint32_t attribute_id)
+{
+    CipSetAttributeList* pattern = (CipSetAttributeList*)snort_calloc(sizeof(CipSetAttributeList));
+    if (!pattern)
+    {
+        return;
+    }
+
+    pattern->data.app_id = app_id;
+    pattern->data.class_id = class_id;
+    pattern->data.is_class_instance = is_class_instance;
+    pattern->data.attribute_id = attribute_id;
+
+    pattern->next = set_attribute_list;
+    set_attribute_list = pattern;
+} 
+
+void CipPatternMatchers::cip_add_connection_class(AppId app_id, uint32_t class_id)
+{
+    CipConnectionClassList* pattern = (CipConnectionClassList*)snort_calloc(sizeof(CipConnectionClassList));
+    if (!pattern)
+    {
+        return;
+    }
+
+    pattern->data.app_id = app_id;
+    pattern->data.class_id = class_id;
+
+    pattern->next = connection_list;
+    connection_list = pattern;
+}
+
+void CipPatternMatchers::cip_add_extended_symbol_service(AppId app_id, uint8_t service_id)
+{
+    CipServiceList* pattern = (CipServiceList*)snort_calloc(sizeof(CipServiceList));
+    if (!pattern)
+    {
+        return;
+    }
+
+    pattern->data.app_id = app_id;
+    pattern->data.service_id = service_id;
+
+    pattern->next = symbol_list;
+    symbol_list = pattern;
+}
+
+void CipPatternMatchers::cip_add_service(AppId app_id, uint8_t service_id)
+{
+    CipServiceList* pattern = (CipServiceList*)snort_calloc(sizeof(CipServiceList));
+    if (!pattern)
+    {
+        return;
+    }
+
+    pattern->data.app_id = app_id;
+    pattern->data.service_id = service_id;
+
+    pattern->next = service_list;
+    service_list = pattern;
+}
+
+static AppId match_enip_command(const EnipCommandList* enip_command_list, const CipEventData* event_data)
+{
+    AppId found_app_id = APP_ID_ENIP;
+
+    while (enip_command_list)
+    {
+        if (event_data->enip_command_id == enip_command_list->data.command_id)
+        {
+            found_app_id = enip_command_list->data.app_id;
+            break;
+        }
+
+        enip_command_list = enip_command_list->next;
+    }
+
+    return found_app_id;
+}
+
+static AppId match_cip_service(const CipServiceList* service_list, const CipEventData* event_data)
+{
+    AppId found_app_id = APP_ID_CIP_UNKNOWN;
+
+    while (service_list)
+    {
+        if (event_data->service_id == service_list->data.service_id)
+        {
+            found_app_id = service_list->data.app_id;
+            break;
+        }
+
+        service_list = service_list->next;
+    }
+
+    return found_app_id;
+}
+
+static AppId match_cip_path(const CipPathList* path_list, const CipEventData* event_data)
+{
+    AppId found_app_id = APP_ID_CIP_UNKNOWN;
+
+    while (path_list)
+    {
+        if ((event_data->class_id == path_list->data.class_id)
+            and (event_data->service_id == path_list->data.service_id))
+        {
+            found_app_id = path_list->data.app_id;
+            break;
+        }
+
+        path_list = path_list->next;
+    }
+
+    return found_app_id;
+}
+
+static AppId match_cip_set_attribute(const CipSetAttributeList* set_attribute_list, const CipEventData* event_data)
+{
+    AppId found_app_id = APP_ID_CIP_UNKNOWN;
+
+    bool is_class_instance = (event_data->instance_id == 0);
+
+    while (set_attribute_list)
+    {
+        if ((event_data->class_id == set_attribute_list->data.class_id)
+            and (is_class_instance == set_attribute_list->data.is_class_instance)
+            and (event_data->attribute_id == set_attribute_list->data.attribute_id))
+        {
+            found_app_id = set_attribute_list->data.app_id;
+            break;
+        }
+
+        set_attribute_list = set_attribute_list->next;
+    }
+
+    return found_app_id;
+}
+
+static AppId match_cip_connection(const CipConnectionClassList* connection_list, const CipEventData* event_data)
+{
+    AppId found_app_id = APP_ID_CIP_UNKNOWN;
+
+    while (connection_list)
+    {
+        if (event_data->class_id == connection_list->data.class_id)
+        {
+            found_app_id = connection_list->data.app_id;
+            break;
+        }
+
+        connection_list = connection_list->next;
+    }
+
+    return found_app_id;
+}
+
+AppId CipPatternMatchers::get_cip_payload_id(const CipEventData* event_data)
+{
+    AppId found_app_id = APP_ID_CIP_UNKNOWN;
+
+    switch (event_data->type)
+    {
+    case CIP_DATA_TYPE_PATH_CLASS:
+        found_app_id = match_cip_path(path_list, event_data);
+
+        if (found_app_id == APP_ID_CIP_UNKNOWN)
+        {
+            found_app_id = match_cip_service(service_list, event_data);
+        }
+        break;
+
+    case CIP_DATA_TYPE_PATH_EXT_SYMBOL:
+        found_app_id = match_cip_service(symbol_list, event_data);
+
+        if (found_app_id == APP_ID_CIP_UNKNOWN)
+        {
+            found_app_id = match_cip_service(service_list, event_data);
+        }
+        break;
+
+    case CIP_DATA_TYPE_SET_ATTRIBUTE:
+        found_app_id = match_cip_set_attribute(set_attribute_list, event_data);
+
+        if (found_app_id == APP_ID_CIP_UNKNOWN)
+        {
+            found_app_id = match_cip_service(symbol_list, event_data);
+
+            if (found_app_id == APP_ID_CIP_UNKNOWN)
+            {
+                found_app_id = match_cip_service(service_list, event_data);
+            }
+        }
+        break;
+
+    case CIP_DATA_TYPE_CONNECTION:
+    case CIP_DATA_TYPE_IMPLICIT:
+        found_app_id = match_cip_connection(connection_list, event_data);
+        break;
+
+    case CIP_DATA_TYPE_MALFORMED:
+        found_app_id = APP_ID_CIP_MALFORMED;
+        break;
+
+    case CIP_DATA_TYPE_ENIP_COMMAND:
+        found_app_id = match_enip_command(enip_command_list, event_data);
+        break;
+
+    default:
+        break;
+    }
+    return found_app_id;
+}
+
+static void free_enip_command_list(EnipCommandList* enip_command_list)
+{
+    EnipCommandList* node;
+    for (node = enip_command_list; node != nullptr; node = enip_command_list)
+    {
+        enip_command_list = node->next;
+        snort_free(node);
+    }
+}
+
+static void free_cip_path_list(CipPathList* path_list)
+{
+    CipPathList* node;
+    for (node = path_list; node != nullptr; node = path_list)
+    {
+        path_list = node->next;
+        snort_free(node);
+    }
+}
+
+static void free_cip_set_attribute_list( CipSetAttributeList* set_attribute_list)
+{
+    CipSetAttributeList* node;
+    for (node = set_attribute_list; node != nullptr; node = set_attribute_list)
+    {
+        set_attribute_list = node->next;
+        snort_free(node);
+    }
+}
+
+static void free_cip_connection_class_list(CipConnectionClassList* connection_list)
+{
+    CipConnectionClassList* node;
+    for (node = connection_list; node != nullptr; node = connection_list)
+    {
+        connection_list = node->next;
+        snort_free(node);
+    }
+}
+
+static void free_cip_extended_symbol_service_list(CipServiceList* symbol_list)
+{
+    CipServiceList* node;
+    for (node = symbol_list; node != nullptr; node = symbol_list)
+    {
+        symbol_list = node->next;
+        snort_free(node);
+    }
+}
+
+static void free_cip_service_list(CipServiceList* service_list)
+{
+    CipServiceList* node;
+    for (node = service_list; node != nullptr; node = service_list)
+    {
+        service_list = node->next;
+        snort_free(node);
+    }
+}
+
+CipPatternMatchers::~CipPatternMatchers()
+{
+    free_enip_command_list(enip_command_list);
+    enip_command_list = nullptr;
+    
+    free_cip_path_list(path_list);
+    path_list = nullptr;
+    
+    free_cip_set_attribute_list(set_attribute_list);
+    set_attribute_list = nullptr;
+    
+    free_cip_connection_class_list(connection_list);
+    connection_list = nullptr;
+    
+    free_cip_extended_symbol_service_list(symbol_list);
+    symbol_list = nullptr;
+    
+    free_cip_service_list(service_list);
+    service_list = nullptr;
+}
diff --git a/src/network_inspectors/appid/detector_plugins/cip_patterns.h b/src/network_inspectors/appid/detector_plugins/cip_patterns.h
new file mode 100644 (file)
index 0000000..c3f4d22
--- /dev/null
@@ -0,0 +1,111 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2023-2023 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.
+// --------------------------------------------------------------------------------
+// cip_patterns.h author Suriya Balu <subalu@cisco.com>
+
+#ifndef CIP_PATTERN_H
+#define CIP_PATTERN_H
+
+#include "pub_sub/cip_events.h"
+#include "application_ids.h"
+
+struct EnipCommandData
+{
+    AppId app_id;
+    uint16_t command_id;
+} ;
+
+struct EnipCommandList
+{
+    EnipCommandData data;
+    struct EnipCommandList* next;
+} ;
+
+struct CipPathData
+{
+    AppId app_id;
+    uint32_t class_id;
+    uint8_t service_id;
+} ;
+
+struct CipPathList
+{
+    CipPathData data;
+    struct CipPathList* next;
+} ;
+
+struct CipSetAttributeData
+{
+    AppId app_id;
+    uint32_t class_id;
+    bool is_class_instance;
+    uint32_t attribute_id;
+} ;
+
+struct CipSetAttributeList
+{
+    CipSetAttributeData data;
+    struct CipSetAttributeList* next;
+} ;
+
+struct CipConnectionClassData
+{
+    AppId app_id;
+    uint32_t class_id;
+} ;
+
+struct CipConnectionClassList
+{
+    CipConnectionClassData data;
+    struct CipConnectionClassList* next;
+} ;
+
+struct CipServiceData
+{
+    AppId app_id;
+    uint8_t service_id;
+} ;
+
+struct CipServiceList
+{
+    CipServiceData data;
+    struct CipServiceList* next;
+} ;
+
+class CipPatternMatchers
+{
+public:
+    ~CipPatternMatchers();
+    void cip_add_enip_command(AppId app_id, uint16_t command_id);
+    void cip_add_path(AppId app_id, uint32_t class_id, uint8_t service_id);
+    void cip_add_set_attribute(AppId app_id, uint32_t class_id, bool is_class_instance, uint32_t attribute_id);
+    void cip_add_extended_symbol_service(AppId app_id, uint8_t service_id);
+    void cip_add_service(AppId app_id, uint8_t service_id);
+    void cip_add_connection_class(AppId app_id, uint32_t class_id);
+    AppId get_cip_payload_id(const CipEventData* event_data);
+
+private:
+    EnipCommandList* enip_command_list = nullptr;
+    CipPathList* path_list = nullptr;
+    CipSetAttributeList* set_attribute_list = nullptr;
+    CipConnectionClassList* connection_list = nullptr;
+    CipServiceList* symbol_list = nullptr;
+    CipServiceList* service_list = nullptr;
+} ;
+
+#endif  // CIP_PATTERN_H
index c1f38cfe8235e6cf14a9098e453e9fbedaba90ba..e6b7c6d00171063cb0a6c7f4ab4641ccc564bb40 100644 (file)
@@ -157,6 +157,7 @@ EveCaPatternMatchers::~EveCaPatternMatchers() = default;
 SslPatternMatchers::~SslPatternMatchers() = default;
 HttpPatternMatchers::~HttpPatternMatchers() = default;
 AlpnPatternMatchers::~AlpnPatternMatchers() = default;
+CipPatternMatchers::~CipPatternMatchers() = default;
 
 ClientDetector::ClientDetector() { }
 
index 303b9224b3b9d387f42ff182810e375be54fa004..f4ffa9a0cb2539c52e923db3f6f88a9bd6a3a25a 100644 (file)
@@ -88,6 +88,7 @@ EveCaPatternMatchers::~EveCaPatternMatchers() = default;
 SipPatternMatchers::~SipPatternMatchers() = default;
 SslPatternMatchers::~SslPatternMatchers() = default;
 AlpnPatternMatchers::~AlpnPatternMatchers() = default;
+CipPatternMatchers::~CipPatternMatchers() = default;
 void AppIdModule::reset_stats() {}
 bool AppIdInspector::configure(snort::SnortConfig*) { return true; }
 
index 0ef36d2d5684e2b9415347a87fafce6a94dd0df6..c55bb33c98751f38012ce6b7eb9d31a9f1541358 100644 (file)
@@ -41,6 +41,7 @@
 #include "appid_inspector.h"
 #include "appid_peg_counts.h"
 #include "client_plugins/client_discovery.h"
+#include "detector_plugins/cip_patterns.h"
 #include "detector_plugins/detector_dns.h"
 #include "detector_plugins/detector_pattern.h"
 #include "detector_plugins/detector_sip.h"
@@ -2186,7 +2187,7 @@ static int detector_add_rtmp_url(lua_State* L)
     return 0;
 }
 
-/*Lua should inject patterns in <clientAppId, clientVersion, multi-Pattern> format. */
+/*Lua should inject patterns in <client_id, clientVersion, multi-Pattern> format. */
 static int detector_add_sip_user_agent(lua_State* L)
 {
     auto& ud = *UserData<LuaObject>::check(L, DETECTOR, 1);
@@ -2547,7 +2548,7 @@ static int add_port_pattern_service(lua_State* L)
     return 0;
 }
 
-/*Lua should inject patterns in <clientAppId, clientVersion, multi-Pattern> format. */
+/*Lua should inject patterns in <client_id, clientVersion, multi-Pattern> format. */
 static int detector_add_sip_server(lua_State* L)
 {
     auto& ud = *UserData<LuaObject>::check(L, DETECTOR, 1);
@@ -2765,6 +2766,129 @@ static int get_http_tunneled_port(lua_State* L)
     return 1;
 }
 
+/*Lua should inject patterns in <client_id, class_id> format. */
+static int detector_add_cip_connection_class(lua_State *L)
+{
+    int index = 1;
+
+    auto& ud = *UserData<LuaObject>::check(L, DETECTOR, 1);
+    // Verify detector user data and that we are NOT in packet context
+    ud->validate_lua_state(false);
+    if (!init(L)) 
+        return 0;
+
+    uint32_t app_id = lua_tointeger(L, ++index);
+    uint32_t class_id = lua_tointeger(L, ++index);
+
+    ud->get_odp_ctxt().get_cip_matchers().cip_add_connection_class(app_id, class_id);
+    ud->get_odp_ctxt().get_app_info_mgr().set_app_info_active(app_id);
+
+    return 0;
+}
+
+/*Lua should inject patterns in <client_id, class_id, service_id> format. */
+static int detector_add_cip_path(lua_State *L)
+{
+    int index = 1;
+
+    auto& ud = *UserData<LuaObject>::check(L, DETECTOR, 1);
+    // Verify detector user data and that we are NOT in packet context
+    ud->validate_lua_state(false);
+    if (!init(L)) 
+        return 0;
+
+    uint32_t app_id = lua_tointeger(L, ++index);
+    uint32_t class_id = lua_tointeger(L, ++index);
+    uint8_t service_id = lua_tointeger(L, ++index);
+
+    ud->get_odp_ctxt().get_cip_matchers().cip_add_path(app_id, class_id, service_id);
+    ud->get_odp_ctxt().get_app_info_mgr().set_app_info_active(app_id);
+
+    return 0;
+}
+
+/*Lua should inject patterns in <client_id, class_id, is_class_instance, attribute_id> format. */
+static int detector_add_cip_set_attribute(lua_State *L)
+{
+    int index = 1;
+
+    auto& ud = *UserData<LuaObject>::check(L, DETECTOR, 1);
+    // Verify detector user data and that we are NOT in packet context
+    ud->validate_lua_state(false);
+    if (!init(L)) 
+        return 0;
+
+    uint32_t app_id = lua_tointeger(L, ++index);
+    uint32_t class_id = lua_tointeger(L, ++index);
+    bool is_class_instance = lua_toboolean(L, ++index);
+    uint32_t attribute_id = lua_tointeger(L, ++index);
+
+    ud->get_odp_ctxt().get_cip_matchers().cip_add_set_attribute(app_id, class_id, is_class_instance, attribute_id);
+    ud->get_odp_ctxt().get_app_info_mgr().set_app_info_active(app_id);
+
+    return 0;
+}
+
+/*Lua should inject patterns in <client_id, service_id> format. */
+static int detector_add_cip_extended_symbol_service(lua_State *L)
+{
+    int index = 1;
+
+    auto& ud = *UserData<LuaObject>::check(L, DETECTOR, 1);
+    // Verify detector user data and that we are NOT in packet context
+    ud->validate_lua_state(false);
+    if (!init(L)) 
+        return 0;
+
+    uint32_t app_id = lua_tointeger(L, ++index);
+    uint8_t service_id = lua_tointeger(L, ++index);
+
+    ud->get_odp_ctxt().get_cip_matchers().cip_add_extended_symbol_service(app_id, service_id);
+    ud->get_odp_ctxt().get_app_info_mgr().set_app_info_active(app_id);
+
+    return 0;
+}
+
+/*Lua should inject patterns in <client_id, service_id> format. */
+static int detector_add_cip_service(lua_State *L)
+{
+    int index = 1;
+
+    auto& ud = *UserData<LuaObject>::check(L, DETECTOR, 1);
+    // Verify detector user data and that we are NOT in packet context
+    ud->validate_lua_state(false);
+    if (!init(L)) 
+        return 0;
+
+    uint32_t app_id = lua_tointeger(L, ++index);
+    uint8_t service_id = lua_tointeger(L, ++index);
+
+    ud->get_odp_ctxt().get_cip_matchers().cip_add_service(app_id, service_id);
+    ud->get_odp_ctxt().get_app_info_mgr().set_app_info_active(app_id);
+
+    return 0;
+}
+
+/*Lua should inject patterns in <client_id, enip_command_id> format. */
+static int detector_add_enip_command(lua_State *L)
+{
+    int index = 1;
+
+    auto& ud = *UserData<LuaObject>::check(L, DETECTOR, 1);
+    // Verify detector user data and that we are NOT in packet context
+    ud->validate_lua_state(false);
+    if (!init(L)) 
+        return 0;
+
+    uint32_t app_id = lua_tointeger(L, ++index);
+    uint16_t command_id = lua_tointeger(L, ++index);
+
+    ud->get_odp_ctxt().get_cip_matchers().cip_add_enip_command(app_id, command_id);
+    ud->get_odp_ctxt().get_app_info_mgr().set_app_info_active(app_id);
+
+    return 0;
+}
+
 static const luaL_Reg detector_methods[] =
 {
     /* Obsolete API names.  No longer use these!  They are here for backward
@@ -2878,6 +3002,14 @@ static const luaL_Reg detector_methods[] =
     { "getHttpTunneledIp",        get_http_tunneled_ip },
     { "getHttpTunneledPort",      get_http_tunneled_port },
 
+     /* CIP registration */
+    {"addCipConnectionClass",    detector_add_cip_connection_class},
+    {"addCipPath",               detector_add_cip_path},
+    {"addCipSetAttribute",       detector_add_cip_set_attribute},
+    {"addCipExtendedSymbolService", detector_add_cip_extended_symbol_service},
+    {"addCipService",            detector_add_cip_service},
+    {"addEnipCommand",           detector_add_enip_command},
+
     { nullptr, nullptr }
 };
 
index 2e6729c1507035a5505ae4b585dad99e9efc07d6..f06915726f85c7d064db2451ee975486d8f7559f 100644 (file)
@@ -88,6 +88,7 @@ SslPatternMatchers::~SslPatternMatchers() { }
 SipPatternMatchers::~SipPatternMatchers() { }
 HttpPatternMatchers::~HttpPatternMatchers() { }
 DnsPatternMatchers::~DnsPatternMatchers() { }
+CipPatternMatchers::~CipPatternMatchers() { }
 void ClientDiscovery::initialize(AppIdInspector&) {}
 void ClientDiscovery::reload() {}
 FpSMBData* smb_data = nullptr;
index d7edeea7e3abf3694a338e7fddd205e75abdf80d..e0a014146421840d8839afb9b6922a3570e8b0eb 100644 (file)
@@ -148,6 +148,7 @@ HttpPatternMatchers::~HttpPatternMatchers() = default;
 SipPatternMatchers::~SipPatternMatchers() = default;
 SslPatternMatchers::~SslPatternMatchers() = default;
 AlpnPatternMatchers::~AlpnPatternMatchers() = default;
+CipPatternMatchers::~CipPatternMatchers() = default;
 
 void ApplicationDescriptor::set_id(const Packet&, AppIdSession&, AppidSessionDirection, AppId, AppidChangeBits&) { }
 void ApplicationDescriptor::set_id(AppId app_id){my_id = app_id;}
index 6f046045e3cb11506dc282c392b7b64f68ce241c..4726813eec605d132449dd749756b87623ecc8d3 100644 (file)
@@ -87,6 +87,7 @@ HttpPatternMatchers::~HttpPatternMatchers() = default;
 SipPatternMatchers::~SipPatternMatchers() = default;
 SslPatternMatchers::~SslPatternMatchers() = default;
 AlpnPatternMatchers::~AlpnPatternMatchers() = default;
+CipPatternMatchers::~CipPatternMatchers() = default;
 
 void Field::set(int32_t length, const uint8_t* start, bool own_the_buffer_)
 {
index b204bd2e603874b68e96191e0815b207e0fb4afa..4e4e3315dcb083a504948005a3c5b1220a9d4322 100644 (file)
@@ -128,6 +128,7 @@ HttpPatternMatchers::~HttpPatternMatchers() = default;
 SipPatternMatchers::~SipPatternMatchers() = default;
 SslPatternMatchers::~SslPatternMatchers() = default;
 AlpnPatternMatchers::~AlpnPatternMatchers() = default;
+CipPatternMatchers::~CipPatternMatchers() = default;
 snort::SearchTool::SearchTool(bool) { }
 snort::SearchTool::~SearchTool() = default;
 
index 6045ac200aa8ac572e33e610d9a8e06b9effb341..34d3b28cb15cb615326d1f5019b0aed1f71dfd72 100644 (file)
@@ -61,6 +61,7 @@ HttpPatternMatchers::~HttpPatternMatchers() = default;
 SipPatternMatchers::~SipPatternMatchers() = default;
 SslPatternMatchers::~SslPatternMatchers() = default;
 AlpnPatternMatchers::~AlpnPatternMatchers() = default;
+CipPatternMatchers::~CipPatternMatchers() = default;
 AppIdConfig::~AppIdConfig() = default;
 OdpContext::OdpContext(const AppIdConfig&, snort::SnortConfig*) { }
 void ServiceDiscovery::initialize(AppIdInspector&) { }
index 57e5e1fd55426c1a2f1316f964e8698cc0cca3c8..37c0016b876da84f063b690fac72a672e165da9c 100644 (file)
@@ -28,9 +28,9 @@
 using namespace snort;
 using namespace std;
 
-CipEvent::CipEvent(const Packet* p, const CipEventData* EventData)
+CipEvent::CipEvent(const Packet* p, const CipEventData* event_data)
 {
     this->p = p;
-    this->EventData = EventData;
+    this->event_data = event_data;
 }
 
index 6e0fd852c67a9b2d55d171e52ce04d84e96c4341..3ab445ff96eac9d396db6faf16e20235832788f7 100644 (file)
@@ -47,9 +47,11 @@ public:
     const snort::Packet* get_packet() const override
     { return p; }
 
+    const CipEventData* get_event_data()
+    { return event_data; }         
 private:
     const snort::Packet* p;
-    const CipEventData* EventData;
+    const CipEventData* event_data;
 };
 
 #endif