Add parsing for GTPv1 extension headers and control messages.

Added a generic gtpv1_message event generated for any GTP message type.

Added specific events for the create/update/delete PDP context
request/response messages.

Addresses #934.
This commit is contained in:
Jon Siwek 2013-02-07 14:59:02 -06:00
parent a2556642e6
commit 26bf99c5a3
18 changed files with 1435 additions and 62 deletions

View file

@ -88,10 +88,10 @@ redef dpd_config += { [ANALYZER_AYIYA] = [$ports = ayiya_ports] };
const teredo_ports = { 3544/udp }; const teredo_ports = { 3544/udp };
redef dpd_config += { [ANALYZER_TEREDO] = [$ports = teredo_ports] }; redef dpd_config += { [ANALYZER_TEREDO] = [$ports = teredo_ports] };
const gtpv1u_ports = { 2152/udp }; const gtpv1_ports = { 2152/udp, 2123/udp };
redef dpd_config += { [ANALYZER_GTPV1] = [$ports = gtpv1u_ports] }; redef dpd_config += { [ANALYZER_GTPV1] = [$ports = gtpv1_ports] };
redef likely_server_ports += { ayiya_ports, teredo_ports, gtpv1u_ports }; redef likely_server_ports += { ayiya_ports, teredo_ports, gtpv1_ports };
event bro_init() &priority=5 event bro_init() &priority=5
{ {

View file

@ -1488,6 +1488,146 @@ type gtpv1_hdr: record {
next_type: count &optional; next_type: count &optional;
}; };
type gtp_cause: count;
type gtp_imsi: count;
type gtp_teardown_ind: bool;
type gtp_nsapi: count;
type gtp_recovery: count;
type gtp_teid1: count;
type gtp_teid_control_plane: count;
type gtp_charging_id: count;
type gtp_charging_gateway_addr: addr;
type gtp_trace_reference: count;
type gtp_trace_type: count;
type gtp_tft: string;
type gtp_trigger_id: string;
type gtp_omc_id: string;
type gtp_reordering_required: bool;
type gtp_proto_config_options: string;
type gtp_charging_characteristics: count;
type gtp_selection_mode: count;
type gtp_access_point_name: string;
type gtp_msisdn: string;
type gtp_gsn_addr: record {
## If the GSN Address information element has length 4 or 16, then this
## field is set to be the informational element's value interpreted as
## an IPv4 or IPv6 address, respectively.
ip: addr &optional;
## This field is set if it's not an IPv4 or IPv6 address.
other: string &optional;
};
type gtp_end_user_addr: record {
pdp_type_org: count;
pdp_type_num: count;
## Set if the End User Address information element is IPv4/IPv6.
pdp_ip: addr &optional;
## Set if the End User Address information element isn't IPv4/IPv6.
pdp_other_addr: string &optional;
};
type gtp_rai: record {
mcc: count;
mnc: count;
lac: count;
rac: count;
};
type gtp_qos_profile: record {
priority: count;
data: string;
};
type gtp_private_extension: record {
id: count;
value: string;
};
type gtp_create_pdp_ctx_request_elements: record {
imsi: gtp_imsi &optional;
rai: gtp_rai &optional;
recovery: gtp_recovery &optional;
select_mode: gtp_selection_mode &optional;
data1: gtp_teid1;
cp: gtp_teid_control_plane &optional;
nsapi: gtp_nsapi;
linked_nsapi: gtp_nsapi &optional;
charge_character: gtp_charging_characteristics &optional;
trace_ref: gtp_trace_reference &optional;
trace_type: gtp_trace_type &optional;
end_user_addr: gtp_end_user_addr &optional;
ap_name: gtp_access_point_name &optional;
opts: gtp_proto_config_options &optional;
signal_addr: gtp_gsn_addr;
user_addr: gtp_gsn_addr;
msisdn: gtp_msisdn &optional;
qos_prof: gtp_qos_profile;
tft: gtp_tft &optional;
trigger_id: gtp_trigger_id &optional;
omc_id: gtp_omc_id &optional;
ext: gtp_private_extension &optional;
};
type gtp_create_pdp_ctx_response_elements: record {
cause: gtp_cause;
reorder_req: gtp_reordering_required &optional;
recovery: gtp_recovery &optional;
data1: gtp_teid1 &optional;
cp: gtp_teid_control_plane &optional;
charging_id: gtp_charging_id &optional;
end_user_addr: gtp_end_user_addr &optional;
opts: gtp_proto_config_options &optional;
cp_addr: gtp_gsn_addr &optional;
user_addr: gtp_gsn_addr &optional;
qos_prof: gtp_qos_profile &optional;
charge_gateway: gtp_charging_gateway_addr &optional;
ext: gtp_private_extension &optional;
};
type gtp_update_pdp_ctx_request_elements: record {
imsi: gtp_imsi &optional;
rai: gtp_rai &optional;
recovery: gtp_recovery &optional;
data1: gtp_teid1;
cp: gtp_teid_control_plane &optional;
nsapi: gtp_nsapi;
trace_ref: gtp_trace_reference &optional;
trace_type: gtp_trace_type &optional;
cp_addr: gtp_gsn_addr;
user_addr: gtp_gsn_addr;
qos_prof: gtp_qos_profile;
tft: gtp_tft &optional;
trigger_id: gtp_trigger_id &optional;
omc_id: gtp_omc_id &optional;
ext: gtp_private_extension &optional;
end_user_addr: gtp_end_user_addr &optional;
};
type gtp_update_pdp_ctx_response_elements: record {
cause: gtp_cause;
recovery: gtp_recovery &optional;
data1: gtp_teid1 &optional;
cp: gtp_teid_control_plane &optional;
charging_id: gtp_charging_id &optional;
cp_addr: gtp_gsn_addr &optional;
user_addr: gtp_gsn_addr &optional;
qos_prof: gtp_qos_profile &optional;
charge_gateway: gtp_charging_gateway_addr &optional;
ext: gtp_private_extension &optional;
};
type gtp_delete_pdp_ctx_request_elements: record {
teardown_ind: gtp_teardown_ind &optional;
nsapi: gtp_nsapi;
ext: gtp_private_extension &optional;
};
type gtp_delete_pdp_ctx_response_elements: record {
cause: gtp_cause;
ext: gtp_private_extension &optional;
};
## Definition of "secondary filters". A secondary filter is a BPF filter given as ## Definition of "secondary filters". A secondary filter is a BPF filter given as
## index in this table. For each such filter, the corresponding event is raised for ## index in this table. For each such filter, the corresponding event is raised for
## all matching packets. ## all matching packets.

View file

@ -5,7 +5,6 @@
#include "Var.h" #include "Var.h"
#include "NetVar.h" #include "NetVar.h"
RecordType* gtpv1_hdr_type;
RecordType* conn_id; RecordType* conn_id;
RecordType* endpoint; RecordType* endpoint;
RecordType* endpoint_stats; RecordType* endpoint_stats;
@ -309,7 +308,6 @@ void init_net_var()
#include "input.bif.netvar_init" #include "input.bif.netvar_init"
#include "reporter.bif.netvar_init" #include "reporter.bif.netvar_init"
gtpv1_hdr_type = internal_type("gtpv1_hdr")->AsRecordType();
conn_id = internal_type("conn_id")->AsRecordType(); conn_id = internal_type("conn_id")->AsRecordType();
endpoint = internal_type("endpoint")->AsRecordType(); endpoint = internal_type("endpoint")->AsRecordType();
endpoint_stats = internal_type("endpoint_stats")->AsRecordType(); endpoint_stats = internal_type("endpoint_stats")->AsRecordType();

View file

@ -8,7 +8,6 @@
#include "EventRegistry.h" #include "EventRegistry.h"
#include "Stats.h" #include "Stats.h"
extern RecordType* gtpv1_hdr_type;
extern RecordType* conn_id; extern RecordType* conn_id;
extern RecordType* endpoint; extern RecordType* endpoint;
extern RecordType* endpoint_stats; extern RecordType* endpoint_stats;

View file

@ -577,6 +577,13 @@ event teredo_origin_indication%(outer: connection, inner: teredo_hdr%);
## it may become particularly expensive for real-time analysis. ## it may become particularly expensive for real-time analysis.
event teredo_bubble%(outer: connection, inner: teredo_hdr%); event teredo_bubble%(outer: connection, inner: teredo_hdr%);
## Generated for any GTP message with a GTPv1 header.
##
## c: The connection over which the message is sent.
##
## hdr: The GTPv1 header.
event gtpv1_message%(c: connection, hdr: gtpv1_hdr%);
## Generated for GTPv1 G-PDU packets. That is, packets with a UDP payload ## Generated for GTPv1 G-PDU packets. That is, packets with a UDP payload
## that includes a GTP header followed by an IPv4 or IPv6 packet. ## that includes a GTP header followed by an IPv4 or IPv6 packet.
## ##
@ -590,6 +597,60 @@ event teredo_bubble%(outer: connection, inner: teredo_hdr%);
## it may become particularly expensive for real-time analysis. ## it may become particularly expensive for real-time analysis.
event gtpv1_g_pdu_packet%(outer: connection, inner_gtp: gtpv1_hdr, inner_ip: pkt_hdr%); event gtpv1_g_pdu_packet%(outer: connection, inner_gtp: gtpv1_hdr, inner_ip: pkt_hdr%);
## Generated for GTPv1-C Create PDP Context Request messages.
##
## c: The connection over which the message is sent.
##
## hdr: The GTPv1 header.
##
## elements: The set of Information Elements comprising the message.
event gtpv1_create_pdp_ctx_request%(c: connection, hdr: gtpv1_hdr, elements: gtp_create_pdp_ctx_request_elements%);
## Generated for GTPv1-C Create PDP Context Response messages.
##
## c: The connection over which the message is sent.
##
## hdr: The GTPv1 header.
##
## elements: The set of Information Elements comprising the message.
event gtpv1_create_pdp_ctx_response%(c: connection, hdr: gtpv1_hdr, elements: gtp_create_pdp_ctx_response_elements%);
## Generated for GTPv1-C Update PDP Context Request messages.
##
## c: The connection over which the message is sent.
##
## hdr: The GTPv1 header.
##
## elements: The set of Information Elements comprising the message.
event gtpv1_update_pdp_ctx_request%(c: connection, hdr: gtpv1_hdr, elements: gtp_update_pdp_ctx_request_elements%);
## Generated for GTPv1-C Update PDP Context Response messages.
##
## c: The connection over which the message is sent.
##
## hdr: The GTPv1 header.
##
## elements: The set of Information Elements comprising the message.
event gtpv1_update_pdp_ctx_response%(c: connection, hdr: gtpv1_hdr, elements: gtp_update_pdp_ctx_response_elements%);
## Generated for GTPv1-C Delete PDP Context Request messages.
##
## c: The connection over which the message is sent.
##
## hdr: The GTPv1 header.
##
## elements: The set of Information Elements comprising the message.
event gtpv1_delete_pdp_ctx_request%(c: connection, hdr: gtpv1_hdr, elements: gtp_delete_pdp_ctx_request_elements%);
## Generated for GTPv1-C Delete PDP Context Response messages.
##
## c: The connection over which the message is sent.
##
## hdr: The GTPv1 header.
##
## elements: The set of Information Elements comprising the message.
event gtpv1_delete_pdp_ctx_response%(c: connection, hdr: gtpv1_hdr, elements: gtp_delete_pdp_ctx_response_elements%);
## Generated for every packet that has a non-empty transport-layer payload. ## Generated for every packet that has a non-empty transport-layer payload.
## This is a very low-level and expensive event that should be avoided when ## This is a very low-level and expensive event that should be avoided when
## at all possible. It's usually infeasible to handle when processing even ## at all possible. It's usually infeasible to handle when processing even

View file

@ -1,4 +1,602 @@
%code{
RecordVal* BuildGTPv1Hdr(const GTPv1_Header* pdu)
{
RecordVal* rv = new RecordVal(BifType::Record::gtpv1_hdr);
rv->Assign(0, new Val(pdu->version(), TYPE_COUNT));
rv->Assign(1, new Val(pdu->pt_flag(), TYPE_BOOL));
rv->Assign(2, new Val(pdu->rsv(), TYPE_BOOL));
rv->Assign(3, new Val(pdu->e_flag(), TYPE_BOOL));
rv->Assign(4, new Val(pdu->s_flag(), TYPE_BOOL));
rv->Assign(5, new Val(pdu->pn_flag(), TYPE_BOOL));
rv->Assign(6, new Val(pdu->msg_type(), TYPE_COUNT));
rv->Assign(7, new Val(pdu->length(), TYPE_COUNT));
rv->Assign(8, new Val(pdu->teid(), TYPE_COUNT));
if ( pdu->has_opt() )
{
rv->Assign(9, new Val(pdu->opt_hdr()->seq(), TYPE_COUNT));
rv->Assign(10, new Val(pdu->opt_hdr()->n_pdu(), TYPE_COUNT));
rv->Assign(11, new Val(pdu->opt_hdr()->next_type(), TYPE_COUNT));
}
return rv;
}
Val* BuildIMSI(const InformationElement* ie)
{
return new Val(ie->imsi()->value(), TYPE_COUNT);
}
Val* BuildRAI(const InformationElement* ie)
{
RecordVal* ev = new RecordVal(BifType::Record::gtp_rai);
ev->Assign(0, new Val(ie->rai()->mcc(), TYPE_COUNT));
ev->Assign(1, new Val(ie->rai()->mnc(), TYPE_COUNT));
ev->Assign(2, new Val(ie->rai()->lac(), TYPE_COUNT));
ev->Assign(3, new Val(ie->rai()->rac(), TYPE_COUNT));
return ev;
}
Val* BuildRecovery(const InformationElement* ie)
{
return new Val(ie->recovery()->restart_counter(), TYPE_COUNT);
}
Val* BuildSelectionMode(const InformationElement* ie)
{
return new Val(ie->selection_mode()->mode(), TYPE_COUNT);
}
Val* BuildTEID1(const InformationElement* ie)
{
return new Val(ie->teid1()->value(), TYPE_COUNT);
}
Val* BuildTEID_ControlPlane(const InformationElement* ie)
{
return new Val(ie->teidcp()->value(), TYPE_COUNT);
}
Val* BuildNSAPI(const InformationElement* ie)
{
return new Val(ie->nsapi()->nsapi(), TYPE_COUNT);
}
Val* BuildChargingCharacteristics(const InformationElement* ie)
{
return new Val(ie->charging_characteristics()->value(), TYPE_COUNT);
}
Val* BuildTraceReference(const InformationElement* ie)
{
return new Val(ie->trace_reference()->value(), TYPE_COUNT);
}
Val* BuildTraceType(const InformationElement* ie)
{
return new Val(ie->trace_type()->value(), TYPE_COUNT);
}
Val* BuildEndUserAddr(const InformationElement* ie)
{
RecordVal* ev = new RecordVal(BifType::Record::gtp_end_user_addr);
ev->Assign(0, new Val(ie->end_user_addr()->pdp_type_org(), TYPE_COUNT));
ev->Assign(1, new Val(ie->end_user_addr()->pdp_type_num(), TYPE_COUNT));
int len = ie->end_user_addr()->pdp_addr().length();
if ( len > 0 )
{
const uint8* d = ie->end_user_addr()->pdp_addr().data();
switch ( ie->end_user_addr()->pdp_type_num() ) {
case 0x21:
ev->Assign(2, new AddrVal(
IPAddr(IPv4, (const uint32*) d, IPAddr::Network)));
break;
case 0x57:
ev->Assign(2, new AddrVal(
IPAddr(IPv6, (const uint32*) d, IPAddr::Network)));
break;
default:
ev->Assign(3, new StringVal(
new BroString((const u_char*) d, len, 0)));
break;
}
}
return ev;
}
Val* BuildAccessPointName(const InformationElement* ie)
{
BroString* bs = new BroString((const u_char*) ie->ap_name()->value().data(),
ie->ap_name()->value().length(), 0);
return new StringVal(bs);
}
Val* BuildProtoConfigOptions(const InformationElement* ie)
{
const u_char* d = (const u_char*) ie->proto_config_opts()->value().data();
int len = ie->proto_config_opts()->value().length();
return new StringVal(new BroString(d, len, 0));
}
Val* BuildGSN_Addr(const InformationElement* ie)
{
RecordVal* ev = new RecordVal(BifType::Record::gtp_gsn_addr);
int len = ie->gsn_addr()->value().length();
const uint8* d = ie->gsn_addr()->value().data();
if ( len == 4 )
ev->Assign(0, new AddrVal(
IPAddr(IPv4, (const uint32*) d, IPAddr::Network)));
else if ( len == 16 )
ev->Assign(0, new AddrVal(
IPAddr(IPv6, (const uint32*) d, IPAddr::Network)));
else
ev->Assign(1, new StringVal(new BroString((const u_char*) d, len, 0)));
return ev;
}
Val* BuildMSISDN(const InformationElement* ie)
{
const u_char* d = (const u_char*) ie->msisdn()->value().data();
int len = ie->msisdn()->value().length();
return new StringVal(new BroString(d, len, 0));
}
Val* BuildQoS_Profile(const InformationElement* ie)
{
RecordVal* ev = new RecordVal(BifType::Record::gtp_qos_profile);
const u_char* d = (const u_char*) ie->qos_profile()->data().data();
int len = ie->qos_profile()->data().length();
ev->Assign(0, new Val(ie->qos_profile()->alloc_retention_priority(),
TYPE_COUNT));
ev->Assign(1, new StringVal(new BroString(d, len, 0)));
return ev;
}
Val* BuildTrafficFlowTemplate(const InformationElement* ie)
{
const uint8* d = ie->traffic_flow_template()->value().data();
int len = ie->traffic_flow_template()->value().length();
return new StringVal(new BroString((const u_char*) d, len, 0));
}
Val* BuildTriggerID(const InformationElement* ie)
{
const uint8* d = ie->trigger_id()->value().data();
int len = ie->trigger_id()->value().length();
return new StringVal(new BroString((const u_char*) d, len, 0));
}
Val* BuildOMC_ID(const InformationElement* ie)
{
const uint8* d = ie->omc_id()->value().data();
int len = ie->omc_id()->value().length();
return new StringVal(new BroString((const u_char*) d, len, 0));
}
Val* BuildPrivateExt(const InformationElement* ie)
{
RecordVal* ev = new RecordVal(BifType::Record::gtp_private_extension);
const uint8* d = ie->private_ext()->value().data();
int len = ie->private_ext()->value().length();
ev->Assign(0, new Val(ie->private_ext()->id(), TYPE_COUNT));
ev->Assign(1, new StringVal(new BroString((const u_char*) d, len, 0)));
return ev;
}
Val* BuildCause(const InformationElement* ie)
{
return new Val(ie->cause()->value(), TYPE_COUNT);
}
Val* BuildReorderReq(const InformationElement* ie)
{
return new Val(ie->reorder_req()->req(), TYPE_BOOL);
}
Val* BuildChargingID(const InformationElement* ie)
{
return new Val(ie->charging_id()->value(), TYPE_COUNT);;
}
Val* BuildChargingGatewayAddr(const InformationElement* ie)
{
const uint8* d = ie->charging_gateway_addr()->value().data();
int len = ie->charging_gateway_addr()->value().length();
if ( len == 4 )
return new AddrVal(IPAddr(IPv4, (const uint32*) d, IPAddr::Network));
else if ( len == 16 )
return new AddrVal(IPAddr(IPv6, (const uint32*) d, IPAddr::Network));
else
return 0;
}
Val* BuildTeardownInd(const InformationElement* ie)
{
return new Val(ie->teardown_ind()->ind(), TYPE_BOOL);
}
void CreatePDP_Request(const BroAnalyzer& a, const GTPv1_Header* pdu)
{
if ( ! ::gtpv1_create_pdp_ctx_request ) return;
RecordVal* rv = new RecordVal(
BifType::Record::gtp_create_pdp_ctx_request_elements);
const vector<InformationElement *> * v = pdu->create_pdp_ctx_request();
bool second_nsapi = false;
bool second_gsn_addr = false;
for ( size_t i = 0; i < v->size(); ++i )
{
const InformationElement* ie = (*v)[i];
switch ( ie->type() ) {
case GTPv1::TYPE_IMSI:
rv->Assign(0, BuildIMSI(ie));
break;
case GTPv1::TYPE_RAI:
rv->Assign(1, BuildRAI(ie));
break;
case GTPv1::TYPE_RECOVERY:
rv->Assign(2, BuildRecovery(ie));
break;
case GTPv1::TYPE_SELECTION_MODE:
rv->Assign(3, BuildSelectionMode(ie));
break;
case GTPv1::TYPE_TEID1:
rv->Assign(4, BuildTEID1(ie));
break;
case GTPv1::TYPE_TEID_CONTROL_PLANE:
rv->Assign(5, BuildTEID_ControlPlane(ie));
break;
case GTPv1::TYPE_NSAPI:
if ( second_nsapi )
rv->Assign(7, BuildNSAPI(ie));
else
{
second_nsapi = true;
rv->Assign(6, BuildNSAPI(ie));
}
break;
case GTPv1::TYPE_CHARGING_CHARACTERISTICS:
rv->Assign(8, BuildChargingCharacteristics(ie));
break;
case GTPv1::TYPE_TRACE_REFERENCE:
rv->Assign(9, BuildTraceReference(ie));
break;
case GTPv1::TYPE_TRACE_TYPE:
rv->Assign(10, BuildTraceType(ie));
break;
case GTPv1::TYPE_END_USER_ADDR:
rv->Assign(11, BuildEndUserAddr(ie));
break;
case GTPv1::TYPE_ACCESS_POINT_NAME:
rv->Assign(12, BuildAccessPointName(ie));
break;
case GTPv1::TYPE_PROTO_CONFIG_OPTIONS:
rv->Assign(13, BuildProtoConfigOptions(ie));
break;
case GTPv1::TYPE_GSN_ADDR:
if ( second_gsn_addr )
rv->Assign(15, BuildGSN_Addr(ie));
else
{
second_gsn_addr = true;
rv->Assign(14, BuildGSN_Addr(ie));
}
break;
case GTPv1::TYPE_MSISDN:
rv->Assign(16, BuildMSISDN(ie));
break;
case GTPv1::TYPE_QOS_PROFILE:
rv->Assign(17, BuildQoS_Profile(ie));
break;
case GTPv1::TYPE_TRAFFIC_FLOW_TEMPLATE:
rv->Assign(18, BuildTrafficFlowTemplate(ie));
break;
case GTPv1::TYPE_TRIGGER_ID:
rv->Assign(19, BuildTriggerID(ie));
break;
case GTPv1::TYPE_OMC_ID:
rv->Assign(20, BuildOMC_ID(ie));
break;
case GTPv1::TYPE_PRIVATE_EXT:
rv->Assign(21, BuildPrivateExt(ie));
break;
default:
a->Weird(fmt("gtp_invalid_info_element_%d", (*v)[i]->type()));
break;
}
}
BifEvent::generate_gtpv1_create_pdp_ctx_request(a, a->Conn(),
BuildGTPv1Hdr(pdu), rv);
}
void CreatePDP_Response(const BroAnalyzer& a, const GTPv1_Header* pdu)
{
if ( ! ::gtpv1_create_pdp_ctx_response ) return;
RecordVal* rv = new RecordVal(
BifType::Record::gtp_create_pdp_ctx_response_elements);
const vector<InformationElement *> * v = pdu->create_pdp_ctx_response();
bool second_gsn_addr = false;
for ( size_t i = 0; i < v->size(); ++i )
{
const InformationElement* ie = (*v)[i];
switch ( ie->type() ) {
case GTPv1::TYPE_CAUSE:
rv->Assign(0, BuildCause(ie));
break;
case GTPv1::TYPE_REORDER_REQ:
rv->Assign(1, BuildReorderReq(ie));
break;
case GTPv1::TYPE_RECOVERY:
rv->Assign(2, BuildRecovery(ie));
break;
case GTPv1::TYPE_TEID1:
rv->Assign(3, BuildTEID1(ie));
break;
case GTPv1::TYPE_TEID_CONTROL_PLANE:
rv->Assign(4, BuildTEID_ControlPlane(ie));
break;
case GTPv1::TYPE_CHARGING_ID:
rv->Assign(5, BuildChargingID(ie));
break;
case GTPv1::TYPE_END_USER_ADDR:
rv->Assign(6, BuildEndUserAddr(ie));
break;
case GTPv1::TYPE_PROTO_CONFIG_OPTIONS:
rv->Assign(7, BuildProtoConfigOptions(ie));
break;
case GTPv1::TYPE_GSN_ADDR:
if ( second_gsn_addr )
rv->Assign(9, BuildGSN_Addr(ie));
else
{
second_gsn_addr = true;
rv->Assign(8, BuildGSN_Addr(ie));
}
break;
case GTPv1::TYPE_QOS_PROFILE:
rv->Assign(10, BuildQoS_Profile(ie));
break;
case GTPv1::TYPE_CHARGING_GATEWAY_ADDR:
rv->Assign(11, BuildChargingGatewayAddr(ie));
break;
case GTPv1::TYPE_PRIVATE_EXT:
rv->Assign(12, BuildPrivateExt(ie));
break;
default:
a->Weird(fmt("gtp_invalid_info_element_%d", (*v)[i]->type()));
break;
}
}
BifEvent::generate_gtpv1_create_pdp_ctx_response(a, a->Conn(),
BuildGTPv1Hdr(pdu), rv);
}
void UpdatePDP_Request(const BroAnalyzer& a, const GTPv1_Header* pdu)
{
if ( ! ::gtpv1_update_pdp_ctx_request ) return;
RecordVal* rv = new RecordVal(
BifType::Record::gtp_update_pdp_ctx_request_elements);
const vector<InformationElement *> * v = pdu->update_pdp_ctx_request();
bool second_gsn_addr = false;
for ( size_t i = 0; i < v->size(); ++i )
{
const InformationElement* ie = (*v)[i];
switch ( ie->type() ) {
case GTPv1::TYPE_IMSI:
rv->Assign(0, BuildIMSI(ie));
break;
case GTPv1::TYPE_RAI:
rv->Assign(1, BuildRAI(ie));
break;
case GTPv1::TYPE_RECOVERY:
rv->Assign(2, BuildRecovery(ie));
break;
case GTPv1::TYPE_TEID1:
rv->Assign(3, BuildTEID1(ie));
break;
case GTPv1::TYPE_TEID_CONTROL_PLANE:
rv->Assign(4, BuildTEID_ControlPlane(ie));
break;
case GTPv1::TYPE_NSAPI:
rv->Assign(5, BuildNSAPI(ie));
break;
case GTPv1::TYPE_TRACE_REFERENCE:
rv->Assign(6, BuildTraceReference(ie));
break;
case GTPv1::TYPE_TRACE_TYPE:
rv->Assign(7, BuildTraceType(ie));
break;
case GTPv1::TYPE_GSN_ADDR:
if ( second_gsn_addr )
rv->Assign(9, BuildGSN_Addr(ie));
else
{
second_gsn_addr = true;
rv->Assign(8, BuildGSN_Addr(ie));
}
break;
case GTPv1::TYPE_QOS_PROFILE:
rv->Assign(10, BuildQoS_Profile(ie));
break;
case GTPv1::TYPE_TRAFFIC_FLOW_TEMPLATE:
rv->Assign(11, BuildTrafficFlowTemplate(ie));
break;
case GTPv1::TYPE_TRIGGER_ID:
rv->Assign(12, BuildTriggerID(ie));
break;
case GTPv1::TYPE_OMC_ID:
rv->Assign(13, BuildOMC_ID(ie));
break;
case GTPv1::TYPE_PRIVATE_EXT:
rv->Assign(14, BuildPrivateExt(ie));
break;
case GTPv1::TYPE_END_USER_ADDR:
rv->Assign(15, BuildEndUserAddr(ie));
break;
default:
a->Weird(fmt("gtp_invalid_info_element_%d", (*v)[i]->type()));
break;
}
}
BifEvent::generate_gtpv1_update_pdp_ctx_request(a, a->Conn(),
BuildGTPv1Hdr(pdu), rv);
}
void UpdatePDP_Response(const BroAnalyzer& a, const GTPv1_Header* pdu)
{
if ( ! ::gtpv1_update_pdp_ctx_response ) return;
RecordVal* rv = new RecordVal(
BifType::Record::gtp_update_pdp_ctx_response_elements);
const vector<InformationElement *> * v = pdu->update_pdp_ctx_response();
bool second_gsn_addr = false;
for ( size_t i = 0; i < v->size(); ++i )
{
const InformationElement* ie = (*v)[i];
switch ( ie->type() ) {
case GTPv1::TYPE_CAUSE:
rv->Assign(0, BuildCause(ie));
break;
case GTPv1::TYPE_RECOVERY:
rv->Assign(1, BuildRecovery(ie));
break;
case GTPv1::TYPE_TEID1:
rv->Assign(2, BuildTEID1(ie));
break;
case GTPv1::TYPE_TEID_CONTROL_PLANE:
rv->Assign(3, BuildTEID_ControlPlane(ie));
break;
case GTPv1::TYPE_CHARGING_ID:
rv->Assign(4, BuildChargingID(ie));
break;
case GTPv1::TYPE_GSN_ADDR:
if ( second_gsn_addr )
rv->Assign(6, BuildGSN_Addr(ie));
else
{
second_gsn_addr = true;
rv->Assign(5, BuildGSN_Addr(ie));
}
break;
case GTPv1::TYPE_QOS_PROFILE:
rv->Assign(7, BuildQoS_Profile(ie));
break;
case GTPv1::TYPE_CHARGING_GATEWAY_ADDR:
rv->Assign(8, BuildChargingGatewayAddr(ie));
break;
case GTPv1::TYPE_PRIVATE_EXT:
rv->Assign(9, BuildPrivateExt(ie));
break;
default:
a->Weird(fmt("gtp_invalid_info_element_%d", (*v)[i]->type()));
break;
}
}
BifEvent::generate_gtpv1_update_pdp_ctx_response(a, a->Conn(),
BuildGTPv1Hdr(pdu), rv);
}
void DeletePDP_Request(const BroAnalyzer& a, const GTPv1_Header* pdu)
{
if ( ! ::gtpv1_delete_pdp_ctx_request ) return;
RecordVal* rv = new RecordVal(
BifType::Record::gtp_delete_pdp_ctx_request_elements);
const vector<InformationElement *> * v = pdu->delete_pdp_ctx_request();
for ( size_t i = 0; i < v->size(); ++i )
{
const InformationElement* ie = (*v)[i];
switch ( ie->type() ) {
case GTPv1::TYPE_TEARDOWN_IND:
rv->Assign(0, BuildTeardownInd(ie));
break;
case GTPv1::TYPE_NSAPI:
rv->Assign(1, BuildNSAPI(ie));
break;
case GTPv1::TYPE_PRIVATE_EXT:
rv->Assign(2, BuildPrivateExt(ie));
break;
default:
a->Weird(fmt("gtp_invalid_info_element_%d", (*v)[i]->type()));
break;
}
}
BifEvent::generate_gtpv1_delete_pdp_ctx_request(a, a->Conn(),
BuildGTPv1Hdr(pdu), rv);
}
void DeletePDP_Response(const BroAnalyzer& a, const GTPv1_Header* pdu)
{
if ( ! ::gtpv1_delete_pdp_ctx_response ) return;
RecordVal* rv = new RecordVal(
BifType::Record::gtp_delete_pdp_ctx_response_elements);
const vector<InformationElement *> * v = pdu->delete_pdp_ctx_response();
for ( size_t i = 0; i < v->size(); ++i )
{
const InformationElement* ie = (*v)[i];
switch ( ie->type() ) {
case GTPv1::TYPE_CAUSE:
rv->Assign(0, BuildCause(ie));
break;
case GTPv1::TYPE_PRIVATE_EXT:
rv->Assign(1, BuildPrivateExt(ie));
break;
default:
a->Weird(fmt("gtp_invalid_info_element_%d", (*v)[i]->type()));
break;
}
}
BifEvent::generate_gtpv1_delete_pdp_ctx_response(a, a->Conn(),
BuildGTPv1Hdr(pdu), rv);
}
%}
connection GTPv1_Conn(bro_analyzer: BroAnalyzer) connection GTPv1_Conn(bro_analyzer: BroAnalyzer)
{ {
upflow = GTPv1_Flow(true); upflow = GTPv1_Flow(true);
@ -27,17 +625,17 @@ connection GTPv1_Conn(bro_analyzer: BroAnalyzer)
%} %}
} }
%code{
inline void violate(const char* r, const BroAnalyzer& a, const bytestring& p)
{
a->ProtocolViolation(r, (const char*) p.data(), p.length());
}
%}
flow GTPv1_Flow(is_orig: bool) flow GTPv1_Flow(is_orig: bool)
{ {
datagram = GTPv1_Header withcontext(connection, this); datagram = GTPv1_Header withcontext(connection, this);
function violate(r: string, pdu: GTPv1_Header): void
%{
BroAnalyzer a = connection()->bro_analyzer();
const_bytestring b = ${pdu.sourcedata};
a->ProtocolViolation(r.c_str(), (const char*) b.begin(), b.length());
%}
function process_gtpv1(pdu: GTPv1_Header): bool function process_gtpv1(pdu: GTPv1_Header): bool
%{ %{
BroAnalyzer a = connection()->bro_analyzer(); BroAnalyzer a = connection()->bro_analyzer();
@ -55,14 +653,14 @@ flow GTPv1_Flow(is_orig: bool)
if ( e && e->LastType() == BifEnum::Tunnel::GTPv1 ) if ( e && e->LastType() == BifEnum::Tunnel::GTPv1 )
{ {
// GTP is never tunneled in GTP so, this must be a regular packet // GTP is never tunneled in GTP so, this must be a regular packet
violate("GTP-in-GTP", a, ${pdu.packet}); violate("GTP-in-GTP", pdu);
return false; return false;
} }
if ( ${pdu.version} != 1 ) if ( ${pdu.version} != 1 )
{ {
// Only know of GTPv1 with Version == 1 // Only know of GTPv1 with Version == 1
violate("GTPv1 bad Version", a, ${pdu.packet}); violate("GTPv1 bad Version", pdu);
return false; return false;
} }
@ -72,21 +670,46 @@ flow GTPv1_Flow(is_orig: bool)
return false; return false;
} }
if ( ${pdu.e_flag} ) if ( ::gtpv1_message )
{ BifEvent::generate_gtpv1_message(a, c, BuildGTPv1Hdr(pdu));
// TODO: can't currently parse past extension headers
switch ( ${pdu.msg_type} ) {
case 16:
CreatePDP_Request(a, pdu);
return true;
case 17:
CreatePDP_Response(a, pdu);
return true;
case 18:
UpdatePDP_Request(a, pdu);
return true;
case 19:
UpdatePDP_Response(a, pdu);
return true;
case 20:
DeletePDP_Request(a, pdu);
return true;
case 21:
DeletePDP_Response(a, pdu);
return true;
case 255:
return process_g_pdu(pdu);
default:
return false; return false;
} }
if ( ${pdu.msg_type} != 0xff )
{
// Only interested in decapsulating user plane data beyond here.
return false; return false;
} %}
function process_g_pdu(pdu: GTPv1_Header): bool
%{
BroAnalyzer a = connection()->bro_analyzer();
Connection *c = a->Conn();
const EncapsulationStack* e = c->GetEncapsulation();
if ( ${pdu.packet}.length() < (int)sizeof(struct ip) ) if ( ${pdu.packet}.length() < (int)sizeof(struct ip) )
{ {
violate("Truncated GTPv1", a, ${pdu.packet}); violate("Truncated GTPv1", pdu);
return false; return false;
} }
@ -94,7 +717,7 @@ flow GTPv1_Flow(is_orig: bool)
if ( ip->ip_v != 4 && ip->ip_v != 6 ) if ( ip->ip_v != 4 && ip->ip_v != 6 )
{ {
violate("non-IP packet in GTPv1", a, ${pdu.packet}); violate("non-IP packet in GTPv1", pdu);
return false; return false;
} }
@ -113,10 +736,10 @@ flow GTPv1_Flow(is_orig: bool)
} }
else if ( result < 0 ) else if ( result < 0 )
violate("Truncated GTPv1", a, ${pdu.packet}); violate("Truncated GTPv1", pdu);
else else
violate("GTPv1 payload length", a, ${pdu.packet}); violate("GTPv1 payload length", pdu);
if ( result != 0 ) if ( result != 0 )
{ {
@ -125,37 +748,16 @@ flow GTPv1_Flow(is_orig: bool)
} }
if ( ::gtpv1_g_pdu_packet ) if ( ::gtpv1_g_pdu_packet )
{ BifEvent::generate_gtpv1_g_pdu_packet(a, c, BuildGTPv1Hdr(pdu),
RecordVal* rv = new RecordVal(gtpv1_hdr_type);
rv->Assign(0, new Val(${pdu.version}, TYPE_COUNT));
rv->Assign(1, new Val(${pdu.pt_flag}, TYPE_BOOL));
rv->Assign(2, new Val(${pdu.rsv}, TYPE_BOOL));
rv->Assign(3, new Val(${pdu.e_flag}, TYPE_BOOL));
rv->Assign(4, new Val(${pdu.s_flag}, TYPE_BOOL));
rv->Assign(5, new Val(${pdu.pn_flag}, TYPE_BOOL));
rv->Assign(6, new Val(${pdu.msg_type}, TYPE_COUNT));
rv->Assign(7, new Val(ntohs(${pdu.length}), TYPE_COUNT));
rv->Assign(8, new Val(ntohl(${pdu.teid}), TYPE_COUNT));
if ( ${pdu.has_opt} )
{
rv->Assign(9, new Val(ntohs(${pdu.opt_hdr.seq}), TYPE_COUNT));
rv->Assign(10, new Val(${pdu.opt_hdr.n_pdu}, TYPE_COUNT));
rv->Assign(11, new Val(${pdu.opt_hdr.next_type}, TYPE_COUNT));
}
BifEvent::generate_gtpv1_g_pdu_packet(a, c, rv,
inner->BuildPktHdrVal()); inner->BuildPktHdrVal());
}
EncapsulatingConn ec(c, BifEnum::Tunnel::GTPv1); EncapsulatingConn ec(c, BifEnum::Tunnel::GTPv1);
sessions->DoNextInnerPacket(network_time(), 0, inner, e, ec); sessions->DoNextInnerPacket(network_time(), 0, inner, e, ec);
return (result == 0) ? true : false; return true;
%} %}
}; };
refine typeattr GTPv1_Header += &let { proc_gtpv1 = $context.flow.process_gtpv1(this); }; refine typeattr GTPv1_Header += &let { proc_gtpv1 = $context.flow.process_gtpv1(this); };

