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 \
==== Build
* configure will use clang++ by default if it is installed.
-To compile with g++ instead:
+ To compile with g++ instead:
export CXX=g++
==== 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).
==== 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).
==== 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 ( )
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).
+
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>
+
arp_spoof = { }
back_orifice = { }
dns = { }
+gtp_inspect = default_gtp
imap = { }
smtp = { }
perf_monitor = { }
{ 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/' }
}
---------------------------------------------------------------------------
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 },
+}
+
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 \
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",
codec_event(codec, DECODE_GTP_BAD_LEN);
return false;
}
-
break;
+
default:
DebugMessage(DEBUG_DECODE, "Unknown protocol version.\n");
return false;
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)
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 )
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; }
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
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"
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)
if (STATIC_INSPECTORS)
set (STATIC_INSECTOR_LIBS
back_orifice
- ftp_telnet
dns
+ ftp_telnet
+ gtp
imap
nhttp_inspect
pop
back_orifice \
dns \
ftp_telnet \
+gtp \
http_inspect \
imap \
nhttp_inspect \
--- /dev/null
+
+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)
+
--- /dev/null
+
+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@
+
--- /dev/null
+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.
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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(>pMsg, 0, GTPMSG_ZERO_LEN);
+
+ /* msg_id is used to associate message with information elements
+ * If msg_id matches, the information element in the info_elements
+ * belongs to the message
+ * Using msg_id avoids initializing info_elements for every message
+ * Tabled based info_elements improves information element search performance */
+
+ /* To avoid id overlap, clean table when msgId resets*/
+ if ( msgId == 0)
+ gtp_cleanInfoElements();
+
+ gtpMsg.msg_id = ++msgId;
+
+ int status = gtp_parse(>pMsg, gtp_buff, p->dsize);
+
+ /*Update the session data*/
+ pRopts->gtp_type = gtpMsg.msg_type;
+ pRopts->gtp_version = gtpMsg.version;
+ pRopts->gtp_infoElements = gtpMsg.info_elements;
+ pRopts->gtp_header = gtpMsg.gtp_header;
+ pRopts->msg_id = gtpMsg.msg_id;
+
+ DEBUG_WRAP(DebugFormat(DEBUG_GTP, "GTP message version: %d\n", gtpMsg.version));
+ DEBUG_WRAP(DebugFormat(DEBUG_GTP, "GTP message type: %d\n", gtpMsg.msg_type));
+
+ return status;
+}
+
+static GTP_Roptions* GTPGetNewSession(Packet* packetp)
+{
+ GtpFlowData* gfd = new GtpFlowData;
+ packetp->flow->set_application_data(gfd);
+
+ GTP_Roptions* pRopts = &gfd->ropts;
+ gtp_stats.sessions++;
+
+ return pRopts;
+}
+
+// Main runtime entry point for GTP preprocessor.
+void GTPmain(Packet* packetp)
+{
+ /* Attempt to get a previously allocated GTP block. */
+ GtpFlowData* gfd = (GtpFlowData*)packetp->flow->get_application_data(GtpFlowData::flow_id);
+ GTP_Roptions* pRopts = gfd ? &gfd->ropts : nullptr;
+
+ if ( !pRopts )
+ {
+ pRopts = GTPGetNewSession(packetp);
+
+ if ( !pRopts )
+ {
+ /* Could not get/create the session data for this packet. */
+ DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Create session error - not inspecting.\n"));
+ return;
+ }
+ }
+
+ GTP_Process(packetp, pRopts);
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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[] =
+{
+ >p_api.base,
+ ips_gtp_info,
+ ips_gtp_type,
+ ips_gtp_version,
+ nullptr
+};
+#else
+const BaseApi* sin_gtp = >p_api.base;
+#endif
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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*)>p_stats; }
+
+//-------------------------------------------------------------------------
+// rules
+//-------------------------------------------------------------------------
+
+static const RuleMap gtp_rules[] =
+{
+ { GTP_EVENT_BAD_MSG_LEN, GTP_EVENT_BAD_MSG_LEN_STR },
+ { GTP_EVENT_BAD_IE_LEN, GTP_EVENT_BAD_IE_LEN_STR },
+ { GTP_EVENT_OUT_OF_ORDER_IE, GTP_EVENT_OUT_OF_ORDER_IE_STR },
+
+ { 0, nullptr }
+};
+
+const RuleMap* GtpInspectModule::get_rules() const
+{ return gtp_rules; }
+
+//-------------------------------------------------------------------------
+// params
+//-------------------------------------------------------------------------
+
+static const Parameter gtp_msg_params[] =
+{
+ { "type", Parameter::PT_INT, "0:255", "0",
+ "message type code" },
+
+ { "name", Parameter::PT_STRING, nullptr, nullptr,
+ "message name" },
+
+ { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+static const Parameter gtp_info_params[] =
+{
+ { "type", Parameter::PT_INT, "0:255", "0",
+ "information element type code" },
+
+ { "name", Parameter::PT_STRING, nullptr, nullptr,
+ "information element name" },
+
+ { "length", Parameter::PT_INT, "0:255", "0",
+ "information element type code" },
+
+ { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+
+static const Parameter gtp_params[] =
+{
+ { "version", Parameter::PT_INT, "0:2", "2",
+ "gtp version" },
+
+ { "messages", Parameter::PT_LIST, gtp_msg_params, nullptr,
+ "message dictionary" },
+
+ { "infos", Parameter::PT_LIST, gtp_info_params, nullptr,
+ "information element dictionary" },
+
+ { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+GtpInspectModule::GtpInspectModule() :
+ Module(GTP_NAME, GTP_HELP, gtp_params, true)
+{ }
+
+bool GtpInspectModule::set(const char*, Value& v, SnortConfig*)
+{
+ if ( v.is("version") )
+ stuff.version = v.get_long();
+
+ else if ( v.is("type") )
+ stuff.type = v.get_long();
+
+ else if ( v.is("length") )
+ stuff.length = v.get_long();
+
+ else if ( v.is("name") )
+ stuff.name = v.get_string();
+
+ else
+ return false;
+
+ return true;
+}
+
+bool GtpInspectModule::begin(const char* fqn, int idx, SnortConfig*)
+{
+ if ( !strcmp(fqn, "gtp_inspect") and !idx )
+ {
+ temp.clear();
+ config.clear();
+ }
+
+ // version persists
+ stuff.name.clear();
+ stuff.type = 0;
+ stuff.length = -1;
+
+ return true;
+}
+
+// we may not get current version until after lists are loaded
+// so the lists go to temp and when the list item is closed we
+// move to the main config.
+bool GtpInspectModule::end(const char* fqn, int idx, SnortConfig*)
+{
+ if ( !strcmp(fqn, "gtp_inspect") and idx )
+ {
+ for ( unsigned i = 0; i < temp.size(); ++i )
+ {
+ temp[i].version = stuff.version;
+ config.push_back(temp[i]);
+ }
+ temp.clear();
+ }
+ else if ( !strcmp(fqn, "gtp_inspect.messages") and idx )
+ {
+ assert(stuff.length < 0);
+ temp.push_back(stuff);
+ }
+ else if ( !strcmp(fqn, "gtp_inspect.infos") and idx )
+ {
+ assert(stuff.length >= 0);
+ temp.push_back(stuff);
+ }
+ return true;
+}
--- /dev/null
+//--------------------------------------------------------------------------
+// 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 >p_inspect_prof; }
+
+public:
+ GtpStuff stuff;
+ std::vector<GtpStuff> temp;
+ std::vector<GtpStuff> config;
+};
+
+#endif
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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 = >p_eval_config->infov[msg->version][type];
+
+ if ( NULL == ie )
+ {
+ DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Unsupported Information elements!\n"); );
+ gtp_stats.unknownIEs++;
+ return false;
+ }
+
+ /*For fixed length, use the table*/
+ if (ie->length)
+ {
+ length = ie->length;
+ }
+ else /*For variable length, use the length field*/
+ {
+ GTP_IE_Hdr* ieHdr;
+ /*check the length before reading*/
+ if (sizeof(*ieHdr) > (unsigned)unprocessed_len)
+ {
+ alert(GTP_EVENT_BAD_IE_LEN);
+ return false;
+ }
+ ieHdr = (GTP_IE_Hdr*)start;
+ length = ntohs(ieHdr->length);
+ /*Check the length */
+ if (length > UINT16_MAX - GTP_MIN_HEADER_LEN - sizeof(*ieHdr))
+ {
+ alert(GTP_EVENT_BAD_IE_LEN);
+ return false;
+ }
+
+ if (msg->version == 2)
+ length += 4;
+ else
+ length += 3;
+ }
+
+ if (length > unprocessed_len )
+ {
+ alert(GTP_EVENT_BAD_IE_LEN);
+ return false;
+ }
+
+ /*Combine the same information element type into one buffer*/
+ if ((previous_type == type) && (msg->info_elements[type].msg_id == msg->msg_id))
+ {
+ msg->info_elements[type].length += length;
+ }
+ else
+ {
+ msg->info_elements[type].length = length;
+ msg->info_elements[type].shift = start - msg->gtp_header;
+ msg->info_elements[type].msg_id = msg->msg_id;
+ }
+
+ DEBUG_WRAP(DebugFormat(DEBUG_GTP, "GTP information element: %s(%d), length: %d\n",
+ ie->name.c_str(), type, length));
+ start += length;
+ unprocessed_len -= length;
+ previous_type = type;
+ }
+ DEBUG_WRAP(printInfoElements(msg->info_elements, msg); );
+ return true;
+}
+
+/********************************************************************
+ * Function: gtp_parse_v0()
+ *
+ * process the GTP v0 message.
+ *
+ * Arguments:
+ * GTPMsg * - gtp message
+ * char* buff - start of the gtp message buffer
+ * uint16_t - length of the message
+ *
+ * Returns:
+ * false
+ * true
+ * Bits
+ *Octets 8 7 6 5 4 3 2 1
+ *1 Version PT 1 1 1 SNN
+ *2 Message Type
+ *3-4 Length
+ *5-6 Sequence Number
+ *7-8 Flow Label
+ *9 SNDCP N-PDULLC Number
+ *10 Spare ‘ 1 1 1 1 1 1 1 1 ‘
+ *11 Spare ‘ 1 1 1 1 1 1 1 1 ‘
+ *12 Spare ‘ 1 1 1 1 1 1 1 1 ‘
+ *13-20 TID
+ *
+ ********************************************************************/
+
+static int gtp_parse_v0(GTPMsg* msg, const uint8_t* buff, uint16_t gtp_len)
+{
+ GTP_C_Hdr* hdr;
+
+ DEBUG_WRAP(DebugMessage(DEBUG_GTP, "This is a GTP v0 packet.\n"); );
+
+ hdr = (GTP_C_Hdr*)buff;
+
+ msg->header_len = GTP_HEADER_LEN_V0;
+
+ /*Check the length field. */
+ if (gtp_len != ((unsigned int)ntohs(hdr->length) + GTP_LENGTH_OFFSET_V0))
+ {
+ DEBUG_WRAP(DebugFormat(DEBUG_GTP, "Calculated length %d != %d in header.\n",
+ gtp_len - GTP_LENGTH_OFFSET_V0, ntohs(hdr->length)); );
+ alert(GTP_EVENT_BAD_MSG_LEN);
+ return false;
+ }
+
+ return true;
+}
+
+/********************************************************************
+ * Function: gtp_parse_v1()
+ *
+ * process the GTP v1 message.
+ *
+ * Arguments:
+ * GTPMsg * - gtp message
+ * char* buff - start of the gtp message buffer
+ * uint16_t - length of the message
+ *
+ * Returns:
+ * false
+ * true
+ *
+ * Octets 8 7 6 5 4 3 2 1
+ * 1 Version PT (*) E S PN
+ * 2 Message Type
+ * 3 Length (1st Octet)
+ * 4 Length (2nd Octet)
+ * 5 Tunnel Endpoint Identifier (1st Octet)
+ * 6 Tunnel Endpoint Identifier (2nd Octet)
+ * 7 Tunnel Endpoint Identifier (3rd Octet)
+ * 8 Tunnel Endpoint Identifier (4th Octet)
+ * 9 Sequence Number (1st Octet)
+ * 10 Sequence Number (2nd Octet)
+ * 11 N-PDU Number
+ * 12 Next Extension Header Type
+ ********************************************************************/
+static int gtp_parse_v1(GTPMsg* msg, const uint8_t* buff, uint16_t gtp_len)
+{
+ uint8_t next_hdr_type;
+ GTP_C_Hdr* hdr;
+
+ DEBUG_WRAP(DebugMessage(DEBUG_GTP, "This ia a GTP v1 packet.\n"); );
+
+ hdr = (GTP_C_Hdr*)buff;
+
+ /*Check the length based on optional fields and extension header*/
+ if (hdr->flag & 0x07)
+ {
+ msg->header_len = GTP_HEADER_LEN_V1;
+ /*Check optional fields*/
+ if (gtp_len < msg->header_len)
+ {
+ alert(GTP_EVENT_BAD_MSG_LEN);
+ return false;
+ }
+
+ next_hdr_type = *(buff + msg->header_len - 1);
+
+ /*Check extension headers*/
+ while (next_hdr_type)
+ {
+ uint16_t ext_header_len;
+
+ /*check length before reading data, at lease 4 bytes per extension header*/
+ if (gtp_len < msg->header_len + 4)
+ {
+ alert(GTP_EVENT_BAD_MSG_LEN);
+ return false;
+ }
+
+ ext_header_len = *(buff + msg->header_len);
+
+ if (!ext_header_len)
+ {
+ alert(GTP_EVENT_BAD_MSG_LEN);
+ return false;
+ }
+
+ /*Extension header length is a unit of 4 octets*/
+ msg->header_len += ext_header_len*4;
+
+ /*check length before reading data*/
+ if (gtp_len < msg->header_len)
+ {
+ alert(GTP_EVENT_BAD_MSG_LEN);
+ return false;
+ }
+ next_hdr_type = *(buff + msg->header_len - 1);
+ }
+ }
+ else
+ msg->header_len = GTP_HEADER_LEN_V1;
+
+ /*Check the length field. */
+ if (gtp_len != ((unsigned int)ntohs(hdr->length) + GTP_LENGTH_OFFSET_V1))
+ {
+ DEBUG_WRAP(DebugFormat(DEBUG_GTP, "Calculated length %d != %d in header.\n",
+ gtp_len - GTP_LENGTH_OFFSET_V1, ntohs(hdr->length)); );
+ alert(GTP_EVENT_BAD_MSG_LEN);
+ return false;
+ }
+
+ return true;
+}
+
+/********************************************************************
+ * Function: gtp_parse_v2()
+ *
+ * process the GTP v2 message.
+ *
+ * Arguments:
+ * GTPMsg * - gtp message
+ * char* buff - start of the gtp message buffer
+ * uint16_t - length of the message
+ *
+ * Returns:
+ * false
+ * true
+ *
+ *Octets 8 7 6 5 4 3 2 1
+ *1 Version P T Spare Spare Spare
+ *2 Message Type
+ *3 Message Length (1st Octet)
+ *4 Message Length (2nd Octet)
+ *m to k(m+3) If T flag is set to 1, then TEID shall be placed into octets 5-8.
+ * Otherwise, TEID field is not present at all.
+ *n to (n+2) Sequence Number
+ *(n+3) Spare
+ ********************************************************************/
+static int gtp_parse_v2(GTPMsg* msg, const uint8_t* buff, uint16_t gtp_len)
+{
+ GTP_C_Hdr* hdr;
+
+ DEBUG_WRAP(DebugMessage(DEBUG_GTP, "This ia a GTP v2 packet.\n"); );
+
+ hdr = (GTP_C_Hdr*)buff;
+
+ if (hdr->flag & 0x8)
+ msg->header_len = GTP_HEADER_LEN_EPC_V2;
+ else
+ msg->header_len = GTP_HEADER_LEN_V2;
+
+ /*Check the length field. */
+ if (gtp_len != ((unsigned int)ntohs(hdr->length) + GTP_LENGTH_OFFSET_V2))
+ {
+ DEBUG_WRAP(DebugFormat(DEBUG_GTP, "Calculated length %d != %d in header.\n",
+ gtp_len - GTP_LENGTH_OFFSET_V2, ntohs(hdr->length)); );
+ alert(GTP_EVENT_BAD_MSG_LEN);
+ return false;
+ }
+
+ return true;
+}
+
+/********************************************************************
+ * Function: gtp_parse()
+ *
+ * The main entry for parser: process the gtp messages.
+ *
+ * Arguments:
+ * GTPMsg * - gtp message
+ * char* buff - start of the gtp message buffer
+ * uint16_t - length of the message
+ *
+ * Returns:
+ * false
+ * true
+ ********************************************************************/
+int gtp_parse(GTPMsg* msg, const uint8_t* buff, uint16_t gtp_len)
+{
+ int status;
+ GTP_C_Hdr* hdr;
+ GTP_MsgType* msgType;
+
+ /*Initialize key values*/
+
+ status = true;
+
+ DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Start parsing...\n"));
+
+ hdr = (GTP_C_Hdr*)buff;
+
+ /*Check the length*/
+ DEBUG_WRAP(DebugFormat(DEBUG_GTP, "Basic header length: %d\n", GTP_MIN_HEADER_LEN));
+ if (gtp_len < GTP_MIN_HEADER_LEN)
+ return false;
+
+ /*The first 3 bits are version number*/
+ msg->version = (hdr->flag & 0xE0) >> 5;
+ msg->msg_type = hdr->type;
+ msg->gtp_header = (uint8_t*)buff;
+
+ if (msg->version > MAX_GTP_VERSION_CODE)
+ {
+ DEBUG_WRAP(DebugFormat(DEBUG_GTP, "Unsupported GTP version: %d!\n",msg->version); );
+ return false;
+ }
+ /*Check whether this is GTP or GTP', Exit if GTP'*/
+ if (!(hdr->flag & 0x10))
+ {
+ DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Unsupported GTP'!\n"); );
+ return false;
+ }
+
+ msgType = >p_eval_config->msgv[msg->version][msg->msg_type];
+
+ if ( NULL == msgType )
+ {
+ DEBUG_WRAP(DebugFormat(DEBUG_GTP, "Unsupported GTP message type: %d!\n",msg->msg_type); );
+ gtp_stats.unknownTypes++;
+ return false;
+ }
+ else
+ {
+ DEBUG_WRAP(DebugFormat(DEBUG_GTP, "GTP version: %d, message type: %s(%d)\n",
+ msg->version, msgType->name.c_str(), msg->msg_type));
+ }
+
+ // FIXIT-L need to implement stats retrieval from module
+ //gtp_stats.messages[msg->version][msg->msg_type]++;
+
+ /* We only care about control types*/
+ if ( hdr->type == 255)
+ return false;
+
+ switch (msg->version)
+ {
+ case 0: /*GTP v0*/
+
+ status = gtp_parse_v0(msg, buff, gtp_len);
+ break;
+ case 1: /*GTP v1*/
+
+ status = gtp_parse_v1(msg, buff, gtp_len);
+ break;
+
+ case 2: /*GTP v2 */
+ status = gtp_parse_v2(msg, buff, gtp_len);
+
+ break;
+ default:
+ DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Unknown protocol version.\n"); );
+ return false;
+ }
+
+ /*Parse information elements*/
+ if ((msg->header_len < gtp_len)&& (true == status))
+ {
+ msg->info_elements = gtp_ies;
+ buff += msg->header_len;
+ status = gtp_processInfoElements(msg, buff, (uint16_t)(gtp_len - msg->header_len));
+ }
+ return status;
+}
+
+/********************************************************************
+ * Function: gtp_cleanInfoElements()
+ *
+ * Clean up the shared information elements table
+ *
+ * Arguments:
+ * None
+ *
+ * Returns:
+ * None
+ ********************************************************************/
+
+void gtp_cleanInfoElements(void)
+{
+ DEBUG_WRAP(DebugFormat(DEBUG_GTP, "Cleaned total bytes %d, length %d.\n",
+ (MAX_GTP_IE_CODE + 1) * sizeof(GTP_IEData), sizeof(gtp_ies)); );
+ memset(gtp_ies, 0, sizeof(gtp_ies));
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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 >p_info_prof; }
+
+ uint8_t types[MAX_GTP_VERSION_CODE + 1];
+};
+
+bool GtpInfoModule::set_types(long t)
+{
+ if ( t < MIN_GTP_IE_CODE or t > MAX_GTP_IE_CODE )
+ return false;
+
+ for ( int v = 0; v <= MAX_GTP_VERSION_CODE; ++v )
+ types[v] = (uint8_t)t;
+
+ return true;
+}
+
+bool GtpInfoModule::set_types(const char* name)
+{
+ bool ok = false;
+
+ for ( int v = 0; v <= MAX_GTP_VERSION_CODE; ++v )
+ {
+ int t = get_info_type(v, name);
+
+ if ( t < 0 )
+ continue;
+
+ types[v] = t;
+ ok = true;
+ }
+ return ok;
+}
+
+bool GtpInfoModule::set(const char*, Value& v, SnortConfig*)
+{
+ if ( !v.is("~") )
+ return false;
+
+ long n;
+
+ if ( v.strtol(n) )
+ return set_types(n);
+
+ return set_types(v.get_string());
+}
+
+//-------------------------------------------------------------------------
+// api
+//-------------------------------------------------------------------------
+
+static Module* mod_ctor()
+{
+ return new GtpInfoModule;
+}
+
+static void mod_dtor(Module* m)
+{
+ delete m;
+}
+
+static IpsOption* opt_ctor(Module* m, OptTreeNode*)
+{
+ GtpInfoModule* mod = (GtpInfoModule*)m;
+ return new GtpInfoOption(mod->types);
+}
+
+static void opt_dtor(IpsOption* p)
+{
+ delete p;
+}
+
+static const IpsApi ips_api =
+{
+ {
+ PT_IPS_OPTION,
+ sizeof(IpsApi),
+ IPSAPI_VERSION,
+ 0,
+ API_RESERVED,
+ API_OPTIONS,
+ s_name,
+ s_help,
+ mod_ctor,
+ mod_dtor
+ },
+ OPT_TYPE_DETECTION,
+ 0, PROTO_BIT__TCP,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ opt_ctor,
+ opt_dtor,
+ nullptr
+};
+
+const BaseApi* ips_gtp_info = &ips_api.base;
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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 >p_type_prof; }
+
+ ByteBitSet types[MAX_GTP_VERSION_CODE + 1];
+};
+
+bool GtpTypeModule::begin(const char*, int, SnortConfig*)
+{
+ for ( int v = 0; v <= MAX_GTP_VERSION_CODE; ++v )
+ types[v].reset();
+
+ return true;
+}
+
+bool GtpTypeModule::set_types(long t)
+{
+ if ( t < MIN_GTP_TYPE_CODE or t > MAX_GTP_TYPE_CODE )
+ return false;
+
+ for ( int v = 0; v <= MAX_GTP_VERSION_CODE; ++v )
+ types[v].set((uint8_t)t);
+
+ return true;
+}
+
+bool GtpTypeModule::set_types(const char* name)
+{
+ bool ok = false;
+
+ for ( int v = 0; v <= MAX_GTP_VERSION_CODE; ++v )
+ {
+ int t = get_message_type(v, name);
+
+ if ( t < 0 )
+ continue;
+
+ types[v].set((uint8_t)t);
+ ok = true;
+ }
+ return ok;
+}
+
+bool GtpTypeModule::set(const char*, Value& v, SnortConfig*)
+{
+ if ( !v.is("~") )
+ return false;
+
+ v.set_first_token();
+ std::string tok;
+
+ while ( v.get_next_token(tok) )
+ {
+ long n;
+
+ if ( tok[0] == '"' )
+ tok.erase(0, 1);
+
+ if ( tok[tok.length()-1] == '"' )
+ tok.erase(tok.length()-1, 1);
+
+ if ( v.strtol(n, tok) )
+ {
+ if ( !set_types(n) )
+ return false;
+ }
+ else if ( !set_types(tok.c_str()) )
+ return false;
+ }
+ return true;
+}
+
+//-------------------------------------------------------------------------
+// api
+//-------------------------------------------------------------------------
+
+static Module* mod_ctor()
+{
+ return new GtpTypeModule;
+}
+
+static void mod_dtor(Module* m)
+{
+ delete m;
+}
+
+static IpsOption* opt_ctor(Module* m, OptTreeNode*)
+{
+ GtpTypeModule* mod = (GtpTypeModule*)m;
+ return new GtpTypeOption(mod->types);
+}
+
+static void opt_dtor(IpsOption* p)
+{
+ delete p;
+}
+
+static const IpsApi ips_api =
+{
+ {
+ PT_IPS_OPTION,
+ sizeof(IpsApi),
+ IPSAPI_VERSION,
+ 0,
+ API_RESERVED,
+ API_OPTIONS,
+ s_name,
+ s_help,
+ mod_ctor,
+ mod_dtor
+ },
+ OPT_TYPE_DETECTION,
+ 0, PROTO_BIT__TCP,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ opt_ctor,
+ opt_dtor,
+ nullptr
+};
+
+const BaseApi* ips_gtp_type = &ips_api.base;
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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 >p_ver_prof; }
+
+ uint8_t version;
+};
+
+bool GtpVersionModule::set(const char*, Value& v, SnortConfig*)
+{
+ if ( !v.is("~") )
+ return false;
+
+ version = v.get_long();
+ return true;
+}
+
+//-------------------------------------------------------------------------
+// api
+//-------------------------------------------------------------------------
+
+static Module* mod_ctor()
+{
+ return new GtpVersionModule;
+}
+
+static void mod_dtor(Module* m)
+{
+ delete m;
+}
+
+static IpsOption* opt_ctor(Module* m, OptTreeNode*)
+{
+ GtpVersionModule* mod = (GtpVersionModule*)m;
+ return new GtpVersionOption(mod->version);
+}
+
+static void opt_dtor(IpsOption* p)
+{
+ delete p;
+}
+
+static const IpsApi ips_api =
+{
+ {
+ PT_IPS_OPTION,
+ sizeof(IpsApi),
+ IPSAPI_VERSION,
+ 0,
+ API_RESERVED,
+ API_OPTIONS,
+ s_name,
+ s_help,
+ mod_ctor,
+ mod_dtor
+ },
+ OPT_TYPE_DETECTION,
+ 0, PROTO_BIT__TCP,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ opt_ctor,
+ opt_dtor,
+ nullptr
+};
+
+const BaseApi* ips_gtp_version = &ips_api.base;
+
//--------------------------------------------------------------------------
/**
-** @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
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;
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;
sin_http_inspect,
#ifdef STATIC_INSPECTORS
+ ips_gtp_info,
+ ips_gtp_type,
+ ips_gtp_version,
ips_sip_body,
ips_sip_header,
ips_sip_method,
sin_ftp_client,
sin_ftp_server,
sin_ftp_data,
+ sin_gtp,
sin_imap,
sin_nhttp,
sin_pop,