]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #603 in SNORT/snort3 from appid_rsync1 to master
authorTom Peters (thopeter) <thopeter@cisco.com>
Thu, 25 Aug 2016 16:52:05 +0000 (12:52 -0400)
committerTom Peters (thopeter) <thopeter@cisco.com>
Thu, 25 Aug 2016 16:52:05 +0000 (12:52 -0400)
Squashed commit of the following:

commit d9f8bd1751d2deb3e9682a648b0b22c7bfb6c583
Merge: 011b8de 1c9b2e3
Author: Steve Chew <stechew@cisco.com>
Date:   Wed Aug 24 12:34:30 2016 -0400

    Merge branch 'appid_rsync1' of ssh://bitbucket-eng-rtp1.cisco.com:7999/snort/snort3 into appid_rsync1

commit 011b8de0c61fea1413025d9b8a74c0c9ad823fb3
Author: Steve Chew <stechew@cisco.com>
Date:   Wed Aug 24 12:22:31 2016 -0400

    Fixed Cmake test build.

commit e25092d29345716ea5ce491232ee79251ea1727e
Author: Steve Chew <stechew@cisco.com>
Date:   Tue Aug 23 09:50:02 2016 -0400

    include service_rsync.cc file in tests so we can access private data.

commit 2703075fd0440ceb71c01be91d2ea3a28ba0f0fe
Author: Steve Chew <stechew@cisco.com>
Date:   Fri Aug 19 16:36:50 2016 -0400

    Added rsync flow counter and rsync_validate unit tests.

commit 1c9b2e3b28f68a488e264b26ea10f5fe23e5073b
Author: Steve Chew <stechew@cisco.com>
Date:   Tue Aug 23 09:50:02 2016 -0400

    include service_rsync.cc file in tests so we can access private data.

commit 0257acc0f2432d05684f28c4f3efc9b721a84eb2
Author: Steve Chew <stechew@cisco.com>
Date:   Fri Aug 19 16:36:50 2016 -0400

    Added rsync flow counter and rsync_validate unit tests.

configure.ac
src/network_inspectors/appid/CMakeLists.txt
src/network_inspectors/appid/Makefile.am
src/network_inspectors/appid/appid_module.cc
src/network_inspectors/appid/appid_module.h
src/network_inspectors/appid/appid_stats_counter.cc [new file with mode: 0644]
src/network_inspectors/appid/service_plugins/service_rsync.cc
src/network_inspectors/appid/service_plugins/service_rsync.h
src/network_inspectors/appid/service_plugins/test/CMakeLists.txt [new file with mode: 0644]
src/network_inspectors/appid/service_plugins/test/Makefile.am [new file with mode: 0644]
src/network_inspectors/appid/service_plugins/test/service_rsync_test.cc [new file with mode: 0644]

index 236aace52817091ce167d17cf1b80697d91d5501..2673c9dd5bb5304bd547e59b6922b10057a0fb8a 100644 (file)
@@ -1158,6 +1158,7 @@ src/stream/user/Makefile \
 src/stream/file/Makefile \
 src/network_inspectors/Makefile \
 src/network_inspectors/appid/Makefile \
+src/network_inspectors/appid/service_plugins/test/Makefile \
 src/network_inspectors/arp_spoof/Makefile \
 src/network_inspectors/binder/Makefile \
 src/network_inspectors/normalize/Makefile \