View file

@ -4,11 +4,27 @@ type GTPv1_Header = record {
msg_type: uint8; msg_type: uint8;
length: uint16; length: uint16;
teid: uint32; teid: uint32;
opt: case has_opt of { opt: case has_opt of {
true -> opt_hdr: GTPv1_Opt_Header; true -> opt_hdr: GTPv1_Opt_Header;
false -> no_opt: empty; false -> no_opt: empty;
} &requires(has_opt); };
packet: bytestring &restofdata;
ext: case e_flag of {
true -> ext_hdrs: GTPv1_Ext_Header[] &until($element.next_type == 0);
false -> no_ext: empty;
};
msg: case msg_type of {
16 -> create_pdp_ctx_request: InformationElement[];
17 -> create_pdp_ctx_response: InformationElement[];
18 -> update_pdp_ctx_request: InformationElement[];
19 -> update_pdp_ctx_response: InformationElement[];
20 -> delete_pdp_ctx_request: InformationElement[];
21 -> delete_pdp_ctx_response: InformationElement[];
255 -> packet: bytestring &restofdata;
default -> unknown: bytestring &restofdata;
};
} &let { } &let {
version: uint8 = (flags & 0xE0) >> 5; version: uint8 = (flags & 0xE0) >> 5;
@ -18,10 +34,463 @@ type GTPv1_Header = record {
s_flag: bool = flags & 0x02; s_flag: bool = flags & 0x02;
pn_flag: bool = flags & 0x01; pn_flag: bool = flags & 0x01;
has_opt: bool = flags & 0x07; has_opt: bool = flags & 0x07;
} &byteorder = littleendian; } &byteorder = bigendian, &exportsourcedata;
type GTPv1_Opt_Header = record { type GTPv1_Opt_Header = record {
seq: uint16; seq: uint16;
n_pdu: uint8; n_pdu: uint8;
next_type: uint8; next_type: uint8;
} };
type GTPv1_Ext_Header = record {
length: uint8;
contents: bytestring &length=(length * 4 - 2);
next_type: uint8;
};
enum InfoElementType {
TYPE_CAUSE = 1,
TYPE_IMSI = 2,
TYPE_RAI = 3,
TYPE_TLLI = 4,
TYPE_P_TMSI = 5,
TYPE_REORDER_REQ = 8,
TYPE_AUTHN_TRIPLET = 9,
TYPE_MAP_CAUSE = 11,
TYPE_P_TMSI_SIG = 12,
TYPE_MS_VALID = 13,
TYPE_RECOVERY = 14,
TYPE_SELECTION_MODE = 15,
TYPE_TEID1 = 16,
TYPE_TEID_CONTROL_PLANE = 17,
TYPE_TEID2 = 18,
TYPE_TEARDOWN_IND = 19,
TYPE_NSAPI = 20,
TYPE_RANAP_CAUSE = 21,
TYPE_RAB_CTX = 22,
TYPE_RADIO_PRIORITY_SMS = 23,
TYPE_RADIO_PRIORITY = 24,
TYPE_PACKET_FLOW_ID = 25,
TYPE_CHARGING_CHARACTERISTICS = 26,
TYPE_TRACE_REFERENCE = 27,
TYPE_TRACE_TYPE = 28,
TYPE_MS_NOT_REACHABLE_REASON = 29,
TYPE_CHARGING_ID = 127,
TYPE_END_USER_ADDR = 128,
TYPE_MM_CTX = 129,
TYPE_PDP_CTX = 130,
TYPE_ACCESS_POINT_NAME = 131,
TYPE_PROTO_CONFIG_OPTIONS = 132,
TYPE_GSN_ADDR = 133,
TYPE_MSISDN = 134,
TYPE_QOS_PROFILE = 135,
TYPE_AUTHN_QUINTUPLET = 136,
TYPE_TRAFFIC_FLOW_TEMPLATE = 137,
TYPE_TARGET_ID = 138,
TYPE_UTRAN_TRANSPARENT_CONTAINER = 139,
TYPE_RAB_SETUP_INFO = 140,
TYPE_EXT_HEADER_TYPE_LIST = 141,
TYPE_TRIGGER_ID = 142,
TYPE_OMC_ID = 143,
TYPE_CHARGING_GATEWAY_ADDR = 251,
TYPE_PRIVATE_EXT = 255,
};
type InformationElement = record {
type: uint8;
len: case is_tlv of {
true -> tlv_len: uint16;
false -> no_len: empty;
};
value: case type of {
TYPE_CAUSE -> cause: Cause;
TYPE_IMSI -> imsi: IMSI;
TYPE_RAI -> rai: RAI;
TYPE_TLLI -> tlli: TLLI;
TYPE_P_TMSI -> p_tmsi: P_TMSI;
TYPE_REORDER_REQ -> reorder_req: ReorderReq;
TYPE_AUTHN_TRIPLET -> authn_triplet: AuthN_Triplet;
TYPE_MAP_CAUSE -> map_cause: MAP_Cause;
TYPE_P_TMSI_SIG -> p_tmsi_sig: P_TMSI_Sig;
TYPE_MS_VALID -> ms_valid: MS_Valid;
TYPE_RECOVERY -> recovery: Recovery;
TYPE_SELECTION_MODE -> selection_mode: SelectionMode;
TYPE_TEID1 -> teid1: TEID1;
TYPE_TEID_CONTROL_PLANE -> teidcp: TEID_ControlPlane;
TYPE_TEID2 -> teid2: TEID2;
TYPE_TEARDOWN_IND -> teardown_ind: TeardownInd;
TYPE_NSAPI -> nsapi: NSAPI;
TYPE_RANAP_CAUSE -> ranap_cause: RANAP_Cause;
TYPE_RAB_CTX -> rab_ctx: RAB_Ctx;
TYPE_RADIO_PRIORITY_SMS -> radio_priority_sms: RadioPrioritySMS;
TYPE_RADIO_PRIORITY -> radio_priority: RadioPriority;
TYPE_PACKET_FLOW_ID -> packet_flow_id: PacketFlowID;
TYPE_CHARGING_CHARACTERISTICS -> charging_characteristics: ChargingCharacteristics;
TYPE_TRACE_REFERENCE -> trace_reference: TraceReference;
TYPE_TRACE_TYPE -> trace_type: TraceType;
TYPE_MS_NOT_REACHABLE_REASON -> ms_not_reachable_reason: MS_Not_Reachable_Reason;
TYPE_CHARGING_ID -> charging_id: ChargingID;
TYPE_END_USER_ADDR -> end_user_addr: EndUserAddr(length);
TYPE_MM_CTX -> mm_ctx: MM_Ctx(length);
TYPE_PDP_CTX -> pdp_ctx: PDP_Ctx(length);
TYPE_ACCESS_POINT_NAME -> ap_name: AP_Name(length);
TYPE_PROTO_CONFIG_OPTIONS -> proto_config_opts: ProtoConfigOpts(length);
TYPE_GSN_ADDR -> gsn_addr: GSN_Addr(length);
TYPE_MSISDN -> msisdn: MSISDN(length);
TYPE_QOS_PROFILE -> qos_profile: QoS_Profile(length);
TYPE_AUTHN_QUINTUPLET -> authn_quintuplet: AuthN_Quintuplet(length);
TYPE_TRAFFIC_FLOW_TEMPLATE -> traffic_flow_template: TrafficFlowTemplate(length);
TYPE_TARGET_ID -> target_id: TargetID(length);
TYPE_UTRAN_TRANSPARENT_CONTAINER -> utran_transparent_container: UTRAN_TransparentContainer(length);
TYPE_RAB_SETUP_INFO -> rab_setup_info: RAB_SetupInfo(length);
TYPE_EXT_HEADER_TYPE_LIST -> ext_hdr_type_list: ExtHdrTypeList(length);
TYPE_TRIGGER_ID -> trigger_id: TriggerID(length);
TYPE_OMC_ID -> omc_id: OMC_ID(length);
TYPE_CHARGING_GATEWAY_ADDR -> charging_gateway_addr: ChargingGatewayAddr(length);
TYPE_PRIVATE_EXT -> private_ext: PrivateExt(length);
default -> unknown: bytestring &length=length;
} &requires(length);
} &let {
is_tlv: bool = (type & 0x80);
length: uint16 = is_tlv ? tlv_len : Get_IE_Len(type);
};
type Cause = record {
value: uint8;
};
function decode_imsi(v: uint8[8]): uint64
%{
uint64 rval = 0;
uint8 digits[16];
for ( size_t i = 0; i < v->size(); ++i )
{
digits[2 * i + 1] = ((*v)[i] & 0xf0) >> 4;
digits[2 * i] = (*v)[i] & 0x0f;
}
int power = 0;
for ( int i = 15; i >= 0; --i )
{
if ( digits[i] == 0x0f ) continue;
rval += digits[i] * pow(10, power);
++power;
}
return rval;
%}
type IMSI = record {
tbcd_encoded_value: uint8[8];
} &let {
value: uint64 = decode_imsi(tbcd_encoded_value);
};
type RAI = record {
mcc2_mcc1: uint8;
mnc3_mcc3: uint8;
mnc2_mnc1: uint8;
lac: uint16;
rac: uint8;
} &let {
mcc1: uint8 = (mcc2_mcc1 & 0x0f);
mcc2: uint8 = ((mcc2_mcc1 & 0xf0)>>4);
mcc3: uint8 = (mnc3_mcc3 & 0x0f);
mcc: uint16 = mcc1 * 100 + mcc2 * 10 + mcc3;
mnc1: uint8 = (mnc2_mnc1 & 0x0f);
mnc2: uint8 = ((mnc2_mnc1 & 0xf0)>>4);
mnc3: uint8 = (mnc3_mcc3 & 0xf0)>>4;
mnc: uint16 = (mnc3 & 0x0f) ? mnc1 * 10 + mnc2 : mnc1 * 100 + mnc2 * 10 + mnc3;
};
type TLLI = record {
value: uint32;
};
type P_TMSI = record {
value: uint32;
};
type ReorderReq = record {
value: uint8;
} &let {
req: bool = value & 0x01;
};
type AuthN_Triplet = record {
rand: bytestring &length=16;
sres: uint32;
kc: uint64;
};
type MAP_Cause = record {
value: uint8;
};
type P_TMSI_Sig = record {
value: bytestring &length=3;
};
type MS_Valid = record {
value: uint8;
};
type Recovery = record {
restart_counter: uint8;
};
type SelectionMode = record {
value: uint8;
} &let {
mode: uint8 = value & 0x01;
};
type TEID1 = record {
value: uint32;
};
type TEID_ControlPlane = record {
value: uint32;
};
type TEID2 = record {
spare_nsapi: uint8;
teid2: uint32;
};
type TeardownInd = record {
value: uint8;
} &let {
ind: bool = value & 0x01;
};
type NSAPI = record {
xxxx_nsapi: uint8;
} &let {
nsapi: uint8 = xxxx_nsapi & 0x0f;
};
type RANAP_Cause = record {
value: uint8;
};
type RAB_Ctx = record {
spare_nsapi: uint8;
dl_gtpu_seq_num: uint16;
ul_gtpu_seq_num: uint16;
dl_pdcp_seq_num: uint16;
ul_pdcp_seq_num: uint16;
};
type RadioPrioritySMS = record {
value: uint8;
};
type RadioPriority = record {
nsapi_radio_priority: uint8;
};
type PacketFlowID = record {
rsv_nsapi: uint8;
packet_flow_id: uint8;
};
type ChargingCharacteristics = record {
value: uint16;
};
type TraceReference = record {
value: uint16;
};
type TraceType = record {
value: uint16;
};
type MS_Not_Reachable_Reason = record {
value: uint8;
};
type ChargingID = record {
value: uint32;
};
type EndUserAddr(n: uint16) = record {
spare_pdp_type_org: uint8;
pdp_type_num: uint8;
pdp_addr: bytestring &length=(n-2);
} &let {
pdp_type_org: uint8 = spare_pdp_type_org & 0x0f;
};
type MM_Ctx(n: uint16) = record {
spare_cksn_ksi: uint8;
security_params: uint8;
keys: case gsm_keys of {
true -> kc: uint64;
false -> ck_ik: bytestring &length=32;
};
vector_len: case have_triplets of {
true -> no_quint_len: empty;
false -> quint_len: uint16;
};
vectors: case have_triplets of {
true -> triplets: AuthN_Triplet[num_vectors];
false -> quintuplets: AuthN_Quintuplet(quint_len)[num_vectors];
} &requires(num_vectors);
drx_param: uint16;
ms_net_capability_len: uint8;
ms_net_capability: bytestring &length=ms_net_capability_len;
container_len: uint16;
container: bytestring &length=container_len;
} &let {
security_mode: uint8 = security_params >> 6;
gsm_keys: bool = security_mode & 0x01;
have_triplets: bool = (security_mode == 1);
num_vectors: uint8 = (security_params & 0x38) >> 3;
};
type PDP_Ctx(n: uint16) = record {
rsv_nsapi: uint8;
xxxx_sapi: uint8;
qos_sub_len: uint8;
qos_sub: QoS_Profile(qos_sub_len);
qos_req_len: uint8;
qos_req: QoS_Profile(qos_req_len);
qos_neg_len: uint8;
qos_neg: QoS_Profile(qos_neg_len);
snd: uint16;
snu: uint16;
send_npdu_num: uint8;
recv_npdu_num: uint8;
ul_teid_cp: TEID_ControlPlane;
ul_teid_data1: TEID1;
pdp_ctx_id: uint8;
spare_pdp_type_org: uint8;
pdp_type_num: uint8;
pdp_addr_len: uint8;
pdp_addr: bytestring &length=pdp_addr_len;
ggsn_addr_control_plane_len: uint8;
ggsn_addr_control_plane: bytestring &length=ggsn_addr_control_plane_len;
ggsn_addr_user_traffic_len: uint8;
ggsn_addr_user_traffic: bytestring &length=ggsn_addr_user_traffic_len;
apn_len: uint8;
apn: AP_Name(apn_len);
spare_transaction_id: uint8;
transaction_id: uint8;
};
type AP_Name(n: uint16) = record {
value: bytestring &length=n;
};
type ProtoConfigOpts(n: uint16) = record {
value: bytestring &length=n;
};
type GSN_Addr(n: uint16) = record {
value: bytestring &length=n;
};
type MSISDN(n: uint16) = record {
value: bytestring &length=n;
};
type QoS_Profile(n: uint16) = record {
alloc_retention_priority: uint8;
data: bytestring &length=n-1;
};
type AuthN_Quintuplet(n: uint16) = record {
rand: bytestring &length=16;
xres_len: uint8;
xres: bytestring &length=xres_len;
ck: bytestring &length=16;
ik: bytestring &length=16;
autn_len: uint8;
autn: bytestring &length=autn_len;
};
type TrafficFlowTemplate(n: uint16) = record {
value: bytestring &length=n;
};
type TargetID(n: uint16) = record {
value: bytestring &length=n;
};
type UTRAN_TransparentContainer(n: uint16) = record {
value: bytestring &length=n;
};
type RAB_SetupInfo(n: uint16) = record {
xxxx_nsapi: uint8;
have_teid: case n of {
1 -> no_teid: empty;
default -> teid: TEID1;
};
have_addr: case n of {
1 -> no_addr: empty;
default -> rnc_addr: bytestring &length=n-5;
};
};
type ExtHdrTypeList(n: uint16) = record {
value: uint8[n];
};
type TriggerID(n: uint16) = record {
value: bytestring &length=n;
};
type OMC_ID(n: uint16) = record {
value: bytestring &length=n;
};
type ChargingGatewayAddr(n: uint16) = record {
value: bytestring &length=n;
};
type PrivateExt(n: uint16) = record {
id: uint16;
value: bytestring &length=n-2;
};
function Get_IE_Len(t: uint8): uint16 =
case t of {
TYPE_CAUSE -> 1;
TYPE_IMSI -> 8;
TYPE_RAI -> 6;
TYPE_TLLI -> 4;
TYPE_P_TMSI -> 4;
TYPE_REORDER_REQ -> 1;
TYPE_AUTHN_TRIPLET -> 28;
TYPE_MAP_CAUSE -> 1;
TYPE_P_TMSI_SIG -> 3;
TYPE_MS_VALID -> 1;
TYPE_RECOVERY -> 1;
TYPE_SELECTION_MODE -> 1;
TYPE_TEID1 -> 4;
TYPE_TEID_CONTROL_PLANE -> 4;
TYPE_TEID2 -> 5;
TYPE_TEARDOWN_IND -> 1;
TYPE_NSAPI -> 1;
TYPE_RANAP_CAUSE -> 1;
TYPE_RAB_CTX -> 9;
TYPE_RADIO_PRIORITY_SMS -> 1;
TYPE_RADIO_PRIORITY -> 1;
TYPE_PACKET_FLOW_ID -> 2;
TYPE_CHARGING_CHARACTERISTICS -> 2;
TYPE_TRACE_REFERENCE -> 2;
TYPE_TRACE_TYPE -> 2;
TYPE_MS_NOT_REACHABLE_REASON -> 1;
TYPE_CHARGING_ID -> 4;
};

