]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #88 in SNORT/snort3 from crc/gtp to master
authorRuss Combs (rucombs) <rucombs@cisco.com>
Wed, 21 Oct 2015 14:32:53 +0000 (10:32 -0400)
committerRuss Combs (rucombs) <rucombs@cisco.com>
Wed, 21 Oct 2015 14:32:53 +0000 (10:32 -0400)
Squashed commit of the following:

commit 4e987387e53ddc84f807df00aafcbb73d3dd8b92
Author: Russ Combs <rucombs@cisco.com>
Date:   Tue Oct 20 12:00:50 2015 -0400

    fix multi gtp encap alert

commit 1f718dcb84f461740493f4df586909813469ff17
Author: Russ Combs <rucombs@cisco.com>
Date:   Tue Oct 20 11:24:35 2015 -0400

    update bug list

commit e29dfb142dbf645f3c7f30891ff0032417035848
Author: Russ Combs <rucombs@cisco.com>
Date:   Tue Oct 20 06:48:18 2015 -0400

    test fixes and readability changes

commit 9f976d3f8d74ac5b3fa0700c424f4397c78c5385
Author: Russ Combs <rucombs@cisco.com>
Date:   Fri Oct 16 07:53:21 2015 -0400

    initial port of gtp preprocessor

29 files changed:
configure.ac
doc/bugs.txt
doc/style.txt
lua/snort.lua
lua/snort_defaults.lua
src/Makefile.am
src/codecs/misc/cd_gtp.cc
src/framework/value.cc
src/framework/value.h
src/protocols/packet.h
src/protocols/packet_manager.cc
src/service_inspectors/CMakeLists.txt
src/service_inspectors/Makefile.am
src/service_inspectors/gtp/CMakeLists.txt [new file with mode: 0644]
src/service_inspectors/gtp/Makefile.am [new file with mode: 0644]
src/service_inspectors/gtp/dev_notes.txt [new file with mode: 0644]
src/service_inspectors/gtp/gtp.cc [new file with mode: 0644]
src/service_inspectors/gtp/gtp.h [new file with mode: 0644]
src/service_inspectors/gtp/gtp_inspect.cc [new file with mode: 0644]
src/service_inspectors/gtp/gtp_inspect.h [new file with mode: 0644]
src/service_inspectors/gtp/gtp_module.cc [new file with mode: 0644]
src/service_inspectors/gtp/gtp_module.h [new file with mode: 0644]
src/service_inspectors/gtp/gtp_parser.cc [new file with mode: 0644]
src/service_inspectors/gtp/gtp_parser.h [new file with mode: 0644]
src/service_inspectors/gtp/ips_gtp_info.cc [new file with mode: 0644]
src/service_inspectors/gtp/ips_gtp_type.cc [new file with mode: 0644]
src/service_inspectors/gtp/ips_gtp_version.cc [new file with mode: 0644]
src/service_inspectors/http_inspect/http_inspect.cc
src/service_inspectors/service_inspectors.cc

index c092868800f98c5f67e035eec2889626c9f55c55..97d3e40dd09753d6d69b205aca7eddd6d330af21 100644 (file)
@@ -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 \
index 6d0307c8aba66b0f7523f295dcb2efdec14e9010..dc2990dbe6bfbdbbf08ef14318c10dc74af86c8b 100644 (file)
@@ -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 <mask> 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).
+
index 39b57cf8d450e19d373b6ea725ec74ee0d5e4cd0..ebc8f4898ec4b9ebe056118c0a29b2fd4feca450 100644 (file)
@@ -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 <file>
+
index abd9d022118f90629245ea440b97f7b1e993765d..f80e1b199a472f9aa3607be112bae81d45d5de93 100644 (file)
@@ -68,6 +68,7 @@ stream_file = { }
 arp_spoof = { }
 back_orifice = { }
 dns = { }
+gtp_inspect = default_gtp
 imap = { }
 smtp = { }
 perf_monitor = { }