index a07d58b12dd6ea3d3d7392c757d590b4e064fc48..8c0110e5ddb6b344ae4081a2b6724dba710e0fea 100644 (file)
@@ -147,6 +147,7 @@ set ( APPID_SOURCES
     appid_module.cc
     appid_module.h
     appid_stats.cc
+    appid_stats_counter.cc
     appid_stats.h
     app_info_table.cc
     app_info_table.h
@@ -197,7 +198,7 @@ endif (STATIC_INSPECTORS)
 
 target_include_directories ( appid PRIVATE ${APPID_INCLUDE_DIR} )
 
-#  FIXIT-H: Add unit tests
+add_subdirectory(service_plugins/test)
 
 #install (FILES ${APPID_INCLUDES}
 #    DESTINATION "${INCLUDE_INSTALL_PATH}/appid"
index fe0c777d70984452aa0421d165e58fb46f80d9df..2aa2212b18ac579f38e0450dcf55d55d96ca5456 100644 (file)
@@ -143,6 +143,7 @@ appid_inspector.h \
 appid_module.cc \
 appid_module.h \
 appid_stats.cc \
+appid_stats_counter.cc \
 appid_stats.h \
 app_info_table.cc \
 app_info_table.h \
@@ -190,8 +191,7 @@ $(dp_file_list) \
 $(util_file_list)
 endif
 
-#if BUILD_CPPUTESTS
-#SUBDIRS = test
-#endif
-
+if ENABLE_UNIT_TESTS
+SUBDIRS=service_plugins/test
+endif
 
index c77c20f8eabd82cf6c75ab2eac477f05747e9eb0..ef7fce3ff7bdfda7717d5a6a58fa124179074385 100644 (file)
@@ -59,6 +59,7 @@ const PegInfo appid_pegs[] =
     { "mysql_flows", "count of mysql service flows discovered by appid" },
     { "netbios_flows", "count of netbios service flows discovered by appid" },
     { "pop_flows", "count of pop service flows discovered by appid" },
+    { "rsync_flows", "count of rsync service flows discovered by appid" },
     { "smtp_flows", "count of smtp flows discovered by appid" },
     { "smtps_flows", "count of smtps flows discovered by appid" },
     { "ssh_clients", "count of ssh clients discovered by appid" },
@@ -69,8 +70,6 @@ const PegInfo appid_pegs[] =
     { nullptr, nullptr }
 };
 
