From 08e3998a22e4396eb01aa7cd0077b6c01c5e3b57 Mon Sep 17 00:00:00 2001 From: "Russ Combs (rucombs)" Date: Wed, 21 Oct 2015 10:32:53 -0400 Subject: [PATCH] Merge pull request #88 in SNORT/snort3 from crc/gtp to master Squashed commit of the following: commit 4e987387e53ddc84f807df00aafcbb73d3dd8b92 Author: Russ Combs Date: Tue Oct 20 12:00:50 2015 -0400 fix multi gtp encap alert commit 1f718dcb84f461740493f4df586909813469ff17 Author: Russ Combs Date: Tue Oct 20 11:24:35 2015 -0400 update bug list commit e29dfb142dbf645f3c7f30891ff0032417035848 Author: Russ Combs Date: Tue Oct 20 06:48:18 2015 -0400 test fixes and readability changes commit 9f976d3f8d74ac5b3fa0700c424f4397c78c5385 Author: Russ Combs Date: Fri Oct 16 07:53:21 2015 -0400 initial port of gtp preprocessor --- configure.ac | 1 + doc/bugs.txt | 33 +- doc/style.txt | 4 + lua/snort.lua | 1 + lua/snort_defaults.lua | 491 ++++++++++++++- src/Makefile.am | 1 + src/codecs/misc/cd_gtp.cc | 14 +- src/framework/value.cc | 17 + src/framework/value.h | 1 + src/protocols/packet.h | 3 + src/protocols/packet_manager.cc | 2 - src/service_inspectors/CMakeLists.txt | 6 +- src/service_inspectors/Makefile.am | 1 + src/service_inspectors/gtp/CMakeLists.txt | 23 + src/service_inspectors/gtp/Makefile.am | 27 + src/service_inspectors/gtp/dev_notes.txt | 18 + src/service_inspectors/gtp/gtp.cc | 122 ++++ src/service_inspectors/gtp/gtp.h | 77 +++ src/service_inspectors/gtp/gtp_inspect.cc | 225 +++++++ src/service_inspectors/gtp/gtp_inspect.h | 53 ++ src/service_inspectors/gtp/gtp_module.cc | 177 ++++++ src/service_inspectors/gtp/gtp_module.h | 76 +++ src/service_inspectors/gtp/gtp_parser.cc | 571 ++++++++++++++++++ src/service_inspectors/gtp/gtp_parser.h | 51 ++ src/service_inspectors/gtp/ips_gtp_info.cc | 253 ++++++++ src/service_inspectors/gtp/ips_gtp_type.cc | 268 ++++++++ src/service_inspectors/gtp/ips_gtp_version.cc | 182 ++++++ .../http_inspect/http_inspect.cc | 5 +- src/service_inspectors/service_inspectors.cc | 8 + 29 files changed, 2680 insertions(+), 31 deletions(-) create mode 100644 src/service_inspectors/gtp/CMakeLists.txt create mode 100644 src/service_inspectors/gtp/Makefile.am create mode 100644 src/service_inspectors/gtp/dev_notes.txt create mode 100644 src/service_inspectors/gtp/gtp.cc create mode 100644 src/service_inspectors/gtp/gtp.h create mode 100644 src/service_inspectors/gtp/gtp_inspect.cc create mode 100644 src/service_inspectors/gtp/gtp_inspect.h create mode 100644 src/service_inspectors/gtp/gtp_module.cc create mode 100644 src/service_inspectors/gtp/gtp_module.h create mode 100644 src/service_inspectors/gtp/gtp_parser.cc create mode 100644 src/service_inspectors/gtp/gtp_parser.h create mode 100644 src/service_inspectors/gtp/ips_gtp_info.cc create mode 100644 src/service_inspectors/gtp/ips_gtp_type.cc create mode 100644 src/service_inspectors/gtp/ips_gtp_version.cc diff --git a/configure.ac b/configure.ac index c09286880..97d3e40dd 100644 --- a/configure.ac +++ b/configure.ac @@ -1001,6 +1001,7 @@ src/service_inspectors/Makefile \ src/service_inspectors/back_orifice/Makefile \ src/service_inspectors/dns/Makefile \ src/service_inspectors/ftp_telnet/Makefile \ +src/service_inspectors/gtp/Makefile \ src/service_inspectors/http_inspect/Makefile \ src/service_inspectors/imap/Makefile \ src/service_inspectors/nhttp_inspect/Makefile \ diff --git a/doc/bugs.txt b/doc/bugs.txt index 6d0307c8a..dc2990dbe 100644 --- a/doc/bugs.txt +++ b/doc/bugs.txt @@ -1,7 +1,7 @@ ==== Build * configure will use clang++ by default if it is installed. -To compile with g++ instead: + To compile with g++ instead: export CXX=g++ @@ -26,14 +26,14 @@ To compile with g++ instead: ==== Config * Parsing issue with IP lists. can't parse rules with $EXTERNAL_NET -defined as below because or the space between ! and 10. + defined as below because or the space between ! and 10. HOME_NET = [[ 10.0.17.0/24 10.0.14.0/24 10.247.0.0/16 10.246.0.0/16 ]] EXTERNAL_NET = '! ' .. HOME_NET * Multiple versions of luajit scripts are not handled correctly. The -first loaded version will always be executed even though plugin manager -saves the correct version. + first loaded version will always be executed even though plugin manager + saves the correct version. * When using -c and -L together, the last on the command line wins (-c -L will dump; -L -c will analyze). @@ -45,10 +45,10 @@ saves the correct version. ==== Rules * metdata:service foo; metadata:service foo; won't cause a duplicate service -warning as does metadata:service foo, service foo; + warning as does metadata:service foo, service foo; * ip_proto doesn't work properly with reassembled packets so it can't be -used to restrict the protocol of service rules. + used to restrict the protocol of service rules. * Inspector events generated while parsing TCP payload in non-IPS mode will indicate the wrong direction (ie they will be based on the ACK packet). @@ -58,14 +58,14 @@ used to restrict the protocol of service rules. ==== snort2lua * uricontent:"foo"; content:"bar"; -> http_uri; content:"foo"; content:"bar"; -(missing pkt_data) + (missing pkt_data) * stream_tcp ports and protocols both go into a single binder.when; this is -incorrect as the when fields are logically anded together (ie must all be -true). Should create 2 separate bindings. + incorrect as the when fields are logically anded together (ie must all be + true). Should create 2 separate bindings. * There is a bug in pps_stream_tcp.cc.. when stream_tcp: is -specified without any arguments, snort2lua doesn't convert it. + specified without any arguments, snort2lua doesn't convert it. * Loses the ip list delimiters [ ]; change to ( ) @@ -73,16 +73,21 @@ specified without any arguments, snort2lua doesn't convert it. in snort.lua: HOME_NET = [[A B C]] * Won't convert packet rules (alert tcp etc.) to service rules (alert http -etc.). + etc.). * alert_fast and alert_full: output configuration includes "file = 'foo.bar'", but file is a bool -and you cannot specify an output file name in the configuration. + and you cannot specify an output file name in the configuration. -==== obfuscation +==== Runtime * -B feature does not work. It does ordinary IP address obfuscation instead of using the -mask. + mask. * Obfuscation does not work for csv format. +* The hext DAQ will append a newline to text lines (starting with '"'). + +* The hext DAQ does not support embedded quotes in text lines (use hex + lines as a workaround). + diff --git a/doc/style.txt b/doc/style.txt index 39b57cf8d..ebc8f4898 100644 --- a/doc/style.txt +++ b/doc/style.txt @@ -244,3 +244,7 @@ The working config is crusty.cfg in the top level directory. It does well but will munge some things. Specially formatted INDENT-OFF comments were added in 2 places to avoid a real mess. +Example usage: + + uncrustify -c crusty.cfg --replace + diff --git a/lua/snort.lua b/lua/snort.lua index abd9d0221..f80e1b199 100644 --- a/lua/snort.lua +++ b/lua/snort.lua @@ -68,6 +68,7 @@ stream_file = { } arp_spoof = { } back_orifice = { } dns = { } +gtp_inspect = default_gtp imap = { } smtp = { } perf_monitor = { } diff --git a/lua/snort_defaults.lua b/lua/snort_defaults.lua index 10fcd51f9..bd8c6557b 100644 --- a/lua/snort_defaults.lua +++ b/lua/snort_defaults.lua @@ -449,10 +449,10 @@ references = { name = 'cve', url = 'http://cve.mitre.org/cgi-bin/cvename.cgi?name=' }, { name = 'arachNIDS', url = 'http://www.whitehats.com/info/IDS' }, { name = 'osvdb', url = 'http://osvdb.org/show/osvdb/' }, - { name = 'McAfee', url = 'http://vil.nai.com/vil/content/v_' }, - { name = 'nessus', url = 'http://cgi.nessus.org/plugins/dump.php3?id=' }, - { name = 'url', url = 'http://' }, - { name = 'msb', url = 'http://technet.microsoft.com/en-us/security/bulletin/' } + { name = 'McAfee', url = 'http://vil.nai.com/vil/content/v_' }, + { name = 'nessus', url = 'http://cgi.nessus.org/plugins/dump.php3?id=' }, + { name = 'url', url = 'http://' }, + { name = 'msb', url = 'http://technet.microsoft.com/en-us/security/bulletin/' } } --------------------------------------------------------------------------- @@ -576,3 +576,486 @@ classifications = text = 'Known client side exploit attempt' } } +--------------------------------------------------------------------------- +-- gtp defaults +--------------------------------------------------------------------------- + +gtp_v0_msg = +{ + { type = 1, name = "echo_request" }, + { type = 2, name = "echo_response" }, + { type = 3, name = "version_not_supported" }, + { type = 4, name = "node_alive_request" }, + { type = 5, name = "node_alive_response" }, + { type = 6, name = "redirection_request" }, + { type = 7, name = "redirection_response" }, + + { type = 16, name = "create_pdp_context_request" }, + { type = 17, name = "create_pdp_context_response" }, + { type = 18, name = "update_pdp_context_request" }, + { type = 19, name = "update_pdp_context_response" }, + { type = 20, name = "delete_pdp_context_request" }, + { type = 21, name = "delete_pdp_context_response" }, + { type = 22, name = "create_aa_pdp_context_request" }, + { type = 23, name = "create_aa_pdp_context_response" }, + { type = 24, name = "delete_aa_pdp_context_request" }, + { type = 25, name = "delete_aa_pdp_context_response" }, + { type = 26, name = "error_indication" }, + { type = 27, name = "pdu_notification_request" }, + { type = 28, name = "pdu_notification_response" }, + { type = 29, name = "pdu_notification_reject_request" }, + { type = 30, name = "pdu_notification_reject_response" }, + + { type = 32, name = "send_routing_info_request" }, + { type = 33, name = "send_routing_info_response" }, + { type = 34, name = "failure_report_request" }, + { type = 35, name = "failure_report_response" }, + { type = 36, name = "note_ms_present_request" }, + { type = 37, name = "note_ms_present_response" }, + + { type = 48, name = "identification_request" }, + { type = 49, name = "identification_response" }, + { type = 50, name = "sgsn_context_request" }, + { type = 51, name = "sgsn_context_response" }, + { type = 52, name = "sgsn_context_ack" }, + + { type = 240, name = "data_record_transfer_request" }, + { type = 241, name = "data_record_transfer_response" }, + + { type = 255, name = "pdu" }, +} + +gtp_v1_msg = +{ + { type = 1, name = "echo_request" }, + { type = 2, name = "echo_response" }, + { type = 3, name = "version_not_supported" }, + { type = 4, name = "node_alive_request" }, + { type = 5, name = "node_alive_response" }, + { type = 6, name = "redirection_request" }, + { type = 7, name = "redirection_response" }, + + { type = 16, name = "create_pdp_context_request" }, + { type = 17, name = "create_pdp_context_response" }, + { type = 18, name = "update_pdp_context_request" }, + { type = 19, name = "update_pdp_context_response" }, + { type = 20, name = "delete_pdp_context_request" }, + { type = 21, name = "delete_pdp_context_response" }, + { type = 22, name = "init_pdp_context_activation_request" }, + { type = 23, name = "init_pdp_context_activation_response" }, + + { type = 26, name = "error_indication" }, + { type = 27, name = "pdu_notification_request" }, + { type = 28, name = "pdu_notification_response" }, + { type = 29, name = "pdu_notification_reject_request" }, + { type = 30, name = "pdu_notification_reject_response" }, + { type = 31, name = "supported_ext_header_notification" }, + { type = 32, name = "send_routing_info_request" }, + { type = 33, name = "send_routing_info_response" }, + { type = 34, name = "failure_report_request" }, + { type = 35, name = "failure_report_response" }, + { type = 36, name = "note_ms_present_request" }, + { type = 37, name = "note_ms_present_response" }, + + { type = 48, name = "identification_request" }, + { type = 49, name = "identification_response" }, + { type = 50, name = "sgsn_context_request" }, + { type = 51, name = "sgsn_context_response" }, + { type = 52, name = "sgsn_context_ack" }, + { type = 53, name = "forward_relocation_request" }, + { type = 54, name = "forward_relocation_response" }, + { type = 55, name = "forward_relocation_complete" }, + { type = 56, name = "relocation_cancel_request" }, + { type = 57, name = "relocation_cancel_response" }, + { type = 58, name = "forward_srns_contex" }, + { type = 59, name = "forward_relocation_complete_ack" }, + { type = 60, name = "forward_srns_contex_ack" }, + + { type = 70, name = "ran_info_relay" }, + + { type = 96, name = "mbms_notification_request" }, + { type = 97, name = "mbms_notification_response" }, + { type = 98, name = "mbms_notification_reject_request" }, + { type = 99, name = "mbms_notification_reject_response" }, + { type = 100, name = "create_mbms_context_request" }, + { type = 101, name = "create_mbms_context_response" }, + { type = 102, name = "update_mbms_context_request" }, + { type = 103, name = "update_mbms_context_response" }, + { type = 104, name = "delete_mbms_context_request" }, + { type = 105, name = "delete_mbms_context_response" }, + + { type = 112, name = "mbms_register_request" }, + { type = 113, name = "mbms_register_response" }, + { type = 114, name = "mbms_deregister_request" }, + { type = 115, name = "mbms_deregister_response" }, + { type = 116, name = "mbms_session_start_request" }, + { type = 117, name = "mbms_session_start_response" }, + { type = 118, name = "mbms_session_stop_request" }, + { type = 119, name = "mbms_session_stop_response" }, + { type = 120, name = "mbms_session_update_request" }, + { type = 121, name = "mbms_session_update_response" }, + + { type = 128, name = "ms_info_change_request" }, + { type = 129, name = "ms_info_change_response" }, + + { type = 240, name = "data_record_transfer_request" }, + { type = 241, name = "data_record_transfer_response" }, + + { type = 254, name = "end_marker" }, + { type = 255, name = "pdu" }, +} + +gtp_v2_msg = +{ + { type = 1, name = "echo_request" }, + { type = 2, name = "echo_response" }, + { type = 3, name = "version_not_supported" }, + + { type = 32, name = "create_session_request" }, + { type = 33, name = "create_session_response" }, + { type = 34, name = "modify_bearer_request" }, + { type = 35, name = "modify_bearer_response" }, + { type = 36, name = "delete_session_request" }, + { type = 37, name = "delete_session_response" }, + { type = 38, name = "change_notification_request" }, + { type = 39, name = "change_notification_response" }, + + { type = 64, name = "modify_bearer_command" }, + { type = 65, name = "modify_bearer_failure_indication" }, + { type = 66, name = "delete_bearer_command" }, + { type = 67, name = "delete_bearer_failure_indication" }, + { type = 68, name = "bearer_resource_command" }, + { type = 69, name = "bearer_resource_failure_indication" }, + { type = 70, name = "downlink_failure_indication" }, + { type = 71, name = "trace_session_activation" }, + { type = 72, name = "trace_session_deactivation" }, + { type = 73, name = "stop_paging_indication" }, + + { type = 95, name = "create_bearer_request" }, + { type = 96, name = "create_bearer_response" }, + { type = 97, name = "update_bearer_request" }, + { type = 98, name = "update_bearer_response" }, + { type = 99, name = "delete_bearer_request" }, + { type = 100, name = "delete_bearer_response" }, + { type = 101, name = "delete_pdn_request" }, + { type = 102, name = "delete_pdn_response" }, + + { type = 128, name = "identification_request" }, + { type = 129, name = "identification_response" }, + { type = 130, name = "sgsn_context_request" }, + { type = 131, name = "sgsn_context_response" }, + { type = 132, name = "sgsn_context_ack" }, + { type = 133, name = "forward_relocation_request" }, + { type = 134, name = "forward_relocation_response" }, + { type = 135, name = "forward_relocation_complete" }, + { type = 136, name = "forward_relocation_complete_ack" }, + { type = 137, name = "forward_access" }, + { type = 138, name = "forward_access_ack" }, + { type = 139, name = "relocation_cancel_request" }, + { type = 140, name = "relocation_cancel_response" }, + { type = 141, name = "configuration_transfer_tunnel" }, + + { type = 149, name = "detach" }, + { type = 150, name = "detach_ack" }, + { type = 151, name = "cs_paging" }, + { type = 152, name = "ran_info_relay" }, + { type = 153, name = "alert_mme" }, + { type = 154, name = "alert_mme_ack" }, + { type = 155, name = "ue_activity" }, + { type = 156, name = "ue_activity_ack" }, + + { type = 160, name = "create_forward_tunnel_request" }, + { type = 161, name = "create_forward_tunnel_response" }, + { type = 162, name = "suspend" }, + { type = 163, name = "suspend_ack" }, + { type = 164, name = "resume" }, + { type = 165, name = "resume_ack" }, + { type = 166, name = "create_indirect_forward_tunnel_request" }, + { type = 167, name = "create_indirect_forward_tunnel_response" }, + { type = 168, name = "delete_indirect_forward_tunnel_request" }, + { type = 169, name = "delete_indirect_forward_tunnel_response" }, + { type = 170, name = "release_access_bearer_request" }, + { type = 171, name = "release_access_bearer_response" }, + + { type = 176, name = "downlink_data" }, + { type = 177, name = "downlink_data_ack" }, + + { type = 179, name = "pgw_restart" }, + { type = 180, name = "pgw_restart_ack" }, + + { type = 200, name = "update_pdn_request" }, + { type = 201, name = "update_pdn_response" }, + + { type = 211, name = "modify_access_bearer_request" }, + { type = 212, name = "modify_access_bearer_response" }, + + { type = 231, name = "mbms_session_start_request" }, + { type = 232, name = "mbms_session_start_response" }, + { type = 233, name = "mbms_session_update_request" }, + { type = 234, name = "mbms_session_update_response" }, + { type = 235, name = "mbms_session_stop_request" }, + { type = 236, name = "mbms_session_stop_response" }, +}; + +-- length = 0 indicates variable length + +gtp_v0_info = +{ + { type = 1, name = "cause", length = 2 }, + { type = 2, name = "imsi", length = 9 }, + { type = 3, name = "rai", length = 7 }, + { type = 4, name = "tlli", length = 5 }, + { type = 5, name = "p_tmsi", length = 5 }, + { type = 6, name = "qos", length = 4 }, + + { type = 8, name = "recording_required", length = 2 }, + { type = 9, name = "authentication", length = 29 }, + + { type = 11, name = "map_cause", length = 2 }, + { type = 12, name = "p_tmsi_sig", length = 4 }, + { type = 13, name = "ms_validated", length = 2 }, + { type = 14, name = "recovery", length = 2 }, + { type = 15, name = "selection_mode", length = 2 }, + { type = 16, name = "flow_label_data_1", length = 3 }, + { type = 17, name = "flow_label_signalling", length = 3 }, + { type = 18, name = "flow_label_data_2", length = 4 }, + { type = 19, name = "ms_unreachable", length = 2 }, + + { type = 127, name = "charge_id", length = 5 }, + { type = 128, name = "end_user_address", length = 0 }, + { type = 129, name = "mm_context", length = 0 }, + { type = 130, name = "pdp_context", length = 0 }, + { type = 131, name = "apn", length = 0 }, + { type = 132, name = "protocol_config", length = 0 }, + { type = 133, name = "gsn", length = 0 }, + { type = 134, name = "msisdn", length = 0 }, + + { type = 251, name = "charging_gateway_addr", length = 0 }, + + { type = 255, name = "private_extension", length = 0 }, +} + +gtp_v1_info = +{ + { type = 1, name = "cause", length = 2 }, + { type = 2, name = "imsi", length = 9 }, + { type = 3, name = "rai", length = 7 }, + { type = 4, name = "tlli", length = 5 }, + { type = 5, name = "p_tmsi", length = 5 }, + + { type = 8, name = "recording_required", length = 2 }, + { type = 9, name = "authentication", length = 29 }, + + { type = 11, name = "map_cause", length = 2 }, + { type = 12, name = "p_tmsi_sig", length = 4 }, + { type = 13, name = "ms_validated", length = 2 }, + { type = 14, name = "recovery", length = 2 }, + { type = 15, name = "selection_mode", length = 2 }, + { type = 16, name = "teid_1", length = 5 }, + { type = 17, name = "teid_control", length = 5 }, + { type = 18, name = "teid_2", length = 6 }, + { type = 19, name = "teardown_ind", length = 2 }, + { type = 20, name = "nsapi", length = 2 }, + { type = 21, name = "ranap", length = 2 }, + { type = 22, name = "rab_context", length = 10 }, + { type = 23, name = "radio_priority_sms", length = 2 }, + { type = 24, name = "radio_priority", length = 2 }, + { type = 25, name = "packet_flow_id", length = 3 }, + { type = 26, name = "charging_char", length = 3 }, + { type = 27, name = "trace_ref", length = 3 }, + { type = 28, name = "trace_type", length = 3 }, + { type = 29, name = "ms_unreachable", length = 2 }, + + { type =127, name = "charge_id", length = 5 }, + { type = 128, name = "end_user_address", length = 0 }, + { type = 129, name = "mm_context", length = 0 }, + { type = 130, name = "pdp_context", length = 0 }, + { type = 131, name = "apn", length = 0 }, + { type = 132, name = "protocol_config", length = 0 }, + { type = 133, name = "gsn", length = 0 }, + { type = 134, name = "msisdn", length = 0 }, + { type = 135, name = "qos", length = 0 }, + { type = 136, name = "authentication_qu", length = 0 }, + { type = 137, name = "tft", length = 0 }, + { type = 138, name = "target_id", length = 0 }, + { type = 139, name = "utran_trans", length = 0 }, + { type = 140, name = "rab_setup", length = 0 }, + { type = 141, name = "ext_header", length = 0 }, + { type = 142, name = "trigger_id", length = 0 }, + { type = 143, name = "omc_id", length = 0 }, + { type = 144, name = "ran_trans", length = 0 }, + { type = 145, name = "pdp_context_pri", length = 0 }, + { type = 146, name = "addi_rab_setup", length = 0 }, + { type = 147, name = "sgsn_number", length = 0 }, + { type = 148, name = "common_flag", length = 0 }, + { type = 149, name = "apn_restriction", length = 0 }, + { type = 150, name = "radio_priority_lcs", length = 4 }, + { type = 151, name = "rat_type", length = 0 }, + { type = 152, name = "user_loc_info", length = 0 }, + { type = 153, name = "ms_time_zone", length = 0 }, + { type = 154, name = "imei_sv", length = 0 }, + { type = 155, name = "camel", length = 0 }, + { type = 156, name = "mbms_ue_context", length = 0 }, + { type = 157, name = "tmp_mobile_group_id", length = 0 }, + { type = 158, name = "rim_routing_addr", length = 0 }, + { type = 159, name = "mbms_config", length = 0 }, + { type = 160, name = "mbms_service_area", length = 0 }, + { type = 161, name = "src_rnc_pdcp", length = 0 }, + { type = 162, name = "addi_trace_info", length = 0 }, + { type = 163, name = "hop_counter", length = 0 }, + { type = 164, name = "plmn_id", length = 0 }, + { type = 165, name = "mbms_session_id", length = 0 }, + { type = 166, name = "mbms_2g3g_indicator", length = 0 }, + { type = 167, name = "enhanced_nsapi", length = 0 }, + { type = 168, name = "mbms_session_duration", length = 0 }, + { type = 169, name = "addi_mbms_trace_info", length = 0 }, + { type = 170, name = "mbms_session_repetition_num", length = 0 }, + { type = 171, name = "mbms_time_to_data", length = 0 }, + + { type = 173, name = "bss", length = 0 }, + { type = 174, name = "cell_id", length = 0 }, + { type = 175, name = "pdu_num", length = 0 }, + { type = 177, name = "mbms_bearer_capab", length = 0 }, + { type = 178, name = "rim_routing_disc", length = 0 }, + { type = 179, name = "list_pfc", length = 0 }, + { type = 180, name = "ps_xid", length = 0 }, + { type = 181, name = "ms_info_change_report", length = 4 }, + { type = 182, name = "direct_tunnel_flags", length = 0 }, + { type = 183, name = "correlation_id", length = 0 }, + { type = 184, name = "bearer_control_mode", length = 0 }, + { type = 185, name = "mbms_flow_id", length = 0 }, + { type = 186, name = "mbms_ip_multicast", length = 0 }, + { type = 187, name = "mbms_distribution_ack", length = 4 }, + { type = 188, name = "reliable_inter_rat_handover", length = 0 }, + { type = 189, name = "rfsp_index", length = 0 }, + { type = 190, name = "fqdn", length = 0 }, + { type = 191, name = "evolved_allocation1", length = 0 }, + { type = 192, name = "evolved_allocation2", length = 0 }, + { type = 193, name = "extended_flags", length = 0 }, + { type = 194, name = "uci", length = 0 }, + { type = 195, name = "csg_info", length = 0 }, + { type = 196, name = "csg_id", length = 0 }, + { type = 197, name = "cmi", length = 4 }, + { type = 198, name = "apn_ambr", length = 0 }, + { type = 199, name = "ue_network", length = 0 }, + { type = 200, name = "ue_ambr", length = 0 }, + { type = 201, name = "apn_ambr_nsapi", length = 0 }, + { type = 202, name = "ggsn_backoff_timer", length = 0 }, + { type = 203, name = "signalling_priority_indication", length = 0 }, + { type = 204, name = "signalling_priority_indication_nsapi", length = 0 }, + { type = 205, name = "high_bitrate", length = 4 }, + { type = 206, name = "max_mbr", length = 0 }, + + { type = 251, name = "charging_gateway_addr", length = 0 }, + + { type = 255, name = "private_extension", length = 0 }, +} + +gtp_v2_info = +{ + { type = 1, name = "imsi", length = 0 }, + { type = 2, name = "cause", length = 0 }, + { type = 3, name = "recovery", length = 0 }, + + { type = 71, name = "apn", length = 0 }, + { type = 72, name = "ambr", length = 0 }, + { type = 73, name = "ebi", length = 0 }, + { type = 74, name = "ip_addr", length = 0 }, + { type = 75, name = "mei", length = 0 }, + { type = 76, name = "msisdn", length = 0 }, + { type = 77, name = "indication", length = 0 }, + { type = 78, name = "pco", length = 0 }, + { type = 79, name = "paa", length = 0 }, + { type = 80, name = "bearer_qos", length = 0 }, + { type = 81, name = "flow_qos", length = 0 }, + { type = 82, name = "rat_type", length = 0 }, + { type = 83, name = "serving_network", length = 0 }, + { type = 84, name = "bearer_tft", length = 0 }, + { type = 85, name = "tad", length = 0 }, + { type = 86, name = "uli", length = 0 }, + { type = 87, name = "f_teid", length = 0 }, + { type = 88, name = "tmsi", length = 0 }, + { type = 89, name = "cn_id", length = 0 }, + { type = 90, name = "s103pdf", length = 0 }, + { type = 91, name = "s1udf", length = 0 }, + { type = 92, name = "delay_value", length = 0 }, + { type = 93, name = "bearer_context", length = 0 }, + { type = 94, name = "charging_id", length = 0 }, + { type = 95, name = "charging_char", length = 0 }, + { type = 96, name = "trace_info", length = 0 }, + { type = 97, name = "bearer_flag", length = 0 }, + + { type = 99, name = "pdn_type", length = 0 }, + { type = 100, name = "pti", length = 0 }, + { type = 101, name = "drx_parameter", length = 0 }, + + { type = 103, name = "gsm_key_tri", length = 0 }, + { type = 104, name = "umts_key_cipher_quin", length = 0 }, + { type = 105, name = "gsm_key_cipher_quin", length = 0 }, + { type = 106, name = "umts_key_quin", length = 0 }, + { type = 107, name = "eps_quad", length = 0 }, + { type = 108, name = "umts_key_quad_quin", length = 0 }, + { type = 109, name = "pdn_connection", length = 0 }, + { type = 110, name = "pdn_number", length = 0 }, + { type = 111, name = "p_tmsi", length = 0 }, + { type = 112, name = "p_tmsi_sig", length = 0 }, + { type = 113, name = "hop_counter", length = 0 }, + { type = 114, name = "ue_time_zone", length = 0 }, + { type = 115, name = "trace_ref", length = 0 }, + { type = 116, name = "complete_request_msg", length = 0 }, + { type = 117, name = "guti", length = 0 }, + { type = 118, name = "f_container", length = 0 }, + { type = 119, name = "f_cause", length = 0 }, + { type = 120, name = "plmn_id", length = 0 }, + { type = 121, name = "target_id", length = 0 }, + + { type = 123, name = "packet_flow_id", length = 0 }, + { type = 124, name = "rab_contex", length = 0 }, + { type = 125, name = "src_rnc_pdcp", length = 0 }, + { type = 126, name = "udp_src_port", length = 0 }, + { type = 127, name = "apn_restriction", length = 0 }, + { type = 128, name = "selection_mode", length = 0 }, + { type = 129, name = "src_id", length = 0 }, + + { type = 131, name = "change_report_action", length = 0 }, + { type = 132, name = "fq_csid", length = 0 }, + { type = 133, name = "channel", length = 0 }, + { type = 134, name = "emlpp_pri", length = 0 }, + { type = 135, name = "node_type", length = 0 }, + { type = 136, name = "fqdn", length = 0 }, + { type = 137, name = "ti", length = 0 }, + { type = 138, name = "mbms_session_duration", length = 0 }, + { type = 139, name = "mbms_service_area", length = 0 }, + { type = 140, name = "mbms_session_id", length = 0 }, + { type = 141, name = "mbms_flow_id", length = 0 }, + { type = 142, name = "mbms_ip_multicast", length = 0 }, + { type = 143, name = "mbms_distribution_ack", length = 0 }, + { type = 144, name = "rfsp_index", length = 0 }, + { type = 145, name = "uci", length = 0 }, + { type = 146, name = "csg_info", length = 0 }, + { type = 147, name = "csg_id", length = 0 }, + { type = 148, name = "cmi", length = 0 }, + { type = 149, name = "service_indicator", length = 0 }, + { type = 150, name = "detach_type", length = 0 }, + { type = 151, name = "ldn", length = 0 }, + { type = 152, name = "node_feature", length = 0 }, + { type = 153, name = "mbms_time_to_transfer", length = 0 }, + { type = 154, name = "throttling", length = 0 }, + { type = 155, name = "arp", length = 0 }, + { type = 156, name = "epc_timer", length = 0 }, + { type = 157, name = "signalling_priority_indication", length = 0 }, + { type = 158, name = "tmgi", length = 0 }, + { type = 159, name = "mm_srvcc", length = 0 }, + { type = 160, name = "flags_srvcc", length = 0 }, + { type = 161, name = "mmbr", length = 0 }, + + { type = 255, name = "private_extension", length = 0 }, +} + +default_gtp = +{ + { version = 0, messages = gtp_v0_msg, infos = gtp_v0_info }, + { version = 1, messages = gtp_v1_msg, infos = gtp_v1_info }, + { version = 2, messages = gtp_v2_msg, infos = gtp_v2_info }, +} + diff --git a/src/Makefile.am b/src/Makefile.am index ee1fcb6db..021998053 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,6 +11,7 @@ network_inspectors/arp_spoof/libarp_spoof.a \ service_inspectors/back_orifice/libback_orifice.a \ service_inspectors/dns/libdns.a \ service_inspectors/ftp_telnet/libftp_telnet.a \ +service_inspectors/gtp/libgtp_inspect.a \ service_inspectors/imap/libimap.a \ service_inspectors/nhttp_inspect/libnhttp_inspect.a \ service_inspectors/pop/libpop.a \ diff --git a/src/codecs/misc/cd_gtp.cc b/src/codecs/misc/cd_gtp.cc index f322ca04e..709678f4a 100644 --- a/src/codecs/misc/cd_gtp.cc +++ b/src/codecs/misc/cd_gtp.cc @@ -173,9 +173,6 @@ bool GtpCodec::decode(const RawData& raw, CodecData& codec, DecodeData&) else len = GTP_MIN_LEN; - codec.lyr_len = len; - codec.proto_bits |= PROTO_BIT__GTP; - if (raw.len != ((unsigned int)ntohs(hdr->length) + GTP_MIN_LEN)) { DebugFormat(DEBUG_DECODE, "Calculated length %d != %d in header.\n", @@ -183,8 +180,8 @@ bool GtpCodec::decode(const RawData& raw, CodecData& codec, DecodeData&) codec_event(codec, DECODE_GTP_BAD_LEN); return false; } - break; + default: DebugMessage(DEBUG_DECODE, "Unknown protocol version.\n"); return false; @@ -193,11 +190,18 @@ bool GtpCodec::decode(const RawData& raw, CodecData& codec, DecodeData&) if ( SnortConfig::tunnel_bypass_enabled(TUNNEL_GTP) ) Active::set_tunnel_bypass(); + codec.lyr_len = len; + + if ( codec.proto_bits & PROTO_BIT__GTP ) + codec_event(codec, DECODE_GTP_MULTIPLE_ENCAPSULATION); + else + codec.proto_bits |= PROTO_BIT__GTP; + if (raw.len > 0) { codec.codec_flags |= CODEC_ENCAP_LAYER; - ip_ver = *(raw.data + GTP_MIN_LEN) & 0xF0; + ip_ver = *(raw.data + len) & 0xF0; if (ip_ver == 0x40) codec.next_prot_id = IPPROTO_ID_IPIP; else if (ip_ver == 0x60) diff --git a/src/framework/value.cc b/src/framework/value.cc index 6d832aa6e..c4e694b51 100644 --- a/src/framework/value.cc +++ b/src/framework/value.cc @@ -162,6 +162,23 @@ bool Value::strtol(long& n) const return true; } +bool Value::strtol(long& n, const std::string& tok) const +{ + const char* s = tok.c_str(); + + if ( !*s ) + return false; + + char* end = nullptr; + + n = ::strtol(s, &end, 0); + + if ( *end ) + return false; + + return true; +} + const char* Value::get_as_string() { switch ( type ) diff --git a/src/framework/value.h b/src/framework/value.h index 07fe5cc30..41204366b 100644 --- a/src/framework/value.h +++ b/src/framework/value.h @@ -101,6 +101,7 @@ public: const char* get_as_string(); bool strtol(long&) const; + bool strtol(long&, const std::string&) const; bool operator==(const char* s) const { return str == s; } diff --git a/src/protocols/packet.h b/src/protocols/packet.h index d55d6d52c..553c7cfca 100644 --- a/src/protocols/packet.h +++ b/src/protocols/packet.h @@ -208,6 +208,9 @@ struct SO_PUBLIC Packet inline bool has_tcp_data() const { return (proto_bits & PROTO_BIT__TCP) and data and dsize; } + inline bool has_udp_data() const + { return (proto_bits & PROTO_BIT__UDP) and data and dsize; } + /* Get general, non-boolean information */ inline PktType type() const { return ptrs.get_pkt_type(); } // defined in codec.h diff --git a/src/protocols/packet_manager.cc b/src/protocols/packet_manager.cc index 844190009..e5c469b61 100644 --- a/src/protocols/packet_manager.cc +++ b/src/protocols/packet_manager.cc @@ -272,11 +272,9 @@ void PacketManager::decode( assert(curr_lyr_len <= raw.len); raw.len -= curr_lyr_len; raw.data += curr_lyr_len; - p->proto_bits |= codec_data.proto_bits; codec_data.next_prot_id = FINISHED_DECODE; codec_data.lyr_len = 0; codec_data.invalid_bytes = 0; - codec_data.proto_bits = 0; } DebugFormat(DEBUG_DECODE, "Codec %s (protocol_id: %hu: ip header" diff --git a/src/service_inspectors/CMakeLists.txt b/src/service_inspectors/CMakeLists.txt index 8e3744d68..ba11297b7 100644 --- a/src/service_inspectors/CMakeLists.txt +++ b/src/service_inspectors/CMakeLists.txt @@ -1,7 +1,8 @@ add_subdirectory(back_orifice) -add_subdirectory(ftp_telnet) add_subdirectory(dns) +add_subdirectory(ftp_telnet) +add_subdirectory(gtp) add_subdirectory(http_inspect) add_subdirectory(imap) add_subdirectory(nhttp_inspect) @@ -16,8 +17,9 @@ add_subdirectory(wizard) if (STATIC_INSPECTORS) set (STATIC_INSECTOR_LIBS back_orifice - ftp_telnet dns + ftp_telnet + gtp imap nhttp_inspect pop diff --git a/src/service_inspectors/Makefile.am b/src/service_inspectors/Makefile.am index f7d2c8535..dea53a1aa 100644 --- a/src/service_inspectors/Makefile.am +++ b/src/service_inspectors/Makefile.am @@ -18,6 +18,7 @@ SUBDIRS = \ back_orifice \ dns \ ftp_telnet \ +gtp \ http_inspect \ imap \ nhttp_inspect \ diff --git a/src/service_inspectors/gtp/CMakeLists.txt b/src/service_inspectors/gtp/CMakeLists.txt new file mode 100644 index 000000000..9e4d71746 --- /dev/null +++ b/src/service_inspectors/gtp/CMakeLists.txt @@ -0,0 +1,23 @@ + +set( FILE_LIST + gtp.cc + gtp.h + gtp_inspect.cc + gtp_inspect.h + gtp_module.cc + gtp_module.h + gtp_parser.cc + gtp_parser.h + ips_gtp_info.cc + ips_gtp_type.cc + ips_gtp_version.cc +) + +if (STATIC_INSPECTORS) + add_library(gtp STATIC ${FILE_LIST}) + +else (STATIC_INSPECTORS) + add_shared_library(gtp inspectors ${FILE_LIST}) + +endif (STATIC_INSPECTORS) + diff --git a/src/service_inspectors/gtp/Makefile.am b/src/service_inspectors/gtp/Makefile.am new file mode 100644 index 000000000..0f95b30d7 --- /dev/null +++ b/src/service_inspectors/gtp/Makefile.am @@ -0,0 +1,27 @@ + +file_list = \ +gtp.cc \ +gtp.h \ +gtp_inspect.cc \ +gtp_inspect.h \ +gtp_module.cc \ +gtp_module.h \ +gtp_parser.cc \ +gtp_parser.h \ +ips_gtp_info.cc \ +ips_gtp_type.cc \ +ips_gtp_version.cc + +if STATIC_INSPECTORS +noinst_LIBRARIES = libgtp_inspect.a +libgtp_inspect_a_SOURCES = $(file_list) +else +shlibdir = $(pkglibdir)/inspectors +shlib_LTLIBRARIES = libgtp_inspect.la +libgtp_inspect_la_CXXFLAGS = $(AM_CXXFLAGS) -DBUILDING_SO +libgtp_inspect_la_LDFLAGS = -export-dynamic -shared +libgtp_inspect_la_SOURCES = $(file_list) +endif + +AM_CXXFLAGS = @AM_CXXFLAGS@ + diff --git a/src/service_inspectors/gtp/dev_notes.txt b/src/service_inspectors/gtp/dev_notes.txt new file mode 100644 index 000000000..2a96954aa --- /dev/null +++ b/src/service_inspectors/gtp/dev_notes.txt @@ -0,0 +1,18 @@ +gtp_inspect provides anomaly detection and IPS rule options for matching on +version, types, and information elements in GTP control messages. The +inspector is independent of the codec used for data channel encapsulations. + +At present 3 versions are supported: 0, 1, and 2. The basic configuration +is provided in snort_defaults.lua. Adding a version 3 requires updating +both code and lua defaults. The key code change is to MAX_GTP_VERSION_CODE, +which is defined in gtp.h. + +PDU processing for all versions is currently in gtp_parser.cc. A message +ID is used to determine if information element data applies to the current +message. This eliminates the need to reset all possible information +element offsets. This data is used to support rule options. + +GTP control messages do not contain sufficient information to enable +automatic protocol detection, hence there is no support in the wizard. +Ports, typically UDP 2123, must be configured in the binder. + diff --git a/src/service_inspectors/gtp/gtp.cc b/src/service_inspectors/gtp/gtp.cc new file mode 100644 index 000000000..06688b2e3 --- /dev/null +++ b/src/service_inspectors/gtp/gtp.cc @@ -0,0 +1,122 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved. +// Copyright (C) 2011-2013 Sourcefire, Inc. +// +// 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. +//-------------------------------------------------------------------------- + +// gtp.cc author Hui Cao +// This is the main entry point for this preprocessor + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gtp.h" + +#include +#include +#include +#include +#include +#include + +#ifndef WIN32 +#include +#include +#endif + +#include "main/snort_debug.h" +#include "main/snort_types.h" +#include "protocols/packet.h" +#include "time/profiler.h" + +#include "gtp.h" +#include "gtp_inspect.h" +#include "gtp_parser.h" + +#define GTPMSG_ZERO_LEN offsetof(GTPMsg, msg_id) + +THREAD_LOCAL GTP_Stats gtp_stats; + +// Analyzes GTP packets for anomalies/exploits. +static inline int GTP_Process(Packet* p, GTP_Roptions* pRopts) +{ + const uint8_t* gtp_buff = p->data; + static THREAD_LOCAL uint32_t msgId = 0; + + GTPMsg gtpMsg; + memset(>pMsg, 0, GTPMSG_ZERO_LEN); + + /* msg_id is used to associate message with information elements + * If msg_id matches, the information element in the info_elements + * belongs to the message + * Using msg_id avoids initializing info_elements for every message + * Tabled based info_elements improves information element search performance */ + + /* To avoid id overlap, clean table when msgId resets*/ + if ( msgId == 0) + gtp_cleanInfoElements(); + + gtpMsg.msg_id = ++msgId; + + int status = gtp_parse(>pMsg, gtp_buff, p->dsize); + + /*Update the session data*/ + pRopts->gtp_type = gtpMsg.msg_type; + pRopts->gtp_version = gtpMsg.version; + pRopts->gtp_infoElements = gtpMsg.info_elements; + pRopts->gtp_header = gtpMsg.gtp_header; + pRopts->msg_id = gtpMsg.msg_id; + + DEBUG_WRAP(DebugFormat(DEBUG_GTP, "GTP message version: %d\n", gtpMsg.version)); + DEBUG_WRAP(DebugFormat(DEBUG_GTP, "GTP message type: %d\n", gtpMsg.msg_type)); + + return status; +} + +static GTP_Roptions* GTPGetNewSession(Packet* packetp) +{ + GtpFlowData* gfd = new GtpFlowData; + packetp->flow->set_application_data(gfd); + + GTP_Roptions* pRopts = &gfd->ropts; + gtp_stats.sessions++; + + return pRopts; +} + +// Main runtime entry point for GTP preprocessor. +void GTPmain(Packet* packetp) +{ + /* Attempt to get a previously allocated GTP block. */ + GtpFlowData* gfd = (GtpFlowData*)packetp->flow->get_application_data(GtpFlowData::flow_id); + GTP_Roptions* pRopts = gfd ? &gfd->ropts : nullptr; + + if ( !pRopts ) + { + pRopts = GTPGetNewSession(packetp); + + if ( !pRopts ) + { + /* Could not get/create the session data for this packet. */ + DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Create session error - not inspecting.\n")); + return; + } + } + + GTP_Process(packetp, pRopts); +} + diff --git a/src/service_inspectors/gtp/gtp.h b/src/service_inspectors/gtp/gtp.h new file mode 100644 index 000000000..f02733d3a --- /dev/null +++ b/src/service_inspectors/gtp/gtp.h @@ -0,0 +1,77 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved. +// Copyright (C) 2011-2013 Sourcefire, Inc. +// +// 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. +//-------------------------------------------------------------------------- + +// gtp.h author Hui Cao + +#ifndef GTP_H +#define GTP_H + +// Provides convenience functions for parsing and querying configuration. + +#include +#include "main/thread.h" +#include "framework/counts.h" + +#define MIN_GTP_VERSION_CODE (0) +#define MAX_GTP_VERSION_CODE (2) + +#define MIN_GTP_TYPE_CODE (0) +#define MAX_GTP_TYPE_CODE (255) + +#define MIN_GTP_IE_CODE (0) +#define MAX_GTP_IE_CODE (255) + +struct GTP_MsgType +{ + std::string name; +}; + +struct GTP_InfoElement +{ + std::string name; + uint16_t length; // 0 for variable length +}; + +struct GTPConfig +{ + GTP_MsgType msgv[MAX_GTP_VERSION_CODE + 1][MAX_GTP_TYPE_CODE + 1]; + GTP_InfoElement infov[MAX_GTP_VERSION_CODE + 1][MAX_GTP_IE_CODE + 1]; +}; + +struct GTP_Stats +{ + PegCount sessions; + PegCount events; + PegCount unknownTypes; + PegCount unknownIEs; + + // FIXIT-L add these stats + //PegCount messages[MAX_GTP_VERSION_CODE + 1][MAX_GTP_TYPE_CODE + 1]; + + // FIXIT-L can't put non-pegs in stats; why is this here? + //GTP_MsgType* msgTypeTable[MAX_GTP_VERSION_CODE + 1][MAX_GTP_TYPE_CODE + 1]; +}; + +extern THREAD_LOCAL GTPConfig* gtp_eval_config; +extern THREAD_LOCAL GTP_Stats gtp_stats; + +void GTPmain(struct Packet*); + +#endif + diff --git a/src/service_inspectors/gtp/gtp_inspect.cc b/src/service_inspectors/gtp/gtp_inspect.cc new file mode 100644 index 000000000..3c63e05b7 --- /dev/null +++ b/src/service_inspectors/gtp/gtp_inspect.cc @@ -0,0 +1,225 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 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. +//-------------------------------------------------------------------------- + +// gtp_inspect.cc author Russ Combs +// adapt 2x preprocessor code to 3x inspector + +#include "gtp_inspect.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "managers/inspector_manager.h" +#include "time/profiler.h" + +#include "gtp.h" +#include "gtp_module.h" + +THREAD_LOCAL GTPConfig* gtp_eval_config = nullptr; + +//------------------------------------------------------------------------- +// flow stuff +//------------------------------------------------------------------------- + +unsigned GtpFlowData::flow_id = 0; + +void GtpFlowData::init() +{ + flow_id = FlowData::get_flow_id(); +} + +GtpFlowData::GtpFlowData() : FlowData(flow_id) +{ + memset(&ropts, 0, sizeof(ropts)); +} + +//------------------------------------------------------------------------- +// class stuff +//------------------------------------------------------------------------- + +class GtpInspect : public Inspector +{ +public: + GtpInspect(std::vector&); + + void eval(Packet*) override; + + int get_message_type(int version, const char* name); + int get_info_type(int version, const char* name); + +private: + GTPConfig config; +}; + +GtpInspect::GtpInspect(std::vector& v) +{ + for ( unsigned i = 0; i < v.size(); ++i ) + { + GtpStuff& gs = v[i]; + + if ( gs.length < 0 ) + { + config.msgv[gs.version][gs.type].name = gs.name; + } + else + { + config.infov[gs.version][gs.type].name = gs.name; + config.infov[gs.version][gs.type].length = gs.length; + } + } +} + +void GtpInspect::eval(Packet* p) +{ + PERF_PROFILE(gtp_inspect_prof); + + // preconditions - what we registered for + assert(p->has_udp_data()); + + gtp_eval_config = &config; + GTPmain(p); +} + +//------------------------------------------------------------------------- +// public lookups +//------------------------------------------------------------------------- + +int GtpInspect::get_message_type(int version, const char* name) +{ + if ( version < 0 or version > MAX_GTP_VERSION_CODE ) + return -1; + + for ( int i = 0; i <= MAX_GTP_TYPE_CODE; ++i ) + if ( config.msgv[version][i].name == name ) + return i; + + return -1; +} + +int get_message_type(int version, const char* name) +{ + GtpInspect* ins = (GtpInspect*)InspectorManager::get_inspector(GTP_NAME); + + if ( !ins ) + return -1; + + return ins->get_message_type(version, name); +} + +int GtpInspect::get_info_type(int version, const char* name) +{ + if ( version < 0 or version > MAX_GTP_VERSION_CODE ) + return -1; + + for ( int i = 0; i <= MAX_GTP_TYPE_CODE; ++i ) + if ( config.infov[version][i].name == name ) + return i; + + return -1; +} + +int get_info_type(int version, const char* name) +{ + GtpInspect* ins = (GtpInspect*)InspectorManager::get_inspector(GTP_NAME); + + if ( !ins ) + return -1; + + return ins->get_info_type(version, name); +} + +//------------------------------------------------------------------------- +// plugin stuff +//------------------------------------------------------------------------- + +static Module* mod_ctor() +{ return new GtpInspectModule; } + +static void mod_dtor(Module* m) +{ delete m; } + +static void gtp_init() +{ + GtpFlowData::init(); +} + +static void gtp_term() +{ +} + +static Inspector* gtp_ctor(Module* m) +{ + GtpInspectModule* mod = (GtpInspectModule*)m; + // this move assures the stuff is cleared + std::vector v = std::move(mod->config); + return new GtpInspect(v); +} + +static void gtp_dtor(Inspector* p) +{ + delete p; +} + +//------------------------------------------------------------------------- + +static const InspectApi gtp_api = +{ + { + PT_INSPECTOR, + sizeof(InspectApi), + INSAPI_VERSION, + 0, + API_RESERVED, + API_OPTIONS, + GTP_NAME, + GTP_HELP, + mod_ctor, + mod_dtor + }, + IT_SERVICE, + (uint16_t)PktType::UDP, + nullptr, + "gtp", + gtp_init, + gtp_term, + nullptr, // tinit + nullptr, // tterm + gtp_ctor, + gtp_dtor, + nullptr, // ssn + nullptr // reset +}; + +#ifdef BUILDING_SO +extern const BaseApi* ips_gtp_info; +extern const BaseApi* ips_gtp_type; +extern const BaseApi* ips_gtp_version; + +SO_PUBLIC const BaseApi* snort_plugins[] = +{ + >p_api.base, + ips_gtp_info, + ips_gtp_type, + ips_gtp_version, + nullptr +}; +#else +const BaseApi* sin_gtp = >p_api.base; +#endif + diff --git a/src/service_inspectors/gtp/gtp_inspect.h b/src/service_inspectors/gtp/gtp_inspect.h new file mode 100644 index 000000000..13542e8f1 --- /dev/null +++ b/src/service_inspectors/gtp/gtp_inspect.h @@ -0,0 +1,53 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 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. +//-------------------------------------------------------------------------- + +// gtp_inspect.h author Russ Combs + +#ifndef GTP_INSPECT_H +#define GTP_INSPECT_H + +#include "flow/flow.h" +#include "gtp_parser.h" + +// FIXIT-H why store per packet on flow? +struct GTP_Roptions +{ + uint8_t gtp_type; + uint8_t gtp_version; + uint8_t* gtp_header; + uint32_t msg_id; /* used to associate to current msg */ + GTP_IEData* gtp_infoElements; +}; + +class GtpFlowData : public FlowData +{ +public: + GtpFlowData(); + + static void init(); + +public: + static unsigned flow_id; + GTP_Roptions ropts; +}; + +int get_message_type(int version, const char* name); +int get_info_type(int version, const char* name); + +#endif + diff --git a/src/service_inspectors/gtp/gtp_module.cc b/src/service_inspectors/gtp/gtp_module.cc new file mode 100644 index 000000000..e9608399b --- /dev/null +++ b/src/service_inspectors/gtp/gtp_module.cc @@ -0,0 +1,177 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2014-2015 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. +//-------------------------------------------------------------------------- + +// gtp_module.cc author Russ Combs + +#include "gtp_module.h" + +#include "gtp.h" +#include "time/profiler.h" + +THREAD_LOCAL ProfileStats gtp_inspect_prof; + +#define GTP_EVENT_BAD_MSG_LEN_STR "message length is invalid" +#define GTP_EVENT_BAD_IE_LEN_STR "information element length is invalid" +#define GTP_EVENT_OUT_OF_ORDER_IE_STR "information elements are out of order" + +//------------------------------------------------------------------------- +// stats +//------------------------------------------------------------------------- + +const PegInfo peg_names[] = +{ + { "sessions", "total sessions processed" }, + { "events", "requests" }, + { "unknown types", "unknown message types" }, + { "unknown infos", "unknown information elements" }, + + { nullptr, nullptr } +}; + +const PegInfo* GtpInspectModule::get_pegs() const +{ return peg_names; } + +PegCount* GtpInspectModule::get_counts() const +{ return (PegCount*)>p_stats; } + +//------------------------------------------------------------------------- +// rules +//------------------------------------------------------------------------- + +static const RuleMap gtp_rules[] = +{ + { GTP_EVENT_BAD_MSG_LEN, GTP_EVENT_BAD_MSG_LEN_STR }, + { GTP_EVENT_BAD_IE_LEN, GTP_EVENT_BAD_IE_LEN_STR }, + { GTP_EVENT_OUT_OF_ORDER_IE, GTP_EVENT_OUT_OF_ORDER_IE_STR }, + + { 0, nullptr } +}; + +const RuleMap* GtpInspectModule::get_rules() const +{ return gtp_rules; } + +//------------------------------------------------------------------------- +// params +//------------------------------------------------------------------------- + +static const Parameter gtp_msg_params[] = +{ + { "type", Parameter::PT_INT, "0:255", "0", + "message type code" }, + + { "name", Parameter::PT_STRING, nullptr, nullptr, + "message name" }, + + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + +static const Parameter gtp_info_params[] = +{ + { "type", Parameter::PT_INT, "0:255", "0", + "information element type code" }, + + { "name", Parameter::PT_STRING, nullptr, nullptr, + "information element name" }, + + { "length", Parameter::PT_INT, "0:255", "0", + "information element type code" }, + + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + + +static const Parameter gtp_params[] = +{ + { "version", Parameter::PT_INT, "0:2", "2", + "gtp version" }, + + { "messages", Parameter::PT_LIST, gtp_msg_params, nullptr, + "message dictionary" }, + + { "infos", Parameter::PT_LIST, gtp_info_params, nullptr, + "information element dictionary" }, + + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + +GtpInspectModule::GtpInspectModule() : + Module(GTP_NAME, GTP_HELP, gtp_params, true) +{ } + +bool GtpInspectModule::set(const char*, Value& v, SnortConfig*) +{ + if ( v.is("version") ) + stuff.version = v.get_long(); + + else if ( v.is("type") ) + stuff.type = v.get_long(); + + else if ( v.is("length") ) + stuff.length = v.get_long(); + + else if ( v.is("name") ) + stuff.name = v.get_string(); + + else + return false; + + return true; +} + +bool GtpInspectModule::begin(const char* fqn, int idx, SnortConfig*) +{ + if ( !strcmp(fqn, "gtp_inspect") and !idx ) + { + temp.clear(); + config.clear(); + } + + // version persists + stuff.name.clear(); + stuff.type = 0; + stuff.length = -1; + + return true; +} + +// we may not get current version until after lists are loaded +// so the lists go to temp and when the list item is closed we +// move to the main config. +bool GtpInspectModule::end(const char* fqn, int idx, SnortConfig*) +{ + if ( !strcmp(fqn, "gtp_inspect") and idx ) + { + for ( unsigned i = 0; i < temp.size(); ++i ) + { + temp[i].version = stuff.version; + config.push_back(temp[i]); + } + temp.clear(); + } + else if ( !strcmp(fqn, "gtp_inspect.messages") and idx ) + { + assert(stuff.length < 0); + temp.push_back(stuff); + } + else if ( !strcmp(fqn, "gtp_inspect.infos") and idx ) + { + assert(stuff.length >= 0); + temp.push_back(stuff); + } + return true; +} diff --git a/src/service_inspectors/gtp/gtp_module.h b/src/service_inspectors/gtp/gtp_module.h new file mode 100644 index 000000000..d349abb3c --- /dev/null +++ b/src/service_inspectors/gtp/gtp_module.h @@ -0,0 +1,76 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2014-2015 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. +//-------------------------------------------------------------------------- + +// gtp_module.cc author Russ Combs + +#ifndef GTP_MODULE_H +#define GTP_MODULE_H + +#include +#include + +#include "framework/module.h" +#include "main/thread.h" + +#define GID_GTP 143 + +#define GTP_EVENT_BAD_MSG_LEN (1) +#define GTP_EVENT_BAD_IE_LEN (2) +#define GTP_EVENT_OUT_OF_ORDER_IE (3) + +#define GTP_NAME "gtp_inspect" +#define GTP_HELP "gtp control channel inspection" + +extern THREAD_LOCAL ProfileStats gtp_inspect_prof; + +struct GtpStuff +{ + std::string name; + int version; + int type; + int length; +}; + +class GtpInspectModule : public Module +{ +public: + GtpInspectModule(); + + bool set(const char*, Value&, SnortConfig*) override; + bool begin(const char*, int, SnortConfig*) override; + bool end(const char*, int, SnortConfig*) override; + + unsigned get_gid() const override + { return GID_GTP; } + + const RuleMap* get_rules() const override; + + const PegInfo* get_pegs() const override; + PegCount* get_counts() const override; + + ProfileStats* get_profile() const override + { return >p_inspect_prof; } + +public: + GtpStuff stuff; + std::vector temp; + std::vector config; +}; + +#endif + diff --git a/src/service_inspectors/gtp/gtp_parser.cc b/src/service_inspectors/gtp/gtp_parser.cc new file mode 100644 index 000000000..1d240d94e --- /dev/null +++ b/src/service_inspectors/gtp/gtp_parser.cc @@ -0,0 +1,571 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved. +// Copyright (C) 2011-2013 Sourcefire, Inc. +// +// 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. +//-------------------------------------------------------------------------- +// gtp_parser.cc author Hui Cao + +// parses gtp control messages + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gtp_parser.h" + +#include + +#include "main/snort_types.h" +#include "main/snort_debug.h" +#include "events/event_queue.h" +#include "protocols/packet.h" + +#include "gtp.h" +#include "gtp_module.h" + +#ifdef WIN32 +#pragma pack(push,gtp_hdrs,1) +#else +#pragma pack(1) +#endif + +static inline void alert(int sid) +{ + SnortEventqAdd(GID_GTP, sid); + gtp_stats.events++; +} + +/* GTP basic Header */ +struct GTP_C_Hdr +{ + uint8_t flag; /* flag: version (bit 6-8), PT (5), E (3), S (2), PN (1) */ + uint8_t type; /* message type */ + uint16_t length; /* length */ +}; + +struct GTP_C_Hdr_v0 +{ + GTP_C_Hdr hdr; + uint16_t sequence_num; + uint16_t flow_lable; + uint64_t tid; +}; + +/* GTP Information element Header */ +struct GTP_IE_Hdr +{ + uint8_t type; + uint16_t length; /* length */ +}; + +#ifdef WIN32 +#pragma pack(pop,gtp_hdrs) +#else +#pragma pack() +#endif + +/* This table stores all the information elements in a packet + * To save memory, only one table for all packets, because we inspect + * one packet at a time + * The information in the table might from previous packet, + * use msg_id to find out whether the information is current. + * */ +THREAD_LOCAL GTP_IEData gtp_ies[MAX_GTP_IE_CODE + 1]; + +#define GTP_HEADER_LEN_V0 (20) +#define GTP_HEADER_LEN_V1 (12) +#define GTP_HEADER_LEN_V2 (8) +#define GTP_HEADER_LEN_EPC_V2 (12) +#define GTP_LENGTH_OFFSET_V0 (GTP_HEADER_LEN_V0) +#define GTP_LENGTH_OFFSET_V1 (8) +#define GTP_LENGTH_OFFSET_V2 (4) + +#define GTP_MIN_HEADER_LEN (8) + +#ifdef DEBUG_MSGS +/*Display the content*/ +static void convertToHex(char* output, int outputSize, const uint8_t* input, int inputSize) +{ + int i = 0; + int length; + int numBytesInLine = 0; + int totalBytes = outputSize; + char* buf_ptr = output; + + while ((i < inputSize)&&(totalBytes > 0)) + { + length = snprintf(buf_ptr, totalBytes, "%.2x ", (uint8_t)input[i]); + buf_ptr += length; + totalBytes -= length; + if (totalBytes < 0) + break; + numBytesInLine += length; + + if (numBytesInLine > 80) + { + snprintf(buf_ptr++, totalBytes, "\n"); + totalBytes--; + numBytesInLine = 0; + } + i++; + } +} + +/* Display the information elements*/ +static void printInfoElements(GTP_IEData* info_elements, GTPMsg* msg) +{ + int i; + + for (i=0; i < MAX_GTP_IE_CODE + 1; i++) + { + char buf[STD_BUF]; + if (info_elements[i].msg_id == msg->msg_id) + { + convertToHex( (char*)buf, sizeof(buf), + msg->gtp_header + info_elements[i].shift, info_elements[i].length); + DEBUG_WRAP(DebugFormat(DEBUG_GTP, "Info type: %.3d, content: %s\n", i, buf); ); + } + } +} +#endif + +/******************************************************************** + * Function: gtp_processInfoElements() + * + * Process information elements + * + * Arguments: + * GTPMsg *: the GTP message + * + * char * + * Pointer to the current position in the GTP message. + * + * uint8_t * + * Pointer to the port array mask to set bits for the ports + * parsed. + * + * Returns: + * GTP_Ret + * true if we were able to successfully parse the + * port list. + * false if an error occured in parsing the port list. + * + ********************************************************************/ +static int gtp_processInfoElements(GTPMsg* msg, const uint8_t* buff, uint16_t len) +{ + uint8_t* start; + uint8_t type; + int32_t unprocessed_len; + uint8_t previous_type; + + DEBUG_WRAP(DebugFormat(DEBUG_GTP, "Information elements: length: %d\n", len); ); + + start = (uint8_t*)buff; + previous_type = (uint8_t)*start; + unprocessed_len = len; + + while ( unprocessed_len > 0) + { + GTP_InfoElement* ie; + uint16_t length; + + type = *start; + + if (previous_type > type) + alert(GTP_EVENT_OUT_OF_ORDER_IE); + + ie = >p_eval_config->infov[msg->version][type]; + + if ( NULL == ie ) + { + DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Unsupported Information elements!\n"); ); + gtp_stats.unknownIEs++; + return false; + } + + /*For fixed length, use the table*/ + if (ie->length) + { + length = ie->length; + } + else /*For variable length, use the length field*/ + { + GTP_IE_Hdr* ieHdr; + /*check the length before reading*/ + if (sizeof(*ieHdr) > (unsigned)unprocessed_len) + { + alert(GTP_EVENT_BAD_IE_LEN); + return false; + } + ieHdr = (GTP_IE_Hdr*)start; + length = ntohs(ieHdr->length); + /*Check the length */ + if (length > UINT16_MAX - GTP_MIN_HEADER_LEN - sizeof(*ieHdr)) + { + alert(GTP_EVENT_BAD_IE_LEN); + return false; + } + + if (msg->version == 2) + length += 4; + else + length += 3; + } + + if (length > unprocessed_len ) + { + alert(GTP_EVENT_BAD_IE_LEN); + return false; + } + + /*Combine the same information element type into one buffer*/ + if ((previous_type == type) && (msg->info_elements[type].msg_id == msg->msg_id)) + { + msg->info_elements[type].length += length; + } + else + { + msg->info_elements[type].length = length; + msg->info_elements[type].shift = start - msg->gtp_header; + msg->info_elements[type].msg_id = msg->msg_id; + } + + DEBUG_WRAP(DebugFormat(DEBUG_GTP, "GTP information element: %s(%d), length: %d\n", + ie->name.c_str(), type, length)); + start += length; + unprocessed_len -= length; + previous_type = type; + } + DEBUG_WRAP(printInfoElements(msg->info_elements, msg); ); + return true; +} + +/******************************************************************** + * Function: gtp_parse_v0() + * + * process the GTP v0 message. + * + * Arguments: + * GTPMsg * - gtp message + * char* buff - start of the gtp message buffer + * uint16_t - length of the message + * + * Returns: + * false + * true + * Bits + *Octets 8 7 6 5 4 3 2 1 + *1 Version PT 1 1 1 SNN + *2 Message Type + *3-4 Length + *5-6 Sequence Number + *7-8 Flow Label + *9 SNDCP N-PDULLC Number + *10 Spare ‘ 1 1 1 1 1 1 1 1 ‘ + *11 Spare ‘ 1 1 1 1 1 1 1 1 ‘ + *12 Spare ‘ 1 1 1 1 1 1 1 1 ‘ + *13-20 TID + * + ********************************************************************/ + +static int gtp_parse_v0(GTPMsg* msg, const uint8_t* buff, uint16_t gtp_len) +{ + GTP_C_Hdr* hdr; + + DEBUG_WRAP(DebugMessage(DEBUG_GTP, "This is a GTP v0 packet.\n"); ); + + hdr = (GTP_C_Hdr*)buff; + + msg->header_len = GTP_HEADER_LEN_V0; + + /*Check the length field. */ + if (gtp_len != ((unsigned int)ntohs(hdr->length) + GTP_LENGTH_OFFSET_V0)) + { + DEBUG_WRAP(DebugFormat(DEBUG_GTP, "Calculated length %d != %d in header.\n", + gtp_len - GTP_LENGTH_OFFSET_V0, ntohs(hdr->length)); ); + alert(GTP_EVENT_BAD_MSG_LEN); + return false; + } + + return true; +} + +/******************************************************************** + * Function: gtp_parse_v1() + * + * process the GTP v1 message. + * + * Arguments: + * GTPMsg * - gtp message + * char* buff - start of the gtp message buffer + * uint16_t - length of the message + * + * Returns: + * false + * true + * + * Octets 8 7 6 5 4 3 2 1 + * 1 Version PT (*) E S PN + * 2 Message Type + * 3 Length (1st Octet) + * 4 Length (2nd Octet) + * 5 Tunnel Endpoint Identifier (1st Octet) + * 6 Tunnel Endpoint Identifier (2nd Octet) + * 7 Tunnel Endpoint Identifier (3rd Octet) + * 8 Tunnel Endpoint Identifier (4th Octet) + * 9 Sequence Number (1st Octet) + * 10 Sequence Number (2nd Octet) + * 11 N-PDU Number + * 12 Next Extension Header Type + ********************************************************************/ +static int gtp_parse_v1(GTPMsg* msg, const uint8_t* buff, uint16_t gtp_len) +{ + uint8_t next_hdr_type; + GTP_C_Hdr* hdr; + + DEBUG_WRAP(DebugMessage(DEBUG_GTP, "This ia a GTP v1 packet.\n"); ); + + hdr = (GTP_C_Hdr*)buff; + + /*Check the length based on optional fields and extension header*/ + if (hdr->flag & 0x07) + { + msg->header_len = GTP_HEADER_LEN_V1; + /*Check optional fields*/ + if (gtp_len < msg->header_len) + { + alert(GTP_EVENT_BAD_MSG_LEN); + return false; + } + + next_hdr_type = *(buff + msg->header_len - 1); + + /*Check extension headers*/ + while (next_hdr_type) + { + uint16_t ext_header_len; + + /*check length before reading data, at lease 4 bytes per extension header*/ + if (gtp_len < msg->header_len + 4) + { + alert(GTP_EVENT_BAD_MSG_LEN); + return false; + } + + ext_header_len = *(buff + msg->header_len); + + if (!ext_header_len) + { + alert(GTP_EVENT_BAD_MSG_LEN); + return false; + } + + /*Extension header length is a unit of 4 octets*/ + msg->header_len += ext_header_len*4; + + /*check length before reading data*/ + if (gtp_len < msg->header_len) + { + alert(GTP_EVENT_BAD_MSG_LEN); + return false; + } + next_hdr_type = *(buff + msg->header_len - 1); + } + } + else + msg->header_len = GTP_HEADER_LEN_V1; + + /*Check the length field. */ + if (gtp_len != ((unsigned int)ntohs(hdr->length) + GTP_LENGTH_OFFSET_V1)) + { + DEBUG_WRAP(DebugFormat(DEBUG_GTP, "Calculated length %d != %d in header.\n", + gtp_len - GTP_LENGTH_OFFSET_V1, ntohs(hdr->length)); ); + alert(GTP_EVENT_BAD_MSG_LEN); + return false; + } + + return true; +} + +/******************************************************************** + * Function: gtp_parse_v2() + * + * process the GTP v2 message. + * + * Arguments: + * GTPMsg * - gtp message + * char* buff - start of the gtp message buffer + * uint16_t - length of the message + * + * Returns: + * false + * true + * + *Octets 8 7 6 5 4 3 2 1 + *1 Version P T Spare Spare Spare + *2 Message Type + *3 Message Length (1st Octet) + *4 Message Length (2nd Octet) + *m to k(m+3) If T flag is set to 1, then TEID shall be placed into octets 5-8. + * Otherwise, TEID field is not present at all. + *n to (n+2) Sequence Number + *(n+3) Spare + ********************************************************************/ +static int gtp_parse_v2(GTPMsg* msg, const uint8_t* buff, uint16_t gtp_len) +{ + GTP_C_Hdr* hdr; + + DEBUG_WRAP(DebugMessage(DEBUG_GTP, "This ia a GTP v2 packet.\n"); ); + + hdr = (GTP_C_Hdr*)buff; + + if (hdr->flag & 0x8) + msg->header_len = GTP_HEADER_LEN_EPC_V2; + else + msg->header_len = GTP_HEADER_LEN_V2; + + /*Check the length field. */ + if (gtp_len != ((unsigned int)ntohs(hdr->length) + GTP_LENGTH_OFFSET_V2)) + { + DEBUG_WRAP(DebugFormat(DEBUG_GTP, "Calculated length %d != %d in header.\n", + gtp_len - GTP_LENGTH_OFFSET_V2, ntohs(hdr->length)); ); + alert(GTP_EVENT_BAD_MSG_LEN); + return false; + } + + return true; +} + +/******************************************************************** + * Function: gtp_parse() + * + * The main entry for parser: process the gtp messages. + * + * Arguments: + * GTPMsg * - gtp message + * char* buff - start of the gtp message buffer + * uint16_t - length of the message + * + * Returns: + * false + * true + ********************************************************************/ +int gtp_parse(GTPMsg* msg, const uint8_t* buff, uint16_t gtp_len) +{ + int status; + GTP_C_Hdr* hdr; + GTP_MsgType* msgType; + + /*Initialize key values*/ + + status = true; + + DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Start parsing...\n")); + + hdr = (GTP_C_Hdr*)buff; + + /*Check the length*/ + DEBUG_WRAP(DebugFormat(DEBUG_GTP, "Basic header length: %d\n", GTP_MIN_HEADER_LEN)); + if (gtp_len < GTP_MIN_HEADER_LEN) + return false; + + /*The first 3 bits are version number*/ + msg->version = (hdr->flag & 0xE0) >> 5; + msg->msg_type = hdr->type; + msg->gtp_header = (uint8_t*)buff; + + if (msg->version > MAX_GTP_VERSION_CODE) + { + DEBUG_WRAP(DebugFormat(DEBUG_GTP, "Unsupported GTP version: %d!\n",msg->version); ); + return false; + } + /*Check whether this is GTP or GTP', Exit if GTP'*/ + if (!(hdr->flag & 0x10)) + { + DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Unsupported GTP'!\n"); ); + return false; + } + + msgType = >p_eval_config->msgv[msg->version][msg->msg_type]; + + if ( NULL == msgType ) + { + DEBUG_WRAP(DebugFormat(DEBUG_GTP, "Unsupported GTP message type: %d!\n",msg->msg_type); ); + gtp_stats.unknownTypes++; + return false; + } + else + { + DEBUG_WRAP(DebugFormat(DEBUG_GTP, "GTP version: %d, message type: %s(%d)\n", + msg->version, msgType->name.c_str(), msg->msg_type)); + } + + // FIXIT-L need to implement stats retrieval from module + //gtp_stats.messages[msg->version][msg->msg_type]++; + + /* We only care about control types*/ + if ( hdr->type == 255) + return false; + + switch (msg->version) + { + case 0: /*GTP v0*/ + + status = gtp_parse_v0(msg, buff, gtp_len); + break; + case 1: /*GTP v1*/ + + status = gtp_parse_v1(msg, buff, gtp_len); + break; + + case 2: /*GTP v2 */ + status = gtp_parse_v2(msg, buff, gtp_len); + + break; + default: + DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Unknown protocol version.\n"); ); + return false; + } + + /*Parse information elements*/ + if ((msg->header_len < gtp_len)&& (true == status)) + { + msg->info_elements = gtp_ies; + buff += msg->header_len; + status = gtp_processInfoElements(msg, buff, (uint16_t)(gtp_len - msg->header_len)); + } + return status; +} + +/******************************************************************** + * Function: gtp_cleanInfoElements() + * + * Clean up the shared information elements table + * + * Arguments: + * None + * + * Returns: + * None + ********************************************************************/ + +void gtp_cleanInfoElements(void) +{ + DEBUG_WRAP(DebugFormat(DEBUG_GTP, "Cleaned total bytes %d, length %d.\n", + (MAX_GTP_IE_CODE + 1) * sizeof(GTP_IEData), sizeof(gtp_ies)); ); + memset(gtp_ies, 0, sizeof(gtp_ies)); +} + diff --git a/src/service_inspectors/gtp/gtp_parser.h b/src/service_inspectors/gtp/gtp_parser.h new file mode 100644 index 000000000..53c142e33 --- /dev/null +++ b/src/service_inspectors/gtp/gtp_parser.h @@ -0,0 +1,51 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved. +// Copyright (C) 2011-2013 Sourcefire, Inc. +// +// 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. +//-------------------------------------------------------------------------- + +// gtp_parser.h author Hui Cao + +#ifndef GTP_PARSER_H +#define GTP_PARSER_H + +#include "main/snort_types.h" + +struct GTP_IEData +{ + uint16_t length; + uint16_t shift; /*shift relative to the header*/ + uint32_t msg_id; /* used to associate to current msg */ +}; + +struct GTPMsg +{ + uint8_t version; + uint8_t msg_type; + uint16_t msg_length; + uint16_t header_len; + uint8_t* gtp_header; + GTP_IEData* info_elements; + + /* nothing after this point is zeroed ...*/ + uint32_t msg_id; /*internal state, new msg will have a new id*/ +}; + +int gtp_parse(struct GTPMsg*, const uint8_t*, uint16_t); +void gtp_cleanInfoElements(); + +#endif + diff --git a/src/service_inspectors/gtp/ips_gtp_info.cc b/src/service_inspectors/gtp/ips_gtp_info.cc new file mode 100644 index 000000000..46f757a8a --- /dev/null +++ b/src/service_inspectors/gtp/ips_gtp_info.cc @@ -0,0 +1,253 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 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. +//-------------------------------------------------------------------------- + +// ips_gtp_info.cc author Russ Combs + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +// gtp_info rule option implementation + +#include "main/snort_types.h" +#include "main/snort_debug.h" +#include "detection/detection_defines.h" +#include "framework/cursor.h" +#include "framework/ips_option.h" +#include "framework/module.h" +#include "hash/sfhashfcn.h" +#include "time/profiler.h" + +#include "gtp.h" +#include "gtp_inspect.h" + +static const char* s_name = "gtp_info"; + +//------------------------------------------------------------------------- +// version option +//------------------------------------------------------------------------- + +static THREAD_LOCAL ProfileStats gtp_info_prof; + +class GtpInfoOption : public IpsOption +{ +public: + GtpInfoOption(uint8_t*); + + CursorActionType get_cursor_type() const override + { return CAT_SET_OTHER; } + + uint32_t hash() const override; + bool operator==(const IpsOption&) const override; + + int eval(Cursor&, Packet*) override; + +public: + // byte n is for version n (named types can have + // different codes in different versions) + uint8_t types[MAX_GTP_VERSION_CODE + 1]; +}; + +GtpInfoOption::GtpInfoOption(uint8_t* t) : IpsOption(s_name) +{ + for ( int v = 0; v <= MAX_GTP_VERSION_CODE; ++v ) + types[v] = t[v]; +} + +uint32_t GtpInfoOption::hash() const +{ + assert(MAX_GTP_VERSION_CODE == 2); + + uint32_t a = types[0]; + uint32_t b = types[1]; + uint32_t c = types[2]; + + mix_str(a, b, c, get_name()); + finalize(a,b,c); + + return c; +} + +bool GtpInfoOption::operator==(const IpsOption& ips) const +{ + if ( strcmp(get_name(), ips.get_name()) ) + return false; + + GtpInfoOption& rhs = (GtpInfoOption&)ips; + + for ( int v = 0; v <= MAX_GTP_VERSION_CODE; ++v ) + if ( types[v] != rhs.types[v] ) + return false; + + return true; +} + +int GtpInfoOption::eval(Cursor& c, Packet* p) +{ + PERF_PROFILE(gtp_info_prof); + + if ( !p or !p->flow ) + return DETECTION_OPTION_NO_MATCH; + + GtpFlowData* gfd = (GtpFlowData*)p->flow->get_application_data(GtpFlowData::flow_id); + + if ( !gfd or !gfd->ropts.gtp_infoElements ) + return DETECTION_OPTION_NO_MATCH; + + GTP_Roptions& ropts = gfd->ropts; + + // match the status code + uint8_t ieType = types[ropts.gtp_version]; + + if ( !ieType ) + return DETECTION_OPTION_NO_MATCH; + + GTP_IEData* ieData = ropts.gtp_infoElements + ieType; + + // bail if the data is not up to date + if ( ieData->msg_id != ropts.msg_id ) + return DETECTION_OPTION_NO_MATCH; + + c.set(s_name, ieData->shift + (uint8_t*)ropts.gtp_header, ieData->length); + return DETECTION_OPTION_MATCH; +} + +//------------------------------------------------------------------------- +// module +//------------------------------------------------------------------------- + +static const Parameter s_params[] = +{ + { "~", Parameter::PT_STRING, nullptr, nullptr, + "info element to match" }, + + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + +#define s_help \ + "rule option to check gtp info element" + +class GtpInfoModule : public Module +{ +public: + GtpInfoModule() : Module(s_name, s_help, s_params) { } + + bool set(const char*, Value&, SnortConfig*) override; + + bool set_types(long); + bool set_types(const char*); + + ProfileStats* get_profile() const override + { return >p_info_prof; } + + uint8_t types[MAX_GTP_VERSION_CODE + 1]; +}; + +bool GtpInfoModule::set_types(long t) +{ + if ( t < MIN_GTP_IE_CODE or t > MAX_GTP_IE_CODE ) + return false; + + for ( int v = 0; v <= MAX_GTP_VERSION_CODE; ++v ) + types[v] = (uint8_t)t; + + return true; +} + +bool GtpInfoModule::set_types(const char* name) +{ + bool ok = false; + + for ( int v = 0; v <= MAX_GTP_VERSION_CODE; ++v ) + { + int t = get_info_type(v, name); + + if ( t < 0 ) + continue; + + types[v] = t; + ok = true; + } + return ok; +} + +bool GtpInfoModule::set(const char*, Value& v, SnortConfig*) +{ + if ( !v.is("~") ) + return false; + + long n; + + if ( v.strtol(n) ) + return set_types(n); + + return set_types(v.get_string()); +} + +//------------------------------------------------------------------------- +// api +//------------------------------------------------------------------------- + +static Module* mod_ctor() +{ + return new GtpInfoModule; +} + +static void mod_dtor(Module* m) +{ + delete m; +} + +static IpsOption* opt_ctor(Module* m, OptTreeNode*) +{ + GtpInfoModule* mod = (GtpInfoModule*)m; + return new GtpInfoOption(mod->types); +} + +static void opt_dtor(IpsOption* p) +{ + delete p; +} + +static const IpsApi ips_api = +{ + { + PT_IPS_OPTION, + sizeof(IpsApi), + IPSAPI_VERSION, + 0, + API_RESERVED, + API_OPTIONS, + s_name, + s_help, + mod_ctor, + mod_dtor + }, + OPT_TYPE_DETECTION, + 0, PROTO_BIT__TCP, + nullptr, + nullptr, + nullptr, + nullptr, + opt_ctor, + opt_dtor, + nullptr +}; + +const BaseApi* ips_gtp_info = &ips_api.base; + diff --git a/src/service_inspectors/gtp/ips_gtp_type.cc b/src/service_inspectors/gtp/ips_gtp_type.cc new file mode 100644 index 000000000..987e206fc --- /dev/null +++ b/src/service_inspectors/gtp/ips_gtp_type.cc @@ -0,0 +1,268 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 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. +//-------------------------------------------------------------------------- + +// ips_gtp_type.cc author Russ Combs + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +// gtp_type rule option implementation + +#include "main/snort_types.h" +#include "main/snort_debug.h" +#include "detection/detection_defines.h" +#include "framework/bits.h" +#include "framework/ips_option.h" +#include "framework/module.h" +#include "hash/sfhashfcn.h" +#include "time/profiler.h" + +#include "gtp.h" +#include "gtp_inspect.h" + +static const char* s_name = "gtp_type"; + +//------------------------------------------------------------------------- +// version option +//------------------------------------------------------------------------- + +static THREAD_LOCAL ProfileStats gtp_type_prof; + +class GtpTypeOption : public IpsOption +{ +public: + GtpTypeOption(ByteBitSet*); + + CursorActionType get_cursor_type() const override + { return CAT_SET_OTHER; } + + uint32_t hash() const override; + bool operator==(const IpsOption&) const override; + + int eval(Cursor&, Packet*) override; + +public: + // set n is for version n (named types can have + // different codes in different versions) + ByteBitSet types[MAX_GTP_VERSION_CODE + 1]; +}; + +GtpTypeOption::GtpTypeOption(ByteBitSet* t) : IpsOption(s_name) +{ + for ( int v = 0; v <= MAX_GTP_VERSION_CODE; ++v ) + types[v] = t[v]; +} + +uint32_t GtpTypeOption::hash() const +{ + assert(MAX_GTP_VERSION_CODE == 2); + + uint32_t a = types[0].count(); + uint32_t b = types[1].count(); + uint32_t c = types[2].count(); + + mix_str(a, b, c, get_name()); + finalize(a,b,c); + + return c; +} + +bool GtpTypeOption::operator==(const IpsOption& ips) const +{ + if ( strcmp(get_name(), ips.get_name()) ) + return false; + + GtpTypeOption& rhs = (GtpTypeOption&)ips; + + for ( int v = 0; v <= MAX_GTP_VERSION_CODE; ++v ) + if ( types[v] != rhs.types[v] ) + return false; + + return true; +} + +int GtpTypeOption::eval(Cursor&, Packet* p) +{ + PERF_PROFILE(gtp_type_prof); + + if ( !p or !p->flow ) + return DETECTION_OPTION_NO_MATCH; + + GtpFlowData* gfd = (GtpFlowData*)p->flow->get_application_data(GtpFlowData::flow_id); + + if ( !gfd ) + return DETECTION_OPTION_NO_MATCH; + + GTP_Roptions& ropts = gfd->ropts; + + if ( !types[ropts.gtp_version].test(ropts.gtp_type) ) + return DETECTION_OPTION_NO_MATCH; + + return DETECTION_OPTION_MATCH; +} + +//------------------------------------------------------------------------- +// module +//------------------------------------------------------------------------- + +static const Parameter s_params[] = +{ + { "~", Parameter::PT_STRING, nullptr, nullptr, + "list of types to match" }, + + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + +#define s_help \ + "rule option to check gtp types" + +class GtpTypeModule : public Module +{ +public: + GtpTypeModule() : Module(s_name, s_help, s_params) { } + + bool begin(const char*, int, SnortConfig*) override; + bool set(const char*, Value&, SnortConfig*) override; + + bool set_types(long); + bool set_types(const char*); + + ProfileStats* get_profile() const override + { return >p_type_prof; } + + ByteBitSet types[MAX_GTP_VERSION_CODE + 1]; +}; + +bool GtpTypeModule::begin(const char*, int, SnortConfig*) +{ + for ( int v = 0; v <= MAX_GTP_VERSION_CODE; ++v ) + types[v].reset(); + + return true; +} + +bool GtpTypeModule::set_types(long t) +{ + if ( t < MIN_GTP_TYPE_CODE or t > MAX_GTP_TYPE_CODE ) + return false; + + for ( int v = 0; v <= MAX_GTP_VERSION_CODE; ++v ) + types[v].set((uint8_t)t); + + return true; +} + +bool GtpTypeModule::set_types(const char* name) +{ + bool ok = false; + + for ( int v = 0; v <= MAX_GTP_VERSION_CODE; ++v ) + { + int t = get_message_type(v, name); + + if ( t < 0 ) + continue; + + types[v].set((uint8_t)t); + ok = true; + } + return ok; +} + +bool GtpTypeModule::set(const char*, Value& v, SnortConfig*) +{ + if ( !v.is("~") ) + return false; + + v.set_first_token(); + std::string tok; + + while ( v.get_next_token(tok) ) + { + long n; + + if ( tok[0] == '"' ) + tok.erase(0, 1); + + if ( tok[tok.length()-1] == '"' ) + tok.erase(tok.length()-1, 1); + + if ( v.strtol(n, tok) ) + { + if ( !set_types(n) ) + return false; + } + else if ( !set_types(tok.c_str()) ) + return false; + } + return true; +} + +//------------------------------------------------------------------------- +// api +//------------------------------------------------------------------------- + +static Module* mod_ctor() +{ + return new GtpTypeModule; +} + +static void mod_dtor(Module* m) +{ + delete m; +} + +static IpsOption* opt_ctor(Module* m, OptTreeNode*) +{ + GtpTypeModule* mod = (GtpTypeModule*)m; + return new GtpTypeOption(mod->types); +} + +static void opt_dtor(IpsOption* p) +{ + delete p; +} + +static const IpsApi ips_api = +{ + { + PT_IPS_OPTION, + sizeof(IpsApi), + IPSAPI_VERSION, + 0, + API_RESERVED, + API_OPTIONS, + s_name, + s_help, + mod_ctor, + mod_dtor + }, + OPT_TYPE_DETECTION, + 0, PROTO_BIT__TCP, + nullptr, + nullptr, + nullptr, + nullptr, + opt_ctor, + opt_dtor, + nullptr +}; + +const BaseApi* ips_gtp_type = &ips_api.base; + diff --git a/src/service_inspectors/gtp/ips_gtp_version.cc b/src/service_inspectors/gtp/ips_gtp_version.cc new file mode 100644 index 000000000..dc6ae6bd9 --- /dev/null +++ b/src/service_inspectors/gtp/ips_gtp_version.cc @@ -0,0 +1,182 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2015 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. +//-------------------------------------------------------------------------- + +// ips_gtp_version.cc author Russ Combs + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +// gtp_version rule option implementation + +#include "main/snort_types.h" +#include "main/snort_debug.h" +#include "detection/detection_defines.h" +#include "framework/ips_option.h" +#include "framework/module.h" +#include "hash/sfhashfcn.h" +#include "time/profiler.h" + +#include "gtp_inspect.h" + +static const char* s_name = "gtp_version"; + +//------------------------------------------------------------------------- +// version option +//------------------------------------------------------------------------- + +static THREAD_LOCAL ProfileStats gtp_ver_prof; + +class GtpVersionOption : public IpsOption +{ +public: + GtpVersionOption(uint8_t v) : IpsOption(s_name) + { version = v; } + + uint32_t hash() const override; + bool operator==(const IpsOption&) const override; + + int eval(Cursor&, Packet*) override; + +public: + uint8_t version; +}; + +uint32_t GtpVersionOption::hash() const +{ + uint32_t a = version, b = 0, c = 0; + + mix_str(a, b, c, get_name()); + finalize(a,b,c); + + return c; +} + +bool GtpVersionOption::operator==(const IpsOption& ips) const +{ + if ( strcmp(get_name(), ips.get_name()) ) + return false; + + GtpVersionOption& rhs = (GtpVersionOption&)ips; + return ( version == rhs.version ); +} + +int GtpVersionOption::eval(Cursor&, Packet* p) +{ + PERF_PROFILE(gtp_ver_prof); + + if ( !p or !p->flow ) + return DETECTION_OPTION_NO_MATCH; + + GtpFlowData* gfd = (GtpFlowData*)p->flow->get_application_data(GtpFlowData::flow_id); + + if ( gfd and version == gfd->ropts.gtp_version ) + return DETECTION_OPTION_MATCH; + + return DETECTION_OPTION_NO_MATCH; +} + +//------------------------------------------------------------------------- +// module +//------------------------------------------------------------------------- + +static const Parameter s_params[] = +{ + { "~", Parameter::PT_INT, "0:2", nullptr, + "version to match" }, + + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + +#define s_help \ + "rule option to check gtp version" + +class GtpVersionModule : public Module +{ +public: + GtpVersionModule() : Module(s_name, s_help, s_params) { } + + bool set(const char*, Value&, SnortConfig*) override; + + ProfileStats* get_profile() const override + { return >p_ver_prof; } + + uint8_t version; +}; + +bool GtpVersionModule::set(const char*, Value& v, SnortConfig*) +{ + if ( !v.is("~") ) + return false; + + version = v.get_long(); + return true; +} + +//------------------------------------------------------------------------- +// api +//------------------------------------------------------------------------- + +static Module* mod_ctor() +{ + return new GtpVersionModule; +} + +static void mod_dtor(Module* m) +{ + delete m; +} + +static IpsOption* opt_ctor(Module* m, OptTreeNode*) +{ + GtpVersionModule* mod = (GtpVersionModule*)m; + return new GtpVersionOption(mod->version); +} + +static void opt_dtor(IpsOption* p) +{ + delete p; +} + +static const IpsApi ips_api = +{ + { + PT_IPS_OPTION, + sizeof(IpsApi), + IPSAPI_VERSION, + 0, + API_RESERVED, + API_OPTIONS, + s_name, + s_help, + mod_ctor, + mod_dtor + }, + OPT_TYPE_DETECTION, + 0, PROTO_BIT__TCP, + nullptr, + nullptr, + nullptr, + nullptr, + opt_ctor, + opt_dtor, + nullptr +}; + +const BaseApi* ips_gtp_version = &ips_api.base; + diff --git a/src/service_inspectors/http_inspect/http_inspect.cc b/src/service_inspectors/http_inspect/http_inspect.cc index 9dc8f36c4..08baaa9e5 100644 --- a/src/service_inspectors/http_inspect/http_inspect.cc +++ b/src/service_inspectors/http_inspect/http_inspect.cc @@ -18,10 +18,7 @@ //-------------------------------------------------------------------------- /** -** @author Daniel Roelker -** -** @brief This file initializes HttpInspect as a Snort -** preprocessor. +** original author Daniel Roelker ** ** This file registers the HttpInspect initialization function, ** adds the HttpInspect function into the preprocessor list, reads diff --git a/src/service_inspectors/service_inspectors.cc b/src/service_inspectors/service_inspectors.cc index 5e320385e..55f4ac215 100644 --- a/src/service_inspectors/service_inspectors.cc +++ b/src/service_inspectors/service_inspectors.cc @@ -28,6 +28,9 @@ extern const BaseApi* sin_http_global; extern const BaseApi* sin_http_inspect; #ifdef STATIC_INSPECTORS +extern const BaseApi* ips_gtp_info; +extern const BaseApi* ips_gtp_type; +extern const BaseApi* ips_gtp_version; extern const BaseApi* ips_sip_body; extern const BaseApi* ips_sip_header; extern const BaseApi* ips_sip_method; @@ -39,6 +42,7 @@ extern const BaseApi* sin_dns; extern const BaseApi* sin_ftp_client; extern const BaseApi* sin_ftp_server; extern const BaseApi* sin_ftp_data; +extern const BaseApi* sin_gtp; extern const BaseApi* sin_imap; extern const BaseApi* sin_nhttp; extern const BaseApi* sin_pop; @@ -57,6 +61,9 @@ const BaseApi* service_inspectors[] = sin_http_inspect, #ifdef STATIC_INSPECTORS + ips_gtp_info, + ips_gtp_type, + ips_gtp_version, ips_sip_body, ips_sip_header, ips_sip_method, @@ -68,6 +75,7 @@ const BaseApi* service_inspectors[] = sin_ftp_client, sin_ftp_server, sin_ftp_data, + sin_gtp, sin_imap, sin_nhttp, sin_pop, -- 2.47.3