index 10fcd51f9d6352d26a7c9017468ee43d3eb352b2..bd8c6557b9cabac584f98dabbcd1d641fd48dac1 100644 (file)
@@ -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 },
+}
+
index ee1fcb6db297952013690b0858f72520d01df32c..021998053db30a088e336bf70b2820a92c091806 100644 (file)
@@ -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 \
index f322ca04ed0815c2a38281450bb921ce9f28597a..709678f4a3b4b177e5bb7cc279681ca376b34c80 100644 (file)
@@ -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)
index 6d832aa6e58a4372beb4aab89315166acd7bb73f..c4e694b514b7739a6efd349ec429670200abbbb9 100644 (file)
@@ -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 )
index 07fe5cc30a07a8e9e0f0282123c736c53d6d4d88..41204366b39d7bb8673695d9fd1b018fcd1dfda1 100644 (file)
@@ -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; }
index d55d6d52c3640628f4f93338cc38722a28fe1f8b..553c7cfcacd9834af151fa7a0699b529db480347 100644 (file)
@@ -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
index 8441900095a3e03863130b437cfea639391d1f0f..e5c469b61cb5499ab141734ca205b2a0d7c36b9d 100644 (file)
@@ -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"
index 8e3744d68fc276471633b7c74de79c505dbcb5ca..ba11297b7e91df31af13561a84b62930af4338ad 100644 (file)
@@ -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
index f7d2c853596c77ae952467f4ea49d42d32f7530b..dea53a1aa7844f0b0e3afdd038d073a87f620e83 100644 (file)
@@ -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 (file)
index 0000000..9e4d717
--- /dev/null
@@ -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 (file)
index 0000000..0f95b30
--- /dev/null
@@ -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 (file)
index 0000000..2a96954
--- /dev/null
@@ -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 (file)
index 0000000..06688b2
--- /dev/null
@@ -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 <hcao@sourcefire.com>
+// This is the main entry point for this preprocessor
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gtp.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <string.h>
+
+#ifndef WIN32
+#include <strings.h>
+#include <sys/time.h>
+#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(&gtpMsg, 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(&gtpMsg, 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 (file)
index 0000000..f02733d
--- /dev/null
@@ -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 <hcao@sourcefire.com>
+
+#ifndef GTP_H
+#define GTP_H
+
+// Provides convenience functions for parsing and querying configuration.
+
+#include <string>
+#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 (file)
index 0000000..3c63e05
--- /dev/null
@@ -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 <rucombs@cisco.com>
+// 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<GtpStuff>&);
+
+    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<GtpStuff>& 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<GtpStuff> 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[] =
+{
+    &gtp_api.base,
+    ips_gtp_info,
+    ips_gtp_type,
+    ips_gtp_version,
+    nullptr
+};
+#else
+const BaseApi* sin_gtp = &gtp_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 (file)
index 0000000..13542e8
--- /dev/null
@@ -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 <rucombs@cisco.com>
+
+#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 (file)
index 0000000..e960839
--- /dev/null
@@ -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 <rucombs@cisco.com>
+
+#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*)&gtp_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 (file)
index 0000000..d349abb
--- /dev/null
@@ -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 <rucombs@cisco.com>
+
+#ifndef GTP_MODULE_H
+#define GTP_MODULE_H
+
+#include <vector>
+#include <string>
+
+#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 &gtp_inspect_prof; }
+
+public:
+    GtpStuff stuff;
+    std::vector<GtpStuff> temp;
+    std::vector<GtpStuff> config;
+};
+
+#endif
+
diff --git a/src/service_inspectors/gtp/gtp_parser.cc b/src/service_inspectors/gtp/gtp_parser.cc
new file mode 100644 (file)
index 0000000..1d240d9
--- /dev/null
@@ -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 <hcao@sourcefire.com>
+
+// parses gtp control messages
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gtp_parser.h"
+
+#include <ctype.h>
+
+#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 = &gtp_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 = &gtp_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 (file)
index 0000000..53c142e
--- /dev/null
@@ -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 <hcao@sourcefire.com>
+
+#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 (file)
index 0000000..46f757a
--- /dev/null
@@ -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 <rucombs@cisco.com>
+
+#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 &gtp_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 (file)
index 0000000..987e206
--- /dev/null
@@ -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 <rucombs@cisco.com>
+
+#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 &gtp_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 (file)
index 0000000..dc6ae6b
--- /dev/null
@@ -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 <rucombs@cisco.com>
+
+#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 &gtp_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;
+
index 9dc8f36c4ee067205825721d407d4779da7a410d..08baaa9e53a36425f5df6f9bd0776c4ff82472a7 100644 (file)
 //--------------------------------------------------------------------------
 
 /**
-**  @author     Daniel Roelker <droelker@sourcefire.com>
-**
-**  @brief      This file initializes HttpInspect as a Snort
-**              preprocessor.
+**  original author Daniel Roelker <droelker@sourcefire.com>
 **
 **  This file registers the HttpInspect initialization function,
 **  adds the HttpInspect function into the preprocessor list, reads
index 5e320385e3422b311ee1f41677eca9eeccc89833..55f4ac21518b56082b7826abe3dca9f943c309b4 100644 (file)
@@ -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,