-THREAD_LOCAL AppIdStats appid_stats;
-
 static const Parameter s_params[] =
 {
     { "conf", Parameter::PT_STRING, nullptr, nullptr,
index 093288c9655c1086b9e3b772f341c150ccdbe1b6..2375ad13dfce77ef66f52f78457735bb40d66b65 100644 (file)
@@ -60,6 +60,7 @@ struct AppIdStats
     PegCount mysql_flows;
     PegCount netbios_flows;
     PegCount pop_flows;
+    PegCount rsync_flows;
     PegCount smtp_flows;
     PegCount smtps_flows;
     PegCount ssh_clients;
diff --git a/src/network_inspectors/appid/appid_stats_counter.cc b/src/network_inspectors/appid/appid_stats_counter.cc
new file mode 100644 (file)
index 0000000..098ab84
--- /dev/null
@@ -0,0 +1,26 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2016-2016 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_module.cc author Steve Chew <stechew@cisco.com>
+// Created on: Auguest 18, 2016
+
+#include "main/thread.h"
+#include "appid_module.h"
+
+THREAD_LOCAL AppIdStats appid_stats;
+
index fc59e5cb7bbc52e2aa1ab3be02843131ea6be8c6..a6574d38cd9e60315ff2161ac0189ae3a92ff1a4 100644 (file)
@@ -24,6 +24,7 @@
 #include "application_ids.h"
 #include "service_api.h"
 #include "app_info_table.h"
+#include "appid_module.h"
 
 #include "main/snort_debug.h"
 #include "utils/util.h"
@@ -102,6 +103,11 @@ static int rsync_validate(ServiceValidationArgs* args)
 {
     ServiceRSYNCData* rd;
     int i;
+
+    // FIXIT-L: Should this be an assert instead?
+    if (!args)
+        return SERVICE_NOMATCH;
+
     AppIdData* flowp = args->flowp;
     const uint8_t* data = args->data;
     uint16_t size = args->size;
@@ -155,6 +161,7 @@ inprocess:
 success:
     rsync_service_mod.api->add_service(flowp, args->pkt, args->dir, &svc_element,
         APP_ID_RSYNC, nullptr, nullptr, nullptr);
+    appid_stats.rsync_flows++;
     return SERVICE_SUCCESS;
 
 fail:
index 8782a1f77cb675ed9cdd051cfd89d986a831bfd5..ee41030276760212c03ea1bcbe3055f5a2cabe9b 100644 (file)
@@ -22,7 +22,8 @@
 #ifndef SERVICE_RSYNC_H
 #define SERVICE_RSYNC_H
 
-struct RNAServiceValidationModule;
+#include "service_api.h"
+
 //  FIXIT-L: Make the globals const or, if necessary, thread-local.
 extern RNAServiceValidationModule rsync_service_mod;
 
diff --git a/src/network_inspectors/appid/service_plugins/test/CMakeLists.txt b/src/network_inspectors/appid/service_plugins/test/CMakeLists.txt
new file mode 100644 (file)
index 0000000..d17e3f8
--- /dev/null
@@ -0,0 +1,8 @@
+
+add_library(depends_on_lib ../../appid_stats_counter.cc)
+
+add_cpputest(service_rsync_test depends_on_lib)
+
+include_directories ( appid PRIVATE ${APPID_INCLUDE_DIR} )
+
+
diff --git a/src/network_inspectors/appid/service_plugins/test/Makefile.am b/src/network_inspectors/appid/service_plugins/test/Makefile.am
new file mode 100644 (file)
index 0000000..9f3d140
--- /dev/null
@@ -0,0 +1,13 @@
+
+AM_DEFAULT_SOURCE_EXT = .cc
+
+check_PROGRAMS = \
+service_rsync_test
+
+TESTS = $(check_PROGRAMS)
+
+service_rsync_test_CPPFLAGS = -I$(top_srcdir)/src/network_inspectors/appid @AM_CPPFLAGS@ @CPPUTEST_CPPFLAGS@
+service_rsync_test_LDADD = \
+../../appid_stats_counter.o \
+@CPPUTEST_LDFLAGS@
+
diff --git a/src/network_inspectors/appid/service_plugins/test/service_rsync_test.cc b/src/network_inspectors/appid/service_plugins/test/service_rsync_test.cc
new file mode 100644 (file)
index 0000000..bbc0aac
--- /dev/null
@@ -0,0 +1,346 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2016-2016 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.
+//--------------------------------------------------------------------------
+
+// service_rsync_test.cc author Steve Chew <stechew@cisco.com>
+// unit test for service_rsync
+
+#include <CppUTest/CommandLineTestRunner.h>
+#include <CppUTest/TestHarness.h>
+#include <CppUTestExt/MockSupport.h>
+
+#include "network_inspectors/appid/service_plugins/service_rsync.cc"
+
+void Debug::print(const char*, int, uint64_t, const char*, ...) { }
+
+extern int rsync_validate(ServiceValidationArgs*);
+
+int fake_service_inprocess(AppIdData*, const Packet*, int, const RNAServiceElement*)
+{
+    mock().actualCall("service_inprocess");
+    return -1;
+}
+
+ServiceRSYNCData* fake_rsync_data = NULL;
+
+void* fake_service_flowdata_get(AppIdData*, unsigned)
+{
+    mock().actualCall("data_get");
+    return fake_rsync_data;
+}
+
+int fake_data_add(AppIdData*, void* data, unsigned, AppIdFreeFCN)
+{
+    mock().actualCall("data_add");
+    fake_rsync_data = (ServiceRSYNCData*)data;
+    return -1;
+}
+
+int fake_fail_service(AppIdData*, const Packet*, int, const RNAServiceElement*, unsigned, const AppIdConfig*)
+{
+    mock().actualCall("fail_service");
+    return -1;
+}
+
+int fake_add_service(AppIdData*, const Packet*, int, 
+    const RNAServiceElement*, AppId, const char*, const char *,
+    const RNAServiceSubtype*)
+{
+    mock().actualCall("add_service");
+    return -1;
+}
+
+const ServiceApi fake_serviceapi =
+{
+    &fake_service_flowdata_get,
+    &fake_data_add,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    &fake_add_service,
+    &fake_fail_service,
+    &fake_service_inprocess,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+};
+
+TEST_GROUP(service_rsync)
+{
+    void setup()
+    {
+        fake_rsync_data = NULL;
+    }
+
+    void teardown()
+    {
+        snort_free(fake_rsync_data);
+        mock().clear();
+    }
+};
+
+TEST(service_rsync, rsync_validate_null_args)
+{
+    LONGS_EQUAL(SERVICE_NOMATCH, rsync_validate(nullptr));
+}
+
+TEST(service_rsync, rsync_validate_zero_size)
+{
+    ServiceValidationArgs args;
+    args.size = 0;
+    rsync_service_mod.api = &fake_serviceapi;
+
+    mock().expectOneCall("service_inprocess");
+    LONGS_EQUAL(SERVICE_INPROCESS, rsync_validate(&args));
+    mock().checkExpectations();
+}
+
+TEST(service_rsync, rsync_validate_skip_data_from_client)
+{
+    ServiceValidationArgs args;
+    args.size = 1;
+    args.dir  = APP_ID_FROM_INITIATOR;
+    rsync_service_mod.api = &fake_serviceapi;
+
+    mock().expectOneCall("service_inprocess");
+    LONGS_EQUAL(SERVICE_INPROCESS, rsync_validate(&args));
+    mock().checkExpectations();
+}
+
+TEST(service_rsync, rsync_validate_no_rsync_data_size_too_small)
+{
+    ServiceValidationArgs args;
+    args.size = 1;
+    args.dir  = APP_ID_FROM_RESPONDER;
+    rsync_service_mod.api = &fake_serviceapi;
+
+    mock().strictOrder();
+    mock().expectOneCall("data_get");
+    mock().expectOneCall("data_add");
+    mock().expectOneCall("fail_service");
+
+    LONGS_EQUAL(SERVICE_NOMATCH, rsync_validate(&args));
+
+    mock().checkExpectations();
+}
+
+#define RSYNC_BANNER_VALID       RSYNC_BANNER "26\n"
+#define RSYNC_BANNER_NO_LINEFEED RSYNC_BANNER "26"
+#define RSYNC_BANNER_BAD_VERSION RSYNC_BANNER "26a\n"
+#define RSYNC_BANNER_INVALID     "INVALID: 26\n"
+#define RSYNC_MOTD             "motd\n"
+#define RSYNC_MOTD_NO_LINEFEED "motd"
+#define RSYNC_MOTD_INVALID_STR "mo\btd\n"
+
+TEST(service_rsync, rsync_validate_banner_missing_linefeed)
+{
+    ServiceValidationArgs args;
+    args.dir  = APP_ID_FROM_RESPONDER;
+    args.data = (const uint8_t*)RSYNC_BANNER_NO_LINEFEED;
+    args.size = strlen((const char *)args.data);
+    rsync_service_mod.api = &fake_serviceapi;
+
+    mock().strictOrder();
+    mock().expectOneCall("data_get");
+    mock().expectOneCall("data_add");
+    mock().expectOneCall("fail_service");
+
+    LONGS_EQUAL(SERVICE_NOMATCH, rsync_validate(&args));
+
+    mock().checkExpectations();
+}
+
+TEST(service_rsync, rsync_validate_banner_bad_version)
+{
+    ServiceValidationArgs args;
+    args.dir  = APP_ID_FROM_RESPONDER;
+    args.data = (const uint8_t*)RSYNC_BANNER_BAD_VERSION;
+    args.size = strlen((const char *)args.data);
+    rsync_service_mod.api = &fake_serviceapi;
+
+    mock().strictOrder();
+    mock().expectOneCall("data_get");
+    mock().expectOneCall("data_add");
+    mock().expectOneCall("fail_service");
+
+    LONGS_EQUAL(SERVICE_NOMATCH, rsync_validate(&args));
+
+    mock().checkExpectations();
+}
+
+TEST(service_rsync, rsync_validate_banner_invalid_text)
+{
+    ServiceValidationArgs args;
+    args.dir  = APP_ID_FROM_RESPONDER;
+    args.data = (const uint8_t*)RSYNC_BANNER_INVALID;
+    args.size = strlen((const char *)args.data);
+    rsync_service_mod.api = &fake_serviceapi;
+
+    mock().strictOrder();
+    mock().expectOneCall("data_get");
+    mock().expectOneCall("data_add");
+    mock().expectOneCall("fail_service");
+
+    LONGS_EQUAL(SERVICE_NOMATCH, rsync_validate(&args));
+
+    mock().checkExpectations();
+}
+
+TEST(service_rsync, rsync_validate_banner_valid)
+{
+    ServiceValidationArgs args;
+    args.dir  = APP_ID_FROM_RESPONDER;
+    args.data = (const uint8_t*)RSYNC_BANNER_VALID;
+    args.size = strlen((const char *)args.data);
+    rsync_service_mod.api = &fake_serviceapi;
+
+    mock().strictOrder();
+    mock().expectOneCall("data_get");
+    mock().expectOneCall("data_add");
+    mock().expectOneCall("service_inprocess");
+
+    LONGS_EQUAL(SERVICE_INPROCESS, rsync_validate(&args));
+    LONGS_EQUAL(RSYNC_STATE_MOTD, fake_rsync_data->state);
+
+    mock().checkExpectations();
+}
+
+TEST(service_rsync, rsync_validate_motd_no_linefeed)
+{
+    ServiceValidationArgs args;
+    args.dir  = APP_ID_FROM_RESPONDER;
+    args.data = (const uint8_t*)RSYNC_MOTD_NO_LINEFEED;
+    args.size = strlen((const char *)args.data);
+    rsync_service_mod.api = &fake_serviceapi;
+
+    fake_rsync_data = (ServiceRSYNCData*)snort_calloc(sizeof(ServiceRSYNCData));
+    fake_rsync_data->state = RSYNC_STATE_MOTD;
+
+    mock().strictOrder();
+    mock().expectOneCall("data_get");
+    mock().expectOneCall("fail_service");
+
+    LONGS_EQUAL(SERVICE_NOMATCH, rsync_validate(&args));
+    LONGS_EQUAL(RSYNC_STATE_MOTD, fake_rsync_data->state);
+
+    mock().checkExpectations();
+}
+
+TEST(service_rsync, rsync_validate_motd_invalid_str)
+{
+    ServiceValidationArgs args;
+    args.dir  = APP_ID_FROM_RESPONDER;
+    args.data = (const uint8_t*)RSYNC_MOTD_INVALID_STR;
+    args.size = strlen((const char *)args.data);
+    rsync_service_mod.api = &fake_serviceapi;
+
+    fake_rsync_data = (ServiceRSYNCData*)snort_calloc(sizeof(ServiceRSYNCData));
+    fake_rsync_data->state = RSYNC_STATE_MOTD;
+
+    mock().strictOrder();
+    mock().expectOneCall("data_get");
+    mock().expectOneCall("fail_service");
+
+    LONGS_EQUAL(SERVICE_NOMATCH, rsync_validate(&args));
+    LONGS_EQUAL(RSYNC_STATE_MOTD, fake_rsync_data->state);
+
+    mock().checkExpectations();
+}
+
+TEST(service_rsync, rsync_validate_motd_valid)
+{
+    ServiceValidationArgs args;
+    args.dir  = APP_ID_FROM_RESPONDER;
+    args.data = (const uint8_t*)RSYNC_MOTD;
+    args.size = strlen((const char *)args.data);
+    rsync_service_mod.api = &fake_serviceapi;
+
+    fake_rsync_data = (ServiceRSYNCData*)snort_calloc(sizeof(ServiceRSYNCData));
+    fake_rsync_data->state = RSYNC_STATE_MOTD;
+
+    mock().strictOrder();
+    mock().expectOneCall("data_get");
+    mock().expectOneCall("add_service");
+
+    LONGS_EQUAL(SERVICE_SUCCESS, rsync_validate(&args));
+    LONGS_EQUAL(RSYNC_STATE_DONE, fake_rsync_data->state);
+
+    mock().checkExpectations();
+}
+
+//  It's an error to get another call to rsync_validate if we've
+//  already reached the DONE state.
+TEST(service_rsync, rsync_validate_should_not_called_after_done)
+{
+    ServiceValidationArgs args;
+    args.dir  = APP_ID_FROM_RESPONDER;
+    args.data = (const uint8_t*)RSYNC_MOTD;
+    args.size = strlen((const char *)args.data);
+    rsync_service_mod.api = &fake_serviceapi;
+
+    fake_rsync_data = (ServiceRSYNCData*)snort_calloc(sizeof(ServiceRSYNCData));
+    fake_rsync_data->state = RSYNC_STATE_MOTD;
+
+    mock().strictOrder();
+    mock().expectOneCall("data_get");
+    mock().expectOneCall("add_service");
+    mock().expectOneCall("data_get");
+    mock().expectOneCall("fail_service");
+
+    LONGS_EQUAL(SERVICE_SUCCESS, rsync_validate(&args));
+    LONGS_EQUAL(RSYNC_STATE_DONE, fake_rsync_data->state);
+
+    LONGS_EQUAL(SERVICE_NOMATCH, rsync_validate(&args));
+    mock().checkExpectations();
+}
+
+TEST(service_rsync, rsync_validate_count_rsync_flow_on_success)
+{
+    ServiceValidationArgs args;
+    args.dir  = APP_ID_FROM_RESPONDER;
+    args.data = (const uint8_t*)RSYNC_MOTD;
+    args.size = strlen((const char *)args.data);
+    rsync_service_mod.api = &fake_serviceapi;
+
+    fake_rsync_data = (ServiceRSYNCData*)snort_calloc(sizeof(ServiceRSYNCData));
+    fake_rsync_data->state = RSYNC_STATE_MOTD;
+
+    mock().strictOrder();
+    mock().expectOneCall("data_get");
+    mock().expectOneCall("add_service");
+
+    LONGS_EQUAL(SERVICE_SUCCESS, rsync_validate(&args));
+    LONGS_EQUAL(RSYNC_STATE_DONE, fake_rsync_data->state);
+    LONGS_EQUAL(1, appid_stats.rsync_flows);
+
+    mock().checkExpectations();
+}
+
+int main(int argc, char** argv)
+{
+    int return_value = CommandLineTestRunner::RunAllTests(argc, argv);
+    return return_value;
+}
+