View file

@ -211,3 +211,17 @@ enum Mode %{
%} %}
module GLOBAL; module GLOBAL;
type gtpv1_hdr: record;
type gtp_create_pdp_ctx_request_elements: record;
type gtp_create_pdp_ctx_response_elements: record;
type gtp_update_pdp_ctx_request_elements: record;
type gtp_update_pdp_ctx_response_elements: record;
type gtp_delete_pdp_ctx_request_elements: record;
type gtp_delete_pdp_ctx_response_elements: record;
type gtp_end_user_addr: record;
type gtp_rai: record;
type gtp_qos_profile: record;
type gtp_private_extension: record;
type gtp_gsn_addr: record;

View file

@ -0,0 +1,2 @@
gtpv1_message, [orig_h=10.155.148.149, orig_p=9000/udp, resp_h=10.155.148.157, resp_p=2152/udp]
[version=1, pt_flag=T, rsv=F, e_flag=T, s_flag=T, pn_flag=F, msg_type=255, length=1508, teid=1050199, seq=5, n_pdu=0, next_type=192]

View file

@ -1 +1 @@
protocol_violation, [orig_h=74.125.216.149, orig_p=2152/udp, resp_h=10.131.138.69, resp_p=2152/udp], GTP-in-GTP [n\xd9'|\x00\x00\x01\xb6[\xf6\xdc0\xb7d\xe5\xe6\xa76\x91\xfbk\x0e\x02\xc8A\x05\xa8\xe6\xf3Gi\x80(]\xcew\x84\xae}\xd2...] protocol_violation, [orig_h=74.125.216.149, orig_p=2152/udp, resp_h=10.131.138.69, resp_p=2152/udp], GTP-in-GTP [\x80\xe1Bc.\xe20\xebn\xd9'|\x00\x00\x01\xb6[\xf6\xdc0\xb7d\xe5\xe6\xa76\x91\xfbk\x0e\x02\xc8A\x05\xa8\xe6\xf3Gi\x80...]

View file

@ -0,0 +1,24 @@
gtpv1_message, [orig_h=192.169.100.1, orig_p=34273/udp, resp_h=10.100.200.33, resp_p=2123/udp]
[version=1, pt_flag=T, rsv=F, e_flag=F, s_flag=T, pn_flag=F, msg_type=16, length=137, teid=0, seq=4875, n_pdu=0, next_type=0]
gtp create request, [orig_h=192.169.100.1, orig_p=34273/udp, resp_h=10.100.200.33, resp_p=2123/udp]
[version=1, pt_flag=T, rsv=F, e_flag=F, s_flag=T, pn_flag=F, msg_type=16, length=137, teid=0, seq=4875, n_pdu=0, next_type=0]
[imsi=460004100000101, rai=[mcc=460, mnc=6, lac=65534, rac=255], recovery=176, select_mode=1, data1=854600697, cp=854600697, nsapi=5, linked_nsapi=<uninitialized>, charge_character=<uninitialized>, trace_ref=<uninitialized>, trace_type=<uninitialized>, end_user_addr=[pdp_type_org=1, pdp_type_num=33, pdp_ip=<uninitialized>, pdp_other_addr=<uninitialized>], ap_name=^Feetest, opts=\x80\x80!^V^A^A\0^V^C^F\0\0\0\0\x81^F\0\0\0\0\x83^F\0\0\0\0, signal_addr=[ip=192.169.100.1, other=<uninitialized>], user_addr=[ip=192.169.100.1, other=<uninitialized>], msisdn=\x91hQ"^A\0^A\xf1, qos_prof=[priority=2, data=\x1bB\x1fs\x8c@@tK@@], tft=<uninitialized>, trigger_id=<uninitialized>, omc_id=<uninitialized>, ext=[id=10923, value=^B^A^C]]
gtpv1_message, [orig_h=192.169.100.1, orig_p=34273/udp, resp_h=10.100.200.33, resp_p=2123/udp]
[version=1, pt_flag=T, rsv=F, e_flag=F, s_flag=T, pn_flag=F, msg_type=17, length=101, teid=854600697, seq=4875, n_pdu=0, next_type=0]
gtp create response, [orig_h=192.169.100.1, orig_p=34273/udp, resp_h=10.100.200.33, resp_p=2123/udp]
[version=1, pt_flag=T, rsv=F, e_flag=F, s_flag=T, pn_flag=F, msg_type=17, length=101, teid=854600697, seq=4875, n_pdu=0, next_type=0]
[cause=128, reorder_req=F, recovery=24, data1=268435589, cp=268435584, charging_id=103000009, end_user_addr=[pdp_type_org=1, pdp_type_num=33, pdp_ip=192.168.252.130, pdp_other_addr=<uninitialized>], opts=\x80\x80!^P^D^A\0^P\x81^F\0\0\0\0\x83^F\0\0\0\0\x80!^J^C^A\0^J^C^F\xc0\xa8\xfc\x82, cp_addr=[ip=10.100.200.34, other=<uninitialized>], user_addr=[ip=10.100.200.49, other=<uninitialized>], qos_prof=[priority=2, data=\x1bB\x1fs\x8c@@tK@@], charge_gateway=<uninitialized>, ext=<uninitialized>]
gtpv1_message, [orig_h=127.0.0.2, orig_p=2123/udp, resp_h=127.0.0.1, resp_p=2123/udp]
[version=1, pt_flag=T, rsv=F, e_flag=F, s_flag=T, pn_flag=F, msg_type=1, length=4, teid=0, seq=3072, n_pdu=0, next_type=0]
gtpv1_message, [orig_h=127.0.0.2, orig_p=2123/udp, resp_h=127.0.0.1, resp_p=2123/udp]
[version=1, pt_flag=T, rsv=F, e_flag=F, s_flag=T, pn_flag=F, msg_type=2, length=6, teid=0, seq=3072, n_pdu=0, next_type=0]
gtpv1_message, [orig_h=127.0.0.2, orig_p=2123/udp, resp_h=127.0.0.1, resp_p=2123/udp]
[version=1, pt_flag=T, rsv=F, e_flag=F, s_flag=T, pn_flag=F, msg_type=16, length=104, teid=0, seq=3073, n_pdu=0, next_type=0]
gtp create request, [orig_h=127.0.0.2, orig_p=2123/udp, resp_h=127.0.0.1, resp_p=2123/udp]
[version=1, pt_flag=T, rsv=F, e_flag=F, s_flag=T, pn_flag=F, msg_type=16, length=104, teid=0, seq=3073, n_pdu=0, next_type=0]
[imsi=240010123456789, rai=<uninitialized>, recovery=3, select_mode=1, data1=1, cp=1, nsapi=0, linked_nsapi=<uninitialized>, charge_character=2048, trace_ref=<uninitialized>, trace_type=<uninitialized>, end_user_addr=[pdp_type_org=1, pdp_type_num=33, pdp_ip=<uninitialized>, pdp_other_addr=<uninitialized>], ap_name=^Hinternet, opts=\x80\xc0#^Q^A^A\0^Q^Cmig^Hhemmelig, signal_addr=[ip=127.0.0.2, other=<uninitialized>], user_addr=[ip=127.0.0.2, other=<uninitialized>], msisdn=\x91d^G^R2T\xf6, qos_prof=[priority=0, data=^K\x92\x1f], tft=<uninitialized>, trigger_id=<uninitialized>, omc_id=<uninitialized>, ext=<uninitialized>]
gtpv1_message, [orig_h=127.0.0.2, orig_p=2123/udp, resp_h=127.0.0.1, resp_p=2123/udp]
[version=1, pt_flag=T, rsv=F, e_flag=F, s_flag=T, pn_flag=F, msg_type=17, length=78, teid=1, seq=3073, n_pdu=0, next_type=0]
gtp create response, [orig_h=127.0.0.2, orig_p=2123/udp, resp_h=127.0.0.1, resp_p=2123/udp]
[version=1, pt_flag=T, rsv=F, e_flag=F, s_flag=T, pn_flag=F, msg_type=17, length=78, teid=1, seq=3073, n_pdu=0, next_type=0]
[cause=128, reorder_req=F, recovery=1, data1=1, cp=1, charging_id=1, end_user_addr=[pdp_type_org=1, pdp_type_num=33, pdp_ip=192.168.0.2, pdp_other_addr=<uninitialized>], opts=\x80\x80!^P^B\0\0^P\x81^F\0\0\0\0\x83^F\0\0\0\0, cp_addr=[ip=127.0.0.1, other=<uninitialized>], user_addr=[ip=127.0.0.1, other=<uninitialized>], qos_prof=[priority=0, data=^K\x92\x1f], charge_gateway=<uninitialized>, ext=<uninitialized>]

View file

@ -3,8 +3,8 @@
#empty_field (empty) #empty_field (empty)
#unset_field - #unset_field -
#path dpd #path dpd
#open 2012-10-19-17-38-54 #open 2013-01-25-21-49-19
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto analyzer failure_reason #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto analyzer failure_reason
#types time string addr port addr port enum string string #types time string addr port addr port enum string string
1333458853.075889 UWkUyAuUGXf 173.86.159.28 2152 213.72.147.186 2152 udp GTPV1 Truncated GTPv1 [E\x00\x05\xc8G\xea@\x00\x80\x06\xb6\x83\x0a\x83w&\xd9\x14\x9c\x04\xd9\xc2\x00P\xddh\xb4\x8f41eVP\x10\x10\xe0u\xcf\x00\x00...] 1333458853.075889 UWkUyAuUGXf 173.86.159.28 2152 213.72.147.186 2152 udp GTPV1 Truncated GTPv1 [0\xff\x00\xac\x98\x13\x01LE\x00\x05\xc8G\xea@\x00\x80\x06\xb6\x83\x0a\x83w&\xd9\x14\x9c\x04\xd9\xc2\x00P\xddh\xb4\x8f41eV...]
#close 2012-10-19-17-38-54 #close 2013-01-25-21-49-19

View file

@ -3,9 +3,9 @@
#empty_field (empty) #empty_field (empty)
#unset_field - #unset_field -
#path tunnel #path tunnel
#open 2012-10-19-17-38-54 #open 2013-01-25-21-49-19
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p tunnel_type action #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p tunnel_type action
#types time string addr port addr port enum enum #types time string addr port addr port enum enum
1333458853.034734 UWkUyAuUGXf 173.86.159.28 2152 213.72.147.186 2152 Tunnel::GTPv1 Tunnel::DISCOVER 1333458853.034734 UWkUyAuUGXf 173.86.159.28 2152 213.72.147.186 2152 Tunnel::GTPv1 Tunnel::DISCOVER
1333458853.108391 UWkUyAuUGXf 173.86.159.28 2152 213.72.147.186 2152 Tunnel::GTPv1 Tunnel::CLOSE 1333458853.108391 UWkUyAuUGXf 173.86.159.28 2152 213.72.147.186 2152 Tunnel::GTPv1 Tunnel::CLOSE
#close 2012-10-19-17-38-54 #close 2013-01-25-21-49-19

Binary file not shown.

View file

@ -0,0 +1,8 @@
# @TEST-EXEC: bro -r $TRACES/tunnels/gtp/gtp_ext_header.pcap %INPUT >out
# @TEST-EXEC: btest-diff out
event gtpv1_message(c: connection, hdr: gtpv1_hdr)
{
print "gtpv1_message", c$id;
print hdr;
}

View file

@ -0,0 +1,56 @@
# @TEST-EXEC: bro -r $TRACES/tunnels/gtp/gtp_control_prime.pcap -r $TRACES/tunnels/gtp/gtp_create_pdp_ctx.pcap %INPUT >out
# @TEST-EXEC: btest-diff out
event gtpv1_message(c: connection, hdr: gtpv1_hdr)
{
print "gtpv1_message", c$id;
print hdr;
}
event gtpv1_create_pdp_ctx_request(c: connection, hdr: gtpv1_hdr,
elements: gtp_create_pdp_ctx_request_elements)
{
print "gtp create request", c$id;
print hdr;
print elements;
}
event gtpv1_create_pdp_ctx_response(c: connection, hdr: gtpv1_hdr,
elements: gtp_create_pdp_ctx_response_elements)
{
print "gtp create response", c$id;
print hdr;
print elements;
}
event gtpv1_update_pdp_ctx_request(c: connection, hdr: gtpv1_hdr,
elements: gtp_update_pdp_ctx_request_elements)
{
print "gtp update request", c$id;
print hdr;
print elements;
}
event gtpv1_update_pdp_ctx_response(c: connection, hdr: gtpv1_hdr,
elements: gtp_update_pdp_ctx_response_elements)
{
print "gtp update response", c$id;
print hdr;
print elements;
}
event gtpv1_delete_pdp_ctx_request(c: connection, hdr: gtpv1_hdr,
elements: gtp_delete_pdp_ctx_request_elements)
{
print "gtp delete request", c$id;
print hdr;
print elements;
}
event gtpv1_delete_pdp_ctx_response(c: connection, hdr: gtpv1_hdr,
elements: gtp_delete_pdp_ctx_response_elements)
{
print "gtp delete response", c$id;
print hdr;
print elements;
}