From 7d61299fa807ab8cece5d37e4d1ee7c95a102db5 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Thu, 23 May 2024 12:57:24 +1200 Subject: [PATCH 01/44] Update debian changelog --- debian/changelog | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 14b5fb8..4788a26 100644 --- a/debian/changelog +++ b/debian/changelog @@ -6,8 +6,10 @@ openli (1.1.6-1) unstable; urgency=medium * Added new parameter for IP intercepts: mobileident -- this is used to indicate whether the user identifier for a mobile data intercept is an MSISDN, IMEI or IMSI. + * VOIP intercepts that are written to pcap files will now include + their corresponding SIP packets alongside the RTP streams. - -- Shane Alcock Tue, 21 May 2024 11:24:07 +1200 + -- Shane Alcock Wed, 22 May 2024 11:08:41 +1200 openli (1.1.5-1) unstable; urgency=medium From 9c3f172e52f8e2b9a2e72685c833dc0b6f038f62 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Thu, 23 May 2024 12:57:46 +1200 Subject: [PATCH 02/44] Fix double free crashes when using SIGHUP to reload intercept config This problem was affecting the provisioner. --- src/provisioner/hup_reload.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/provisioner/hup_reload.c b/src/provisioner/hup_reload.c index c7fb949..a489b6f 100644 --- a/src/provisioner/hup_reload.c +++ b/src/provisioner/hup_reload.c @@ -126,6 +126,10 @@ static inline int ip_intercept_equal(ipintercept_t *a, ipintercept_t *b) { return 0; } + if (a->mobileident != b->mobileident) { + return 0; + } + return 1; } @@ -250,9 +254,11 @@ static void remove_withdrawn_intercept(provision_state_t *currstate, if (!droppedmeds) { announce_hi1_notification_to_mediators(currstate, common, target_info, HI1_LI_DEACTIVATED); - if (target_info) { - free(target_info); - } + } + + if (common->local) { + free(common->local); + common->local = NULL; } logger(LOG_INFO, "OpenLI provisioner: LIID %s has been withdrawn following a config reload.", @@ -606,7 +612,6 @@ static int reload_ipintercepts(provision_state_t *currstate, } remove_withdrawn_intercept(currstate, &(ipint->common), ipint->username, droppedmeds); - continue; } else { int staticchanged = reload_staticips(currstate, ipint, newequiv); From ba4c03671920bd3325d1d30dca5dbf81c11186fa Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Thu, 23 May 2024 12:58:58 +1200 Subject: [PATCH 03/44] Add free_all_staticipranges method to intercept.c --- src/intercept.c | 17 +++++++++++------ src/intercept.h | 1 + 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/intercept.c b/src/intercept.c index 3a0285d..4706c66 100644 --- a/src/intercept.c +++ b/src/intercept.c @@ -403,19 +403,24 @@ void free_single_emailintercept(emailintercept_t *m) { free(m); } -void free_single_ipintercept(ipintercept_t *cept) { +void free_all_staticipranges(static_ipranges_t **ipranges) { static_ipranges_t *ipr, *tmp; + HASH_ITER(hh, *ipranges, ipr, tmp) { + HASH_DELETE(hh, *ipranges, ipr); + free_single_staticiprange(ipr); + } + *ipranges = NULL; +} + +void free_single_ipintercept(ipintercept_t *cept) { + free_intercept_common(&(cept->common)); if (cept->username) { free(cept->username); } - HASH_ITER(hh, cept->statics, ipr, tmp) { - HASH_DELETE(hh, cept->statics, ipr); - free_single_staticiprange(ipr); - } - + free_all_staticipranges(&(cept->statics)); free(cept); } diff --git a/src/intercept.h b/src/intercept.h index 0e77b63..3e0f4c6 100644 --- a/src/intercept.h +++ b/src/intercept.h @@ -436,6 +436,7 @@ void free_all_rtpstreams(rtpstreaminf_t **streams); void free_all_ipsessions(ipsession_t **sessions); void free_all_vendmirror_intercepts(vendmirror_intercept_list_t **mirror_intercepts); void free_all_staticipsessions(staticipsession_t **statintercepts); +void free_all_staticipranges(static_ipranges_t **ipranges); void free_voip_cinmap(voipcinmap_t *cins); void free_single_ipintercept(ipintercept_t *cept); From 772a75a76a4e639548b9a7e03215d6721aa1c519 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Thu, 23 May 2024 12:59:54 +1200 Subject: [PATCH 04/44] Start using separate threads for processing GTP traffic This is work in progress -- as of this commit, we have * GTP worker threads are created and shutdown cleanly * IP Intercepts with a "mobile" accesstype are received from the sync thread and tracked locally in the GTP worker threads. * Queues to allow worker threads to send session IPs back to the collector threads are created (but not yet used). Still to come: * GTP packets are to be sent by the collector threads to a GTP worker thread (based on hash of TEID). * Remove GTP handling from sync thread. * GTP sessions will be managed by the worker threads, and any user->IP announcements that correspond to an intercept target will be passed on to the collector threads as before. * Similarly, push active GTP-IP sessions to the collector threads when a new intercept is received from the sync thread. * GTP-U parsing and matching TEIDs against those used by intercept targets, then creating encoding jobs to pass on to the seqtrackers. --- src/Makefile.am | 1 + src/collector/accessplugins/radius.c | 1 + src/collector/collector.c | 91 ++++- src/collector/collector.h | 14 + src/collector/collector_base.h | 1 + src/collector/collector_sync.c | 32 +- src/collector/collector_sync.h | 2 + src/collector/gtp_worker.c | 499 +++++++++++++++++++++++++++ src/collector/gtp_worker.h | 96 ++++++ src/collector/internetaccess.c | 5 +- src/collector/internetaccess.h | 19 + src/configparser.c | 67 ++-- 12 files changed, 793 insertions(+), 35 deletions(-) create mode 100644 src/collector/gtp_worker.c create mode 100644 src/collector/gtp_worker.h diff --git a/src/Makefile.am b/src/Makefile.am index 0405df9..2f33368 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -72,6 +72,7 @@ openlicollector_SOURCES=collector/collector.c configparser.c configparser.h \ collector/etsiencoding/encryptcontainer.c \ collector/etsiencoding/ipmmiri.c \ collector/sms_worker.c collector/sms_worker.h \ + collector/gtp_worker.c collector/gtp_worker.h \ collector/location.c collector/location.h \ collector/collector_util.c collector/collector_util.h \ $(PLUGIN_SRCS) diff --git a/src/collector/accessplugins/radius.c b/src/collector/accessplugins/radius.c index 0c2b3bc..724f4fe 100644 --- a/src/collector/accessplugins/radius.c +++ b/src/collector/accessplugins/radius.c @@ -1653,6 +1653,7 @@ static access_session_t *radius_update_session_state(access_plugin_t *p, if (!thissess) { thissess = create_access_session(p, sessionid, 5000 - rem); thissess->cin = assign_cin(raddata); + thissess->identifier_type = OPENLI_ACCESS_SESSION_IP; HASH_ADD_KEYPTR(hh, *sesslist, thissess->sessionid, strlen(thissess->sessionid), thissess); diff --git a/src/collector/collector.c b/src/collector/collector.c index 85e1116..5f09216 100644 --- a/src/collector/collector.c +++ b/src/collector/collector.c @@ -121,6 +121,8 @@ static void log_collector_stats(collector_global_t *glob) { glob->stats.packets_sync_email); logger(LOG_INFO, "OpenLI: Packets sent to SMS workers: %lu", glob->stats.packets_sms); + logger(LOG_INFO, "OpenLI: Packets sent to GTP workers: %lu", + glob->stats.packets_gtp); logger(LOG_INFO, "OpenLI: Bad SIP packets: %lu Bad RADIUS packets: %lu", glob->stats.bad_sip_packets, glob->stats.bad_ip_session_packets); logger(LOG_INFO, "OpenLI: Records created... IPCCs: %lu IPIRIs: %lu MobIRIs: %lu", @@ -286,6 +288,24 @@ static void init_collocal(colthread_local_t *loc, collector_global_t *glob, zmq_connect(loc->sms_worker_queues[i], pubsockname); } + loc->fromgtp_queues = calloc(glob->gtp_threads, + sizeof(libtrace_message_queue_t)); + + loc->gtp_worker_queues = calloc(glob->gtp_threads, sizeof(void *)); + for (i = 0; i < glob->gtp_threads; i++) { + char pubsockname[128]; + + snprintf(pubsockname, 128, "inproc://openligtpworker-colrecv%d", i); + loc->gtp_worker_queues[i] = zmq_socket(glob->zmq_ctxt, ZMQ_PUSH); + zmq_setsockopt(loc->gtp_worker_queues[i], ZMQ_SNDHWM, &hwm, + sizeof(hwm)); + zmq_connect(loc->gtp_worker_queues[i], pubsockname); + + libtrace_message_queue_init(&(loc->fromgtp_queues[i]), + sizeof(openli_pushed_t)); + } + loc->gtpq_count = glob->gtp_threads; + loc->fragreass = create_new_ipfrag_reassembler(); loc->tosyncq_ip = zmq_socket(glob->zmq_ctxt, ZMQ_PUSH); @@ -303,6 +323,8 @@ static void *start_processing_thread(libtrace_t *trace, libtrace_thread_t *t, collector_global_t *glob = (collector_global_t *)global; colthread_local_t *loc = NULL; + int i; + sync_sendq_t *syncq, *sendq_hash; pthread_rwlock_wrlock(&(glob->config_mutex)); loc = glob->collocals[glob->nextloc]; @@ -315,6 +337,20 @@ static void *start_processing_thread(libtrace_t *trace, libtrace_thread_t *t, register_sync_queues(&(glob->syncvoip), loc->tosyncq_voip, &(loc->fromsyncq_voip), t); + for (i = 0; i < glob->gtp_threads; i++) { + syncq = (sync_sendq_t *)malloc(sizeof(sync_sendq_t)); + syncq->q = &(loc->fromgtp_queues[i]); + syncq->parent = t; + + pthread_mutex_lock(&(glob->gtpworkers[i].col_queue_mutex)); + + sendq_hash = (sync_sendq_t *)(glob->gtpworkers[i].collector_queues); + HASH_ADD_PTR(sendq_hash, parent, syncq); + glob->gtpworkers[i].collector_queues = (void *)sendq_hash; + + pthread_mutex_unlock(&(glob->gtpworkers[i].col_queue_mutex)); + } + return loc; } @@ -414,6 +450,7 @@ static void stop_processing_thread(libtrace_t *trace, libtrace_thread_t *t, ipv6_target_t *v6, *tmp2; openli_pushed_t syncpush; int zero = 0, i; + sync_sendq_t *syncq, *sendq_hash; if (trace_is_err(trace)) { libtrace_err_t err = trace_get_err(trace); @@ -448,6 +485,33 @@ static void stop_processing_thread(libtrace_t *trace, libtrace_thread_t *t, zmq_close(loc->email_worker_queues[i]); } + for (i = 0; i < glob->gtp_threads; i++) { + openli_gtp_worker_t *worker; + + worker = &(glob->gtpworkers[i]); + + zmq_setsockopt(loc->gtp_worker_queues[i], ZMQ_LINGER, &zero, + sizeof(zero)); + zmq_close(loc->gtp_worker_queues[i]); + + while (libtrace_message_queue_try_get(&(loc->fromgtp_queues[i]), + (void *)&syncpush) != LIBTRACE_MQ_FAILED) { + process_incoming_messages(t, glob, loc, &syncpush); + } + pthread_mutex_lock(&(worker->col_queue_mutex)); + sendq_hash = (sync_sendq_t *)(worker->collector_queues); + + HASH_FIND_PTR(sendq_hash, &t, syncq); + if (syncq) { + HASH_DELETE(hh, sendq_hash, syncq); + free(syncq); + worker->collector_queues = (void *)sendq_hash; + } + pthread_mutex_unlock(&(worker->col_queue_mutex)); + + libtrace_message_queue_destroy(&(loc->fromgtp_queues[i])); + } + for (i = 0; i < glob->sms_threads; i++) { zmq_setsockopt(loc->sms_worker_queues[i], ZMQ_LINGER, &zero, sizeof(zero)); @@ -459,9 +523,11 @@ static void stop_processing_thread(libtrace_t *trace, libtrace_thread_t *t, zmq_setsockopt(loc->tosyncq_voip, ZMQ_LINGER, &zero, sizeof(zero)); zmq_close(loc->tosyncq_voip); + free(loc->fromgtp_queues); free(loc->zmq_pubsocks); free(loc->email_worker_queues); free(loc->sms_worker_queues); + free(loc->gtp_worker_queues); HASH_ITER(hh, loc->activeipv4intercepts, v4, tmp) { free_all_ipsessions(&(v4->intercepts)); @@ -833,7 +899,7 @@ static libtrace_packet_t *process_packet(libtrace_t *trace, uint16_t ethertype; uint32_t rem, iprem; uint8_t proto; - int forwarded = 0, ret; + int forwarded = 0, ret, i; int ipsynced = 0, voipsynced = 0, emailsynced = 0; uint16_t fragoff = 0; uint32_t servhash = 0, smshash = 0; @@ -854,6 +920,14 @@ static libtrace_packet_t *process_packet(libtrace_t *trace, process_incoming_messages(t, glob, loc, &syncpush); } + for (i = 0; i < loc->gtpq_count; i++) { + while (libtrace_message_queue_try_get(&(loc->fromgtp_queues[i]), + (void *)&syncpush) != LIBTRACE_MQ_FAILED) { + + process_incoming_messages(t, glob, loc, &syncpush); + } + } + l3 = trace_get_layer3(pkt, ðertype, &rem); if (l3 == NULL || rem == 0) { @@ -1400,6 +1474,13 @@ static void destroy_collector_state(collector_global_t *glob) { free(glob->emailworkers); } + if (glob->gtpworkers) { + for (i = 0; i < glob->gtp_threads; i++) { + pthread_mutex_destroy(&(glob->gtpworkers[i].col_queue_mutex)); + } + free(glob->gtpworkers); + } + libtrace_message_queue_destroy(&(glob->intersyncq)); if (glob->zmq_encoder_ctrl) { @@ -1630,6 +1711,7 @@ static void init_collector_global(collector_global_t *glob) { glob->forwarding_threads = 1; glob->encoding_threads = 2; glob->email_threads = 1; + glob->gtp_threads = 1; glob->sms_threads = 1; glob->sharedinfo.intpointid = NULL; glob->sharedinfo.intpointid_len = 0; @@ -2253,6 +2335,10 @@ int main(int argc, char *argv[]) { pthread_setname_np(glob->smsworkers[i].threadid, name); } + glob->gtpworkers = calloc(glob->gtp_threads, sizeof(openli_gtp_worker_t)); + for (i = 0; i < glob->gtp_threads; i++) { + start_gtp_worker_thread(&(glob->gtpworkers[i]), i, glob); + } glob->emailworkers = calloc(glob->email_threads, sizeof(openli_email_worker_t)); @@ -2463,6 +2549,9 @@ int main(int argc, char *argv[]) { for (i = 0; i < glob->email_threads; i++) { pthread_join(glob->emailworkers[i].threadid, NULL); } + for (i = 0; i < glob->gtp_threads; i++) { + pthread_join(glob->gtpworkers[i].threadid, NULL); + } for (i = 0; i < glob->sms_threads; i++) { pthread_join(glob->smsworkers[i].threadid, NULL); } diff --git a/src/collector/collector.h b/src/collector/collector.h index b70a2e9..6106d36 100644 --- a/src/collector/collector.h +++ b/src/collector/collector.h @@ -52,6 +52,7 @@ #include "radius_hasher.h" #include "email_ingest_service.h" #include "email_worker.h" +#include "gtp_worker.h" #include "sms_worker.h" #include "sipparsing.h" @@ -213,12 +214,23 @@ typedef struct colthread_local { thread */ libtrace_message_queue_t fromsyncq_voip; + /* Array of message threads for receiving intercept instructions from + * the GTP processing threads + */ + libtrace_message_queue_t *fromgtp_queues; + + /* Number of GTP processing threads that have queues in the above array */ + int gtpq_count; + /* Array of message queues to pass packets to the email worker threads */ void **email_worker_queues; /* Array of message queues to pass packets to the SMS worker threads */ void **sms_worker_queues; + /* Array of message queues to pass packets to the GTP worker threads */ + void **gtp_worker_queues; + /** SIP parser for detecting SMS over SIP */ openli_sip_parser_t *sipparser; @@ -286,6 +298,7 @@ typedef struct collector_global { int encoding_threads; int forwarding_threads; int email_threads; + int gtp_threads; int sms_threads; void *zmq_encoder_ctrl; @@ -302,6 +315,7 @@ typedef struct collector_global { openli_encoder_t *encoders; forwarding_thread_data_t *forwarders; openli_email_worker_t *emailworkers; + openli_gtp_worker_t *gtpworkers; openli_sms_worker_t *smsworkers; colthread_local_t **collocals; int nextloc; diff --git a/src/collector/collector_base.h b/src/collector/collector_base.h index 8daa3d1..9610797 100644 --- a/src/collector/collector_base.h +++ b/src/collector/collector_base.h @@ -84,6 +84,7 @@ typedef struct collector_stats { uint64_t packets_sync_ip; uint64_t packets_sync_voip; uint64_t packets_sync_email; + uint64_t packets_gtp; uint64_t packets_sms; uint64_t ipcc_created; uint64_t ipiri_created; diff --git a/src/collector/collector_sync.c b/src/collector/collector_sync.c index 078177a..8afca2c 100644 --- a/src/collector/collector_sync.c +++ b/src/collector/collector_sync.c @@ -93,10 +93,12 @@ collector_sync_t *init_sync_data(collector_global_t *glob) { sync->forwardcount = glob->forwarding_threads; sync->emailcount = glob->email_threads; sync->smscount = glob->sms_threads; + sync->gtpcount = glob->gtp_threads; sync->zmq_pubsocks = calloc(sync->pubsockcount, sizeof(void *)); sync->zmq_fwdctrlsocks = calloc(sync->forwardcount, sizeof(void *)); sync->zmq_emailsocks = calloc(sync->emailcount, sizeof(void *)); + sync->zmq_gtpsocks = calloc(sync->gtpcount, sizeof(void *)); sync->zmq_smssocks = calloc(sync->smscount, sizeof(void *)); sync->ctx = glob->sslconf.ctx; @@ -116,6 +118,9 @@ collector_sync_t *init_sync_data(collector_global_t *glob) { init_zmq_socket_array(sync->zmq_emailsocks, sync->emailcount, "inproc://openliemailcontrol_sync", glob->zmq_ctxt); + init_zmq_socket_array(sync->zmq_gtpsocks, sync->gtpcount, + "inproc://openligtpcontrol_sync", glob->zmq_ctxt); + init_zmq_socket_array(sync->zmq_smssocks, sync->smscount, "inproc://openlismscontrol_sync", glob->zmq_ctxt); @@ -228,6 +233,8 @@ void clean_sync_data(collector_sync_t *sync) { sync->zmq_fwdctrlsocks, sync->forwardcount); haltfails += send_halt_message_to_zmq_socket_array( sync->zmq_emailsocks, sync->emailcount); + haltfails += send_halt_message_to_zmq_socket_array( + sync->zmq_gtpsocks, sync->gtpcount); haltfails += send_halt_message_to_zmq_socket_array( sync->zmq_smssocks, sync->smscount); @@ -240,6 +247,7 @@ void clean_sync_data(collector_sync_t *sync) { free(sync->zmq_emailsocks); free(sync->zmq_smssocks); + free(sync->zmq_gtpsocks); free(sync->zmq_pubsocks); free(sync->zmq_fwdctrlsocks); @@ -1242,7 +1250,7 @@ static int update_modified_intercept(collector_sync_t *sync, add_intercept_to_user_intercept_list(&sync->userintercepts, ipint); push_existing_user_sessions(sync, ipint); - logger(LOG_INFO, "OpenLI: IP intercept %s has changed target", ipint->common.liid); + logger(LOG_INFO, "OpenLI: IP intercept %s has changed target, resuming interception for new target", ipint->common.liid); } if (ipint->vendmirrorid != modified->vendmirrorid) { @@ -1580,6 +1588,11 @@ static int recv_from_provisioner(collector_sync_t *sync) { if (ret == -1) { return -1; } + ret = forward_provmsg_to_workers(sync->zmq_gtpsocks, + sync->gtpcount, provmsg, msglen, msgtype, "GTP"); + if (ret == -1) { + return -1; + } break; case OPENLI_PROTO_ADD_STATICIPS: ret = new_staticiprange(sync, provmsg, msglen); @@ -1626,6 +1639,11 @@ static int recv_from_provisioner(collector_sync_t *sync) { if (ret == -1) { return -1; } + ret = forward_provmsg_to_workers(sync->zmq_gtpsocks, + sync->gtpcount, provmsg, msglen, msgtype, "GTP"); + if (ret == -1) { + return -1; + } break; case OPENLI_PROTO_ANNOUNCE_DEFAULT_RADIUS: ret = new_default_radius(sync, provmsg, msglen); @@ -1657,6 +1675,11 @@ static int recv_from_provisioner(collector_sync_t *sync) { if (ret < 0) { return -1; } + ret = forward_provmsg_to_workers(sync->zmq_gtpsocks, + sync->gtpcount, provmsg, msglen, msgtype, "GTP"); + if (ret == -1) { + return -1; + } break; case OPENLI_PROTO_START_VOIPINTERCEPT: @@ -1687,6 +1710,11 @@ static int recv_from_provisioner(collector_sync_t *sync) { if (ret == -1) { return -1; } + ret = forward_provmsg_to_workers(sync->zmq_gtpsocks, + sync->gtpcount, provmsg, msglen, msgtype, "GTP"); + if (ret == -1) { + return -1; + } ret = forward_provmsg_to_workers(sync->zmq_smssocks, sync->smscount, provmsg, msglen, msgtype, "SMS"); if (ret == -1) { @@ -1862,6 +1890,8 @@ void sync_disconnect_provisioner(collector_sync_t *sync, uint8_t dropmeds) { forward_provmsg_to_voipsync(sync, NULL, 0, OPENLI_PROTO_DISCONNECT); forward_provmsg_to_workers(sync->zmq_emailsocks, sync->emailcount, NULL, 0, OPENLI_PROTO_DISCONNECT, "email"); + forward_provmsg_to_workers(sync->zmq_gtpsocks, sync->gtpcount, + NULL, 0, OPENLI_PROTO_DISCONNECT, "GTP"); forward_provmsg_to_workers(sync->zmq_smssocks, sync->smscount, NULL, 0, OPENLI_PROTO_DISCONNECT, "SMS"); diff --git a/src/collector/collector_sync.h b/src/collector/collector_sync.h index 088d7ea..3cab888 100644 --- a/src/collector/collector_sync.h +++ b/src/collector/collector_sync.h @@ -51,10 +51,12 @@ typedef struct colsync_data { int forwardcount; int emailcount; int smscount; + int gtpcount; void **zmq_pubsocks; void **zmq_fwdctrlsocks; void **zmq_emailsocks; + void **zmq_gtpsocks; void **zmq_smssocks; void *zmq_colsock; diff --git a/src/collector/gtp_worker.c b/src/collector/gtp_worker.c new file mode 100644 index 0000000..fdd7572 --- /dev/null +++ b/src/collector/gtp_worker.c @@ -0,0 +1,499 @@ +/* + * + * Copyright (c) 2024 Searchlight New Zealand Ltd. + * All rights reserved. + * + * This file is part of OpenLI. + * + * OpenLI was originally developed by the University of Waikato WAND + * research group. For further information please see http://www.wand.net.nz/ + * + * OpenLI is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenLI 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, see . + * + * + */ +#define _GNU_SOURCE + +#include +#include +#include +#include + +#include "gtp_worker.h" +#include "collector.h" +#include "logger.h" +#include "util.h" +#include "intercept.h" +#include "netcomms.h" + +static void remove_gtp_intercept(openli_gtp_worker_t *worker, + ipintercept_t *ipint) { + + /* The sync thread should tell the collector threads that the intercept + * is over, so we don't need to "withdraw" any IP sessions that we've + * announced. + */ + + logger(LOG_INFO, "DEVDEBUG: removing intercept %s from GTP worker %d", + ipint->common.liid, worker->workerid); + remove_intercept_from_user_intercept_list(&worker->userintercepts, ipint); + HASH_DELETE(hh_liid, worker->ipintercepts, ipint); + free_single_ipintercept(ipint); +} + +static void disable_unconfirmed_gtp_intercepts(openli_gtp_worker_t *worker) { + ipintercept_t *ipint, *tmp; + + HASH_ITER(hh_liid, worker->ipintercepts, ipint, tmp) { + if (ipint->awaitingconfirm) { + remove_gtp_intercept(worker, ipint); + } + } +} + +static void flag_gtp_intercepts(ipintercept_t *cepts) { + ipintercept_t *ipint, *tmp; + + /* Don't worry about statics, because we should not be dealing with + * them here anyway */ + HASH_ITER(hh_liid, cepts, ipint, tmp) { + ipint->awaitingconfirm = 1; + } + +} + +static void push_existing_ip_sessions(openli_gtp_worker_t *worker, + ipintercept_t *ipint) { + + /* TODO */ +} + +static int init_gtp_intercept(openli_gtp_worker_t *worker, + ipintercept_t *ipint) { + + if (ipint->accesstype != INTERNET_ACCESS_TYPE_MOBILE) { + /* Only care about "mobile" intercepts */ + free_single_ipintercept(ipint); + return 0; + } + + /* Discard any static IPs announced for this intercept, as they are + * irrelevant for the purposes of this thread. + */ + logger(LOG_INFO, "DEVDEBUG: adding intercept %s -- %s to GTP worker %d", + ipint->common.liid, ipint->username, worker->workerid); + free_all_staticipranges(&(ipint->statics)); + ipint->statics = NULL; + + if (worker->tracker_threads <= 1) { + ipint->common.seqtrackerid = 0; + } else { + ipint->common.seqtrackerid = hash_liid(ipint->common.liid) % + worker->tracker_threads; + } + + add_intercept_to_user_intercept_list(&worker->userintercepts, ipint); + HASH_ADD_KEYPTR(hh_liid, worker->ipintercepts, ipint->common.liid, + ipint->common.liid_len, ipint); + ipint->awaitingconfirm = 0; +} + +static void update_modified_gtp_intercept(openli_gtp_worker_t *worker, + ipintercept_t *found, ipintercept_t *ipint) { + + int r = 0, changed = 0; + + logger(LOG_INFO, "DEVDEBUG: updating intercept %s -- %s on GTP worker %d", + found->common.liid, found->username, worker->workerid); + if (ipint->accesstype != INTERNET_ACCESS_TYPE_MOBILE) { + /* Intercept has changed to be NOT mobile, so just remove it */ + logger(LOG_INFO, "DEVDEBUG: GTP worker %d -- %s is no longer mobile", + worker->workerid, found->common.liid); + remove_intercept_from_user_intercept_list(&worker->userintercepts, + found); + HASH_DELETE(hh_liid, worker->ipintercepts, found); + free_single_ipintercept(ipint); + free_single_ipintercept(found); + return; + } + + if (update_modified_intercept_common(&(found->common), &(ipint->common), + OPENLI_INTERCEPT_TYPE_IP, &changed) < 0) { + r = -1; + } else { + if (strcmp(ipint->username, found->username) != 0 || + ipint->mobileident != found->mobileident) { + logger(LOG_INFO, "DEVDEBUG: GTP worker %d -- %s has new username '%s'", + worker->workerid, found->common.liid, ipint->username); + remove_intercept_from_user_intercept_list(&worker->userintercepts, + found); + free(found->username); + found->username = ipint->username; + found->username_len = ipint->username_len; + found->mobileident = ipint->mobileident; + ipint->username = NULL; + add_intercept_to_user_intercept_list(&worker->userintercepts, + found); + + push_existing_ip_sessions(worker, found); + } + found->awaitingconfirm = 0; + } + free_single_ipintercept(ipint); +} + +static int add_new_gtp_intercept(openli_gtp_worker_t *worker, + provisioner_msg_t *msg) { + + ipintercept_t *ipint, *found; + int ret = 0; + + ipint = calloc(1, sizeof(ipintercept_t)); + if (decode_ipintercept_start(msg->msgbody, msg->msglen, ipint) < 0) { + logger(LOG_INFO, "OpenLI: GTP worker %d failed to decode mobile IP intercept start message from provisioner", worker->workerid); + return -1; + } + + HASH_FIND(hh_liid, worker->ipintercepts, ipint->common.liid, + ipint->common.liid_len, found); + + if (found) { + update_modified_gtp_intercept(worker, found, ipint); + found->awaitingconfirm = 0; + ret = 0; + } else { + ret = init_gtp_intercept(worker, ipint); + } + return ret; +} + +static int modify_gtp_intercept(openli_gtp_worker_t *worker, + provisioner_msg_t *msg) { + ipintercept_t *ipint, *found; + + ipint = calloc(1, sizeof(ipintercept_t)); + if (decode_ipintercept_modify(msg->msgbody, msg->msglen, ipint) < 0) { + logger(LOG_INFO, "OpenLI: GTP worker %d failed to decode mobile IP intercept modify message from provisioner", worker->workerid); + return -1; + } + + HASH_FIND(hh_liid, worker->ipintercepts, ipint->common.liid, + ipint->common.liid_len, found); + if (!found) { + return init_gtp_intercept(worker, ipint); + } else { + update_modified_gtp_intercept(worker, found, ipint); + } + return 0; +} + +static int halt_gtp_intercept(openli_gtp_worker_t *worker, + provisioner_msg_t *msg) { + ipintercept_t *ipint, *found; + + ipint = calloc(1, sizeof(ipintercept_t)); + if (decode_ipintercept_halt(msg->msgbody, msg->msglen, ipint) < 0) { + logger(LOG_INFO, "OpenLI: GTP worker %d failed to decode mobile IP intercept halt message from provisioner", worker->workerid); + return -1; + } + + HASH_FIND(hh_liid, worker->ipintercepts, ipint->common.liid, + ipint->common.liid_len, found); + if (found) { + remove_gtp_intercept(worker, found); + } + free_single_ipintercept(ipint); + return 0; +} + +static int gtp_worker_handle_provisioner_message(openli_gtp_worker_t *worker, + openli_export_recv_t *msg) { + + int ret = 0; + switch(msg->data.provmsg.msgtype) { + case OPENLI_PROTO_NOMORE_INTERCEPTS: + disable_unconfirmed_gtp_intercepts(worker); + break; + case OPENLI_PROTO_DISCONNECT: + flag_gtp_intercepts(worker->ipintercepts); + break; + case OPENLI_PROTO_START_IPINTERCEPT: + ret = add_new_gtp_intercept(worker, &(msg->data.provmsg)); + break; + case OPENLI_PROTO_HALT_IPINTERCEPT: + ret = halt_gtp_intercept(worker, &(msg->data.provmsg)); + break; + case OPENLI_PROTO_MODIFY_IPINTERCEPT: + ret = modify_gtp_intercept(worker, &(msg->data.provmsg)); + break; + default: + logger(LOG_INFO, "OpenLI: GTP worker thread %d received unexpected message type from provisioner: %u", + worker->workerid, msg->data.provmsg.msgtype); + ret = -1; + } + + if (msg->data.provmsg.msgbody) { + free(msg->data.provmsg.msgbody); + } + return ret; +} + +static int gtp_worker_process_sync_thread_message(openli_gtp_worker_t *worker) { + + openli_export_recv_t *msg; + int x; + + do { + x = zmq_recv(worker->zmq_ii_sock, &msg, sizeof(msg), ZMQ_DONTWAIT); + if (x < 0 && errno != EAGAIN) { + logger(LOG_INFO, + "OpenLI: error while receiving II in GTP thread %d: %s", + worker->workerid, strerror(errno)); + return -1; + } + + if (x <= 0) { + break; + } + + if (msg->type == OPENLI_EXPORT_HALT) { + free(msg); + return -1; + } + + if (msg->type == OPENLI_EXPORT_PROVISIONER_MESSAGE) { + if (gtp_worker_handle_provisioner_message(worker, msg) < 0) { + free(msg); + return -1; + } + } + + free(msg); + } while (x > 0); + + return 1; +} + +static int gtp_worker_process_packet(openli_gtp_worker_t *worker) { + openli_state_update_t recvd; + int rc; + + do { + rc = zmq_recv(worker->zmq_colthread_recvsock, &recvd, sizeof(recvd), + ZMQ_DONTWAIT); + if (rc < 0) { + if (errno == EAGAIN) { + return 0; + } + logger(LOG_INFO, + "OpenLI: error while receiving packet in SMS worker thread %d: %s", + worker->workerid, strerror(errno)); + return -1; + } + + if (recvd.type != OPENLI_UPDATE_GTP) { + logger(LOG_INFO, + "OpenLI: GTP worker thread %d received unexpected update type %u", + worker->workerid, recvd.type); + break; + } + + /* TODO insert packet processing code here! */ + + if (recvd.data.pkt) { + trace_destroy_packet(recvd.data.pkt); + } + } while (rc > 0); + + return 0; +} + +static void gtp_worker_main(openli_gtp_worker_t *worker) { + + zmq_pollitem_t *topoll; + sync_epoll_t purgetimer; + struct itimerspec its; + struct timeval tv; + int x; + + logger(LOG_INFO, "OpenLI: starting GTP worker thread %d", + worker->workerid); + + topoll = calloc(3, sizeof(zmq_pollitem_t)); + + its.it_value.tv_sec = 60; + its.it_value.tv_nsec = 0; + its.it_interval.tv_sec = 0; + its.it_interval.tv_nsec = 0; + + purgetimer.fdtype = 0; + purgetimer.fd = timerfd_create(CLOCK_MONOTONIC, 0); + timerfd_settime(purgetimer.fd, 0, &its, NULL); + + while (1) { + topoll[0].socket = worker->zmq_ii_sock; + topoll[0].events = ZMQ_POLLIN; + + topoll[1].socket = worker->zmq_colthread_recvsock; + topoll[1].events = ZMQ_POLLIN; + + topoll[2].socket = NULL; + topoll[2].fd = purgetimer.fd; + topoll[2].events = ZMQ_POLLIN; + + if ((x = zmq_poll(topoll, 3, 50)) < 0) { + if (errno == EINTR) { + continue; + } + logger(LOG_INFO, + "OpenLI: error while polling in GTP worker thread %d: %s", + worker->workerid, strerror(errno)); + break; + } + + if (x == 0) { + continue; + } + + if (topoll[0].revents & ZMQ_POLLIN) { + x = gtp_worker_process_sync_thread_message(worker); + if (x < 0) { + break; + } + topoll[0].revents = 0; + } + + if (topoll[1].revents & ZMQ_POLLIN) { + x = gtp_worker_process_packet(worker); + if (x < 0) { + break; + } + topoll[1].revents = 0; + } + + if (topoll[2].revents & ZMQ_POLLIN) { + topoll[2].revents = 0; + + /* TODO purge "inactive" sessions */ + + purgetimer.fdtype = 0; + purgetimer.fd = timerfd_create(CLOCK_MONOTONIC, 0); + timerfd_settime(purgetimer.fd, 0, &its, NULL); + + topoll[2].fd = purgetimer.fd; + } + } + + free(topoll); +} + +void *gtp_thread_begin(void *arg) { + openli_gtp_worker_t *worker = (openli_gtp_worker_t *)arg; + char sockname[256]; + int zero = 0, x; + openli_state_update_t recvd; + + worker->zmq_pubsocks = calloc(worker->tracker_threads, sizeof(void *)); + init_zmq_socket_array(worker->zmq_pubsocks, worker->tracker_threads, + "inproc://openlipub", worker->zmq_ctxt); + + worker->zmq_ii_sock = zmq_socket(worker->zmq_ctxt, ZMQ_PULL); + snprintf(sockname, 256, "inproc://openligtpcontrol_sync-%d", + worker->workerid); + + if (zmq_bind(worker->zmq_ii_sock, sockname) < 0) { + logger(LOG_INFO, "OpenLI: GTP processing thread %d failed to bind to II zmq: %s", worker->workerid, strerror(errno)); + goto haltgtpworker; + } + + if (zmq_setsockopt(worker->zmq_ii_sock, ZMQ_LINGER, &zero, sizeof(zero)) + != 0) { + logger(LOG_INFO, "OpenLI: GTP processing thread %d failed to configure II zmq: %s", worker->workerid, strerror(errno)); + goto haltgtpworker; + } + + worker->zmq_colthread_recvsock = zmq_socket(worker->zmq_ctxt, ZMQ_PULL); + snprintf(sockname, 256, "inproc://openligtpworker-colrecv%d", + worker->workerid); + + if (zmq_bind(worker->zmq_colthread_recvsock, sockname) < 0) { + logger(LOG_INFO, "OpenLI: GTP processing thread %d failed to bind to colthread zmq: %s", worker->workerid, strerror(errno)); + goto haltgtpworker; + } + + if (zmq_setsockopt(worker->zmq_colthread_recvsock, ZMQ_LINGER, &zero, + sizeof(zero)) != 0) { + logger(LOG_INFO, "OpenLI: GTP processing thread %d failed to configure colthread zmq: %s", worker->workerid, strerror(errno)); + goto haltgtpworker; + } + + gtp_worker_main(worker); + + do { + x = zmq_recv(worker->zmq_colthread_recvsock, &recvd, sizeof(recvd), + ZMQ_DONTWAIT); + if (x > 0) { + trace_destroy_packet(recvd.data.pkt); + } + } while (x > 0); + +haltgtpworker: + logger(LOG_INFO, "OpenLI: halting GTP processing thread %d", + worker->workerid); + + zmq_close(worker->zmq_ii_sock); + zmq_close(worker->zmq_colthread_recvsock); + free_all_users(worker->allusers); + clear_user_intercept_list(worker->userintercepts); + free_all_ipintercepts(&(worker->ipintercepts)); + clear_zmq_socket_array(worker->zmq_pubsocks, worker->tracker_threads); + + if (worker->gtpplugin) { + destroy_access_plugin(worker->gtpplugin); + } + + pthread_exit(NULL); +} + +int start_gtp_worker_thread(openli_gtp_worker_t *worker, int id, + void *globarg) { + collector_global_t *glob = (collector_global_t *)globarg; + char name[1024]; + + snprintf(name, 1024, "gtpworker-%d", id); + + pthread_mutex_init(&(worker->col_queue_mutex), NULL); + + worker->zmq_ctxt = glob->zmq_ctxt; + worker->workerid = id; + worker->stats_mutex = &(glob->stats_mutex); + worker->stats = &(glob->stats); + worker->shared = &(glob->sharedinfo); + worker->zmq_ii_sock = NULL; + worker->zmq_pubsocks = NULL; + worker->zmq_colthread_recvsock = NULL; + worker->collector_queues = NULL; + worker->tracker_threads = glob->seqtracker_threads; + worker->ipintercepts = NULL; + worker->allusers = NULL; + worker->userintercepts = NULL; + worker->gtpplugin = NULL; + + pthread_create(&(worker->threadid), NULL, gtp_thread_begin, + (void *)worker); + pthread_setname_np(worker->threadid, name); + + return 1; +} + diff --git a/src/collector/gtp_worker.h b/src/collector/gtp_worker.h new file mode 100644 index 0000000..c473bf6 --- /dev/null +++ b/src/collector/gtp_worker.h @@ -0,0 +1,96 @@ +/* + * + * Copyright (c) 2024 Searchlight New Zealand Ltd. + * All rights reserved. + * + * This file is part of OpenLI. + * + * OpenLI was originally developed by the University of Waikato WAND + * research group. For further information please see http://www.wand.net.nz/ + * + * OpenLI is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenLI 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, see . + * + * + */ + +#ifndef OPENLI_GTP_WORKER_H_ +#define OPENLI_GTP_WORKER_H_ + +#include "intercept.h" +#include "collector_base.h" +#include "collector_util.h" +#include "internetaccess.h" + +typedef struct openli_gtp_worker { + /* The global zeromq context for the entire program */ + void *zmq_ctxt; + + /* A sequential identifier for this worker thread */ + int workerid; + + /* Mutex to protect the collector stats from races */ + pthread_mutex_t *stats_mutex; + + /* Collector statistics (e.g. CC and IRI counters since starting) */ + collector_stats_t *stats; + + /* Shared global-level configuration for this collector instance */ + collector_identity_t *shared; + + /* RW mutex to protect the shared config against race conditions */ + pthread_rwlock_t *shared_mutex; + + /* ZMQ for receiving instructions from sync thread */ + void *zmq_ii_sock; + + /* ZMQs for publishing to seqtracker threads */ + void **zmq_pubsocks; + + /* ZMQ for receiving from collector threads */ + void *zmq_colthread_recvsock; + + /* Hash map of send_syncq_t instances that are used to push interceptable + * IP addresses back to the collector threads */ + void *collector_queues; + + /* Mutex to protect the collector_queues map */ + pthread_mutex_t col_queue_mutex; + + /* Number of sequence tracker threads operated by this collector */ + int tracker_threads; + + /* The pthread ID for this worker thread */ + pthread_t threadid; + + /* Set of all mobile IP data intercepts announced to this collector */ + ipintercept_t *ipintercepts; + + /* Set of all "users" (i.e. MSISDNs, IMSIs, IMEIs) with active GTP + * sessions */ + internet_user_t *allusers; + + /* Map of usernames -> active intercepts */ + user_intercept_list_t *userintercepts; + + /* Instance of the GTP session state processing plugin used to + * track sessions observed in GTP-C traffic + */ + access_plugin_t *gtpplugin; + +} openli_gtp_worker_t; + +int start_gtp_worker_thread(openli_gtp_worker_t *worker, int id, + void *globarg); + +#endif diff --git a/src/collector/internetaccess.c b/src/collector/internetaccess.c index a264336..07cae7d 100644 --- a/src/collector/internetaccess.c +++ b/src/collector/internetaccess.c @@ -176,6 +176,7 @@ access_session_t *create_access_session(access_plugin_t *p, char *sessid, newsess = (access_session_t *)malloc(sizeof(access_session_t)); + newsess->identifier_type = OPENLI_ACCESS_SESSION_UNKNOWN; newsess->plugin = p; newsess->sessionid = fast_strdup(sessid, sessid_len); newsess->statedata = NULL; @@ -190,13 +191,14 @@ access_session_t *create_access_session(access_plugin_t *p, char *sessid, newsess->started.tv_sec = 0; newsess->started.tv_usec = 0; + newsess->teid = 0; return newsess; } void add_new_session_ip(access_session_t *sess, void *att_val, int family, uint8_t pfxbits, int att_len) { - int ind = sess->sessipcount; + int ind = sess->sessipcount; if (sess->sessipcount > 0 && (sess->sessipcount % SESSION_IP_INCR) == 0) { sess->sessionips = realloc(sess->sessionips, @@ -256,6 +258,7 @@ void add_new_session_ip(access_session_t *sess, void *att_val, sess->sessionips[ind].ipfamily = family; sess->sessionips[ind].prefixbits = pfxbits; sess->sessipcount ++; + sess->identifier_type |= OPENLI_ACCESS_SESSION_IP; } int free_single_session(access_session_t *sess) { diff --git a/src/collector/internetaccess.h b/src/collector/internetaccess.h index d19da36..cc1c68b 100644 --- a/src/collector/internetaccess.h +++ b/src/collector/internetaccess.h @@ -109,13 +109,32 @@ typedef struct ip_to_session { UT_hash_handle hh; } ip_to_session_t; +typedef struct teid_to_session { + uint32_t teid; + int sessioncount; + access_session_t **session; + internet_user_t **owner; + uint32_t cin; + UT_hash_handle hh; +} teid_to_session_t; + +typedef enum { + OPENLI_ACCESS_SESSION_UNKNOWN = 0, + OPENLI_ACCESS_SESSION_IP = 1, + OPENLI_ACCESS_SESSION_TEID = 2, +} openli_access_session_id_t; + struct access_session { + openli_access_session_id_t identifier_type; + internetaccess_ip_t *sessionips; uint8_t sessipcount; session_ipversion_t sessipversion; uint8_t ips_mapped; + uint32_t teid; + access_plugin_t *plugin; void *sessionid; void *statedata; diff --git a/src/configparser.c b/src/configparser.c index 6a30f83..fb436cc 100644 --- a/src/configparser.c +++ b/src/configparser.c @@ -345,6 +345,29 @@ static void parse_email_targets(email_target_t **targets, yaml_document_t *doc, } +static void parse_col_thread_count(int *toset, const char *expectedkey, + yaml_node_t *key, yaml_node_t *value, const char *errlabel) { + + if (key->type != YAML_SCALAR_NODE) { + return; + } + if (value->type != YAML_SCALAR_NODE) { + return; + } + + if (strcmp(expectedkey, (const char *)key->data.scalar.value) != 0) { + return; + } + + *toset = strtoul((const char *)value->data.scalar.value, NULL, 10); + if (*toset <= 0) { + *toset = 1; + logger(LOG_INFO, + "OpenLI: must have at least one %s thread per collector!", + errlabel); + } +} + static void parse_sip_targets(libtrace_list_t *targets, yaml_document_t *doc, yaml_node_t *tgtconf) { @@ -1253,38 +1276,18 @@ static int global_parser(void *arg, yaml_document_t *doc, } } - if (key->type == YAML_SCALAR_NODE && - value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "seqtrackerthreads") == 0) { - glob->seqtracker_threads = strtoul((char *) value->data.scalar.value, - NULL, 10); - if (glob->seqtracker_threads <= 0) { - glob->seqtracker_threads = 1; - logger(LOG_INFO, "OpenLI: must have at least one sequence tracker thread per collector!"); - } - } - - if (key->type == YAML_SCALAR_NODE && - value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "encoderthreads") == 0) { - glob->encoding_threads = strtoul((char *) value->data.scalar.value, - NULL, 10); - if (glob->encoding_threads <= 0) { - glob->encoding_threads = 1; - logger(LOG_INFO, "OpenLI: must have at least one encoder thread per collector!"); - } - } - - if (key->type == YAML_SCALAR_NODE && - value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "forwardingthreads") == 0) { - glob->forwarding_threads = strtoul((char *) value->data.scalar.value, - NULL, 10); - if (glob->forwarding_threads <= 0) { - glob->forwarding_threads = 1; - logger(LOG_INFO, "OpenLI: must have at least one forwarding thread per collector!"); - } - } + parse_col_thread_count(&(glob->encoding_threads), "seqtrackerthreads", + key, value, "sequence tracker"); + parse_col_thread_count(&(glob->encoding_threads), "encoderthreads", + key, value, "encoder"); + parse_col_thread_count(&(glob->forwarding_threads), "forwardingthreads", + key, value, "forwarding"); + parse_col_thread_count(&(glob->email_threads), "emailthreads", + key, value, "email worker"); + parse_col_thread_count(&(glob->sms_threads), "smsthreads", + key, value, "SMS worker"); + parse_col_thread_count(&(glob->gtp_threads), "gtpthreads", + key, value, "GTP worker"); if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && From 41c02381bb3e24e04e867fb7e9bad95168df2a3f Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Thu, 23 May 2024 18:31:21 +1200 Subject: [PATCH 05/44] More progress on separate GTP processing threads * GTP packets are now redirected to the GTP threads instead of the sync thread. * Removed GTP plugin from sync thread data. * Add GTP plugin to each GTP processing thread. * GTP processing threads determine whether GTP packets are GTP-U or GTP-C and hand off to the appropriate processing function (yet to be written). --- src/collector/accessplugins/gtp.c | 18 --- src/collector/collector.c | 212 ++++++++++++++++++------------ src/collector/collector_sync.c | 8 -- src/collector/collector_sync.h | 1 - src/collector/gtp_worker.c | 86 +++++++++++- src/collector/gtp_worker.h | 2 +- src/collector/internetaccess.h | 22 ++++ 7 files changed, 237 insertions(+), 112 deletions(-) diff --git a/src/collector/accessplugins/gtp.c b/src/collector/accessplugins/gtp.c index a394067..fc8717a 100644 --- a/src/collector/accessplugins/gtp.c +++ b/src/collector/accessplugins/gtp.c @@ -86,24 +86,6 @@ enum { GTPV2_DELETE_SESSION_RESPONSE = 37, }; -typedef struct gtpv1_header { - uint8_t octet1; - uint8_t msgtype; - uint16_t msglen; - uint32_t teid; - uint16_t seqno; - uint8_t npdu; - uint8_t next_ext; -} PACKED gtpv1_header_t; - -typedef struct gtpv2_header_teid { - uint8_t octet1; - uint8_t msgtype; - uint16_t msglen; - uint32_t teid; - uint32_t seqno; -} PACKED gtpv2_header_teid_t; - typedef struct gtp_infelem gtp_infoelem_t; struct gtp_infelem { diff --git a/src/collector/collector.c b/src/collector/collector.c index 5f09216..816507b 100644 --- a/src/collector/collector.c +++ b/src/collector/collector.c @@ -663,6 +663,134 @@ static void add_payload_info_from_packet(libtrace_packet_t *pkt, } +static inline uint32_t is_core_server_packet(libtrace_packet_t *pkt, + packet_info_t *pinfo, coreserver_t *servers) { + + coreserver_t *rad, *tmp; + coreserver_t *found = NULL; + uint32_t hashval = 0; + + if (pinfo->srcport == 0 || pinfo->destport == 0) { + return 0; + } + + HASH_ITER(hh, servers, rad, tmp) { + if (rad->info == NULL) { + rad->info = populate_addrinfo(rad->ipstr, rad->portstr, + SOCK_DGRAM); + if (!rad->info) { + logger(LOG_INFO, + "Removing %s:%s from %s server list due to getaddrinfo error", + rad->ipstr, rad->portstr, + coreserver_type_to_string(rad->servertype)); + + HASH_DELETE(hh, servers, rad); + continue; + } + if (rad->info->ai_family == AF_INET) { + rad->portswapped = ntohs(CS_TO_V4(rad)->sin_port); + } else if (rad->info->ai_family == AF_INET6) { + rad->portswapped = ntohs(CS_TO_V6(rad)->sin6_port); + } + } + + if (pinfo->family == AF_INET) { + struct sockaddr_in *sa; + sa = (struct sockaddr_in *)(&(pinfo->srcip)); + + if (CORESERVER_MATCH_V4(rad, sa, pinfo->srcport)) { + found = rad; + break; + } + sa = (struct sockaddr_in *)(&(pinfo->destip)); + if (CORESERVER_MATCH_V4(rad, sa, pinfo->destport)) { + found = rad; + break; + } + } else if (pinfo->family == AF_INET6) { + struct sockaddr_in6 *sa6; + sa6 = (struct sockaddr_in6 *)(&(pinfo->srcip)); + if (CORESERVER_MATCH_V6(rad, sa6, pinfo->srcport)) { + found = rad; + break; + } + sa6 = (struct sockaddr_in6 *)(&(pinfo->destip)); + if (CORESERVER_MATCH_V6(rad, sa6, pinfo->destport)) { + found = rad; + break; + } + } + } + + /* Doesn't match any of our known core servers */ + if (found == NULL) { + return 0; + } + + /* Not technically an LIID, but we just need a hashed ID for the server + * entity. + */ + hashval = hash_liid(found->serverkey); + + /* 0 is our value for "not found", so make sure we never use it... */ + if (hashval == 0) { + hashval = 1; + } + return hashval; + +} + +static uint8_t check_if_gtp(packet_info_t *pinfo, libtrace_packet_t *pkt, + colthread_local_t *loc, collector_global_t *glob) { + + uint32_t fwdto = 0; + gtpv1_header_t *v1_hdr; + gtpv2_header_teid_t *v2_hdr; + + if (loc->gtpservers == NULL) { + return 0; + } + + if ( !is_core_server_packet(pkt, pinfo, loc->gtpservers)) { + return 0; + } + + add_payload_info_from_packet(pkt, pinfo); + if (pinfo->payload_len == 0) { + return 0; + } + + if (loc->gtpq_count > 1) { + /* check GTP version */ + if (((*(pinfo->payload_ptr)) & 0xe8) == 0x48) { + /* GTPv2 */ + if (pinfo->payload_len < sizeof(gtpv2_header_teid_t)) { + return 0; + } + v2_hdr = (gtpv2_header_teid_t *)pinfo->payload_ptr; + fwdto = hashlittle(&(v1_hdr->teid), sizeof(v2_hdr->teid), + 312267023); + + } else if (((*(pinfo->payload_ptr)) & 0xe0) == 0x20) { + /* GTPv1 */ + if (pinfo->payload_len < sizeof(gtpv1_header_t)) { + return 0; + } + + v1_hdr = (gtpv1_header_t *)pinfo->payload_ptr; + fwdto = hashlittle(&(v1_hdr->teid), sizeof(v1_hdr->teid), + 312267023); + } + } + + send_packet_to_sync(pkt, loc->gtp_worker_queues[fwdto], OPENLI_UPDATE_GTP); + + pthread_mutex_lock(&(glob->stats_mutex)); + glob->stats.packets_gtp ++; + pthread_mutex_unlock(&(glob->stats_mutex)); + return 1; +} + static uint8_t is_sms_over_sip(packet_info_t *pinfo, libtrace_packet_t *pkt, colthread_local_t *loc, collector_global_t *glob) { @@ -812,83 +940,6 @@ static inline uint8_t check_for_invalid_sip(packet_info_t *pinfo, return 0; } -static inline uint32_t is_core_server_packet(libtrace_packet_t *pkt, - packet_info_t *pinfo, coreserver_t *servers) { - - coreserver_t *rad, *tmp; - coreserver_t *found = NULL; - uint32_t hashval = 0; - - if (pinfo->srcport == 0 || pinfo->destport == 0) { - return 0; - } - - HASH_ITER(hh, servers, rad, tmp) { - if (rad->info == NULL) { - rad->info = populate_addrinfo(rad->ipstr, rad->portstr, - SOCK_DGRAM); - if (!rad->info) { - logger(LOG_INFO, - "Removing %s:%s from %s server list due to getaddrinfo error", - rad->ipstr, rad->portstr, - coreserver_type_to_string(rad->servertype)); - - HASH_DELETE(hh, servers, rad); - continue; - } - if (rad->info->ai_family == AF_INET) { - rad->portswapped = ntohs(CS_TO_V4(rad)->sin_port); - } else if (rad->info->ai_family == AF_INET6) { - rad->portswapped = ntohs(CS_TO_V6(rad)->sin6_port); - } - } - - if (pinfo->family == AF_INET) { - struct sockaddr_in *sa; - sa = (struct sockaddr_in *)(&(pinfo->srcip)); - - if (CORESERVER_MATCH_V4(rad, sa, pinfo->srcport)) { - found = rad; - break; - } - sa = (struct sockaddr_in *)(&(pinfo->destip)); - if (CORESERVER_MATCH_V4(rad, sa, pinfo->destport)) { - found = rad; - break; - } - } else if (pinfo->family == AF_INET6) { - struct sockaddr_in6 *sa6; - sa6 = (struct sockaddr_in6 *)(&(pinfo->srcip)); - if (CORESERVER_MATCH_V6(rad, sa6, pinfo->srcport)) { - found = rad; - break; - } - sa6 = (struct sockaddr_in6 *)(&(pinfo->destip)); - if (CORESERVER_MATCH_V6(rad, sa6, pinfo->destport)) { - found = rad; - break; - } - } - } - - /* Doesn't match any of our known core servers */ - if (found == NULL) { - return 0; - } - - /* Not technically an LIID, but we just need a hashed ID for the server - * entity. - */ - hashval = hash_liid(found->serverkey); - - /* 0 is our value for "not found", so make sure we never use it... */ - if (hashval == 0) { - hashval = 1; - } - return hashval; - -} - static libtrace_packet_t *process_packet(libtrace_t *trace, libtrace_thread_t *t, void *global, void *tls, libtrace_packet_t *pkt) { @@ -1101,12 +1152,7 @@ static libtrace_packet_t *process_packet(libtrace_t *trace, goto processdone; } - if (loc->gtpservers && is_core_server_packet(pkt, &pinfo, - loc->gtpservers)) { - send_packet_to_sync(pkt, loc->tosyncq_ip, OPENLI_UPDATE_GTP); - ipsynced = 1; - goto processdone; - } + check_if_gtp(&pinfo, pkt, loc, glob); /* Is this a SIP packet? -- if yes, create a state update */ if (loc->sipservers && is_core_server_packet(pkt, &pinfo, diff --git a/src/collector/collector_sync.c b/src/collector/collector_sync.c index 8afca2c..e6964cd 100644 --- a/src/collector/collector_sync.c +++ b/src/collector/collector_sync.c @@ -85,7 +85,6 @@ collector_sync_t *init_sync_data(collector_global_t *glob) { sync->upcomingtimerfd = -1; sync->radiusplugin = init_access_plugin(ACCESS_RADIUS); - sync->gtpplugin = init_access_plugin(ACCESS_GTP); sync->freegenerics = glob->syncgenericfreelist; sync->activeips = NULL; @@ -181,10 +180,6 @@ void clean_sync_data(collector_sync_t *sync) { destroy_access_plugin(sync->radiusplugin); } - if (sync->gtpplugin) { - destroy_access_plugin(sync->gtpplugin); - } - if(sync->ssl){ SSL_free(sync->ssl); } @@ -197,7 +192,6 @@ void clean_sync_data(collector_sync_t *sync) { sync->outgoing = NULL; sync->incoming = NULL; sync->radiusplugin = NULL; - sync->gtpplugin = NULL; sync->activeips = NULL; while (haltattempts < 10) { @@ -2212,8 +2206,6 @@ static int update_user_sessions(collector_sync_t *sync, libtrace_packet_t *pkt, if (accesstype == ACCESS_RADIUS) { p = sync->radiusplugin; - } else if (accesstype == ACCESS_GTP) { - p = sync->gtpplugin; } if (!p) { diff --git a/src/collector/collector_sync.h b/src/collector/collector_sync.h index 3cab888..841f79c 100644 --- a/src/collector/collector_sync.h +++ b/src/collector/collector_sync.h @@ -83,7 +83,6 @@ typedef struct colsync_data { wandder_encoder_t *encoder; access_plugin_t *radiusplugin; - access_plugin_t *gtpplugin; etsili_generic_freelist_t *freegenerics; ip_to_session_t *activeips; diff --git a/src/collector/gtp_worker.c b/src/collector/gtp_worker.c index fdd7572..f76e830 100644 --- a/src/collector/gtp_worker.c +++ b/src/collector/gtp_worker.c @@ -285,6 +285,88 @@ static int gtp_worker_process_sync_thread_message(openli_gtp_worker_t *worker) { return 1; } +static void process_gtp_u_packet(openli_gtp_worker_t *worker, + uint8_t *payload, uint32_t plen, uint32_t teid) { + + +} + +static void process_gtp_c_packet(openli_gtp_worker_t *worker, + libtrace_packet_t *packet) { + + +} + +static void process_gtp_packet(openli_gtp_worker_t *worker, + libtrace_packet_t *packet) { + access_plugin_t *p = worker->gtpplugin; + uint8_t *payload; + uint32_t plen; + uint8_t proto; + uint32_t rem; + void *transport; + uint8_t msgtype; + uint32_t teid; + + if (packet == NULL) { + return; + } + + transport = trace_get_transport(packet, &proto, &rem); + if (transport == NULL || rem == 0) { + return; + } + + plen = trace_get_payload_length(packet); + if (proto != TRACE_IPPROTO_UDP) { + /* should be UDP only */ + return; + } + payload = (uint8_t *)trace_get_payload_from_udp((libtrace_udp_t *)transport, + &rem); + if (rem < plen) { + plen = rem; + } + + if (((*payload) & 0xe8) == 0x48) { + /* GTPv2 */ + gtpv2_header_teid_t *v2hdr = (gtpv2_header_teid_t *)payload; + + if (plen <= sizeof(gtpv2_header_teid_t)) { + return; + } + + msgtype = v2hdr->msgtype; + teid = v2hdr->teid; + payload += sizeof(gtpv2_header_teid_t); + plen -= sizeof(gtpv2_header_teid_t); + + } else if (((*payload) & 0xe0) == 0x20) { + /* GTPv1 */ + gtpv1_header_t *v1hdr = (gtpv1_header_t *)payload; + + if (plen <= sizeof(gtpv1_header_t)) { + return; + } + + msgtype = v1hdr->msgtype; + teid = v1hdr->teid; + payload += sizeof(gtpv1_header_t); + plen -= sizeof(gtpv1_header_t); + + } else { + return; + } + + if (msgtype == 0xff) { + /* This is GTP-U */ + process_gtp_u_packet(worker, payload, plen, teid); + } else { + /* This is GTP-C */ + process_gtp_c_packet(worker, packet); + } +} + static int gtp_worker_process_packet(openli_gtp_worker_t *worker) { openli_state_update_t recvd; int rc; @@ -310,6 +392,7 @@ static int gtp_worker_process_packet(openli_gtp_worker_t *worker) { } /* TODO insert packet processing code here! */ + process_gtp_packet(worker, recvd.data.pkt); if (recvd.data.pkt) { trace_destroy_packet(recvd.data.pkt); @@ -461,6 +544,7 @@ void *gtp_thread_begin(void *arg) { if (worker->gtpplugin) { destroy_access_plugin(worker->gtpplugin); + free(worker->gtpplugin); } pthread_exit(NULL); @@ -488,7 +572,7 @@ int start_gtp_worker_thread(openli_gtp_worker_t *worker, int id, worker->ipintercepts = NULL; worker->allusers = NULL; worker->userintercepts = NULL; - worker->gtpplugin = NULL; + worker->gtpplugin = init_access_plugin(ACCESS_GTP); pthread_create(&(worker->threadid), NULL, gtp_thread_begin, (void *)worker); diff --git a/src/collector/gtp_worker.h b/src/collector/gtp_worker.h index c473bf6..63832d7 100644 --- a/src/collector/gtp_worker.h +++ b/src/collector/gtp_worker.h @@ -80,7 +80,7 @@ typedef struct openli_gtp_worker { * sessions */ internet_user_t *allusers; - /* Map of usernames -> active intercepts */ + /* Map of user identities -> active intercepts */ user_intercept_list_t *userintercepts; /* Instance of the GTP session state processing plugin used to diff --git a/src/collector/internetaccess.h b/src/collector/internetaccess.h index cc1c68b..e239683 100644 --- a/src/collector/internetaccess.h +++ b/src/collector/internetaccess.h @@ -37,6 +37,28 @@ #define SESSION_IP_INCR (5) +/* Need these GTP header definitions in multiple places, so they go in + * here rather than being confined to the GTP plugin... + */ +typedef struct gtpv1_header { + uint8_t octet1; + uint8_t msgtype; + uint16_t msglen; + uint32_t teid; + uint16_t seqno; + uint8_t npdu; + uint8_t next_ext; +} PACKED gtpv1_header_t; + +typedef struct gtpv2_header_teid { + uint8_t octet1; + uint8_t msgtype; + uint16_t msglen; + uint32_t teid; + uint32_t seqno; +} PACKED gtpv2_header_teid_t; + + enum { ACCESS_RADIUS, ACCESS_GTP, From 3860d9ed916cdeb5e3e003a58226631aaf6c1f9a Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Fri, 24 May 2024 10:08:05 +1200 Subject: [PATCH 06/44] Fix bugs that arise when running multiple GTP threads * fix segfaults when determining which thread to forward a GTP packet to * allocate a separate GTP "plugin" for each thread rather than sharing a single static plugin instance --- src/collector/accessplugins/gtp.c | 15 ++++++++++++++- src/collector/collector.c | 6 +++--- src/collector/gtp_worker.c | 5 ++--- src/collector/internetaccess.h | 1 + 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/collector/accessplugins/gtp.c b/src/collector/accessplugins/gtp.c index fc8717a..2b0c785 100644 --- a/src/collector/accessplugins/gtp.c +++ b/src/collector/accessplugins/gtp.c @@ -324,6 +324,7 @@ static void gtp_destroy_plugin_data(access_plugin_t *p) { free(glob->parsedpkt); } free(glob); + p->plugindata = NULL; } static void gtp_uncouple_parsed_data(access_plugin_t *p) { @@ -1931,10 +1932,22 @@ static access_plugin_t gtpplugin = { gtp_get_ip_contents, }; +const char *gtp_plugin_name = "GTP"; + access_plugin_t *get_gtp_access_plugin(void) { - return >pplugin; + access_plugin_t *gtp = calloc(1, sizeof(access_plugin_t)); + + memcpy(gtp, >pplugin, sizeof(access_plugin_t)); + + return gtp; } +void destroy_gtp_access_plugin(access_plugin_t *gtp) { + if (gtp->plugindata) { + gtp_destroy_plugin_data(gtp); + } + free(gtp); +} // vim: set sw=4 tabstop=4 softtabstop=4 expandtab : diff --git a/src/collector/collector.c b/src/collector/collector.c index 816507b..305260a 100644 --- a/src/collector/collector.c +++ b/src/collector/collector.c @@ -768,8 +768,8 @@ static uint8_t check_if_gtp(packet_info_t *pinfo, libtrace_packet_t *pkt, return 0; } v2_hdr = (gtpv2_header_teid_t *)pinfo->payload_ptr; - fwdto = hashlittle(&(v1_hdr->teid), sizeof(v2_hdr->teid), - 312267023); + fwdto = hashlittle(&(v2_hdr->teid), sizeof(v2_hdr->teid), + 312267023) % loc->gtpq_count; } else if (((*(pinfo->payload_ptr)) & 0xe0) == 0x20) { /* GTPv1 */ @@ -779,7 +779,7 @@ static uint8_t check_if_gtp(packet_info_t *pinfo, libtrace_packet_t *pkt, v1_hdr = (gtpv1_header_t *)pinfo->payload_ptr; fwdto = hashlittle(&(v1_hdr->teid), sizeof(v1_hdr->teid), - 312267023); + 312267023) % loc->gtpq_count; } } diff --git a/src/collector/gtp_worker.c b/src/collector/gtp_worker.c index f76e830..86ee719 100644 --- a/src/collector/gtp_worker.c +++ b/src/collector/gtp_worker.c @@ -543,8 +543,7 @@ void *gtp_thread_begin(void *arg) { clear_zmq_socket_array(worker->zmq_pubsocks, worker->tracker_threads); if (worker->gtpplugin) { - destroy_access_plugin(worker->gtpplugin); - free(worker->gtpplugin); + destroy_gtp_access_plugin(worker->gtpplugin); } pthread_exit(NULL); @@ -572,7 +571,7 @@ int start_gtp_worker_thread(openli_gtp_worker_t *worker, int id, worker->ipintercepts = NULL; worker->allusers = NULL; worker->userintercepts = NULL; - worker->gtpplugin = init_access_plugin(ACCESS_GTP); + worker->gtpplugin = get_gtp_access_plugin(); pthread_create(&(worker->threadid), NULL, gtp_thread_begin, (void *)worker); diff --git a/src/collector/internetaccess.h b/src/collector/internetaccess.h index e239683..af8084c 100644 --- a/src/collector/internetaccess.h +++ b/src/collector/internetaccess.h @@ -233,6 +233,7 @@ int free_single_session(access_session_t *sess); access_plugin_t *get_radius_access_plugin(void); access_plugin_t *get_gtp_access_plugin(void); +void destroy_gtp_access_plugin(access_plugin_t *gtp); access_session_t *create_access_session(access_plugin_t *p, char *idstr, int idstr_len); From 1c5e4b5930b98afeec936cd2a65120a446221dcd Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Fri, 24 May 2024 18:45:10 +1200 Subject: [PATCH 07/44] More progress on GTP threads * fix bug where I had forgotten to init GTP plugin local data * move some code from collector_sync.c to internetaccess.c so we can use those methods in the GTP plugin as well * add code to track sessions using GTP-C Known bugs: * memory leak of encoded ETSILI records for UMTS CCs. * GTPv1 C packets for the same session are not consistently going to the same thread if more than 1 GTP thread is in use. --- src/collector/accessplugins/gtp.c | 4 +- src/collector/collector_push_messaging.c | 2 - src/collector/collector_sync.c | 58 +----- src/collector/gtp_worker.c | 224 ++++++++++++++++++++++- src/collector/internetaccess.c | 49 +++++ src/collector/internetaccess.h | 4 + src/intercept.h | 4 + 7 files changed, 288 insertions(+), 57 deletions(-) diff --git a/src/collector/accessplugins/gtp.c b/src/collector/accessplugins/gtp.c index 2b0c785..219b91a 100644 --- a/src/collector/accessplugins/gtp.c +++ b/src/collector/accessplugins/gtp.c @@ -1325,6 +1325,8 @@ static access_session_t *gtp_update_session_state(access_plugin_t *p, ((uint64_t)gparsed->seqno); + printf("DEVDEBUG: TEID=%u\n", gparsed->teid); + if (reqid == gparsed->matched_session->last_reqid && gparsed->msgtype == gparsed->matched_session->last_reqtype) { @@ -1938,7 +1940,7 @@ access_plugin_t *get_gtp_access_plugin(void) { access_plugin_t *gtp = calloc(1, sizeof(access_plugin_t)); memcpy(gtp, >pplugin, sizeof(access_plugin_t)); - + gtp_init_plugin_data(gtp); return gtp; } diff --git a/src/collector/collector_push_messaging.c b/src/collector/collector_push_messaging.c index c0924f7..b142eaf 100644 --- a/src/collector/collector_push_messaging.c +++ b/src/collector/collector_push_messaging.c @@ -503,12 +503,10 @@ void handle_push_ipintercept(libtrace_thread_t *t, colthread_local_t *loc, free_single_ipsession(sess); return; } - /* logger(LOG_INFO, "OpenLI: collector thread %d has started intercepting %s IP session %s", trace_get_perpkt_thread_id(t), accesstype_to_string(sess->accesstype), sess->streamkey); - */ } void handle_push_ipmmintercept(libtrace_thread_t *t, colthread_local_t *loc, diff --git a/src/collector/collector_sync.c b/src/collector/collector_sync.c index e6964cd..42f96f8 100644 --- a/src/collector/collector_sync.c +++ b/src/collector/collector_sync.c @@ -51,10 +51,6 @@ #include "ipiri.h" #include "collector_util.h" -#define INTERCEPT_IS_ACTIVE(cept, now) \ - (cept->common.tostart_time <= now.tv_sec && ( \ - cept->common.toend_time == 0 || cept->common.toend_time > now.tv_sec)) - collector_sync_t *init_sync_data(collector_global_t *glob) { collector_sync_t *sync = (collector_sync_t *) @@ -515,34 +511,6 @@ static inline void push_static_iprange_remove_to_collectors( } -static inline void push_single_ipintercept(collector_sync_t *sync, - libtrace_message_queue_t *q, ipintercept_t *ipint, - access_session_t *session) { - - ipsession_t *ipsess; - openli_pushed_t msg; - int i; - - for (i = 0; i < session->sessipcount; i++) { - - ipsess = create_ipsession(ipint, session->cin, - session->sessionips[i].ipfamily, - (struct sockaddr *)&(session->sessionips[i].assignedip), - session->sessionips[i].prefixbits); - - if (!ipsess) { - logger(LOG_INFO, - "OpenLI: ran out of memory while creating IP session message."); - return; - } - memset(&msg, 0, sizeof(openli_pushed_t)); - msg.type = OPENLI_PUSH_IPINTERCEPT; - msg.data.ipsess = ipsess; - - libtrace_message_queue_put(q, (void *)(&msg)); - } -} - static inline void push_single_vendmirrorid(libtrace_message_queue_t *q, ipintercept_t *ipint, uint8_t msgtype) { @@ -806,24 +774,10 @@ static void push_session_update_to_threads(void *sendqs, access_session_t *sess, ipintercept_t *ipint, int updatetype) { sync_sendq_t *sendq, *tmp; - int i; - - for (i = 0; i < sess->sessipcount; i++) { - openli_pushed_t pmsg; - ipsession_t *sessdup; - - HASH_ITER(hh, (sync_sendq_t *)sendqs, sendq, tmp) { - memset(&pmsg, 0, sizeof(openli_pushed_t)); - pmsg.type = updatetype; - sessdup = create_ipsession(ipint, sess->cin, - sess->sessionips[i].ipfamily, - (struct sockaddr *)&(sess->sessionips[i].assignedip), - sess->sessionips[i].prefixbits); - - pmsg.data.ipsess = sessdup; - libtrace_message_queue_put(sendq->q, &pmsg); - } + HASH_ITER(hh, (sync_sendq_t *)sendqs, sendq, tmp) { + push_session_update_to_collector_queue(sendq->q, ipint, sess, + updatetype); } } @@ -1096,7 +1050,7 @@ static void push_existing_user_sessions(collector_sync_t *sync, HASH_ITER(hh, user->sessions, sess, tmp2) { HASH_ITER(hh, (sync_sendq_t *)(sync->glob->collector_queues), sendq, tmp) { - push_single_ipintercept(sync, sendq->q, cept, sess); + push_session_ips_to_collector_queue(sendq->q, cept, sess); } create_iri_from_session(sync, sess, cept, @@ -1921,7 +1875,7 @@ static void push_all_active_intercepts(collector_sync_t *sync, user = lookup_user_by_intercept(allusers, orig); if (user) { HASH_ITER(hh, user->sessions, sess, tmp2) { - push_single_ipintercept(sync, q, orig, sess); + push_session_ips_to_collector_queue(q, orig, sess); } } } @@ -2155,7 +2109,7 @@ static int newly_active_session(collector_sync_t *sync, } HASH_ITER(hh, (sync_sendq_t *)(sync->glob->collector_queues), sendq, tmpq) { - push_single_ipintercept(sync, sendq->q, ipint, sess); + push_session_ips_to_collector_queue(sendq->q, ipint, sess); } } pthread_mutex_lock(sync->glob->stats_mutex); diff --git a/src/collector/gtp_worker.c b/src/collector/gtp_worker.c index 86ee719..eb18fdf 100644 --- a/src/collector/gtp_worker.c +++ b/src/collector/gtp_worker.c @@ -285,6 +285,147 @@ static int gtp_worker_process_sync_thread_message(openli_gtp_worker_t *worker) { return 1; } +static inline internet_user_t *lookup_gtp_userid(openli_gtp_worker_t *worker, + user_identity_t *userid) { + + internet_user_t *iuser; + + iuser = lookup_user_by_identity(worker->allusers, userid); + + if (iuser == NULL) { + iuser = (internet_user_t *)malloc(sizeof(internet_user_t)); + if (!iuser) { + logger(LOG_INFO, + "OpenLI: unable to allocate memory for new Internet user in GTP worker %d", + worker->workerid); + return NULL; + } + iuser->userid = NULL; + iuser->sessions = NULL; + + add_userid_to_allusers_map(&(worker->allusers), iuser, userid); + } + return iuser; +} + +static void push_gtp_session_over(openli_gtp_worker_t *worker, + user_intercept_list_t *userint, access_session_t *sess) { + + ipintercept_t *ipint, *tmp; + sync_sendq_t *sendq, *tmpq, *queues; + + queues = (sync_sendq_t *)worker->collector_queues; + + if (userint == NULL || sess == NULL ) { + return; + } + + /* For each intercept associated with this user identity, tell + * all of the collector threads to stop intercepting traffic for + * the IP address(es) that belongs to that session. + */ + HASH_ITER(hh_user, userint->intlist, ipint, tmp) { + printf("DEVDEBUG: %d ENDING SESSION: %s %s\n", worker->workerid, + ipint->common.liid, (char *)sess->sessionid); + HASH_ITER(hh, queues, sendq, tmpq) { + push_session_update_to_collector_queue(sendq->q, ipint, sess, + OPENLI_PUSH_HALT_IPINTERCEPT); + } + } +} + + +static void newly_active_gtp_session(openli_gtp_worker_t *worker, + user_intercept_list_t *userint, access_session_t *sess) { + + ipintercept_t *ipint, *tmp; + sync_sendq_t *sendq, *tmpq; + + if (userint == NULL || sess == NULL) { + return; + } + + /* Save the TEID for this session as one that we have to now + * intercept from now on -- TODO + */ + + if (sess->sessipcount == 0) { + return; + } + + /* Tell the collector threads about any IPs associated with this + * newly active session. + */ + HASH_ITER(hh_user, userint->intlist, ipint, tmp) { + printf("DEVDEBUG: %d NEW SESSION: %s %s\n", worker->workerid, + ipint->common.liid, (char *)sess->sessionid); + HASH_ITER(hh, (sync_sendq_t *)(worker->collector_queues), sendq, + tmpq) { + push_session_ips_to_collector_queue(sendq->q, ipint, sess); + } + } + +} + +static void export_raw_gtp_c_packet_content(openli_gtp_worker_t *worker, + ipintercept_t *ipint, void *parseddata, uint32_t seqno, + uint32_t cin) { + + /* Generate a RAW IRI encoding job for each GTP-C packet that contributed + * to the current GTP "action", so that pcapdisk intercepts can + * write them into the pcap file nicely */ + + /* TODO */ + +} + +static void create_iri_from_gtp_action(openli_gtp_worker_t *worker, + ipintercept_t *ipint, access_session_t *sess, void *parseddata) { + + struct timeval now; + + if (ipint->common.tomediate == OPENLI_INTERCEPT_OUTPUTS_CCONLY) { + return; + } + + gettimeofday(&now, NULL); + if (!INTERCEPT_IS_ACTIVE(ipint, now)) { + return; + } + + /* TODO */ + + /* Determine if this requires a UMTS or EPS (or some other?) IRI */ + + + +} + +static void generate_encoding_jobs(openli_gtp_worker_t *worker, + user_intercept_list_t *userint, access_session_t *sess, + void *parseddata, access_action_t action) { + + ipintercept_t *ipint, *tmp; + access_plugin_t *p = worker->gtpplugin; + + if (userint == NULL) { + return; + } + + HASH_ITER(hh_user, userint->intlist, ipint, tmp) { + if (ipint->common.targetagency == NULL || + strcmp(ipint->common.targetagency, "pcapdisk") == 0) { + uint32_t seqno; + seqno = p->get_packet_sequence(p, parseddata); + + export_raw_gtp_c_packet_content(worker, ipint, parseddata, + seqno, sess->cin); + } else if (action != ACCESS_ACTION_NONE) { + create_iri_from_gtp_action(worker, ipint, sess, parseddata); + } + } +} + static void process_gtp_u_packet(openli_gtp_worker_t *worker, uint8_t *payload, uint32_t plen, uint32_t teid) { @@ -294,6 +435,87 @@ static void process_gtp_u_packet(openli_gtp_worker_t *worker, static void process_gtp_c_packet(openli_gtp_worker_t *worker, libtrace_packet_t *packet) { + access_plugin_t *p = worker->gtpplugin; + void *parseddata; + user_identity_t *identities = NULL; + int useridcnt = 0, i; + internet_user_t *iuser; + access_session_t *sess = NULL; + session_state_t oldstate, newstate; + access_action_t accessaction; + user_intercept_list_t *userint; + + parseddata = p->process_packet(p, packet); + if (parseddata == NULL) { + logger(LOG_INFO, + "OpenLI: GTP worker %d was unable to parse GTP-C packet", + worker->workerid); + pthread_mutex_lock(worker->stats_mutex); + worker->stats->bad_ip_session_packets ++; + pthread_mutex_unlock(worker->stats_mutex); + return; + } + + identities = p->get_userid(p, parseddata, &useridcnt); + if (identities == NULL) { + goto end_gtpc_processing; + } + + oldstate = SESSION_STATE_NEW; + newstate = SESSION_STATE_NEW; + + for (i = 0; i < useridcnt; i++) { + iuser = lookup_gtp_userid(worker, &identities[i]); + + if (iuser == NULL) { + break; + } + sess = p->update_session_state(p, parseddata, identities[i].plugindata, + &(iuser->sessions), &oldstate, &newstate, &accessaction); + if (sess == NULL) { + /* Unable to match packet to a session, ignore it */ + continue; + } + + printf("IDCHECK: %s %s %d %d\n", iuser->userid, + (char *)sess->sessionid, oldstate, newstate); + + HASH_FIND(hh, worker->userintercepts, iuser->userid, + strlen(iuser->userid), userint); + + if (oldstate != newstate) { + if (newstate == SESSION_STATE_ACTIVE) { + printf("ACTIVE: %s\n", (char *)sess->sessionid); + newly_active_gtp_session(worker, userint, sess); + + } else if (newstate == SESSION_STATE_OVER) { + printf("OVER: %s\n", (char *)sess->sessionid); + push_gtp_session_over(worker, userint, sess); + /* TODO remove TEID from list of intercepted TEIDs */ + } + } + + generate_encoding_jobs(worker, userint, sess, parseddata, accessaction); + + if (oldstate != newstate && newstate == SESSION_STATE_OVER) { + HASH_DELETE(hh, iuser->sessions, sess); + free_single_session(sess); + } + } + +end_gtpc_processing: + if (parseddata) { + p->destroy_parsed_data(p, parseddata); + } + + if (identities) { + for (i = 0; i < useridcnt; i++) { + if (identities[i].idstr) { + free(identities[i].idstr); + } + } + free(identities); + } } @@ -353,7 +575,6 @@ static void process_gtp_packet(openli_gtp_worker_t *worker, teid = v1hdr->teid; payload += sizeof(gtpv1_header_t); plen -= sizeof(gtpv1_header_t); - } else { return; } @@ -391,7 +612,6 @@ static int gtp_worker_process_packet(openli_gtp_worker_t *worker) { break; } - /* TODO insert packet processing code here! */ process_gtp_packet(worker, recvd.data.pkt); if (recvd.data.pkt) { diff --git a/src/collector/internetaccess.c b/src/collector/internetaccess.c index 07cae7d..dfb0ffb 100644 --- a/src/collector/internetaccess.c +++ b/src/collector/internetaccess.c @@ -27,6 +27,7 @@ #include "logger.h" #include "util.h" #include "internetaccess.h" +#include "collector.h" access_plugin_t *init_access_plugin(uint8_t accessmethod) { @@ -55,6 +56,54 @@ void destroy_access_plugin(access_plugin_t *p) { p->destroy_plugin_data(p); } + +int push_session_ips_to_collector_queue(libtrace_message_queue_t *q, + ipintercept_t *ipint, access_session_t *session) { + + ipsession_t *ipsess; + openli_pushed_t msg; + int i; + + for (i = 0; i < session->sessipcount; i++) { + + ipsess = create_ipsession(ipint, session->cin, + session->sessionips[i].ipfamily, + (struct sockaddr *)&(session->sessionips[i].assignedip), + session->sessionips[i].prefixbits); + + if (!ipsess) { + logger(LOG_INFO, + "OpenLI: ran out of memory while creating IP session message."); + return -1; + } + memset(&msg, 0, sizeof(openli_pushed_t)); + msg.type = OPENLI_PUSH_IPINTERCEPT; + msg.data.ipsess = ipsess; + + libtrace_message_queue_put(q, (void *)(&msg)); + } + return session->sessipcount; +} + +void push_session_update_to_collector_queue(libtrace_message_queue_t *q, + ipintercept_t *ipint, access_session_t *sess, int updatetype) { + + openli_pushed_t pmsg; + int i; + ipsession_t *sessdup; + + for (i = 0; i < sess->sessipcount; i++) { + memset(&pmsg, 0, sizeof(openli_pushed_t)); + pmsg.type = updatetype; + sessdup = create_ipsession(ipint, sess->cin, + sess->sessionips[i].ipfamily, + (struct sockaddr *)&(sess->sessionips[i].assignedip), + sess->sessionips[i].prefixbits); + pmsg.data.ipsess = sessdup; + libtrace_message_queue_put(q, &pmsg); + } +} + static inline void free_session(access_session_t *sess) { if (sess == NULL) { diff --git a/src/collector/internetaccess.h b/src/collector/internetaccess.h index af8084c..c90fab8 100644 --- a/src/collector/internetaccess.h +++ b/src/collector/internetaccess.h @@ -240,6 +240,10 @@ access_session_t *create_access_session(access_plugin_t *p, void add_new_session_ip(access_session_t *sess, void *att_val, int family, uint8_t pfxbits, int att_len); int remove_session_ip(access_session_t *sess, internetaccess_ip_t *sessip); +int push_session_ips_to_collector_queue(libtrace_message_queue_t *q, + ipintercept_t *ipint, access_session_t *session); +void push_session_update_to_collector_queue(libtrace_message_queue_t *q, + ipintercept_t *ipint, access_session_t *sess, int updatetype); const char *accesstype_to_string(internet_access_method_t am); diff --git a/src/intercept.h b/src/intercept.h index 3e0f4c6..4eea6bf 100644 --- a/src/intercept.h +++ b/src/intercept.h @@ -36,6 +36,10 @@ #define OPENLI_VENDOR_MIRROR_NONE (0xffffffff) +#define INTERCEPT_IS_ACTIVE(cept, now) \ + (cept->common.tostart_time <= now.tv_sec && ( \ + cept->common.toend_time == 0 || cept->common.toend_time > now.tv_sec)) + typedef enum { OPENLI_INTERCEPT_TYPE_UNKNOWN = 0, OPENLI_INTERCEPT_TYPE_IP = 1, From 6729961d7d9f4060bc6e9780e5ee2bf1c9670fec Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Thu, 30 May 2024 16:47:26 +1200 Subject: [PATCH 08/44] Fix memory leak when encoding UMTSCCs --- src/etsili_core.c | 3 +-- src/etsili_core.h | 4 ---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/etsili_core.c b/src/etsili_core.c index 4ff3cd9..ffae753 100644 --- a/src/etsili_core.c +++ b/src/etsili_core.c @@ -114,7 +114,7 @@ static inline void encode_hi1_notification_body(wandder_encoder_t *encoder, wandder_encode_endseq(encoder); // End Outermost Sequence } -wandder_encoded_result_t *encode_umtscc_body(wandder_encoder_t *encoder, +void encode_umtscc_body(wandder_encoder_t *encoder, wandder_encode_job_t *precomputed, void *ipcontent, uint32_t iplen, uint8_t dir) { @@ -151,7 +151,6 @@ wandder_encoded_result_t *encode_umtscc_body(wandder_encoder_t *encoder, wandder_encode_next(encoder, WANDDER_TAG_IPPACKET, WANDDER_CLASS_CONTEXT_PRIMITIVE, 4, ipcontent, iplen); END_ENCODED_SEQUENCE(encoder, 4); - return wandder_encode_finish(encoder); } static inline void encode_emailcc_body(wandder_encoder_t *encoder, diff --git a/src/etsili_core.h b/src/etsili_core.h index 4ae927f..849a1fc 100644 --- a/src/etsili_core.h +++ b/src/etsili_core.h @@ -247,10 +247,6 @@ uint8_t DERIVE_INTEGER_LENGTH(uint64_t x); int calculate_pspdu_length(uint32_t contentsize); -wandder_encoded_result_t *encode_umtscc_body(wandder_encoder_t *encoder, - wandder_encode_job_t *precomputed, void *ipcontent, uint32_t iplen, - uint8_t dir); - wandder_encoded_result_t *encode_ipiri_body(wandder_encoder_t *encoder, wandder_encode_job_t *precomputed, etsili_iri_type_t iritype, etsili_generic_t **params); From 80d70c882e3cb86c5233e8f69c6babea5a4730f7 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Tue, 4 Jun 2024 19:29:48 +1200 Subject: [PATCH 09/44] Improved GTP session tracking code * Add fields to store TEID for the "data" sessions, and attempt to extract the data TEIDs for GTPv1 (GTPv2 is a bit more complicated). * Hash GTP packets to GTP threads based on the IP of the session initiator rather than the TEID (TEID is not bidirectional, and it is always 0 in the create request). * Fix double free issues when a GTP session is over (since we can have multiple "users" for a given session). * Fix various memory leaks. * Avoid unnecessary copying of GTP session parameters when dealing with multiple identity types. --- src/collector/accessplugins/gtp.c | 133 +++++++++++++++++++----------- src/collector/collector.c | 35 ++++++++ src/collector/gtp_worker.c | 7 +- src/collector/internetaccess.c | 4 +- src/collector/internetaccess.h | 16 +++- 5 files changed, 143 insertions(+), 52 deletions(-) diff --git a/src/collector/accessplugins/gtp.c b/src/collector/accessplugins/gtp.c index 219b91a..57631ad 100644 --- a/src/collector/accessplugins/gtp.c +++ b/src/collector/accessplugins/gtp.c @@ -39,6 +39,7 @@ enum { GTPV1_IE_CAUSE = 1, GTPV1_IE_IMSI = 2, + GTPV1_IE_TEID_DATA = 16, GTPV1_IE_TEID_CTRL = 17, GTPV1_IE_END_USER_ADDRESS = 128, GTPV1_IE_APNAME = 131, @@ -71,21 +72,6 @@ enum { SM_CAUSE_REGULAR_DEACTIVATION = 36, }; -/* XXX do we need to support other message types here, e.g. for IRI-Report? */ -enum { - GTPV1_CREATE_PDP_CONTEXT_REQUEST = 16, - GTPV1_CREATE_PDP_CONTEXT_RESPONSE = 17, - GTPV1_UPDATE_PDP_CONTEXT_REQUEST = 18, - GTPV1_UPDATE_PDP_CONTEXT_RESPONSE = 19, - GTPV1_DELETE_PDP_CONTEXT_REQUEST = 20, - GTPV1_DELETE_PDP_CONTEXT_RESPONSE = 21, - - GTPV2_CREATE_SESSION_REQUEST = 32, - GTPV2_CREATE_SESSION_RESPONSE = 33, - GTPV2_DELETE_SESSION_REQUEST = 36, - GTPV2_DELETE_SESSION_RESPONSE = 37, -}; - typedef struct gtp_infelem gtp_infoelem_t; struct gtp_infelem { @@ -118,6 +104,7 @@ typedef struct gtp_saved_packet gtp_saved_pkt_t; typedef struct gtp_session { char *sessid; + char *altsessid; gtp_sess_saved_t saved; char idstr_msisdn[64]; @@ -126,7 +113,8 @@ typedef struct gtp_session { int idstr_imsi_len; char idstr_imei[64]; int idstr_imei_len; - uint32_t teid; + uint32_t control_teid[2]; + uint32_t data_teid[2]; internetaccess_ip_t *pdpaddrs; uint8_t pdpaddrcount; @@ -138,13 +126,14 @@ typedef struct gtp_session { session_state_t current; - uint64_t last_reqid; uint8_t last_reqtype; session_state_t savedoldstate; session_state_t savednewstate; gtp_saved_pkt_t *lastsavedpkt; + int refcount; + } gtp_session_t; struct gtp_saved_packet { @@ -171,6 +160,7 @@ typedef struct gtp_parsed { double tvsec; uint32_t teid; uint32_t teid_ctl; + uint32_t teid_data; uint32_t seqno; uint8_t response_cause; @@ -197,6 +187,7 @@ typedef struct gtp_global { Pvoid_t saved_packets; Pvoid_t session_map; Pvoid_t alt_session_map; + Pvoid_t data_sessions; double lastrefresh; } gtp_global_t; @@ -210,6 +201,7 @@ static void reset_parsed_pkt(gtp_parsed_t *parsed) { parsed->tvsec = 0; parsed->teid = 0; parsed->teid_ctl = 0; + parsed->teid_data = 0; parsed->seqno = 0; parsed->response_cause = 0; @@ -246,6 +238,10 @@ static inline void destroy_gtp_session(gtp_session_t *sess) { free(sess->sessid); } + if (sess->altsessid) { + free(sess->altsessid); + } + if (sess->saved.imei) { free(sess->saved.imei); } @@ -296,6 +292,7 @@ static void gtp_destroy_plugin_data(access_plugin_t *p) { return; } + JSLFA(res, glob->alt_session_map); index[0] = '\0'; JSLF(pval, glob->session_map, index); while (pval) { @@ -304,7 +301,6 @@ static void gtp_destroy_plugin_data(access_plugin_t *p) { JSLN(pval, glob->session_map, index); } JSLFA(res, glob->session_map); - JSLFA(res, glob->alt_session_map); indexnum = 0; JLF(pval, glob->saved_packets, indexnum); @@ -558,15 +554,15 @@ static int walk_gtpv1_ies(gtp_parsed_t *parsedpkt, uint8_t *ptr, uint32_t rem, if (gtpel) { if (parsedpkt->msgtype == GTPV1_CREATE_PDP_CONTEXT_REQUEST) { - if (ietype == GTPV1_IE_TEID_CTRL) { - parsedpkt->teid = get_teid_from_teidctl(gtpel); - } if (ietype == GTPV1_IE_IMSI) { get_gtpnum_from_ie(gtpel, parsedpkt->imsi, 0); } if (ietype == GTPV1_IE_MSISDN) { get_gtpnum_from_ie(gtpel, parsedpkt->msisdn, 1); } + if (ietype == GTPV1_IE_TEID_DATA) { + parsedpkt->teid_data = get_teid_from_teidctl(gtpel); + } } if (ietype == GTPV1_IE_TEID_CTRL) { @@ -610,9 +606,6 @@ static void walk_gtpv2_ies(gtp_parsed_t *parsedpkt, uint8_t *ptr, uint32_t rem, parsedpkt->ies = gtpel; if (parsedpkt->msgtype == GTPV2_CREATE_SESSION_REQUEST) { - if (ietype == GTPV2_IE_FTEID) { - parsedpkt->teid = get_teid_from_fteid(gtpel); - } if (ietype == GTPV2_IE_IMSI) { get_gtpnum_from_ie(gtpel, parsedpkt->imsi, 0); } @@ -622,12 +615,11 @@ static void walk_gtpv2_ies(gtp_parsed_t *parsedpkt, uint8_t *ptr, uint32_t rem, if (ietype == GTPV2_IE_MSISDN) { get_gtpnum_from_ie(gtpel, parsedpkt->msisdn, 0); } - } else if (parsedpkt->msgtype == GTPV2_DELETE_SESSION_REQUEST) { - if (ietype == GTPV2_IE_FTEID) { - parsedpkt->teid = get_teid_from_fteid(gtpel); - } } + if (ietype == GTPV2_IE_FTEID) { + parsedpkt->teid_ctl = get_teid_from_fteid(gtpel); + } if (ietype == GTPV2_IE_CAUSE) { parsedpkt->response_cause = get_cause_from_ie(gtpel); } @@ -701,6 +693,9 @@ static int gtp_parse_v2_teid(gtp_global_t *glob, libtrace_packet_t *pkt, walk_gtpv2_ies(glob->parsedpkt, ptr, rem, len); + if (glob->parsedpkt->teid == 0) { + glob->parsedpkt->teid = glob->parsedpkt->teid_ctl; + } return 0; } @@ -742,6 +737,10 @@ static int gtp_parse_v1_teid(gtp_global_t *glob, libtrace_packet_t *pkt, return -1; } + if (glob->parsedpkt->teid == 0) { + glob->parsedpkt->teid = glob->parsedpkt->teid_ctl; + } + return 0; } @@ -965,10 +964,6 @@ static user_identity_t *gtp_get_userid(access_plugin_t *p, void *parsed, save_identifier_strings(gparsed, gparsed->matched_session); } - if (search == glob->alt_session_map) { - gparsed->teid = gparsed->matched_session->teid; - } - /* v1 delete requests use the teid_cp from the create response * as their TEID, so we need to have a reference to this session * for that TEID as well. Otherwise we'll miss the delete requests. @@ -977,8 +972,13 @@ static user_identity_t *gtp_get_userid(access_plugin_t *p, void *parsed, GEN_SESSID((char *)alt_sessid, gparsed, gparsed->teid_ctl); JSLG(pval, glob->alt_session_map, alt_sessid); + gparsed->matched_session->altsessid = strdup(alt_sessid); + gparsed->matched_session->control_teid[1] = gparsed->teid_ctl; + gparsed->matched_session->data_teid[1] = gparsed->teid_data; + if (!pval) { - JSLI(pval, glob->alt_session_map, alt_sessid); + JSLI(pval, glob->alt_session_map, + gparsed->matched_session->altsessid); *pval = (Word_t)gparsed->matched_session; } @@ -1027,9 +1027,11 @@ static user_identity_t *gtp_get_userid(access_plugin_t *p, void *parsed, sess = calloc(1, sizeof(gtp_session_t)); sess->sessid = strdup((char *)sessid); sess->current = SESSION_STATE_NEW; - sess->teid = gparsed->teid; + sess->control_teid[0] = gparsed->teid_ctl; + sess->data_teid[0] = gparsed->teid_data; sess->pdpaddrs = NULL; sess->pdpaddrcount = 0; + sess->refcount = 0; memcpy(sess->serverid, gparsed->serverid, 16); sess->serveripfamily = gparsed->serveripfamily; @@ -1227,10 +1229,12 @@ static void apply_gtp_fsm_logic(gtp_parsed_t *gparsed, access_action_t *action, access_session_t *sess, gtp_saved_pkt_t *gpkt, session_state_t current) { - if (gpkt->version == 1) { - copy_session_params_v1(gparsed, gpkt); - } else { - copy_session_params_v2(gparsed, gpkt); + if (gpkt != gparsed->matched_session->lastsavedpkt) { + if (gpkt->version == 1) { + copy_session_params_v1(gparsed, gpkt); + } else { + copy_session_params_v2(gparsed, gpkt); + } } if (current == SESSION_STATE_NEW && @@ -1250,6 +1254,8 @@ static void apply_gtp_fsm_logic(gtp_parsed_t *gparsed, access_action_t *action, extract_gtp_assigned_ip_address(gpkt, sess, gparsed->matched_session); + /* TODO: set up GTP-U data sessions */ + } else if (gpkt->response_cause >= 64 && gpkt->response_cause <= 239) { current = SESSION_STATE_OVER; *action = ACCESS_ACTION_REJECT; @@ -1263,6 +1269,8 @@ static void apply_gtp_fsm_logic(gtp_parsed_t *gparsed, access_action_t *action, extract_gtp_assigned_ip_address(gpkt, sess, gparsed->matched_session); + + /* TODO: set up GTP-U data sessions */ } else if (gpkt->response_cause >= 192 && gpkt->response_cause <= 255) { current = SESSION_STATE_OVER; *action = ACCESS_ACTION_REJECT; @@ -1288,7 +1296,8 @@ static void apply_gtp_fsm_logic(gtp_parsed_t *gparsed, access_action_t *action, } static inline access_session_t *find_matched_session(access_plugin_t *p, - access_session_t **sesslist, gtp_session_t *match, uint32_t teid) { + access_session_t **sesslist, gtp_session_t *match, uint32_t teid, + uint8_t incr_refcount) { access_session_t *thissess = NULL; @@ -1303,6 +1312,9 @@ static inline access_session_t *find_matched_session(access_plugin_t *p, strlen(match->sessid)); thissess->cin = assign_gtp_cin(teid); match->cin = thissess->cin; + if (incr_refcount) { + match->refcount ++; + } HASH_ADD_KEYPTR(hh, *sesslist, thissess->sessionid, strlen(thissess->sessionid), thissess); @@ -1324,6 +1336,14 @@ static access_session_t *gtp_update_session_state(access_plugin_t *p, uint64_t reqid = (((uint64_t)gparsed->teid) << 32) | ((uint64_t)gparsed->seqno); + uint8_t incr_refcount = 0; + + if (gparsed->msgtype == GTPV2_CREATE_SESSION_REQUEST || + gparsed->msgtype == GTPV1_CREATE_PDP_CONTEXT_REQUEST) { + incr_refcount = 1; + } else { + incr_refcount = 0; + } printf("DEVDEBUG: TEID=%u\n", gparsed->teid); @@ -1335,7 +1355,7 @@ static access_session_t *gtp_update_session_state(access_plugin_t *p, * the packet. */ thissess = find_matched_session(p, sesslist, gparsed->matched_session, - gparsed->teid); + gparsed->teid, incr_refcount); *oldstate = gparsed->matched_session->savedoldstate; apply_gtp_fsm_logic(gparsed, action, thissess, gparsed->matched_session->lastsavedpkt, @@ -1377,7 +1397,7 @@ static access_session_t *gtp_update_session_state(access_plugin_t *p, gparsed->msgtype == GTPV1_DELETE_PDP_CONTEXT_REQUEST) { thissess = find_matched_session(p, sesslist, - gparsed->matched_session, gparsed->teid); + gparsed->matched_session, gparsed->teid, incr_refcount); if (thissess) { *oldstate = gparsed->matched_session->current; gparsed->matched_session->savedoldstate = *oldstate; @@ -1391,7 +1411,7 @@ static access_session_t *gtp_update_session_state(access_plugin_t *p, } else { check = (gtp_saved_pkt_t *)*pval; - + incr_refcount = 0; JLD(rcint, glob->saved_packets, check->reqid); if (saved->type == GTPV2_CREATE_SESSION_REQUEST && @@ -1399,11 +1419,13 @@ static access_session_t *gtp_update_session_state(access_plugin_t *p, gparsed->request = saved; gparsed->response = check; + incr_refcount = 1; } else if (check->type == GTPV2_CREATE_SESSION_REQUEST && saved->type == GTPV2_CREATE_SESSION_RESPONSE) { gparsed->request = check; gparsed->response = saved; + incr_refcount = 1; } else if (saved->type == GTPV2_DELETE_SESSION_REQUEST && check->type == GTPV2_DELETE_SESSION_RESPONSE) { gparsed->request = saved; @@ -1417,11 +1439,13 @@ static access_session_t *gtp_update_session_state(access_plugin_t *p, gparsed->request = saved; gparsed->response = check; + incr_refcount = 1; } else if (check->type == GTPV1_CREATE_PDP_CONTEXT_REQUEST && saved->type == GTPV1_CREATE_PDP_CONTEXT_RESPONSE) { gparsed->request = check; gparsed->response = saved; + incr_refcount = 1; } else if (saved->type == GTPV1_DELETE_PDP_CONTEXT_REQUEST && check->type == GTPV1_DELETE_PDP_CONTEXT_RESPONSE) { gparsed->request = saved; @@ -1457,13 +1481,14 @@ static access_session_t *gtp_update_session_state(access_plugin_t *p, if (gparsed->request->matched_session) { thissess = find_matched_session(p, sesslist, - gparsed->request->matched_session, gparsed->teid); + gparsed->request->matched_session, gparsed->teid, + incr_refcount); *oldstate = gparsed->request->matched_session->current; gparsed->matched_session = gparsed->request->matched_session; gparsed->matched_session->savedoldstate = *oldstate; } else if (gparsed->response->matched_session) { thissess = find_matched_session(p, sesslist, - gparsed->response->matched_session, gparsed->teid); + gparsed->response->matched_session, gparsed->teid, 0); *oldstate = gparsed->response->matched_session->current; gparsed->matched_session = gparsed->response->matched_session; gparsed->matched_session->savedoldstate = *oldstate; @@ -1900,8 +1925,24 @@ static uint8_t *gtp_get_ip_contents(access_plugin_t *p, void *parseddata, static void gtp_destroy_session_data(access_plugin_t *p, access_session_t *sess) { - if (sess->sessionid) { - free(sess->sessionid); + gtp_global_t *glob = (gtp_global_t *)(p->plugindata); + gtp_session_t *gtpsess; + PWord_t pval; + int rc; + + JSLG(pval, glob->session_map, sess->sessionid); + if (pval != NULL) { + gtpsess = (gtp_session_t *)(*pval); + gtpsess->refcount --; + if (gtpsess->refcount <= 0) { + JSLD(rc, glob->session_map, gtpsess->sessid); + if (gtpsess->altsessid) { + JSLD(rc, glob->alt_session_map, gtpsess->altsessid); + } + + destroy_gtp_session(gtpsess); + printf("DEVDEBUG: destroying session %s\n", (char *)sess->sessionid); + } } } diff --git a/src/collector/collector.c b/src/collector/collector.c index 305260a..9ebffb4 100644 --- a/src/collector/collector.c +++ b/src/collector/collector.c @@ -744,6 +744,7 @@ static uint8_t check_if_gtp(packet_info_t *pinfo, libtrace_packet_t *pkt, colthread_local_t *loc, collector_global_t *glob) { uint32_t fwdto = 0; + uint8_t msgtype; gtpv1_header_t *v1_hdr; gtpv2_header_teid_t *v2_hdr; @@ -768,8 +769,12 @@ static uint8_t check_if_gtp(packet_info_t *pinfo, libtrace_packet_t *pkt, return 0; } v2_hdr = (gtpv2_header_teid_t *)pinfo->payload_ptr; + msgtype = v2_hdr->msgtype; + + /* fwdto = hashlittle(&(v2_hdr->teid), sizeof(v2_hdr->teid), 312267023) % loc->gtpq_count; + */ } else if (((*(pinfo->payload_ptr)) & 0xe0) == 0x20) { /* GTPv1 */ @@ -778,8 +783,38 @@ static uint8_t check_if_gtp(packet_info_t *pinfo, libtrace_packet_t *pkt, } v1_hdr = (gtpv1_header_t *)pinfo->payload_ptr; + msgtype = v1_hdr->msgtype; + + /* fwdto = hashlittle(&(v1_hdr->teid), sizeof(v1_hdr->teid), 312267023) % loc->gtpq_count; + */ + + } else { + return 0; + } + + switch(msgtype) { + case GTPV1_CREATE_PDP_CONTEXT_REQUEST: + case GTPV1_UPDATE_PDP_CONTEXT_REQUEST: + case GTPV1_DELETE_PDP_CONTEXT_REQUEST: + case GTPV2_CREATE_SESSION_REQUEST: + case GTPV2_DELETE_SESSION_REQUEST: + fwdto = hashlittle(&(pinfo->srcip), + sizeof(struct sockaddr_storage), 312267023) % + loc->gtpq_count; + break; + case GTPV1_CREATE_PDP_CONTEXT_RESPONSE: + case GTPV1_UPDATE_PDP_CONTEXT_RESPONSE: + case GTPV1_DELETE_PDP_CONTEXT_RESPONSE: + case GTPV2_CREATE_SESSION_RESPONSE: + case GTPV2_DELETE_SESSION_RESPONSE: + fwdto = hashlittle(&(pinfo->destip), + sizeof(struct sockaddr_storage), 312267023) % + loc->gtpq_count; + break; + default: + fwdto = 0; } } diff --git a/src/collector/gtp_worker.c b/src/collector/gtp_worker.c index eb18fdf..33aeed1 100644 --- a/src/collector/gtp_worker.c +++ b/src/collector/gtp_worker.c @@ -345,8 +345,8 @@ static void newly_active_gtp_session(openli_gtp_worker_t *worker, return; } - /* Save the TEID for this session as one that we have to now - * intercept from now on -- TODO + /* Save the Data TEIDs for this session as we have to now + * intercept GTP-U for those TEIDs from now on -- TODO */ if (sess->sessipcount == 0) { @@ -491,13 +491,14 @@ static void process_gtp_c_packet(openli_gtp_worker_t *worker, } else if (newstate == SESSION_STATE_OVER) { printf("OVER: %s\n", (char *)sess->sessionid); push_gtp_session_over(worker, userint, sess); - /* TODO remove TEID from list of intercepted TEIDs */ + } } generate_encoding_jobs(worker, userint, sess, parseddata, accessaction); if (oldstate != newstate && newstate == SESSION_STATE_OVER) { + /* TODO remove data TEID from list of intercepted TEIDs */ HASH_DELETE(hh, iuser->sessions, sess); free_single_session(sess); } diff --git a/src/collector/internetaccess.c b/src/collector/internetaccess.c index dfb0ffb..0cea9a8 100644 --- a/src/collector/internetaccess.c +++ b/src/collector/internetaccess.c @@ -117,6 +117,9 @@ static inline void free_session(access_session_t *sess) { if (sess->sessionips) { free(sess->sessionips); } + if (sess->sessionid) { + free(sess->sessionid); + } free(sess); } @@ -240,7 +243,6 @@ access_session_t *create_access_session(access_plugin_t *p, char *sessid, newsess->started.tv_sec = 0; newsess->started.tv_usec = 0; - newsess->teid = 0; return newsess; } diff --git a/src/collector/internetaccess.h b/src/collector/internetaccess.h index c90fab8..7e3b3cb 100644 --- a/src/collector/internetaccess.h +++ b/src/collector/internetaccess.h @@ -58,6 +58,20 @@ typedef struct gtpv2_header_teid { uint32_t seqno; } PACKED gtpv2_header_teid_t; +enum { + GTPV1_CREATE_PDP_CONTEXT_REQUEST = 16, + GTPV1_CREATE_PDP_CONTEXT_RESPONSE = 17, + GTPV1_UPDATE_PDP_CONTEXT_REQUEST = 18, + GTPV1_UPDATE_PDP_CONTEXT_RESPONSE = 19, + GTPV1_DELETE_PDP_CONTEXT_REQUEST = 20, + GTPV1_DELETE_PDP_CONTEXT_RESPONSE = 21, + + GTPV2_CREATE_SESSION_REQUEST = 32, + GTPV2_CREATE_SESSION_RESPONSE = 33, + GTPV2_DELETE_SESSION_REQUEST = 36, + GTPV2_DELETE_SESSION_RESPONSE = 37, +}; + enum { ACCESS_RADIUS, @@ -155,8 +169,6 @@ struct access_session { session_ipversion_t sessipversion; uint8_t ips_mapped; - uint32_t teid; - access_plugin_t *plugin; void *sessionid; void *statedata; From 156eb684829ba5ec5b33635f112860bf70649773 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Tue, 4 Jun 2024 19:36:58 +1200 Subject: [PATCH 10/44] Fix double free in RADIUS plugin introduced by last commit --- src/collector/accessplugins/radius.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/collector/accessplugins/radius.c b/src/collector/accessplugins/radius.c index 724f4fe..25bf204 100644 --- a/src/collector/accessplugins/radius.c +++ b/src/collector/accessplugins/radius.c @@ -2150,10 +2150,6 @@ static void radius_destroy_session_data(access_plugin_t *p, Word_t rcw; radius_user_session_t *usess = (radius_user_session_t *)sess->statedata; - if (sess->sessionid) { - free(sess->sessionid); - } - if (usess == NULL) { return; } From 6c43a40a75c6590f21927ed3deb54baa1fe075a5 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Wed, 5 Jun 2024 16:00:42 +1200 Subject: [PATCH 11/44] Allow GTP worker threads to create IRIs for GTPv1 sessions Only tested for the BEGIN IRI so far, as I'm lacking suitable samples of complete sessions to test END and various REPORT IRI types. GTPv2 still needs to be implemented (i.e. EPS_IRI). Other changes: * move GTP protocol definitions that are required in multiple places to its own header file, rather than being in internetaccess.h * add additional SM Cause values to cover situations other than a successful session ending (e.g. auth failed, service down, etc). * add method to create an IRI if a context activation failed * remove debug output that is no longer required * add method for determining the GTP version from a generic "parseddata" pointer. --- src/Makefile.am | 1 + src/collector/accessplugins/gtp.c | 154 +++++++++++++++++++----------- src/collector/collector_publish.h | 2 + src/collector/gtp.h | 66 +++++++++++++ src/collector/gtp_worker.c | 56 ++++++----- src/collector/gtp_worker.h | 6 ++ src/collector/internetaccess.h | 36 ------- 7 files changed, 206 insertions(+), 115 deletions(-) create mode 100644 src/collector/gtp.h diff --git a/src/Makefile.am b/src/Makefile.am index 2f33368..8a4788b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -73,6 +73,7 @@ openlicollector_SOURCES=collector/collector.c configparser.c configparser.h \ collector/etsiencoding/ipmmiri.c \ collector/sms_worker.c collector/sms_worker.h \ collector/gtp_worker.c collector/gtp_worker.h \ + collector/gtp.h \ collector/location.c collector/location.h \ collector/collector_util.c collector/collector_util.h \ $(PLUGIN_SRCS) diff --git a/src/collector/accessplugins/gtp.c b/src/collector/accessplugins/gtp.c index 57631ad..04fb24a 100644 --- a/src/collector/accessplugins/gtp.c +++ b/src/collector/accessplugins/gtp.c @@ -33,6 +33,7 @@ #include "logger.h" #include "internetaccess.h" #include "util.h" +#include "gtp.h" #define GTP_FLUSH_OLD_PKT_FREQ 180 @@ -41,6 +42,7 @@ enum { GTPV1_IE_IMSI = 2, GTPV1_IE_TEID_DATA = 16, GTPV1_IE_TEID_CTRL = 17, + GTPV1_IE_RAT_TYPE = 82, GTPV1_IE_END_USER_ADDRESS = 128, GTPV1_IE_APNAME = 131, GTPV1_IE_MSISDN = 134, @@ -66,9 +68,14 @@ enum { enum { GTPV1_CAUSE_REQUEST_ACCEPTED = 128, + GTPV1_CAUSE_SYSTEM_FAILURE = 204, + GTPV1_CAUSE_AUTH_FAILED = 209, }; enum { + SM_CAUSE_USER_AUTH_FAILED = 29, + SM_CAUSE_UNSUPPORTED_OPTION = 32, + SM_CAUSE_TEMP_OUT_OF_ORDER = 34, SM_CAUSE_REGULAR_DEACTIVATION = 36, }; @@ -1229,12 +1236,10 @@ static void apply_gtp_fsm_logic(gtp_parsed_t *gparsed, access_action_t *action, access_session_t *sess, gtp_saved_pkt_t *gpkt, session_state_t current) { - if (gpkt != gparsed->matched_session->lastsavedpkt) { - if (gpkt->version == 1) { - copy_session_params_v1(gparsed, gpkt); - } else { - copy_session_params_v2(gparsed, gpkt); - } + if (gpkt->version == 1) { + copy_session_params_v1(gparsed, gpkt); + } else { + copy_session_params_v2(gparsed, gpkt); } if (current == SESSION_STATE_NEW && @@ -1345,8 +1350,6 @@ static access_session_t *gtp_update_session_state(access_plugin_t *p, incr_refcount = 0; } - printf("DEVDEBUG: TEID=%u\n", gparsed->teid); - if (reqid == gparsed->matched_session->last_reqid && gparsed->msgtype == gparsed->matched_session->last_reqtype) { @@ -1586,7 +1589,7 @@ static void parse_uli_v2(uint8_t *locinfo, } -static int gtp_create_pdp_generic_iri(gtp_parsed_t *gparsed, +static int gtp_create_umts_generic_iri(gtp_parsed_t *gparsed, gtp_session_t *gsess, etsili_generic_t **params, etsili_generic_freelist_t *freelist, uint32_t evtype) { @@ -1709,7 +1712,7 @@ static int gtp_create_pdp_generic_iri(gtp_parsed_t *gparsed, } -static inline uint8_t gtpv2_cause_to_sm(uint8_t *gtpcause) { +static inline uint8_t gtpv2_cause_to_sm(uint8_t *gtpcause, uint32_t evtype) { switch(*gtpcause) { case GTPV2_CAUSE_REQUEST_ACCEPTED: @@ -1719,64 +1722,84 @@ static inline uint8_t gtpv2_cause_to_sm(uint8_t *gtpcause) { return 0; } -static inline uint8_t gtpv1_cause_to_sm(uint8_t *gtpcause) { +static inline uint8_t gtpv1_cause_to_sm(uint8_t *gtpcause, uint32_t evtype) { switch(*gtpcause) { case GTPV1_CAUSE_REQUEST_ACCEPTED: - return SM_CAUSE_REGULAR_DEACTIVATION; + if (evtype == UMTSIRI_EVENT_TYPE_PDPCONTEXT_DEACTIVATION) { + return SM_CAUSE_REGULAR_DEACTIVATION; + } + break; + case GTPV1_CAUSE_AUTH_FAILED: + return SM_CAUSE_USER_AUTH_FAILED; + case GTPV1_CAUSE_SYSTEM_FAILURE: + return SM_CAUSE_TEMP_OUT_OF_ORDER; } return 0; } +static void insert_gtp_cause_as_gprs_error(gtp_infoelem_t *el, + etsili_generic_t **params, etsili_generic_freelist_t *freelist, + uint32_t evtype) { + + uint8_t smcauseval = 0; + uint8_t *attrptr = (uint8_t *)el->iecontent; + uint16_t attrlen = el->ielength; + etsili_generic_t *np; + + if (el->ietype == GTPV2_IE_CAUSE) { + smcauseval = gtpv2_cause_to_sm(attrptr, evtype); + } else if (el->ietype == GTPV1_IE_CAUSE) { + smcauseval = gtpv1_cause_to_sm(attrptr, evtype); + } + + if (smcauseval != 0) { + np = create_etsili_generic(freelist, + UMTSIRI_CONTENTS_GPRS_ERROR_CODE, sizeof(uint8_t), + &(smcauseval)); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), np); + } +} + static int gtp_create_context_deactivation_iri(gtp_parsed_t *gparsed, etsili_generic_t **params, etsili_generic_freelist_t *freelist) { uint32_t evtype = UMTSIRI_EVENT_TYPE_PDPCONTEXT_DEACTIVATION; gtp_infoelem_t *el; - etsili_generic_t *np; - gtp_create_pdp_generic_iri(gparsed, gparsed->matched_session, + gtp_create_umts_generic_iri(gparsed, gparsed->matched_session, params, freelist, evtype); el = gparsed->response->ies; while (el) { - uint8_t ieattr = 0; - uint8_t *attrptr = (uint8_t *)el->iecontent; - uint16_t attrlen = el->ielength; - switch(el->ietype) { - case GTPV2_IE_CAUSE: { - uint8_t smcauseval = gtpv2_cause_to_sm(attrptr); - if (smcauseval != 0) { - np = create_etsili_generic(freelist, - UMTSIRI_CONTENTS_GPRS_ERROR_CODE, - sizeof(uint8_t), &(smcauseval)); - HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), - sizeof(np->itemnum), np); - } - break; - } - case GTPV1_IE_CAUSE: { - uint8_t smcauseval = gtpv1_cause_to_sm(attrptr); - if (smcauseval != 0) { - np = create_etsili_generic(freelist, - UMTSIRI_CONTENTS_GPRS_ERROR_CODE, - sizeof(uint8_t), &(smcauseval)); - HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), - sizeof(np->itemnum), np); - } + case GTPV1_IE_CAUSE: + insert_gtp_cause_as_gprs_error(el, params, freelist, evtype); break; - } - } + el = el->next; + } - if (ieattr != 0) { - np = create_etsili_generic(freelist, ieattr, attrlen, attrptr); - HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), - np); - } + return 0; +} +static int gtp_create_context_activation_failed_iri(gtp_parsed_t *gparsed, + etsili_generic_t **params, etsili_generic_freelist_t *freelist) { + + uint32_t evtype = UMTSIRI_EVENT_TYPE_PDPCONTEXT_ACTIVATION; + gtp_infoelem_t *el; + + gtp_create_umts_generic_iri(gparsed, gparsed->matched_session, + params, freelist, evtype); + + el = gparsed->response->ies; + while (el) { + switch(el->ietype) { + case GTPV1_IE_CAUSE: + insert_gtp_cause_as_gprs_error(el, params, freelist, evtype); + break; + } el = el->next; } @@ -1788,7 +1811,7 @@ static int gtp_create_context_modification_iri(gtp_parsed_t *gparsed, uint32_t evtype = UMTSIRI_EVENT_TYPE_PDPCONTEXT_MODIFICATION; - gtp_create_pdp_generic_iri(gparsed, gparsed->matched_session, + gtp_create_umts_generic_iri(gparsed, gparsed->matched_session, params, freelist, evtype); return 0; @@ -1800,7 +1823,7 @@ static int gtp_create_start_with_context_active_iri(gtp_session_t *gsess, uint32_t evtype = UMTSIRI_EVENT_TYPE_START_WITH_PDPCONTEXT_ACTIVE; - gtp_create_pdp_generic_iri(NULL, gsess, params, freelist, evtype); + gtp_create_umts_generic_iri(NULL, gsess, params, freelist, evtype); return 0; } @@ -1810,7 +1833,7 @@ static int gtp_create_context_activation_iri(gtp_parsed_t *gparsed, uint32_t evtype = UMTSIRI_EVENT_TYPE_PDPCONTEXT_ACTIVATION; - gtp_create_pdp_generic_iri(gparsed, gparsed->matched_session, + gtp_create_umts_generic_iri(gparsed, gparsed->matched_session, params, freelist, evtype); return 0; @@ -1824,27 +1847,36 @@ static int gtp_generate_iri_data(access_plugin_t *p, void *parseddata, if (gparsed->action == ACCESS_ACTION_ACCEPT) { *iritype = ETSILI_IRI_BEGIN; - if (gtp_create_context_activation_iri(gparsed, params, - freelist) < 0) { + if (gparsed->version == 1 && + gtp_create_context_activation_iri(gparsed, params, + freelist) < 0) { return -1; } return 0; } else if (gparsed->action == ACCESS_ACTION_REJECT) { - printf("need to generate a PDP context activation failed IRI\n"); + *iritype = ETSILI_IRI_REPORT; + if (gparsed->version == 1 && + gtp_create_context_activation_failed_iri(gparsed, params, + freelist) < 0) { + return -1; + } + return 0; } else if (gparsed->action == ACCESS_ACTION_INTERIM_UPDATE) { *iritype = ETSILI_IRI_CONTINUE; - if (gtp_create_context_modification_iri(gparsed, params, freelist) < 0) - { + if (gparsed->version == 1 && + gtp_create_context_modification_iri(gparsed, params, + freelist) < 0) { return -1; } return 0; } else if (gparsed->action == ACCESS_ACTION_END) { *iritype = ETSILI_IRI_END; - if (gtp_create_context_deactivation_iri(gparsed, params, - freelist) < 0) { + if (gparsed->version == 1 && + gtp_create_context_deactivation_iri(gparsed, params, + freelist) < 0) { return -1; } return 0; @@ -1941,7 +1973,6 @@ static void gtp_destroy_session_data(access_plugin_t *p, } destroy_gtp_session(gtpsess); - printf("DEVDEBUG: destroying session %s\n", (char *)sess->sessionid); } } @@ -1985,12 +2016,23 @@ access_plugin_t *get_gtp_access_plugin(void) { return gtp; } +uint8_t gtp_get_parsed_version(void *parseddata) { + gtp_parsed_t *gparsed = (gtp_parsed_t *)parseddata; + + if (gparsed) { + return gparsed->version; + } + return 0; +} + void destroy_gtp_access_plugin(access_plugin_t *gtp) { if (gtp->plugindata) { gtp_destroy_plugin_data(gtp); } free(gtp); } + + // vim: set sw=4 tabstop=4 softtabstop=4 expandtab : diff --git a/src/collector/collector_publish.h b/src/collector/collector_publish.h index 9e700f8..44c833e 100644 --- a/src/collector/collector_publish.h +++ b/src/collector/collector_publish.h @@ -61,6 +61,8 @@ enum { OPENLI_EXPORT_EMAILIRI = 22, OPENLI_EXPORT_RAW_CC = 23, OPENLI_EXPORT_RAW_IRI = 24, + OPENLI_EXPORT_EPSCC = 16, + OPENLI_EXPORT_EPSIRI = 17, }; /* This structure is also used for IPMMCCs since they require the same diff --git a/src/collector/gtp.h b/src/collector/gtp.h new file mode 100644 index 0000000..3985ba5 --- /dev/null +++ b/src/collector/gtp.h @@ -0,0 +1,66 @@ +/* + * + * Copyright (c) 2024 Searchlight New Zealand Ltd. + * All rights reserved. + * + * This file is part of OpenLI. + * + * OpenLI was originally developed by the University of Waikato WAND + * research group. For further information please see http://www.wand.net.nz/ + * + * OpenLI is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenLI 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, see . + * + * + */ +#ifndef OPENLI_GTP_H_ +#define OPENLI_GTP_H_ + +/* Need these GTP header definitions in multiple places, so they go in + * here rather than being confined to the GTP plugin... + */ +typedef struct gtpv1_header { + uint8_t octet1; + uint8_t msgtype; + uint16_t msglen; + uint32_t teid; + uint16_t seqno; + uint8_t npdu; + uint8_t next_ext; +} PACKED gtpv1_header_t; + +typedef struct gtpv2_header_teid { + uint8_t octet1; + uint8_t msgtype; + uint16_t msglen; + uint32_t teid; + uint32_t seqno; +} PACKED gtpv2_header_teid_t; + +enum { + GTPV1_CREATE_PDP_CONTEXT_REQUEST = 16, + GTPV1_CREATE_PDP_CONTEXT_RESPONSE = 17, + GTPV1_UPDATE_PDP_CONTEXT_REQUEST = 18, + GTPV1_UPDATE_PDP_CONTEXT_RESPONSE = 19, + GTPV1_DELETE_PDP_CONTEXT_REQUEST = 20, + GTPV1_DELETE_PDP_CONTEXT_RESPONSE = 21, + + GTPV2_CREATE_SESSION_REQUEST = 32, + GTPV2_CREATE_SESSION_RESPONSE = 33, + GTPV2_DELETE_SESSION_REQUEST = 36, + GTPV2_DELETE_SESSION_RESPONSE = 37, +}; + +uint8_t gtp_get_parsed_version(void *parseddata); + +#endif diff --git a/src/collector/gtp_worker.c b/src/collector/gtp_worker.c index 33aeed1..cd76f79 100644 --- a/src/collector/gtp_worker.c +++ b/src/collector/gtp_worker.c @@ -45,8 +45,6 @@ static void remove_gtp_intercept(openli_gtp_worker_t *worker, * announced. */ - logger(LOG_INFO, "DEVDEBUG: removing intercept %s from GTP worker %d", - ipint->common.liid, worker->workerid); remove_intercept_from_user_intercept_list(&worker->userintercepts, ipint); HASH_DELETE(hh_liid, worker->ipintercepts, ipint); free_single_ipintercept(ipint); @@ -91,8 +89,6 @@ static int init_gtp_intercept(openli_gtp_worker_t *worker, /* Discard any static IPs announced for this intercept, as they are * irrelevant for the purposes of this thread. */ - logger(LOG_INFO, "DEVDEBUG: adding intercept %s -- %s to GTP worker %d", - ipint->common.liid, ipint->username, worker->workerid); free_all_staticipranges(&(ipint->statics)); ipint->statics = NULL; @@ -114,12 +110,8 @@ static void update_modified_gtp_intercept(openli_gtp_worker_t *worker, int r = 0, changed = 0; - logger(LOG_INFO, "DEVDEBUG: updating intercept %s -- %s on GTP worker %d", - found->common.liid, found->username, worker->workerid); if (ipint->accesstype != INTERNET_ACCESS_TYPE_MOBILE) { /* Intercept has changed to be NOT mobile, so just remove it */ - logger(LOG_INFO, "DEVDEBUG: GTP worker %d -- %s is no longer mobile", - worker->workerid, found->common.liid); remove_intercept_from_user_intercept_list(&worker->userintercepts, found); HASH_DELETE(hh_liid, worker->ipintercepts, found); @@ -134,8 +126,6 @@ static void update_modified_gtp_intercept(openli_gtp_worker_t *worker, } else { if (strcmp(ipint->username, found->username) != 0 || ipint->mobileident != found->mobileident) { - logger(LOG_INFO, "DEVDEBUG: GTP worker %d -- %s has new username '%s'", - worker->workerid, found->common.liid, ipint->username); remove_intercept_from_user_intercept_list(&worker->userintercepts, found); free(found->username); @@ -325,8 +315,6 @@ static void push_gtp_session_over(openli_gtp_worker_t *worker, * the IP address(es) that belongs to that session. */ HASH_ITER(hh_user, userint->intlist, ipint, tmp) { - printf("DEVDEBUG: %d ENDING SESSION: %s %s\n", worker->workerid, - ipint->common.liid, (char *)sess->sessionid); HASH_ITER(hh, queues, sendq, tmpq) { push_session_update_to_collector_queue(sendq->q, ipint, sess, OPENLI_PUSH_HALT_IPINTERCEPT); @@ -357,8 +345,6 @@ static void newly_active_gtp_session(openli_gtp_worker_t *worker, * newly active session. */ HASH_ITER(hh_user, userint->intlist, ipint, tmp) { - printf("DEVDEBUG: %d NEW SESSION: %s %s\n", worker->workerid, - ipint->common.liid, (char *)sess->sessionid); HASH_ITER(hh, (sync_sendq_t *)(worker->collector_queues), sendq, tmpq) { push_session_ips_to_collector_queue(sendq->q, ipint, sess); @@ -383,6 +369,10 @@ static void create_iri_from_gtp_action(openli_gtp_worker_t *worker, ipintercept_t *ipint, access_session_t *sess, void *parseddata) { struct timeval now; + access_plugin_t *p = worker->gtpplugin; + openli_export_recv_t *irimsg; + int tracker = ipint->common.seqtrackerid; + int ret; if (ipint->common.tomediate == OPENLI_INTERCEPT_OUTPUTS_CCONLY) { return; @@ -393,12 +383,35 @@ static void create_iri_from_gtp_action(openli_gtp_worker_t *worker, return; } - /* TODO */ - - /* Determine if this requires a UMTS or EPS (or some other?) IRI */ - + irimsg = (openli_export_recv_t *)calloc(1, sizeof(openli_export_recv_t)); + irimsg->type = gtp_get_parsed_version(parseddata) == 1 ? + OPENLI_EXPORT_UMTSIRI : OPENLI_EXPORT_EPSIRI; + irimsg->destid = ipint->common.destid; + irimsg->data.mobiri.liid = strdup(ipint->common.liid); + irimsg->data.mobiri.cin = sess->cin; + irimsg->data.mobiri.iritype = ETSILI_IRI_NONE; + irimsg->data.mobiri.customparams = NULL; + ret = p->generate_iri_data(p, parseddata, + &(irimsg->data.mobiri.customparams), + &(irimsg->data.mobiri.iritype), worker->freegenerics, 0); + if (ret == -1) { + logger(LOG_INFO, + "OpenLI: error while creating IRI from GTP session state change for %s (worker=%d)", irimsg->data.mobiri.liid, worker->workerid); + free(irimsg->data.mobiri.liid); + free(irimsg); + return; + } + if (irimsg->data.mobiri.iritype == ETSILI_IRI_NONE) { + free(irimsg->data.mobiri.liid); + free(irimsg); + return; + } + pthread_mutex_lock(worker->stats_mutex); + worker->stats->mobiri_created ++; + pthread_mutex_unlock(worker->stats_mutex); + publish_openli_msg(worker->zmq_pubsocks[tracker], irimsg); } static void generate_encoding_jobs(openli_gtp_worker_t *worker, @@ -477,19 +490,14 @@ static void process_gtp_c_packet(openli_gtp_worker_t *worker, continue; } - printf("IDCHECK: %s %s %d %d\n", iuser->userid, - (char *)sess->sessionid, oldstate, newstate); - HASH_FIND(hh, worker->userintercepts, iuser->userid, strlen(iuser->userid), userint); if (oldstate != newstate) { if (newstate == SESSION_STATE_ACTIVE) { - printf("ACTIVE: %s\n", (char *)sess->sessionid); newly_active_gtp_session(worker, userint, sess); } else if (newstate == SESSION_STATE_OVER) { - printf("OVER: %s\n", (char *)sess->sessionid); push_gtp_session_over(worker, userint, sess); } @@ -762,6 +770,7 @@ void *gtp_thread_begin(void *arg) { clear_user_intercept_list(worker->userintercepts); free_all_ipintercepts(&(worker->ipintercepts)); clear_zmq_socket_array(worker->zmq_pubsocks, worker->tracker_threads); + free_etsili_generics(worker->freegenerics); if (worker->gtpplugin) { destroy_gtp_access_plugin(worker->gtpplugin); @@ -793,6 +802,7 @@ int start_gtp_worker_thread(openli_gtp_worker_t *worker, int id, worker->allusers = NULL; worker->userintercepts = NULL; worker->gtpplugin = get_gtp_access_plugin(); + worker->freegenerics = create_etsili_generic_freelist(1); pthread_create(&(worker->threadid), NULL, gtp_thread_begin, (void *)worker); diff --git a/src/collector/gtp_worker.h b/src/collector/gtp_worker.h index 63832d7..002af27 100644 --- a/src/collector/gtp_worker.h +++ b/src/collector/gtp_worker.h @@ -27,6 +27,7 @@ #ifndef OPENLI_GTP_WORKER_H_ #define OPENLI_GTP_WORKER_H_ +#include "gtp.h" #include "intercept.h" #include "collector_base.h" #include "collector_util.h" @@ -88,6 +89,11 @@ typedef struct openli_gtp_worker { */ access_plugin_t *gtpplugin; + /* Free list of ETSILI generic IEs that have been used for encoding + * fields in previous ETSI records by this thread instance. + */ + etsili_generic_freelist_t *freegenerics; + } openli_gtp_worker_t; int start_gtp_worker_thread(openli_gtp_worker_t *worker, int id, diff --git a/src/collector/internetaccess.h b/src/collector/internetaccess.h index 7e3b3cb..c984499 100644 --- a/src/collector/internetaccess.h +++ b/src/collector/internetaccess.h @@ -37,42 +37,6 @@ #define SESSION_IP_INCR (5) -/* Need these GTP header definitions in multiple places, so they go in - * here rather than being confined to the GTP plugin... - */ -typedef struct gtpv1_header { - uint8_t octet1; - uint8_t msgtype; - uint16_t msglen; - uint32_t teid; - uint16_t seqno; - uint8_t npdu; - uint8_t next_ext; -} PACKED gtpv1_header_t; - -typedef struct gtpv2_header_teid { - uint8_t octet1; - uint8_t msgtype; - uint16_t msglen; - uint32_t teid; - uint32_t seqno; -} PACKED gtpv2_header_teid_t; - -enum { - GTPV1_CREATE_PDP_CONTEXT_REQUEST = 16, - GTPV1_CREATE_PDP_CONTEXT_RESPONSE = 17, - GTPV1_UPDATE_PDP_CONTEXT_REQUEST = 18, - GTPV1_UPDATE_PDP_CONTEXT_RESPONSE = 19, - GTPV1_DELETE_PDP_CONTEXT_REQUEST = 20, - GTPV1_DELETE_PDP_CONTEXT_RESPONSE = 21, - - GTPV2_CREATE_SESSION_REQUEST = 32, - GTPV2_CREATE_SESSION_RESPONSE = 33, - GTPV2_DELETE_SESSION_REQUEST = 36, - GTPV2_DELETE_SESSION_RESPONSE = 37, -}; - - enum { ACCESS_RADIUS, ACCESS_GTP, From 068e0bd67335f6008ca49fae271da1ce46324369 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Thu, 27 Jun 2024 16:46:22 +1200 Subject: [PATCH 12/44] Initial implementation of EPS IRI generation and encoding Still needs plenty of testing and does NOT yet include the encoding of the EPS-GTPv2-SpecificParameters sequence, but the bulk of the code is now present. --- src/Makefile.am | 1 + src/collector/accessplugins/gtp.c | 220 ++++++++++++++- src/collector/collector_publish.h | 4 +- src/collector/collector_seqtracker.c | 3 + src/collector/encoder_worker.c | 82 +++++- src/collector/epsiri.h | 84 ++++++ src/collector/etsiencoding/encryptcontainer.c | 1 + src/collector/etsiencoding/epsiri.c | 254 ++++++++++++++++++ src/collector/etsiencoding/etsiencoding.c | 1 + src/collector/gtp_worker.c | 8 +- src/etsili_core.c | 18 +- src/etsili_core.h | 6 + 12 files changed, 660 insertions(+), 22 deletions(-) create mode 100644 src/collector/epsiri.h create mode 100644 src/collector/etsiencoding/epsiri.c diff --git a/src/Makefile.am b/src/Makefile.am index 8a4788b..6a06fdf 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -71,6 +71,7 @@ openlicollector_SOURCES=collector/collector.c configparser.c configparser.h \ collector/etsiencoding/etsiencoding.c \ collector/etsiencoding/encryptcontainer.c \ collector/etsiencoding/ipmmiri.c \ + collector/etsiencoding/epsiri.c collector/epsiri.h \ collector/sms_worker.c collector/sms_worker.h \ collector/gtp_worker.c collector/gtp_worker.h \ collector/gtp.h \ diff --git a/src/collector/accessplugins/gtp.c b/src/collector/accessplugins/gtp.c index 04fb24a..b91ed46 100644 --- a/src/collector/accessplugins/gtp.c +++ b/src/collector/accessplugins/gtp.c @@ -34,6 +34,7 @@ #include "internetaccess.h" #include "util.h" #include "gtp.h" +#include "epsiri.h" #define GTP_FLUSH_OLD_PKT_FREQ 180 @@ -127,6 +128,7 @@ typedef struct gtp_session { uint8_t pdpaddrcount; uint16_t pdptype; int64_t cin; + uint8_t gtpversion; uint8_t serverid[16]; uint8_t serveripfamily; @@ -1039,6 +1041,7 @@ static user_identity_t *gtp_get_userid(access_plugin_t *p, void *parsed, sess->pdpaddrs = NULL; sess->pdpaddrcount = 0; sess->refcount = 0; + sess->gtpversion = gparsed->version; memcpy(sess->serverid, gparsed->serverid, 16); sess->serveripfamily = gparsed->serveripfamily; @@ -1293,7 +1296,7 @@ static void apply_gtp_fsm_logic(gtp_parsed_t *gparsed, access_action_t *action, *action = ACCESS_ACTION_END; } else if (current == SESSION_STATE_ACTIVE && (gpkt->type == GTPV1_UPDATE_PDP_CONTEXT_RESPONSE)) { - *action = ACCESS_ACTION_INTERIM_UPDATE; + *action = ACCESS_ACTION_MODIFIED; } gparsed->matched_session->current = current; @@ -1589,6 +1592,154 @@ static void parse_uli_v2(uint8_t *locinfo, } +static int gtp_create_eps_generic_iri(gtp_parsed_t *gparsed, + gtp_session_t *gsess, + etsili_generic_t **params, etsili_generic_freelist_t *freelist, + uint32_t evtype) { + + etsili_generic_t *np; + etsili_ipaddress_t ipaddr; + uint32_t initiator = 1; + struct timeval tv; + /* + * - EVENT_TIME = timestamp + * - INITIATOR + * - IMEI + * - IMSI + * - MSISDN + * - EVENT_TYPE + * - APN + * - PDN Address type and addresses + * - Operator Identifier (added later by encoder thread) + * - Correlation Number = CIN + * + * RAW INFORMATION ELEMENTS REQUIRED + * + * PDN Address Allocation + * APN + * PDN Type + * Bearer QOS + * Bearer activation type + * APN-AMBR + * Protocol Configuration Options + * Bearer ID + * Procedure Transaction Identifier ? + * RAT Type + * + */ + + if (gsess->serveripfamily == 4) { + etsili_create_ipaddress_v4((uint32_t *)(gsess->serverid), + ETSILI_IPV4_SUBNET_UNKNOWN, ETSILI_IPADDRESS_ASSIGNED_UNKNOWN, + &ipaddr); + } else { + etsili_create_ipaddress_v6((uint8_t *)(gsess->serverid), + ETSILI_IPV6_SUBNET_UNKNOWN, ETSILI_IPADDRESS_ASSIGNED_UNKNOWN, + &ipaddr); + } + + np = create_etsili_generic(freelist, EPSIRI_CONTENTS_GGSN_IPADDRESS, + sizeof(etsili_ipaddress_t), (uint8_t *)&ipaddr); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), np); + + np = create_etsili_generic(freelist, EPSIRI_CONTENTS_IMSI, + gsess->saved.imsi_len, (uint8_t *)gsess->saved.imsi); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), np); + + np = create_etsili_generic(freelist, EPSIRI_CONTENTS_IMEI, + gsess->saved.imei_len, (uint8_t *)gsess->saved.imei); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), np); + + np = create_etsili_generic(freelist, EPSIRI_CONTENTS_MSISDN, + gsess->saved.msisdn_len, (uint8_t *)gsess->saved.msisdn); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), np); + + np = create_etsili_generic(freelist, EPSIRI_CONTENTS_APNAME, + gsess->saved.apname_len, (uint8_t *)gsess->saved.apname); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), np); + + /* TODO encode all PDP addresses according to the standards */ + if (gsess->pdpaddrcount > 0) { + if (gsess->pdpaddrs[0].ipfamily == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *) + &(gsess->pdpaddrs[0].assignedip); + + etsili_create_ipaddress_v4((uint32_t *)&(sin->sin_addr.s_addr), + ETSILI_IPV4_SUBNET_UNKNOWN, + ETSILI_IPADDRESS_ASSIGNED_DYNAMIC, + &ipaddr); + } else { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) + &(gsess->pdpaddrs[0].assignedip); + + etsili_create_ipaddress_v6((uint8_t *)(sin6->sin6_addr.s6_addr), + ETSILI_IPV6_SUBNET_UNKNOWN, + ETSILI_IPADDRESS_ASSIGNED_DYNAMIC, + &ipaddr); + } + } + + np = create_etsili_generic(freelist, EPSIRI_CONTENTS_PDP_ADDRESS, + sizeof(etsili_ipaddress_t), (uint8_t *)&ipaddr); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), + np); + + np = create_etsili_generic(freelist, EPSIRI_CONTENTS_PDPTYPE, + sizeof(uint16_t), (uint8_t *)&(gsess->pdptype)); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), + np); + + np = create_etsili_generic(freelist, EPSIRI_CONTENTS_EVENT_TYPE, + sizeof(uint32_t), (uint8_t *)&(evtype)); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), + np); + + np = create_etsili_generic(freelist, EPSIRI_CONTENTS_INITIATOR, + sizeof(uint32_t), (uint8_t *)&(initiator)); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), + np); + + if (gparsed) { + TIMESTAMP_TO_TV((&tv), gparsed->response->tvsec); + np = create_etsili_generic(freelist, EPSIRI_CONTENTS_EVENT_TIME, + sizeof(struct timeval), (uint8_t *)(&tv)); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), + np); + + TIMESTAMP_TO_TV((&tv), gparsed->request->tvsec); + np = create_etsili_generic(freelist, EPSIRI_CONTENTS_LOCATION_TIME, + sizeof(struct timeval), (uint8_t *)(&tv)); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), + np); + } else { + gettimeofday(&tv, NULL); + np = create_etsili_generic(freelist, EPSIRI_CONTENTS_EVENT_TIME, + sizeof(struct timeval), (uint8_t *)(&tv)); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), + np); + + np = create_etsili_generic(freelist, EPSIRI_CONTENTS_LOCATION_TIME, + sizeof(struct timeval), (uint8_t *)(&tv)); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), + np); + } + + if (gsess->saved.location) { + np = create_etsili_generic(freelist, EPSIRI_CONTENTS_RAW_ULI, + gsess->saved.location_len, gsess->saved.location); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), + np); + } + + np = create_etsili_generic(freelist, EPSIRI_CONTENTS_GPRS_CORRELATION, + sizeof(int64_t), (uint8_t *)(&(gsess->cin))); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), + np); + + + return 0; +} + static int gtp_create_umts_generic_iri(gtp_parsed_t *gparsed, gtp_session_t *gsess, etsili_generic_t **params, etsili_generic_freelist_t *freelist, @@ -1762,6 +1913,18 @@ static void insert_gtp_cause_as_gprs_error(gtp_infoelem_t *el, } } +static int gtp_create_bearer_deactivation_iri(gtp_parsed_t *gparsed, + etsili_generic_t **params, etsili_generic_freelist_t *freelist) { + + /* + * Bearer deactivation type + * Bearer deactivation cause + */ + + /* TODO */ + return 0; +} + static int gtp_create_context_deactivation_iri(gtp_parsed_t *gparsed, etsili_generic_t **params, etsili_generic_freelist_t *freelist) { @@ -1784,6 +1947,15 @@ static int gtp_create_context_deactivation_iri(gtp_parsed_t *gparsed, return 0; } +static int gtp_create_bearer_activation_failed_iri(gtp_parsed_t *gparsed, + etsili_generic_t **params, etsili_generic_freelist_t *freelist) { + + /* Failed bearer activation reason */ + + /* TODO */ + return 0; +} + static int gtp_create_context_activation_failed_iri(gtp_parsed_t *gparsed, etsili_generic_t **params, etsili_generic_freelist_t *freelist) { @@ -1818,6 +1990,15 @@ static int gtp_create_context_modification_iri(gtp_parsed_t *gparsed, } +static int gtp_create_start_with_bearer_active_iri(gtp_session_t *gsess, + etsili_generic_t **params, etsili_generic_freelist_t *freelist) { + + uint32_t evtype = EPSIRI_EVENT_TYPE_START_WITH_BEARER_ACTIVE; + + gtp_create_eps_generic_iri(NULL, gsess, params, freelist, evtype); + return 0; +} + static int gtp_create_start_with_context_active_iri(gtp_session_t *gsess, etsili_generic_t **params, etsili_generic_freelist_t *freelist) { @@ -1828,6 +2009,16 @@ static int gtp_create_start_with_context_active_iri(gtp_session_t *gsess, return 0; } +static int gtp_create_bearer_activation_iri(gtp_parsed_t *gparsed, + etsili_generic_t **params, etsili_generic_freelist_t *freelist) { + + uint32_t evtype = EPSIRI_EVENT_TYPE_BEARER_ACTIVATION; + + gtp_create_eps_generic_iri(gparsed, gparsed->matched_session, + params, freelist, evtype); + return 0; +} + static int gtp_create_context_activation_iri(gtp_parsed_t *gparsed, etsili_generic_t **params, etsili_generic_freelist_t *freelist) { @@ -1852,6 +2043,11 @@ static int gtp_generate_iri_data(access_plugin_t *p, void *parseddata, freelist) < 0) { return -1; } + if (gparsed->version == 2 && + gtp_create_bearer_activation_iri(gparsed, params, + freelist) < 0) { + return -1; + } return 0; } else if (gparsed->action == ACCESS_ACTION_REJECT) { @@ -1861,17 +2057,27 @@ static int gtp_generate_iri_data(access_plugin_t *p, void *parseddata, freelist) < 0) { return -1; } + if (gparsed->version == 2 && + gtp_create_bearer_activation_failed_iri(gparsed, params, + freelist) < 0) { + return -1; + } return 0; } - else if (gparsed->action == ACCESS_ACTION_INTERIM_UPDATE) { + else if (gparsed->action == ACCESS_ACTION_MODIFIED) { *iritype = ETSILI_IRI_CONTINUE; if (gparsed->version == 1 && gtp_create_context_modification_iri(gparsed, params, freelist) < 0) { return -1; } + /* TODO GTPv2 bearer modification */ return 0; } + else if (gparsed->action == ACCESS_ACTION_INTERIM_UPDATE) { + /* TODO location updates, anything else that requires a REPORT */ + + } else if (gparsed->action == ACCESS_ACTION_END) { *iritype = ETSILI_IRI_END; if (gparsed->version == 1 && @@ -1879,6 +2085,11 @@ static int gtp_generate_iri_data(access_plugin_t *p, void *parseddata, freelist) < 0) { return -1; } + if (gparsed->version == 2 && + gtp_create_bearer_deactivation_iri(gparsed, params, + freelist) < 0) { + return -1; + } return 0; } else { return 0; @@ -1908,8 +2119,9 @@ static int gtp_generate_iri_from_session(access_plugin_t *p, if (trigger == OPENLI_IPIRI_STARTWHILEACTIVE) { *iritype = ETSILI_IRI_BEGIN; - if (gtp_create_start_with_context_active_iri(gsess, params, freelist) - < 0) { + if (gsess->gtpversion == 1 && + gtp_create_start_with_context_active_iri(gsess, params, + freelist) < 0) { return -1; } } diff --git a/src/collector/collector_publish.h b/src/collector/collector_publish.h index 44c833e..ad5c904 100644 --- a/src/collector/collector_publish.h +++ b/src/collector/collector_publish.h @@ -61,8 +61,8 @@ enum { OPENLI_EXPORT_EMAILIRI = 22, OPENLI_EXPORT_RAW_CC = 23, OPENLI_EXPORT_RAW_IRI = 24, - OPENLI_EXPORT_EPSCC = 16, - OPENLI_EXPORT_EPSIRI = 17, + OPENLI_EXPORT_EPSCC = 25, + OPENLI_EXPORT_EPSIRI = 26, }; /* This structure is also used for IPMMCCs since they require the same diff --git a/src/collector/collector_seqtracker.c b/src/collector/collector_seqtracker.c index ce0077e..4f9add5 100644 --- a/src/collector/collector_seqtracker.c +++ b/src/collector/collector_seqtracker.c @@ -73,6 +73,7 @@ static inline char *extract_liid_from_job(openli_export_recv_t *recvd) { case OPENLI_EXPORT_IPMMIRI: return recvd->data.ipmmiri.liid; case OPENLI_EXPORT_UMTSIRI: + case OPENLI_EXPORT_EPSIRI: return recvd->data.mobiri.liid; case OPENLI_EXPORT_RAW_SYNC: case OPENLI_EXPORT_RAW_CC: @@ -98,6 +99,7 @@ static inline uint32_t extract_cin_from_job(openli_export_recv_t *recvd) { case OPENLI_EXPORT_IPMMIRI: return recvd->data.ipmmiri.cin; case OPENLI_EXPORT_UMTSIRI: + case OPENLI_EXPORT_EPSIRI: return recvd->data.mobiri.cin; case OPENLI_EXPORT_RAW_SYNC: case OPENLI_EXPORT_RAW_IRI: @@ -473,6 +475,7 @@ static void seqtracker_main(seqtracker_thread_data_t *seqdata) { case OPENLI_EXPORT_IPIRI: case OPENLI_EXPORT_UMTSCC: case OPENLI_EXPORT_UMTSIRI: + case OPENLI_EXPORT_EPSIRI: case OPENLI_EXPORT_EMAILIRI: case OPENLI_EXPORT_EMAILCC: case OPENLI_EXPORT_RAW_SYNC: diff --git a/src/collector/encoder_worker.c b/src/collector/encoder_worker.c index 85151bb..fe5e142 100644 --- a/src/collector/encoder_worker.c +++ b/src/collector/encoder_worker.c @@ -32,6 +32,7 @@ #include "ipcc.h" #include "ipmmiri.h" #include "umtsiri.h" +#include "epsiri.h" #include "emailiri.h" #include "collector_base.h" #include "logger.h" @@ -152,7 +153,7 @@ static void free_encoded_header_templates(Pvoid_t headers) { } } -static void free_umtsiri_parameters(etsili_generic_t *params) { +static void free_mobileiri_parameters(etsili_generic_t *params) { etsili_generic_t *oldp, *tmp; @@ -481,13 +482,10 @@ static int encode_templated_emailiri(openli_encoder_t *enc, return 1; } -static int encode_templated_umtsiri(openli_encoder_t *enc, - openli_encoding_job_t *job, encoded_header_template_t *hdr_tplate, - openli_encoded_result_t *res) { +static inline void create_mobile_operator_identifier(openli_encoder_t *enc, + openli_mobiri_job_t *irijob, int elem_id) { + - wandder_encoded_result_t *body = NULL; - openli_mobiri_job_t *irijob = - (openli_mobiri_job_t *)&(job->origreq->data.mobiri); etsili_generic_t *np = NULL; char opid[6]; int opidlen; @@ -506,12 +504,73 @@ static int encode_templated_umtsiri(openli_encoder_t *enc, opid[opidlen] = '\0'; pthread_rwlock_unlock(enc->shared_mutex); - np = create_etsili_generic(enc->freegenerics, - UMTSIRI_CONTENTS_OPERATOR_IDENTIFIER, opidlen, + np = create_etsili_generic(enc->freegenerics, elem_id, opidlen, (uint8_t *)opid); HASH_ADD_KEYPTR(hh, irijob->customparams, &(np->itemnum), sizeof(np->itemnum), np); +} + +static int encode_templated_epsiri(openli_encoder_t *enc, + openli_encoding_job_t *job, encoded_header_template_t *hdr_tplate, + openli_encoded_result_t *res) { + + wandder_encoded_result_t *body = NULL; + openli_mobiri_job_t *irijob = + (openli_mobiri_job_t *)&(job->origreq->data.mobiri); + + create_mobile_operator_identifier(enc, irijob, + EPSIRI_CONTENTS_OPERATOR_IDENTIFIER); + + /* Not worth trying to template the body of EPS IRIs -- way too + * many variables in here that may or may not change on a semi-regular + * basis. + */ + reset_wandder_encoder(enc->encoder); + + body = encode_epsiri_body(enc->encoder, job->preencoded, irijob->iritype, + irijob->customparams); + + if (body == NULL || body->len == 0 || body->encoded == NULL) { + logger(LOG_INFO, "OpenLI: failed to encode ETSI EPSIRI body"); + if (body) { + wandder_release_encoded_result(enc->encoder, body); + } + return -1; + } + + if (job->encryptmethod != OPENLI_PAYLOAD_ENCRYPTION_NONE) { + if (create_encrypted_message_body(enc->encoder, &enc->encrypt, + res, hdr_tplate, + body->encoded, body->len, NULL, 0, job) < 0) { + + wandder_release_encoded_result(enc->encoder, body); + return -1; + } + } else { + if (create_etsi_encoded_result(res, hdr_tplate, body->encoded, + body->len, NULL, 0, job) < 0) { + wandder_release_encoded_result(enc->encoder, body); + return -1; + } + } + + wandder_release_encoded_result(enc->encoder, body); + free_mobileiri_parameters(irijob->customparams); + /* Success */ + return 1; +} + +static int encode_templated_umtsiri(openli_encoder_t *enc, + openli_encoding_job_t *job, encoded_header_template_t *hdr_tplate, + openli_encoded_result_t *res) { + + wandder_encoded_result_t *body = NULL; + openli_mobiri_job_t *irijob = + (openli_mobiri_job_t *)&(job->origreq->data.mobiri); + + create_mobile_operator_identifier(enc, irijob, + UMTSIRI_CONTENTS_OPERATOR_IDENTIFIER); /* Not worth trying to template the body of UMTS IRIs -- way too * many variables in here that may or may not change on a semi-regular * basis. @@ -548,7 +607,7 @@ static int encode_templated_umtsiri(openli_encoder_t *enc, } wandder_release_encoded_result(enc->encoder, body); - free_umtsiri_parameters(irijob->customparams); + free_mobileiri_parameters(irijob->customparams); /* Success */ return 1; } @@ -823,6 +882,9 @@ static int encode_etsi(openli_encoder_t *enc, openli_encoding_job_t *job, case OPENLI_EXPORT_UMTSIRI: ret = encode_templated_umtsiri(enc, job, hdr_tplate, res); break; + case OPENLI_EXPORT_EPSIRI: + ret = encode_templated_epsiri(enc, job, hdr_tplate, res); + break; case OPENLI_EXPORT_EMAILIRI: ret = encode_templated_emailiri(enc, job, hdr_tplate, res); break; diff --git a/src/collector/epsiri.h b/src/collector/epsiri.h new file mode 100644 index 0000000..8fa2da9 --- /dev/null +++ b/src/collector/epsiri.h @@ -0,0 +1,84 @@ +/* + * + * Copyright (c) 2024 SearchLight New Zealand. + * All rights reserved. + * + * This file is part of OpenLI. + * + * OpenLI was originally developed by the University of Waikato WAND + * research group. For further information please see http://www.wand.net.nz/ + * + * OpenLI is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenLI 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, see . + * + * + */ + +#ifndef OPENLI_EPSIRI_H_ +#define OPENLI_EPSIRI_H_ + +#include +#include +#include "collector.h" +#include "intercept.h" +#include "internetaccess.h" +#include "etsili_core.h" +#include "collector_sync.h" + +enum { + EPSIRI_CONTENTS_IMSI = 1, + EPSIRI_CONTENTS_MSISDN = 2, + EPSIRI_CONTENTS_IMEI = 3, + EPSIRI_CONTENTS_APNAME = 4, + EPSIRI_CONTENTS_PDP_ADDRESS = 7, + EPSIRI_CONTENTS_EVENT_TYPE = 8, + EPSIRI_CONTENTS_EVENT_TIME = 9, + EPSIRI_CONTENTS_LOCATION_TIME = 10, + EPSIRI_CONTENTS_GPRS_CORRELATION = 11, + EPSIRI_CONTENTS_GGSN_IPADDRESS = 14, + EPSIRI_CONTENTS_INITIATOR = 15, + EPSIRI_CONTENTS_OPERATOR_IDENTIFIER = 16, + EPSIRI_CONTENTS_PDPTYPE = 17, + + /* separate the fields that are a direct copy of the IE from the + * GTPv2 header -- these go in the EPS-GTPV2-SpecificParameters + * sequence in the EPS IRI + */ + EPSIRI_CONTENTS_RAW_ULI = 101, + EPSIRI_CONTENTS_RAW_RAT_TYPE = 102, + EPSIRI_CONTENTS_RAW_BEARER_QOS = 103, + EPSIRI_CONTENTS_RAW_BEARER_ACTIVATION_TYPE = 104, + EPSIRI_CONTENTS_RAW_APN_AMBR = 105, + EPSIRI_CONTENTS_RAW_PROTOCOL_CONFIG = 106, + EPSIRI_CONTENTS_RAW_BEARER_ID = 107, + EPSIRI_CONTENTS_RAW_PROCEDURE_TRANSACTION = 108, + EPSIRI_CONTENTS_RAW_PDN_ADDRESS_ALLOCATION = 109, + EPSIRI_CONTENTS_RAW_PDN_TYPE = 110, + EPSIRI_CONTENTS_RAW_APN = 111, + EPSIRI_CONTENTS_RAW_FAILED_BEARER_ACTIVATION_REASON = 112, + EPSIRI_CONTENTS_RAW_ATTACH_TYPE = 113, + EPSIRI_CONTENTS_RAW_DETACH_TYPE = 114, +}; + +enum { + EPSIRI_EVENT_TYPE_BEARER_ACTIVATION = 18, + EPSIRI_EVENT_TYPE_START_WITH_BEARER_ACTIVE = 19, + EPSIRI_EVENT_TYPE_BEARER_MODIFICATION = 20, + EPSIRI_EVENT_TYPE_BEARER_DEACTIVATION = 21, + EPSIRI_EVENT_TYPE_UE_REQUESTED_BEARER_RESOURCE_MODIFICATION = 22, +}; + + +#endif +// vim: set sw=4 tabstop=4 softtabstop=4 expandtab : + diff --git a/src/collector/etsiencoding/encryptcontainer.c b/src/collector/etsiencoding/encryptcontainer.c index e7cbe76..67b2594 100644 --- a/src/collector/etsiencoding/encryptcontainer.c +++ b/src/collector/etsiencoding/encryptcontainer.c @@ -65,6 +65,7 @@ static inline uint32_t job_origreq_to_encrypted_payload_type( return OPENLI_ENCRYPTED_PAYLOAD_TYPE_PART3; case OPENLI_EXPORT_UMTSCC: case OPENLI_EXPORT_UMTSIRI: + case OPENLI_EXPORT_EPSIRI: return OPENLI_ENCRYPTED_PAYLOAD_TYPE_PART7; case OPENLI_EXPORT_IPMMCC: case OPENLI_EXPORT_IPMMIRI: diff --git a/src/collector/etsiencoding/epsiri.c b/src/collector/etsiencoding/epsiri.c new file mode 100644 index 0000000..bbf62ff --- /dev/null +++ b/src/collector/etsiencoding/epsiri.c @@ -0,0 +1,254 @@ +/* + * + * Copyright (c) 2024 SearchLight NZ + * All rights reserved. + * + * This file is part of OpenLI. + * + * OpenLI was originally developed by the University of Waikato WAND + * research group. For further information please see http://www.wand.net.nz/ + * + * OpenLI is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenLI 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, see . + * + * + */ + +#include +#include "etsiencoding.h" +#include "logger.h" +#include "intercept.h" +#include "etsili_core.h" +#include "location.h" +#include "epsiri.h" + +wandder_encoded_result_t *encode_epsiri_body(wandder_encoder_t *encoder, + wandder_encode_job_t *precomputed, + etsili_iri_type_t iritype, etsili_generic_t *params) { + + wandder_encode_job_t *jobarray[6]; + etsili_generic_t *p, *savedtime; + uint8_t lookup; + uint32_t iriversion = 8; + uint32_t gprstarget = 3; + + jobarray[0] = &(precomputed[OPENLI_PREENCODE_CSEQUENCE_2]); + jobarray[1] = &(precomputed[OPENLI_PREENCODE_CSEQUENCE_0]); + jobarray[2] = &(precomputed[OPENLI_PREENCODE_USEQUENCE]); + wandder_encode_next_preencoded(encoder, jobarray, 3); + + wandder_encode_next(encoder, WANDDER_TAG_ENUM, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 0, &iritype, + sizeof(iritype)); + + /* timeStamp -- as generalized time */ + lookup = EPSIRI_CONTENTS_EVENT_TIME; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + wandder_encode_next(encoder, WANDDER_TAG_GENERALTIME, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 1, + p->itemptr, p->itemlen); + savedtime = p; + } else { + savedtime = NULL; + logger(LOG_INFO, + "OpenLI: warning, no timestamp available for building EPS IRI"); + logger(LOG_INFO, "OpenLI: EPS IRI record may be invalid..."); + } + + jobarray[0] = &(precomputed[OPENLI_PREENCODE_CSEQUENCE_2]); + jobarray[1] = &(precomputed[OPENLI_PREENCODE_CSEQUENCE_15]); + jobarray[2] = &(precomputed[OPENLI_PREENCODE_CSEQUENCE_0]); + + /* IRI-Parameters start here */ + + /* Object identifier (0) */ + jobarray[3] = &(precomputed[OPENLI_PREENCODE_EPSIRIOID]); + + /* LIID (1) -- fortunately the identifier matches the one + * used in the PSHeader, so we can use our preencoded + * version */ + + jobarray[4] = &(precomputed[OPENLI_PREENCODE_LIID]); + + /* timeStamp again (3) -- different format, use UTCTime */ + jobarray[5] = &(precomputed[OPENLI_PREENCODE_CSEQUENCE_3]); + wandder_encode_next_preencoded(encoder, jobarray, 6); + + if (savedtime) { + wandder_encode_next(encoder, WANDDER_TAG_UTCTIME, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 1, + savedtime->itemptr, savedtime->itemlen); + } + END_ENCODED_SEQUENCE(encoder, 1); + + /* initiator (4) */ + lookup = EPSIRI_CONTENTS_INITIATOR; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (!p) { + logger(LOG_INFO, + "OpenLI: warning, no initiator available for building EPS IRI"); + logger(LOG_INFO, "OpenLI: EPS IRI record may be invalid..."); + } else { + wandder_encode_next(encoder, WANDDER_TAG_ENUM, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 4, + p->itemptr, p->itemlen); + } + + /* skip locationOfTheTarget (8) because we're going to encode it later + * on inside ePS-GTPV2-specificParameters as a ULI info element */ + + /* party information (9) -- nested */ + ENC_CSEQUENCE(encoder, 9); + wandder_encode_next(encoder, WANDDER_TAG_ENUM, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 0, &gprstarget, sizeof(gprstarget)); + ENC_CSEQUENCE(encoder, 1); + + lookup = EPSIRI_CONTENTS_IMEI; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 1, p->itemptr, p->itemlen); + } else { + logger(LOG_INFO, + "OpenLI: warning, no IMEI available for building EPS IRI"); + logger(LOG_INFO, "OpenLI: EPS IRI record may be invalid..."); + } + + lookup = EPSIRI_CONTENTS_IMSI; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 3, p->itemptr, p->itemlen); + } else { + logger(LOG_INFO, + "OpenLI: warning, no IMSI available for building EPS IRI"); + logger(LOG_INFO, "OpenLI: EPS IRI record may be invalid..."); + } + + + lookup = EPSIRI_CONTENTS_MSISDN; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 6, p->itemptr, p->itemlen); + } else { + logger(LOG_INFO, + "OpenLI: warning, no MSISDN available for building EPS IRI"); + logger(LOG_INFO, "OpenLI: EPS IRI record may be invalid..."); + } + + END_ENCODED_SEQUENCE(encoder, 1); + + /* servicesDataInformation (pdpAddress, APN etc) */ + ENC_CSEQUENCE(encoder, 4); // services-data-information + ENC_CSEQUENCE(encoder, 1); // gprs-parameters + + + lookup = EPSIRI_CONTENTS_PDP_ADDRESS; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + ENC_CSEQUENCE(encoder, 1); // pdp-address + ENC_CSEQUENCE(encoder, 1); // datanodeaddress + encode_ipaddress(encoder, (etsili_ipaddress_t *)(p->itemptr)); + END_ENCODED_SEQUENCE(encoder, 2); + } + + lookup = EPSIRI_CONTENTS_APNAME; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 2, p->itemptr, p->itemlen); + } + + lookup = EPSIRI_CONTENTS_PDPTYPE; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 3, p->itemptr, p->itemlen); + } + + END_ENCODED_SEQUENCE(encoder, 3); + + /* gprs correlation number (18) */ + lookup = EPSIRI_CONTENTS_GPRS_CORRELATION; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (!p) { + logger(LOG_INFO, + "OpenLI: warning, no GPRS correlation number available for building EPS IRI"); + logger(LOG_INFO, "OpenLI: EPS IRI record may be invalid..."); + } else { + char space[24]; + snprintf(space, 24, "%lu", *((uint64_t *)(p->itemptr))); + + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 18, space, strlen(space)); + } + + /* EPS event (20) */ + lookup = EPSIRI_CONTENTS_EVENT_TYPE; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (!p) { + logger(LOG_INFO, + "OpenLI: warning, no EPS event type available for building EPS IRI"); + logger(LOG_INFO, "OpenLI: EPS IRI record may be invalid..."); + } else { + wandder_encode_next(encoder, WANDDER_TAG_ENUM, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 20, p->itemptr, p->itemlen); + } + + /* ggsnAddress (25) -- also appears in networkIdentifier, but why not... */ + ENC_CSEQUENCE(encoder, 25); + lookup = EPSIRI_CONTENTS_GGSN_IPADDRESS; + + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + ENC_CSEQUENCE(encoder, 1); + ENC_CSEQUENCE(encoder, 5); + encode_ipaddress(encoder, (etsili_ipaddress_t *)(p->itemptr)); + END_ENCODED_SEQUENCE(encoder, 2); + } + END_ENCODED_SEQUENCE(encoder, 1); + + /* networkIdentifier (26) -- nested */ + ENC_CSEQUENCE(encoder, 26); + + lookup = EPSIRI_CONTENTS_OPERATOR_IDENTIFIER; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 0, p->itemptr, p->itemlen); + } else { + logger(LOG_INFO, + "OpenLI: warning, no operator identifier available for building EPS IRI"); + logger(LOG_INFO, "OpenLI: EPS IRI record may be invalid..."); + } + + lookup = EPSIRI_CONTENTS_GGSN_IPADDRESS; + + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + ENC_CSEQUENCE(encoder, 1); + ENC_CSEQUENCE(encoder, 5); + encode_ipaddress(encoder, (etsili_ipaddress_t *)(p->itemptr)); + END_ENCODED_SEQUENCE(encoder, 2); + } + END_ENCODED_SEQUENCE(encoder, 1); + + /* eps-GTPV2-specificParameters (36) */ + ENC_CSEQUENCE(encoder, 36); + + + END_ENCODED_SEQUENCE(encoder, 7); + return wandder_encode_finish(encoder); +} diff --git a/src/collector/etsiencoding/etsiencoding.c b/src/collector/etsiencoding/etsiencoding.c index aa39ed0..0ba0dae 100644 --- a/src/collector/etsiencoding/etsiencoding.c +++ b/src/collector/etsiencoding/etsiencoding.c @@ -171,6 +171,7 @@ int create_etsi_encoded_result(openli_encoded_result_t *res, case OPENLI_EXPORT_IPIRI: case OPENLI_EXPORT_IPMMIRI: case OPENLI_EXPORT_UMTSIRI: + case OPENLI_EXPORT_EPSIRI: case OPENLI_EXPORT_EMAILIRI: res->header.intercepttype = htons(OPENLI_PROTO_ETSI_IRI); break; diff --git a/src/collector/gtp_worker.c b/src/collector/gtp_worker.c index cd76f79..88c4d23 100644 --- a/src/collector/gtp_worker.c +++ b/src/collector/gtp_worker.c @@ -384,14 +384,18 @@ static void create_iri_from_gtp_action(openli_gtp_worker_t *worker, } irimsg = (openli_export_recv_t *)calloc(1, sizeof(openli_export_recv_t)); - irimsg->type = gtp_get_parsed_version(parseddata) == 1 ? - OPENLI_EXPORT_UMTSIRI : OPENLI_EXPORT_EPSIRI; irimsg->destid = ipint->common.destid; irimsg->data.mobiri.liid = strdup(ipint->common.liid); irimsg->data.mobiri.cin = sess->cin; irimsg->data.mobiri.iritype = ETSILI_IRI_NONE; irimsg->data.mobiri.customparams = NULL; + if (gtp_get_parsed_version(parseddata) == 1) { + irimsg->type = OPENLI_EXPORT_UMTSIRI; + } else { + irimsg->type = OPENLI_EXPORT_EPSIRI; + } + ret = p->generate_iri_data(p, parseddata, &(irimsg->data.mobiri.customparams), &(irimsg->data.mobiri.iritype), worker->freegenerics, 0); diff --git a/src/etsili_core.c b/src/etsili_core.c index ffae753..ebb19c5 100644 --- a/src/etsili_core.c +++ b/src/etsili_core.c @@ -42,6 +42,7 @@ uint8_t etsi_emailirioid[4] = {0x05, 0x02, 0x0f, 0x01}; uint8_t etsi_emailccoid[4] = {0x05, 0x02, 0x0f, 0x02}; uint8_t etsi_umtsirioid[9] = {0x00, 0x04, 0x00, 0x02, 0x02, 0x04, 0x01, 0x0f, 0x05}; uint8_t etsi_hi1operationoid[8] = {0x00, 0x04, 0x00, 0x02, 0x02, 0x00, 0x01, 0x06}; +uint8_t etsi_epsirioid[9] = {0x00, 0x04, 0x00, 0x02, 0x02, 0x04, 0x08, 0x11, 0x00}; static inline void encode_tri_body(wandder_encoder_t *encoder) { ENC_CSEQUENCE(encoder, 2); // Payload @@ -455,10 +456,6 @@ wandder_encoded_result_t *encode_umtsiri_body(wandder_encoder_t *encoder, ENC_CSEQUENCE(encoder, 1); // datanodeaddress encode_ipaddress(encoder, (etsili_ipaddress_t *)(p->itemptr)); END_ENCODED_SEQUENCE(encoder, 2); - } else { - logger(LOG_INFO, - "OpenLI: warning, no PDP Address available for constructing UMTS IRI"); - logger(LOG_INFO, "OpenLI: UMTS IRI record may be invalid..."); } /* TODO figure out if we need to include the "length" field in our @@ -1160,6 +1157,13 @@ void etsili_preencode_static_fields( p->valspace = NULL; p->vallen = 0; + p = &(pendarray[OPENLI_PREENCODE_CSEQUENCE_15]); + p->identclass = WANDDER_CLASS_CONTEXT_CONSTRUCT; + p->identifier = 15; + p->encodeas = WANDDER_TAG_SEQUENCE; + p->valspace = NULL; + p->vallen = 0; + p = &(pendarray[OPENLI_PREENCODE_PSDOMAINID]); p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; p->identifier = 0; @@ -1257,6 +1261,12 @@ void etsili_preencode_static_fields( p->encodeas = WANDDER_TAG_OID; wandder_encode_preencoded_value(p, etsi_umtsirioid, sizeof(etsi_umtsirioid)); + p = &(pendarray[OPENLI_PREENCODE_EPSIRIOID]); + p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; + p->identifier = 0; + p->encodeas = WANDDER_TAG_OID; + wandder_encode_preencoded_value(p, etsi_epsirioid, sizeof(etsi_epsirioid)); + p = &(pendarray[OPENLI_PREENCODE_IPMMCCOID]); p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; p->identifier = 0; diff --git a/src/etsili_core.h b/src/etsili_core.h index 849a1fc..c0ac155 100644 --- a/src/etsili_core.h +++ b/src/etsili_core.h @@ -172,6 +172,7 @@ typedef enum { OPENLI_PREENCODE_CSEQUENCE_7, /* Microsecond timestamp */ OPENLI_PREENCODE_CSEQUENCE_11, /* IPMMIRI */ OPENLI_PREENCODE_CSEQUENCE_12, /* IPMMCC */ + OPENLI_PREENCODE_CSEQUENCE_15, /* EPSIRI */ OPENLI_PREENCODE_PSDOMAINID, OPENLI_PREENCODE_LIID, OPENLI_PREENCODE_AUTHCC, @@ -184,6 +185,7 @@ typedef enum { OPENLI_PREENCODE_IPCCOID, OPENLI_PREENCODE_IPIRIOID, OPENLI_PREENCODE_UMTSIRIOID, + OPENLI_PREENCODE_EPSIRIOID, OPENLI_PREENCODE_EMAILIRIOID, OPENLI_PREENCODE_EMAILCCOID, OPENLI_PREENCODE_IPMMCCOID, @@ -255,6 +257,10 @@ wandder_encoded_result_t *encode_umtsiri_body(wandder_encoder_t *encoder, wandder_encode_job_t *precomputed, etsili_iri_type_t iritype, etsili_generic_t *params); +wandder_encoded_result_t *encode_epsiri_body(wandder_encoder_t *encoder, + wandder_encode_job_t *precomputed, + etsili_iri_type_t iritype, etsili_generic_t *params); + wandder_encoded_result_t *encode_emailiri_body(wandder_encoder_t *encoder, wandder_encode_job_t *precomputed, etsili_iri_type_t iritype, etsili_generic_t **params); From 22cff0e4dafe5a14bb9762c79eee2bbf0377e51d Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Wed, 31 Jul 2024 17:06:46 +1200 Subject: [PATCH 13/44] Avoid FD leak in GTP worker thread This is the same type of leak that we had in the SMS thread... --- src/collector/gtp_worker.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/collector/gtp_worker.c b/src/collector/gtp_worker.c index 88c4d23..5cf5141 100644 --- a/src/collector/gtp_worker.c +++ b/src/collector/gtp_worker.c @@ -700,6 +700,7 @@ static void gtp_worker_main(openli_gtp_worker_t *worker) { if (topoll[2].revents & ZMQ_POLLIN) { topoll[2].revents = 0; + close(topoll[2].fd); /* TODO purge "inactive" sessions */ From 133f0d1dd35bbd5a672bef14b311ae5febbe5f3b Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Thu, 1 Aug 2024 18:39:01 +1200 Subject: [PATCH 14/44] Add support to encode the first few EPS-specific IRI fields * PDN Allocated Address * APN * Protocol Configuration Options * EPS Bearer ID * RAT Type Still in the testing phase, and will add further fields once I'm happy with these first few. --- src/collector/accessplugins/gtp.c | 102 ++++++++++++++++++++++++++++ src/collector/epsiri.h | 26 +++---- src/collector/etsiencoding/epsiri.c | 62 ++++++++++++++--- 3 files changed, 166 insertions(+), 24 deletions(-) diff --git a/src/collector/accessplugins/gtp.c b/src/collector/accessplugins/gtp.c index e52ac02..efa2275 100644 --- a/src/collector/accessplugins/gtp.c +++ b/src/collector/accessplugins/gtp.c @@ -57,9 +57,12 @@ enum { GTPV2_IE_APNAME = 71, GTPV2_IE_MEI = 75, GTPV2_IE_MSISDN = 76, + GTPV2_IE_PCO = 78, GTPV2_IE_PDN_ALLOC = 79, + GTPV2_IE_RAT_TYPE = 82, GTPV2_IE_ULI = 86, GTPV2_IE_FTEID = 87, + GTPV2_IE_BEARER_CONTEXT = 93, }; /* TODO add more cause values here */ @@ -381,6 +384,9 @@ static inline bool interesting_info_element(uint8_t gtpv, uint8_t ietype) { case GTPV2_IE_MEI: case GTPV2_IE_APNAME: case GTPV2_IE_ULI: + case GTPV2_IE_BEARER_CONTEXT: + case GTPV2_IE_PCO: + case GTPV2_IE_RAT_TYPE: return true; } } else if (gtpv == 1) { @@ -459,6 +465,55 @@ static inline uint8_t get_cause_from_ie(gtp_infoelem_t *gtpel) { return *((uint8_t *)(gtpel->iecontent)); } +static void walk_bearer_context_ie(etsili_generic_freelist_t *freelist, + gtp_infoelem_t *el, etsili_generic_t **params) { + + uint8_t *ptr = (uint8_t *)el->iecontent; + uint8_t *start = ptr; + uint8_t subtype; + uint16_t sublen; + etsili_generic_t *np; + + /* Need at least 5 bytes for a complete sub-IE (4 for header, plus at + * least one for the value) + */ + while (ptr - start < el->ielength) { + np = NULL; + if (el->ielength - (ptr - start) <= 4) { + logger(LOG_INFO, "OpenLI: incomplete IE header while decoding GTPv2 Bearer Context Information Element"); + break; + } + + subtype = *ptr; + sublen = *(ptr + 1); + sublen = sublen << 8; + sublen += *(ptr + 2); + ptr += 4; + + if (el->ielength - (ptr - start) < sublen) { + logger(LOG_INFO, "OpenLI: truncated IE body while decoding GTPv2 Bearer Context Information Element"); + break; + } + + switch(subtype) { + case 0x49: // EPS Bearer ID + np = create_etsili_generic(freelist, + EPSIRI_CONTENTS_RAW_BEARER_ID, sublen, ptr); + break; + case 0x57: // F-TEID + break; + case 0x50: // Bearer QoS + break; + } + + if (np) { + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), + np); + } + ptr += sublen; + } +} + static inline void get_gtpnum_from_ie(gtp_infoelem_t *gtpel, char *field, int skipfront) { @@ -1615,6 +1670,8 @@ static int gtp_create_eps_generic_iri(gtp_parsed_t *gparsed, etsili_ipaddress_t ipaddr; uint32_t initiator = 1; struct timeval tv; + gtp_infoelem_t *el; + /* * - EVENT_TIME = timestamp * - INITIATOR @@ -1750,6 +1807,51 @@ static int gtp_create_eps_generic_iri(gtp_parsed_t *gparsed, HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), np); + if (gparsed->request) { + el = gparsed->request->ies; + while (el) { + switch(el->ietype) { + case GTPV2_IE_PCO: + np = create_etsili_generic(freelist, + EPSIRI_CONTENTS_RAW_PCO_FROM_UE, el->ielength, + (uint8_t *)(el->iecontent)); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), + sizeof(np->itemnum), np); + break; + case GTPV2_IE_BEARER_CONTEXT: + walk_bearer_context_ie(freelist, el, params); + break; + case GTPV2_IE_RAT_TYPE: + np = create_etsili_generic(freelist, + EPSIRI_CONTENTS_RAW_RAT_TYPE, el->ielength, + (uint8_t *)(el->iecontent)); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), + sizeof(np->itemnum), np); + break; + + } + el = el->next; + } + + } + + if (gparsed->response) { + el = gparsed->response->ies; + while (el) { + switch(el->ietype) { + case GTPV2_IE_PDN_ALLOC: + np = create_etsili_generic(freelist, + EPSIRI_CONTENTS_RAW_PDN_ADDRESS_ALLOCATION, + el->ielength, (uint8_t *)(el->iecontent)); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), + sizeof(np->itemnum), np); + break; + + } + el = el->next; + } + } + return 0; } diff --git a/src/collector/epsiri.h b/src/collector/epsiri.h index 8fa2da9..b993bfe 100644 --- a/src/collector/epsiri.h +++ b/src/collector/epsiri.h @@ -55,19 +55,19 @@ enum { * sequence in the EPS IRI */ EPSIRI_CONTENTS_RAW_ULI = 101, - EPSIRI_CONTENTS_RAW_RAT_TYPE = 102, - EPSIRI_CONTENTS_RAW_BEARER_QOS = 103, - EPSIRI_CONTENTS_RAW_BEARER_ACTIVATION_TYPE = 104, - EPSIRI_CONTENTS_RAW_APN_AMBR = 105, - EPSIRI_CONTENTS_RAW_PROTOCOL_CONFIG = 106, - EPSIRI_CONTENTS_RAW_BEARER_ID = 107, - EPSIRI_CONTENTS_RAW_PROCEDURE_TRANSACTION = 108, - EPSIRI_CONTENTS_RAW_PDN_ADDRESS_ALLOCATION = 109, - EPSIRI_CONTENTS_RAW_PDN_TYPE = 110, - EPSIRI_CONTENTS_RAW_APN = 111, - EPSIRI_CONTENTS_RAW_FAILED_BEARER_ACTIVATION_REASON = 112, - EPSIRI_CONTENTS_RAW_ATTACH_TYPE = 113, - EPSIRI_CONTENTS_RAW_DETACH_TYPE = 114, + EPSIRI_CONTENTS_RAW_RAT_TYPE, + EPSIRI_CONTENTS_RAW_BEARER_QOS, + EPSIRI_CONTENTS_RAW_BEARER_ACTIVATION_TYPE, + EPSIRI_CONTENTS_RAW_APN_AMBR, + EPSIRI_CONTENTS_RAW_PCO_FROM_UE, + EPSIRI_CONTENTS_RAW_PCO_FROM_NETWORK, + EPSIRI_CONTENTS_RAW_BEARER_ID, + EPSIRI_CONTENTS_RAW_PROCEDURE_TRANSACTION, + EPSIRI_CONTENTS_RAW_PDN_ADDRESS_ALLOCATION, + EPSIRI_CONTENTS_RAW_PDN_TYPE, + EPSIRI_CONTENTS_RAW_FAILED_BEARER_ACTIVATION_REASON, + EPSIRI_CONTENTS_RAW_ATTACH_TYPE, + EPSIRI_CONTENTS_RAW_DETACH_TYPE, }; enum { diff --git a/src/collector/etsiencoding/epsiri.c b/src/collector/etsiencoding/epsiri.c index 501ceef..2ce729c 100644 --- a/src/collector/etsiencoding/epsiri.c +++ b/src/collector/etsiencoding/epsiri.c @@ -207,8 +207,8 @@ wandder_encoded_result_t *encode_epsiri_body(wandder_encoder_t *encoder, WANDDER_CLASS_CONTEXT_PRIMITIVE, 20, p->itemptr, p->itemlen); } - /* ggsnAddress (25) -- also appears in networkIdentifier, but why not... */ - ENC_CSEQUENCE(encoder, 25); + /* ggsnAddress (24) -- also appears in networkIdentifier, but why not... */ + ENC_CSEQUENCE(encoder, 24); lookup = EPSIRI_CONTENTS_GGSN_IPADDRESS; HASH_FIND(hh, params, &lookup, sizeof(lookup), p); @@ -218,7 +218,6 @@ wandder_encoded_result_t *encode_epsiri_body(wandder_encoder_t *encoder, encode_ipaddress(encoder, (etsili_ipaddress_t *)(p->itemptr)); END_ENCODED_SEQUENCE(encoder, 2); } - END_ENCODED_SEQUENCE(encoder, 1); /* networkIdentifier (26) -- nested */ ENC_CSEQUENCE(encoder, 26); @@ -234,20 +233,61 @@ wandder_encoded_result_t *encode_epsiri_body(wandder_encoder_t *encoder, logger(LOG_INFO, "OpenLI: EPS IRI record may be invalid..."); } - lookup = EPSIRI_CONTENTS_GGSN_IPADDRESS; + /* eps-GTPV2-specificParameters (36) */ + ENC_CSEQUENCE(encoder, 36); + lookup = EPSIRI_CONTENTS_RAW_PDN_ADDRESS_ALLOCATION; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 1, p->itemptr, p->itemlen); + } + lookup = EPSIRI_CONTENTS_APNAME; HASH_FIND(hh, params, &lookup, sizeof(lookup), p); if (p) { - ENC_CSEQUENCE(encoder, 1); - ENC_CSEQUENCE(encoder, 5); - encode_ipaddress(encoder, (etsili_ipaddress_t *)(p->itemptr)); - END_ENCODED_SEQUENCE(encoder, 2); + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 2, p->itemptr, p->itemlen); } - END_ENCODED_SEQUENCE(encoder, 1); - /* eps-GTPV2-specificParameters (36) */ - ENC_CSEQUENCE(encoder, 36); + /* can we have protconfigoptions from both directions at the same time? + * XXX + */ + lookup = EPSIRI_CONTENTS_RAW_PCO_FROM_UE; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + ENC_CSEQUENCE(encoder, 3); + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 1, p->itemptr, p->itemlen); + END_ENCODED_SEQUENCE(encoder, 1); + } else { + lookup = EPSIRI_CONTENTS_RAW_PCO_FROM_NETWORK; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + ENC_CSEQUENCE(encoder, 3); + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 2, p->itemptr, p->itemlen); + END_ENCODED_SEQUENCE(encoder, 1); + } + } + + /* Attach Type goes here... */ + + lookup = EPSIRI_CONTENTS_RAW_BEARER_ID; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 5, p->itemptr, p->itemlen); + } + + + /* Detach Type goes here... */ + lookup = EPSIRI_CONTENTS_RAW_RAT_TYPE; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 7, p->itemptr, p->itemlen); + } END_ENCODED_SEQUENCE(encoder, 7); return wandder_encode_finish(encoder); From 4b24950f1f8ab6f5b6657022847c5e4ea5a24230 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Mon, 5 Aug 2024 19:13:33 +1200 Subject: [PATCH 15/44] More progress on EPS IRI encoding * fixed some bugs in existing encoding * add support for failedBearerActivationReason, epsBearerQoS and bearerActivationType * GTPv2 sessions now track the "default bearer" ID * populated method for handling session activation failures --- src/collector/accessplugins/gtp.c | 150 +++++++++++++++++++++++++--- src/collector/epsiri.h | 4 +- src/collector/etsiencoding/epsiri.c | 43 +++++++- 3 files changed, 177 insertions(+), 20 deletions(-) diff --git a/src/collector/accessplugins/gtp.c b/src/collector/accessplugins/gtp.c index efa2275..0ba3a24 100644 --- a/src/collector/accessplugins/gtp.c +++ b/src/collector/accessplugins/gtp.c @@ -55,6 +55,7 @@ enum { GTPV2_IE_IMSI = 1, GTPV2_IE_CAUSE = 2, GTPV2_IE_APNAME = 71, + GTPV2_IE_BEARER_ID = 73, GTPV2_IE_MEI = 75, GTPV2_IE_MSISDN = 76, GTPV2_IE_PCO = 78, @@ -145,6 +146,7 @@ typedef struct gtp_session { gtp_saved_pkt_t *lastsavedpkt; int refcount; + uint8_t defaultbearer; } gtp_session_t; @@ -175,6 +177,7 @@ typedef struct gtp_parsed { uint32_t teid_data; uint32_t seqno; uint8_t response_cause; + uint8_t bearerid; uint8_t serveripfamily; uint8_t serverid[16]; @@ -465,8 +468,50 @@ static inline uint8_t get_cause_from_ie(gtp_infoelem_t *gtpel) { return *((uint8_t *)(gtpel->iecontent)); } +static void parse_new_session_bearer_context(gtp_parsed_t *parsedpkt, + gtp_infoelem_t *el) { + + uint8_t *ptr = (uint8_t *)el->iecontent; + uint8_t *start = ptr; + uint8_t subtype; + uint16_t sublen; + uint32_t *teidkey; + + /* Need at least 5 bytes for a complete sub-IE (4 for header, plus at + * least one for the value) + */ + while (ptr - start < el->ielength) { + if (el->ielength - (ptr - start) <= 4) { + logger(LOG_INFO, "OpenLI: incomplete IE header while decoding GTPv2 Bearer Context Information Element"); + break; + } + + subtype = *ptr; + sublen = *(ptr + 1); + sublen = sublen << 8; + sublen += *(ptr + 2); + ptr += 4; + + if (el->ielength - (ptr - start) < sublen) { + logger(LOG_INFO, "OpenLI: truncated IE body while decoding GTPv2 Bearer Context Information Element"); + break; + } + + switch(subtype) { + case 0x49: // EPS Bearer ID + parsedpkt->bearerid = *ptr; + break; + case 0x57: // F-TEID + teidkey = (uint32_t *)(ptr + 1); + parsedpkt->teid_data = ntohl(*teidkey); + break; + } + ptr += sublen; + } +} + static void walk_bearer_context_ie(etsili_generic_freelist_t *freelist, - gtp_infoelem_t *el, etsili_generic_t **params) { + gtp_infoelem_t *el, etsili_generic_t **params, uint8_t is_req) { uint8_t *ptr = (uint8_t *)el->iecontent; uint8_t *start = ptr; @@ -497,12 +542,18 @@ static void walk_bearer_context_ie(etsili_generic_freelist_t *freelist, switch(subtype) { case 0x49: // EPS Bearer ID - np = create_etsili_generic(freelist, - EPSIRI_CONTENTS_RAW_BEARER_ID, sublen, ptr); + if (!is_req) { + np = create_etsili_generic(freelist, + EPSIRI_CONTENTS_RAW_BEARER_ID, sublen, ptr); + } break; case 0x57: // F-TEID break; case 0x50: // Bearer QoS + if (is_req) { + np = create_etsili_generic(freelist, + EPSIRI_CONTENTS_RAW_BEARER_QOS, sublen, ptr); + } break; } @@ -684,6 +735,11 @@ static void walk_gtpv2_ies(gtp_parsed_t *parsedpkt, uint8_t *ptr, uint32_t rem, } } + if (ietype == GTPV2_IE_BEARER_CONTEXT) { + parse_new_session_bearer_context(parsedpkt, gtpel); + } + + if (ietype == GTPV2_IE_FTEID) { parsedpkt->teid_ctl = get_teid_from_fteid(gtpel); } @@ -1052,6 +1108,10 @@ static user_identity_t *gtp_get_userid(access_plugin_t *p, void *parsed, } + if (gparsed->msgtype == GTPV2_CREATE_SESSION_RESPONSE) { + gparsed->matched_session->defaultbearer = gparsed->bearerid; + } + uids = copy_identifiers(gparsed, numberids); return uids; } @@ -1661,13 +1721,30 @@ static void parse_uli_v2(uint8_t *locinfo, } +static void parse_gtpv2_cause(gtp_parsed_t *gparsed, gtp_infoelem_t *el, + etsili_generic_freelist_t *freelist, etsili_generic_t **params) { + uint8_t *ptr = el->iecontent; + etsili_generic_t *np; + + if (gparsed->request->type == GTPV2_CREATE_SESSION_REQUEST) { + if ((*ptr) > 64) { + np = create_etsili_generic(freelist, + EPSIRI_CONTENTS_RAW_FAILED_BEARER_ACTIVATION_REASON, + el->ielength, ptr); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), + np); + } + } + +} + static int gtp_create_eps_generic_iri(gtp_parsed_t *gparsed, gtp_session_t *gsess, etsili_generic_t **params, etsili_generic_freelist_t *freelist, uint32_t evtype) { etsili_generic_t *np; - etsili_ipaddress_t ipaddr; + etsili_ipaddress_t ipaddr, netelipaddr; uint32_t initiator = 1; struct timeval tv; gtp_infoelem_t *el; @@ -1703,16 +1780,27 @@ static int gtp_create_eps_generic_iri(gtp_parsed_t *gparsed, etsili_create_ipaddress_v4((uint32_t *)(gsess->serverid), ETSILI_IPV4_SUBNET_UNKNOWN, ETSILI_IPADDRESS_ASSIGNED_UNKNOWN, &ipaddr); + etsili_create_ipaddress_v4((uint32_t *)(gsess->serverid), + ETSILI_IPV4_SUBNET_UNKNOWN, ETSILI_IPADDRESS_ASSIGNED_UNKNOWN, + &netelipaddr); } else { etsili_create_ipaddress_v6((uint8_t *)(gsess->serverid), ETSILI_IPV6_SUBNET_UNKNOWN, ETSILI_IPADDRESS_ASSIGNED_UNKNOWN, &ipaddr); + etsili_create_ipaddress_v6((uint8_t *)(gsess->serverid), + ETSILI_IPV6_SUBNET_UNKNOWN, ETSILI_IPADDRESS_ASSIGNED_UNKNOWN, + &netelipaddr); } np = create_etsili_generic(freelist, EPSIRI_CONTENTS_GGSN_IPADDRESS, sizeof(etsili_ipaddress_t), (uint8_t *)&ipaddr); HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), np); + np = create_etsili_generic(freelist, + EPSIRI_CONTENTS_NETWORK_ELEMENT_IPADDRESS, + sizeof(etsili_ipaddress_t), (uint8_t *)&netelipaddr); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), np); + np = create_etsili_generic(freelist, EPSIRI_CONTENTS_IMSI, gsess->saved.imsi_len, (uint8_t *)gsess->saved.imsi); HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), np); @@ -1819,7 +1907,7 @@ static int gtp_create_eps_generic_iri(gtp_parsed_t *gparsed, sizeof(np->itemnum), np); break; case GTPV2_IE_BEARER_CONTEXT: - walk_bearer_context_ie(freelist, el, params); + walk_bearer_context_ie(freelist, el, params, 1); break; case GTPV2_IE_RAT_TYPE: np = create_etsili_generic(freelist, @@ -1846,6 +1934,12 @@ static int gtp_create_eps_generic_iri(gtp_parsed_t *gparsed, HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), np); break; + case GTPV2_IE_CAUSE: + parse_gtpv2_cause(gparsed, el, freelist, params); + break; + case GTPV2_IE_BEARER_CONTEXT: + walk_bearer_context_ie(freelist, el, params, 0); + break; } el = el->next; @@ -2064,13 +2158,28 @@ static int gtp_create_context_deactivation_iri(gtp_parsed_t *gparsed, return 0; } -static int gtp_create_bearer_activation_failed_iri(gtp_parsed_t *gparsed UNUSED, - etsili_generic_t **params UNUSED, - etsili_generic_freelist_t *freelist UNUSED) { +static int gtpv2_create_session_activation_failed_iri( + gtp_parsed_t *gparsed, + etsili_generic_t **params, + etsili_generic_freelist_t *freelist) { + + uint32_t evtype = EPSIRI_EVENT_TYPE_BEARER_ACTIVATION; + etsili_generic_t *np = NULL; + uint32_t bearertype = 0; - /* Failed bearer activation reason */ + gtp_create_eps_generic_iri(gparsed, gparsed->matched_session, + params, freelist, evtype); + + /* XXX do we get a valid bearer ID in this case? */ + if (gparsed->bearerid == gparsed->matched_session->defaultbearer) { + bearertype = 1; + } else { + bearertype = 2; + } + np = create_etsili_generic(freelist, EPSIRI_CONTENTS_BEARER_ACTIVATION_TYPE, + sizeof(bearertype), (uint8_t *)(&bearertype)); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), np); - /* TODO */ return 0; } @@ -2127,13 +2236,25 @@ static int gtp_create_start_with_context_active_iri(gtp_session_t *gsess, return 0; } -static int gtp_create_bearer_activation_iri(gtp_parsed_t *gparsed, +static int gtpv2_create_session_activation_iri(gtp_parsed_t *gparsed, etsili_generic_t **params, etsili_generic_freelist_t *freelist) { uint32_t evtype = EPSIRI_EVENT_TYPE_BEARER_ACTIVATION; + etsili_generic_t *np = NULL; + uint32_t bearertype = 0; gtp_create_eps_generic_iri(gparsed, gparsed->matched_session, params, freelist, evtype); + + if (gparsed->bearerid == gparsed->matched_session->defaultbearer) { + bearertype = 1; + } else { + bearertype = 2; + } + np = create_etsili_generic(freelist, EPSIRI_CONTENTS_BEARER_ACTIVATION_TYPE, + sizeof(bearertype), (uint8_t *)(&bearertype)); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), np); + return 0; } @@ -2162,7 +2283,7 @@ static int gtp_generate_iri_data(access_plugin_t *p UNUSED, void *parseddata, return -1; } if (gparsed->version == 2 && - gtp_create_bearer_activation_iri(gparsed, params, + gtpv2_create_session_activation_iri(gparsed, params, freelist) < 0) { return -1; } @@ -2176,10 +2297,11 @@ static int gtp_generate_iri_data(access_plugin_t *p UNUSED, void *parseddata, return -1; } if (gparsed->version == 2 && - gtp_create_bearer_activation_failed_iri(gparsed, params, + gtpv2_create_session_activation_failed_iri(gparsed, params, freelist) < 0) { - /* TODO need to generate a PDP context activation failed IRI */ + return -1; } + return 0; } else if (gparsed->action == ACCESS_ACTION_INTERIM_UPDATE) { *iritype = ETSILI_IRI_CONTINUE; diff --git a/src/collector/epsiri.h b/src/collector/epsiri.h index b993bfe..46364d1 100644 --- a/src/collector/epsiri.h +++ b/src/collector/epsiri.h @@ -49,7 +49,8 @@ enum { EPSIRI_CONTENTS_INITIATOR = 15, EPSIRI_CONTENTS_OPERATOR_IDENTIFIER = 16, EPSIRI_CONTENTS_PDPTYPE = 17, - + EPSIRI_CONTENTS_NETWORK_ELEMENT_IPADDRESS = 18, + EPSIRI_CONTENTS_BEARER_ACTIVATION_TYPE = 19, /* separate the fields that are a direct copy of the IE from the * GTPv2 header -- these go in the EPS-GTPV2-SpecificParameters * sequence in the EPS IRI @@ -70,6 +71,7 @@ enum { EPSIRI_CONTENTS_RAW_DETACH_TYPE, }; +/* Values for EPSEvent as defined in 133.108 Appendix B.9 */ enum { EPSIRI_EVENT_TYPE_BEARER_ACTIVATION = 18, EPSIRI_EVENT_TYPE_START_WITH_BEARER_ACTIVE = 19, diff --git a/src/collector/etsiencoding/epsiri.c b/src/collector/etsiencoding/epsiri.c index 2ce729c..9c58516 100644 --- a/src/collector/etsiencoding/epsiri.c +++ b/src/collector/etsiencoding/epsiri.c @@ -208,20 +208,19 @@ wandder_encoded_result_t *encode_epsiri_body(wandder_encoder_t *encoder, } /* ggsnAddress (24) -- also appears in networkIdentifier, but why not... */ - ENC_CSEQUENCE(encoder, 24); lookup = EPSIRI_CONTENTS_GGSN_IPADDRESS; HASH_FIND(hh, params, &lookup, sizeof(lookup), p); if (p) { - ENC_CSEQUENCE(encoder, 1); - ENC_CSEQUENCE(encoder, 5); + ENC_CSEQUENCE(encoder, 24); + ENC_CSEQUENCE(encoder, 1); // ipAddress encode_ipaddress(encoder, (etsili_ipaddress_t *)(p->itemptr)); END_ENCODED_SEQUENCE(encoder, 2); } /* networkIdentifier (26) -- nested */ - ENC_CSEQUENCE(encoder, 26); + ENC_CSEQUENCE(encoder, 26); lookup = EPSIRI_CONTENTS_OPERATOR_IDENTIFIER; HASH_FIND(hh, params, &lookup, sizeof(lookup), p); if (p) { @@ -233,6 +232,18 @@ wandder_encoded_result_t *encode_epsiri_body(wandder_encoder_t *encoder, logger(LOG_INFO, "OpenLI: EPS IRI record may be invalid..."); } + lookup = EPSIRI_CONTENTS_NETWORK_ELEMENT_IPADDRESS; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + + if (p) { + ENC_CSEQUENCE(encoder, 1); + ENC_CSEQUENCE(encoder, 5); + encode_ipaddress(encoder, (etsili_ipaddress_t *)(p->itemptr)); + END_ENCODED_SEQUENCE(encoder, 2); + } + + END_ENCODED_SEQUENCE(encoder, 1); + /* eps-GTPV2-specificParameters (36) */ ENC_CSEQUENCE(encoder, 36); lookup = EPSIRI_CONTENTS_RAW_PDN_ADDRESS_ALLOCATION; @@ -289,6 +300,28 @@ wandder_encoded_result_t *encode_epsiri_body(wandder_encoder_t *encoder, WANDDER_CLASS_CONTEXT_PRIMITIVE, 7, p->itemptr, p->itemlen); } - END_ENCODED_SEQUENCE(encoder, 7); + lookup = EPSIRI_CONTENTS_RAW_FAILED_BEARER_ACTIVATION_REASON; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 8, p->itemptr, p->itemlen); + } + + lookup = EPSIRI_CONTENTS_RAW_BEARER_QOS; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 9, p->itemptr, p->itemlen); + } + + lookup = EPSIRI_CONTENTS_BEARER_ACTIVATION_TYPE; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + wandder_encode_next(encoder, WANDDER_TAG_ENUM, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 10, p->itemptr, p->itemlen); + } + + + END_ENCODED_SEQUENCE(encoder, 8); return wandder_encode_finish(encoder); } From 90ca0181bef7b868793c19088df2cf2f6944633f Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Wed, 7 Aug 2024 18:27:16 +1200 Subject: [PATCH 16/44] More progress on EPS IRI encoding * Add support for AMBR, bearerDeactivationType, bearerDeactivationCause, and linkedBearerId * Fix bugs with recognising GTP-C tunnels in opposite directions as part of the same session. * Fix bug that could cause the default bearer ID to be zero. * Ensure our generated request IDs are consistent in both directions so we can properly match responses to their corresponding request. * Implement bearer deactivation IRI for handling session ending. * Fix minor memory leak of mobileIRI LIIDs --- src/collector/accessplugins/gtp.c | 383 +++++++++++++++++++++------- src/collector/encoder_worker.c | 2 + src/collector/epsiri.h | 4 + src/collector/etsiencoding/epsiri.c | 42 +++ src/collector/gtp.h | 12 + 5 files changed, 352 insertions(+), 91 deletions(-) diff --git a/src/collector/accessplugins/gtp.c b/src/collector/accessplugins/gtp.c index 0ba3a24..caeae2a 100644 --- a/src/collector/accessplugins/gtp.c +++ b/src/collector/accessplugins/gtp.c @@ -55,6 +55,7 @@ enum { GTPV2_IE_IMSI = 1, GTPV2_IE_CAUSE = 2, GTPV2_IE_APNAME = 71, + GTPV2_IE_AMBR = 72, GTPV2_IE_BEARER_ID = 73, GTPV2_IE_MEI = 75, GTPV2_IE_MSISDN = 76, @@ -157,6 +158,10 @@ struct gtp_saved_packet { uint8_t applied; double tvsec; uint8_t response_cause; + uint8_t bearerid; + uint32_t teid_ctl; + uint32_t teid_data; + uint32_t teid; uint8_t *ipcontent; uint16_t iplen; @@ -201,7 +206,6 @@ typedef struct gtp_global { Pvoid_t saved_packets; Pvoid_t session_map; - Pvoid_t alt_session_map; Pvoid_t data_sessions; double lastrefresh; @@ -219,6 +223,7 @@ static void reset_parsed_pkt(gtp_parsed_t *parsed) { parsed->teid_data = 0; parsed->seqno = 0; parsed->response_cause = 0; + parsed->bearerid = 255; parsed->serveripfamily = 0; memset(parsed->serverid, 0, 16); @@ -233,6 +238,14 @@ static void reset_parsed_pkt(gtp_parsed_t *parsed) { parsed->response = NULL; } +#define GEN_SESSID(sessid, serveripfamily, serverid, teid) \ + if (serveripfamily == 4) { \ + snprintf(sessid, 64, "%u-%u", *(uint32_t *)serverid, teid); \ + } else if (serveripfamily == 6) { \ + snprintf(sessid, 64, "%lu-%lu-%u", *(uint64_t *)serverid, \ + *(uint64_t *)(serverid + 8), teid); \ + } + static void gtp_init_plugin_data(access_plugin_t *p) { gtp_global_t *glob; @@ -299,19 +312,23 @@ static inline void gtp_free_ie_list(gtp_infoelem_t *ies) { static void gtp_destroy_plugin_data(access_plugin_t *p) { gtp_global_t *glob; unsigned char index[64]; + unsigned char altid[64]; PWord_t pval; Word_t res, indexnum; + int rc; glob = (gtp_global_t *)(p->plugindata); if (!glob) { return; } - JSLFA(res, glob->alt_session_map); index[0] = '\0'; JSLF(pval, glob->session_map, index); while (pval) { gtp_session_t *sess = (gtp_session_t *)(*pval); + GEN_SESSID((char *)altid, sess->serveripfamily, sess->serverid, + sess->control_teid[1]); + JSLD(rc, glob->session_map, altid); destroy_gtp_session(sess); JSLN(pval, glob->session_map, index); } @@ -331,6 +348,7 @@ static void gtp_destroy_plugin_data(access_plugin_t *p) { } JLFA(res, glob->saved_packets); + if (glob->parsedpkt) { free(glob->parsedpkt); } @@ -390,6 +408,8 @@ static inline bool interesting_info_element(uint8_t gtpv, uint8_t ietype) { case GTPV2_IE_BEARER_CONTEXT: case GTPV2_IE_PCO: case GTPV2_IE_RAT_TYPE: + case GTPV2_IE_AMBR: + case GTPV2_IE_BEARER_ID: return true; } } else if (gtpv == 1) { @@ -468,7 +488,12 @@ static inline uint8_t get_cause_from_ie(gtp_infoelem_t *gtpel) { return *((uint8_t *)(gtpel->iecontent)); } -static void parse_new_session_bearer_context(gtp_parsed_t *parsedpkt, +static inline uint8_t get_bearer_id_from_ie(gtp_infoelem_t *gtpel) { + + return *((uint8_t *)(gtpel->iecontent)); +} + +static void parse_session_bearer_context(gtp_parsed_t *parsedpkt, gtp_infoelem_t *el) { uint8_t *ptr = (uint8_t *)el->iecontent; @@ -736,9 +761,11 @@ static void walk_gtpv2_ies(gtp_parsed_t *parsedpkt, uint8_t *ptr, uint32_t rem, } if (ietype == GTPV2_IE_BEARER_CONTEXT) { - parse_new_session_bearer_context(parsedpkt, gtpel); + parse_session_bearer_context(parsedpkt, gtpel); + } + if (ietype == GTPV2_IE_BEARER_ID) { + parsedpkt->bearerid = get_bearer_id_from_ie(gtpel); } - if (ietype == GTPV2_IE_FTEID) { parsedpkt->teid_ctl = get_teid_from_fteid(gtpel); @@ -916,9 +943,18 @@ static void *gtp_parse_packet(access_plugin_t *p, libtrace_packet_t *pkt) { glob->parsedpkt->serveripfamily = 4; + /* It appears that update bearer requests are sent by the server. + * Every other request so far is sent by the UE / client */ + switch(glob->parsedpkt->msgtype) { case GTPV2_CREATE_SESSION_REQUEST: case GTPV2_DELETE_SESSION_REQUEST: + case GTPV2_MODIFY_BEARER_REQUEST: + case GTPV2_CREATE_BEARER_REQUEST: + case GTPV2_DELETE_BEARER_REQUEST: + case GTPV2_UPDATE_BEARER_RESPONSE: + case GTPV2_MODIFY_BEARER_COMMAND: + case GTPV2_DELETE_BEARER_COMMAND: case GTPV1_CREATE_PDP_CONTEXT_REQUEST: case GTPV1_UPDATE_PDP_CONTEXT_REQUEST: case GTPV1_DELETE_PDP_CONTEXT_REQUEST: @@ -926,6 +962,12 @@ static void *gtp_parse_packet(access_plugin_t *p, libtrace_packet_t *pkt) { break; case GTPV2_CREATE_SESSION_RESPONSE: case GTPV2_DELETE_SESSION_RESPONSE: + case GTPV2_MODIFY_BEARER_RESPONSE: + case GTPV2_CREATE_BEARER_RESPONSE: + case GTPV2_UPDATE_BEARER_REQUEST: + case GTPV2_DELETE_BEARER_RESPONSE: + case GTPV2_MODIFY_BEARER_FAILURE_INDICATION: + case GTPV2_DELETE_BEARER_FAILURE_INDICATION: case GTPV1_CREATE_PDP_CONTEXT_RESPONSE: case GTPV1_UPDATE_PDP_CONTEXT_RESPONSE: case GTPV1_DELETE_PDP_CONTEXT_RESPONSE: @@ -943,6 +985,12 @@ static void *gtp_parse_packet(access_plugin_t *p, libtrace_packet_t *pkt) { switch(glob->parsedpkt->msgtype) { case GTPV2_CREATE_SESSION_REQUEST: case GTPV2_DELETE_SESSION_REQUEST: + case GTPV2_MODIFY_BEARER_REQUEST: + case GTPV2_CREATE_BEARER_REQUEST: + case GTPV2_UPDATE_BEARER_RESPONSE: + case GTPV2_DELETE_BEARER_REQUEST: + case GTPV2_MODIFY_BEARER_COMMAND: + case GTPV2_DELETE_BEARER_COMMAND: case GTPV1_CREATE_PDP_CONTEXT_REQUEST: case GTPV1_UPDATE_PDP_CONTEXT_REQUEST: case GTPV1_DELETE_PDP_CONTEXT_REQUEST: @@ -951,6 +999,12 @@ static void *gtp_parse_packet(access_plugin_t *p, libtrace_packet_t *pkt) { break; case GTPV2_CREATE_SESSION_RESPONSE: case GTPV2_DELETE_SESSION_RESPONSE: + case GTPV2_MODIFY_BEARER_RESPONSE: + case GTPV2_CREATE_BEARER_RESPONSE: + case GTPV2_UPDATE_BEARER_REQUEST: + case GTPV2_DELETE_BEARER_RESPONSE: + case GTPV2_MODIFY_BEARER_FAILURE_INDICATION: + case GTPV2_DELETE_BEARER_FAILURE_INDICATION: case GTPV1_CREATE_PDP_CONTEXT_RESPONSE: case GTPV1_UPDATE_PDP_CONTEXT_RESPONSE: case GTPV1_DELETE_PDP_CONTEXT_RESPONSE: @@ -1035,25 +1089,15 @@ static void save_identifier_strings(gtp_parsed_t *gparsed, gtp_session_t *sess) } } -#define GEN_SESSID(sessid, gparsed, teid) \ - if (gparsed->serveripfamily == 4) { \ - snprintf(sessid, 64, "%u-%u", *(uint32_t *)gparsed->serverid, teid); \ - } else if (gparsed->serveripfamily == 6) { \ - snprintf(sessid, 64, "%lu-%lu-%u", *(uint64_t *)gparsed->serverid, \ - *(uint64_t *)(gparsed->serverid + 8), teid); \ - } - static user_identity_t *gtp_get_userid(access_plugin_t *p, void *parsed, int *numberids) { gtp_global_t *glob = (gtp_global_t *)(p->plugindata); gtp_parsed_t *gparsed = (gtp_parsed_t *)parsed; unsigned char sessid[64]; - unsigned char alt_sessid[64]; gtp_session_t *sess; PWord_t pval; user_identity_t *uids; - Pvoid_t search; if (glob == NULL || gparsed == NULL) { return NULL; @@ -1069,16 +1113,9 @@ static user_identity_t *gtp_get_userid(access_plugin_t *p, void *parsed, } /* Need to look up the session */ - GEN_SESSID((char *)sessid, gparsed, gparsed->teid); - - if (gparsed->msgtype == GTPV1_DELETE_PDP_CONTEXT_REQUEST || - gparsed->msgtype == GTPV1_UPDATE_PDP_CONTEXT_REQUEST) { - search = glob->alt_session_map; - } else { - search = glob->session_map; - } - - JSLG(pval, search, sessid); + GEN_SESSID((char *)sessid, gparsed->serveripfamily, gparsed->serverid, + gparsed->teid); + JSLG(pval, glob->session_map, sessid); if (pval) { gparsed->matched_session = (gtp_session_t *)(*pval); @@ -1088,28 +1125,10 @@ static user_identity_t *gtp_get_userid(access_plugin_t *p, void *parsed, save_identifier_strings(gparsed, gparsed->matched_session); } - /* v1 delete requests use the teid_cp from the create response - * as their TEID, so we need to have a reference to this session - * for that TEID as well. Otherwise we'll miss the delete requests. - */ - if (gparsed->msgtype == GTPV1_CREATE_PDP_CONTEXT_RESPONSE) { - GEN_SESSID((char *)alt_sessid, gparsed, gparsed->teid_ctl); - JSLG(pval, glob->alt_session_map, alt_sessid); - - gparsed->matched_session->altsessid = strdup((char *)alt_sessid); - gparsed->matched_session->control_teid[1] = gparsed->teid_ctl; - gparsed->matched_session->data_teid[1] = gparsed->teid_data; - - if (!pval) { - JSLI(pval, glob->alt_session_map, - (uint8_t *)gparsed->matched_session->altsessid); - *pval = (Word_t)gparsed->matched_session; - } - - } - if (gparsed->msgtype == GTPV2_CREATE_SESSION_RESPONSE) { - gparsed->matched_session->defaultbearer = gparsed->bearerid; + if (gparsed->bearerid != 255) { + gparsed->matched_session->defaultbearer = gparsed->bearerid; + } } uids = copy_identifiers(gparsed, numberids); @@ -1127,12 +1146,16 @@ static user_identity_t *gtp_get_userid(access_plugin_t *p, void *parsed, ((uint64_t)gparsed->seqno); saved->ies = gparsed->ies; saved->version = gparsed->version; + saved->teid_ctl = gparsed->teid_ctl; + saved->teid_data = gparsed->teid_data; + saved->teid = gparsed->teid; saved->matched_session = NULL; saved->applied = 0; saved->tvsec = gparsed->tvsec; saved->ipcontent = NULL; saved->iplen = 0; saved->response_cause = gparsed->response_cause; + saved->bearerid = gparsed->bearerid; gparsed->ies = NULL; openli_copy_ipcontent(gparsed->origpkt, &(saved->ipcontent), @@ -1161,13 +1184,12 @@ static user_identity_t *gtp_get_userid(access_plugin_t *p, void *parsed, sess->pdpaddrcount = 0; sess->refcount = 0; sess->gtpversion = gparsed->version; - + sess->defaultbearer = 255; memcpy(sess->serverid, gparsed->serverid, 16); sess->serveripfamily = gparsed->serveripfamily; JSLI(pval, glob->session_map, (unsigned char *)sess->sessid); *pval = (Word_t)sess; - gparsed->matched_session = sess; save_identifier_strings(gparsed, sess); @@ -1354,7 +1376,36 @@ static void copy_session_params_v2(gtp_parsed_t *gparsed, } } -static void apply_gtp_fsm_logic(gtp_parsed_t *gparsed, access_action_t *action, +static void create_alt_session_entry(gtp_global_t *glob, + gtp_parsed_t *gparsed, uint32_t teid_ctl) { + + unsigned char alt_sessid[64]; + PWord_t pval; + + /* GTP requests during the session (including DELETEs) + * use the teid_cp from the create response + * as their TEID, so we need to have a reference to this session + * for that TEID as well. Otherwise we'll miss the delete requests. + */ + GEN_SESSID((char *)alt_sessid, gparsed->serveripfamily, + gparsed->serverid, teid_ctl); + + if (gparsed->matched_session->altsessid) { + free(gparsed->matched_session->altsessid); + } + gparsed->matched_session->altsessid = strdup((char *)alt_sessid); + gparsed->matched_session->control_teid[1] = teid_ctl; + + JSLG(pval, glob->session_map, alt_sessid); + if (!pval) { + JSLI(pval, glob->session_map, + (uint8_t *)gparsed->matched_session->altsessid); + *pval = (Word_t)gparsed->matched_session; + } +} + +static void apply_gtp_fsm_logic(gtp_global_t *glob, + gtp_parsed_t *gparsed, access_action_t *action, access_session_t *sess, gtp_saved_pkt_t *gpkt, session_state_t current) { @@ -1364,10 +1415,24 @@ static void apply_gtp_fsm_logic(gtp_parsed_t *gparsed, access_action_t *action, copy_session_params_v2(gparsed, gpkt); } + + /* TODO add appropriate action updates for: + * GTPV2_MODIFY_BEARER_COMMAND + * GTPV2_MODIFY_BEARER_FAILURE_INDICATION + * GTPV2_DELETE_BEARER_COMMAND + * GTPV2_DELETE_BEARER_FAILURE_INDICATION + * GTPV2_CREATE_BEARER_RESPONSE + * GTPV2_DELETE_BEARER_RESPONSE + */ + if (current == SESSION_STATE_NEW && (gpkt->type == GTPV2_CREATE_SESSION_REQUEST || gpkt->type == GTPV1_CREATE_PDP_CONTEXT_REQUEST)) { + if (gpkt->bearerid != 255 && gpkt->version == 2) { + gparsed->matched_session->defaultbearer = gpkt->bearerid; + } + current = SESSION_STATE_AUTHING; *action = ACCESS_ACTION_NONE; @@ -1383,6 +1448,12 @@ static void apply_gtp_fsm_logic(gtp_parsed_t *gparsed, access_action_t *action, /* TODO: set up GTP-U data sessions */ + if (gpkt->teid_ctl != 0) { + create_alt_session_entry(glob, gparsed, gpkt->teid_ctl); + } + if (gpkt->teid_data != 0) { + gparsed->matched_session->data_teid[1] = gpkt->teid_data; + } } else if (gpkt->response_cause >= 64 && gpkt->response_cause <= 239) { current = SESSION_STATE_OVER; *action = ACCESS_ACTION_REJECT; @@ -1398,6 +1469,12 @@ static void apply_gtp_fsm_logic(gtp_parsed_t *gparsed, access_action_t *action, gparsed->matched_session); /* TODO: set up GTP-U data sessions */ + if (gpkt->teid_ctl != 0) { + create_alt_session_entry(glob, gparsed, gpkt->teid_ctl); + } + if (gpkt->teid_data != 0) { + gparsed->matched_session->data_teid[1] = gpkt->teid_data; + } } else if (gpkt->response_cause >= 192) { current = SESSION_STATE_OVER; *action = ACCESS_ACTION_REJECT; @@ -1416,6 +1493,12 @@ static void apply_gtp_fsm_logic(gtp_parsed_t *gparsed, access_action_t *action, } else if (current == SESSION_STATE_ACTIVE && (gpkt->type == GTPV1_UPDATE_PDP_CONTEXT_RESPONSE)) { *action = ACCESS_ACTION_MODIFIED; + } else if (current == SESSION_STATE_ACTIVE && + (gpkt->type == GTPV2_MODIFY_BEARER_RESPONSE)) { + *action = ACCESS_ACTION_MODIFIED; + } else if (current == SESSION_STATE_ACTIVE && + (gpkt->type == GTPV2_UPDATE_BEARER_RESPONSE)) { + *action = ACCESS_ACTION_INTERIM_UPDATE; } gparsed->matched_session->current = current; @@ -1423,7 +1506,7 @@ static void apply_gtp_fsm_logic(gtp_parsed_t *gparsed, access_action_t *action, } static inline access_session_t *find_matched_session(access_plugin_t *p, - access_session_t **sesslist, gtp_session_t *match, uint32_t teid, + access_session_t **sesslist, gtp_session_t *match, uint8_t incr_refcount) { access_session_t *thissess = NULL; @@ -1437,7 +1520,7 @@ static inline access_session_t *find_matched_session(access_plugin_t *p, if (!thissess) { thissess = create_access_session(p, match->sessid, strlen(match->sessid)); - thissess->cin = assign_gtp_cin(teid); + thissess->cin = assign_gtp_cin(match->control_teid[0]); match->cin = thissess->cin; if (incr_refcount) { match->refcount ++; @@ -1460,16 +1543,18 @@ static access_session_t *gtp_update_session_state(access_plugin_t *p, gtp_parsed_t *gparsed = (gtp_parsed_t *)parsed; PWord_t pval; Word_t rcint; - uint64_t reqid = (((uint64_t)gparsed->teid) << 32) | - ((uint64_t)gparsed->seqno); - + uint64_t reqid; uint8_t incr_refcount = 0; + if (gparsed->matched_session == NULL) { *action = ACCESS_ACTION_NONE; return NULL; } + reqid = (((uint64_t)gparsed->matched_session->control_teid[0]) << 32) | + ((uint64_t)gparsed->seqno); + if (gparsed->msgtype == GTPV2_CREATE_SESSION_REQUEST || gparsed->msgtype == GTPV1_CREATE_PDP_CONTEXT_REQUEST) { incr_refcount = 1; @@ -1485,7 +1570,7 @@ static access_session_t *gtp_update_session_state(access_plugin_t *p, * the packet. */ thissess = find_matched_session(p, sesslist, gparsed->matched_session, - gparsed->teid, incr_refcount); + incr_refcount); *oldstate = gparsed->matched_session->savedoldstate; *action = gparsed->action; *newstate = gparsed->matched_session->savednewstate; @@ -1504,6 +1589,10 @@ static access_session_t *gtp_update_session_state(access_plugin_t *p, saved->ipcontent = NULL; saved->iplen = 0; saved->response_cause = gparsed->response_cause; + saved->bearerid = gparsed->bearerid; + saved->teid = gparsed->teid; + saved->teid_ctl = gparsed->teid_ctl; + saved->teid_data = gparsed->teid_data; gparsed->ies = NULL; gparsed->matched_session->last_reqid = reqid; @@ -1513,6 +1602,22 @@ static access_session_t *gtp_update_session_state(access_plugin_t *p, openli_copy_ipcontent(gparsed->origpkt, &(saved->ipcontent), &(saved->iplen)); + if (gparsed->msgtype == GTPV2_MODIFY_BEARER_COMMAND || + gparsed->msgtype == GTPV2_DELETE_BEARER_COMMAND) { + + /* TODO */ + gparsed->matched_session = NULL; + *action = ACCESS_ACTION_NONE; + return NULL; + } else if (gparsed->msgtype == GTPV2_MODIFY_BEARER_FAILURE_INDICATION || + gparsed->msgtype == GTPV2_DELETE_BEARER_FAILURE_INDICATION) { + + /* TODO */ + gparsed->matched_session = NULL; + *action = ACCESS_ACTION_NONE; + return NULL; + } + JLG(pval, glob->saved_packets, saved->reqid); if (pval == NULL) { JLI(pval, glob->saved_packets, saved->reqid); @@ -1520,16 +1625,20 @@ static access_session_t *gtp_update_session_state(access_plugin_t *p, if (gparsed->msgtype == GTPV2_CREATE_SESSION_REQUEST || gparsed->msgtype == GTPV2_DELETE_SESSION_REQUEST || + gparsed->msgtype == GTPV2_MODIFY_BEARER_REQUEST || + gparsed->msgtype == GTPV2_UPDATE_BEARER_REQUEST || + gparsed->msgtype == GTPV2_DELETE_BEARER_REQUEST || + gparsed->msgtype == GTPV2_CREATE_BEARER_REQUEST || gparsed->msgtype == GTPV1_CREATE_PDP_CONTEXT_REQUEST || gparsed->msgtype == GTPV1_DELETE_PDP_CONTEXT_REQUEST || gparsed->msgtype == GTPV1_UPDATE_PDP_CONTEXT_REQUEST) { thissess = find_matched_session(p, sesslist, - gparsed->matched_session, gparsed->teid, incr_refcount); + gparsed->matched_session, incr_refcount); if (thissess) { *oldstate = gparsed->matched_session->current; gparsed->matched_session->savedoldstate = *oldstate; - apply_gtp_fsm_logic(gparsed, &(gparsed->action), thissess, + apply_gtp_fsm_logic(glob, gparsed, &(gparsed->action), thissess, saved, *oldstate); *newstate = gparsed->matched_session->current; gparsed->matched_session->savednewstate = *newstate; @@ -1549,7 +1658,6 @@ static access_session_t *gtp_update_session_state(access_plugin_t *p, if (saved->type == GTPV2_CREATE_SESSION_REQUEST && check->type == GTPV2_CREATE_SESSION_RESPONSE) { - gparsed->request = saved; gparsed->response = check; incr_refcount = 1; @@ -1614,14 +1722,13 @@ static access_session_t *gtp_update_session_state(access_plugin_t *p, if (gparsed->request->matched_session) { thissess = find_matched_session(p, sesslist, - gparsed->request->matched_session, gparsed->teid, - incr_refcount); + gparsed->request->matched_session, incr_refcount); *oldstate = gparsed->request->matched_session->current; gparsed->matched_session = gparsed->request->matched_session; gparsed->matched_session->savedoldstate = *oldstate; } else if (gparsed->response->matched_session) { thissess = find_matched_session(p, sesslist, - gparsed->response->matched_session, gparsed->teid, 0); + gparsed->response->matched_session, 0); *oldstate = gparsed->response->matched_session->current; gparsed->matched_session = gparsed->response->matched_session; gparsed->matched_session->savedoldstate = *oldstate; @@ -1629,12 +1736,12 @@ static access_session_t *gtp_update_session_state(access_plugin_t *p, if (thissess) { if (gparsed->request->applied == 0) { - apply_gtp_fsm_logic(gparsed, &(gparsed->action), thissess, + apply_gtp_fsm_logic(glob, gparsed, &(gparsed->action), thissess, gparsed->request, gparsed->matched_session->current); gparsed->request->applied = 1; } if (gparsed->response->applied == 0) { - apply_gtp_fsm_logic(gparsed, &(gparsed->action), thissess, + apply_gtp_fsm_logic(glob, gparsed, &(gparsed->action), thissess, gparsed->response, gparsed->matched_session->current); gparsed->response->applied = 1; } @@ -1736,6 +1843,24 @@ static void parse_gtpv2_cause(gtp_parsed_t *gparsed, gtp_infoelem_t *el, } } + else if (gparsed->request->type == GTPV2_MODIFY_BEARER_REQUEST) { + if ((*ptr) > 64) { + np = create_etsili_generic(freelist, + EPSIRI_CONTENTS_RAW_FAILED_BEARER_MODIFICATION_REASON, + el->ielength, ptr); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), + np); + } + } + + else if (gparsed->request->type == GTPV2_DELETE_SESSION_REQUEST) { + np = create_etsili_generic(freelist, + EPSIRI_CONTENTS_RAW_BEARER_DEACTIVATION_CAUSE, + el->ielength, ptr); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), + np); + } + } static int gtp_create_eps_generic_iri(gtp_parsed_t *gparsed, @@ -1916,6 +2041,14 @@ static int gtp_create_eps_generic_iri(gtp_parsed_t *gparsed, HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), np); break; + case GTPV2_IE_AMBR: + np = create_etsili_generic(freelist, + EPSIRI_CONTENTS_RAW_APN_AMBR, el->ielength, + (uint8_t *)(el->iecontent)); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), + sizeof(np->itemnum), np); + break; + } el = el->next; @@ -2123,16 +2256,42 @@ static void insert_gtp_cause_as_gprs_error(gtp_infoelem_t *el, } } -static int gtp_create_bearer_deactivation_iri(gtp_parsed_t *gparsed UNUSED, - etsili_generic_t **params UNUSED, - etsili_generic_freelist_t *freelist UNUSED) { +static int gtp_create_bearer_deactivation_iri(gtp_parsed_t *gparsed, + etsili_generic_t **params, + etsili_generic_freelist_t *freelist) { - /* - * Bearer deactivation type - * Bearer deactivation cause - */ + uint32_t evtype = EPSIRI_EVENT_TYPE_BEARER_DEACTIVATION; + etsili_generic_t *np = NULL; + uint32_t bearertype = 0; + uint32_t linkedbearer = 0; + + gtp_create_eps_generic_iri(gparsed, gparsed->matched_session, + params, freelist, evtype); + + /* Bearer ID is only in the DELETE request, not the response so can't + * rely on gparsed itself */ + if (gparsed->request->bearerid == gparsed->matched_session->defaultbearer) { + if (gparsed->request->bearerid != 255) { + bearertype = 1; + } + } else if (gparsed->request->bearerid != 255) { + bearertype = 2; + } - /* TODO */ + if (bearertype != 0) { + np = create_etsili_generic(freelist, + EPSIRI_CONTENTS_BEARER_DEACTIVATION_TYPE, + sizeof(bearertype), (uint8_t *)(&bearertype)); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), np); + } + + if (bearertype == 2) { + linkedbearer = htonl(gparsed->matched_session->defaultbearer); + np = create_etsili_generic(freelist, + EPSIRI_CONTENTS_RAW_LINKED_BEARER_ID, + sizeof(linkedbearer), (uint8_t *)&linkedbearer); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), np); + } return 0; } @@ -2166,19 +2325,33 @@ static int gtpv2_create_session_activation_failed_iri( uint32_t evtype = EPSIRI_EVENT_TYPE_BEARER_ACTIVATION; etsili_generic_t *np = NULL; uint32_t bearertype = 0; + uint32_t linkedbearer = 0; gtp_create_eps_generic_iri(gparsed, gparsed->matched_session, params, freelist, evtype); /* XXX do we get a valid bearer ID in this case? */ - if (gparsed->bearerid == gparsed->matched_session->defaultbearer) { + if (gparsed->bearerid != 255 && + gparsed->bearerid == gparsed->matched_session->defaultbearer) { bearertype = 1; - } else { + } else if (gparsed->bearerid != 255) { bearertype = 2; } - np = create_etsili_generic(freelist, EPSIRI_CONTENTS_BEARER_ACTIVATION_TYPE, - sizeof(bearertype), (uint8_t *)(&bearertype)); - HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), np); + + if (bearertype != 0) { + np = create_etsili_generic(freelist, + EPSIRI_CONTENTS_BEARER_ACTIVATION_TYPE, + sizeof(bearertype), (uint8_t *)(&bearertype)); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), np); + } + + if (bearertype == 2) { + linkedbearer = htonl(gparsed->matched_session->defaultbearer); + np = create_etsili_generic(freelist, + EPSIRI_CONTENTS_RAW_LINKED_BEARER_ID, + sizeof(linkedbearer), (uint8_t *)&linkedbearer); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), np); + } return 0; } @@ -2216,6 +2389,15 @@ static int gtp_create_context_modification_iri(gtp_parsed_t *gparsed, return 0; } +static int gtpv2_create_session_modification_iri(gtp_parsed_t *gparsed, + etsili_generic_t **params, etsili_generic_freelist_t *freelist) { + + uint32_t evtype = EPSIRI_EVENT_TYPE_BEARER_MODIFICATION; + + gtp_create_eps_generic_iri(gparsed, gparsed->matched_session, params, + freelist, evtype); + return 0; +} static int gtp_create_start_with_bearer_active_iri(gtp_session_t *gsess, etsili_generic_t **params, etsili_generic_freelist_t *freelist) { @@ -2241,19 +2423,33 @@ static int gtpv2_create_session_activation_iri(gtp_parsed_t *gparsed, uint32_t evtype = EPSIRI_EVENT_TYPE_BEARER_ACTIVATION; etsili_generic_t *np = NULL; + uint32_t linkedbearer = 0; uint32_t bearertype = 0; gtp_create_eps_generic_iri(gparsed, gparsed->matched_session, params, freelist, evtype); - if (gparsed->bearerid == gparsed->matched_session->defaultbearer) { + if (gparsed->bearerid != 255 && + gparsed->bearerid == gparsed->matched_session->defaultbearer) { bearertype = 1; } else { bearertype = 2; } - np = create_etsili_generic(freelist, EPSIRI_CONTENTS_BEARER_ACTIVATION_TYPE, - sizeof(bearertype), (uint8_t *)(&bearertype)); - HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), np); + + if (bearertype != 0) { + np = create_etsili_generic(freelist, + EPSIRI_CONTENTS_BEARER_ACTIVATION_TYPE, + sizeof(bearertype), (uint8_t *)(&bearertype)); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), np); + } + + if (bearertype == 2) { + linkedbearer = htonl(gparsed->matched_session->defaultbearer); + np = create_etsili_generic(freelist, + EPSIRI_CONTENTS_RAW_LINKED_BEARER_ID, + sizeof(linkedbearer), (uint8_t *)&linkedbearer); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), np); + } return 0; } @@ -2305,8 +2501,13 @@ static int gtp_generate_iri_data(access_plugin_t *p UNUSED, void *parseddata, } else if (gparsed->action == ACCESS_ACTION_INTERIM_UPDATE) { *iritype = ETSILI_IRI_CONTINUE; - if (gtp_create_context_modification_iri(gparsed, params, freelist) < 0) - { + if (gparsed->version == 1 && + gtp_create_context_modification_iri(gparsed, params, + freelist) < 0) { + return -1; + } else if (gparsed->version == 2 && + gtpv2_create_session_modification_iri(gparsed, params, + freelist) < 0) { return -1; } return 0; @@ -2317,13 +2518,13 @@ static int gtp_generate_iri_data(access_plugin_t *p UNUSED, void *parseddata, gtp_create_context_modification_iri(gparsed, params, freelist) < 0) { return -1; + } else if (gparsed->version == 2 && + gtpv2_create_session_modification_iri(gparsed, params, + freelist) < 0) { + return -1; } - /* TODO GTPv2 bearer modification */ - return 0; - } - else if (gparsed->action == ACCESS_ACTION_INTERIM_UPDATE) { - /* TODO location updates, anything else that requires a REPORT */ + return 0; } else if (gparsed->action == ACCESS_ACTION_END) { *iritype = ETSILI_IRI_END; @@ -2424,6 +2625,7 @@ static void gtp_destroy_session_data(access_plugin_t *p UNUSED, gtp_session_t *gtpsess; PWord_t pval; int rc; + unsigned char altid[64]; JSLG(pval, glob->session_map, sess->sessionid); if (pval != NULL) { @@ -2431,10 +2633,9 @@ static void gtp_destroy_session_data(access_plugin_t *p UNUSED, gtpsess->refcount --; if (gtpsess->refcount <= 0) { JSLD(rc, glob->session_map, (uint8_t *)gtpsess->sessid); - if (gtpsess->altsessid) { - JSLD(rc, glob->alt_session_map, (uint8_t *)gtpsess->altsessid); - } - + GEN_SESSID((char *)altid, gtpsess->serveripfamily, + gtpsess->serverid, gtpsess->control_teid[1]); + JSLD(rc, glob->session_map, altid); destroy_gtp_session(gtpsess); } } diff --git a/src/collector/encoder_worker.c b/src/collector/encoder_worker.c index bff69f4..293f41a 100644 --- a/src/collector/encoder_worker.c +++ b/src/collector/encoder_worker.c @@ -557,6 +557,7 @@ static int encode_templated_epsiri(openli_encoder_t *enc, wandder_release_encoded_result(enc->encoder, body); free_mobileiri_parameters(irijob->customparams); + free(irijob->liid); /* Success */ return 1; } @@ -608,6 +609,7 @@ static int encode_templated_umtsiri(openli_encoder_t *enc, wandder_release_encoded_result(enc->encoder, body); free_mobileiri_parameters(irijob->customparams); + free(irijob->liid); /* Success */ return 1; } diff --git a/src/collector/epsiri.h b/src/collector/epsiri.h index 46364d1..06d80cd 100644 --- a/src/collector/epsiri.h +++ b/src/collector/epsiri.h @@ -51,6 +51,7 @@ enum { EPSIRI_CONTENTS_PDPTYPE = 17, EPSIRI_CONTENTS_NETWORK_ELEMENT_IPADDRESS = 18, EPSIRI_CONTENTS_BEARER_ACTIVATION_TYPE = 19, + EPSIRI_CONTENTS_BEARER_DEACTIVATION_TYPE = 20, /* separate the fields that are a direct copy of the IE from the * GTPv2 header -- these go in the EPS-GTPV2-SpecificParameters * sequence in the EPS IRI @@ -69,6 +70,9 @@ enum { EPSIRI_CONTENTS_RAW_FAILED_BEARER_ACTIVATION_REASON, EPSIRI_CONTENTS_RAW_ATTACH_TYPE, EPSIRI_CONTENTS_RAW_DETACH_TYPE, + EPSIRI_CONTENTS_RAW_LINKED_BEARER_ID, + EPSIRI_CONTENTS_RAW_FAILED_BEARER_MODIFICATION_REASON, + EPSIRI_CONTENTS_RAW_BEARER_DEACTIVATION_CAUSE, }; /* Values for EPSEvent as defined in 133.108 Appendix B.9 */ diff --git a/src/collector/etsiencoding/epsiri.c b/src/collector/etsiencoding/epsiri.c index 9c58516..543118d 100644 --- a/src/collector/etsiencoding/epsiri.c +++ b/src/collector/etsiencoding/epsiri.c @@ -321,6 +321,48 @@ wandder_encoded_result_t *encode_epsiri_body(wandder_encoder_t *encoder, WANDDER_CLASS_CONTEXT_PRIMITIVE, 10, p->itemptr, p->itemlen); } + lookup = EPSIRI_CONTENTS_RAW_APN_AMBR; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 11, p->itemptr, p->itemlen); + } + + /* procedureTransactionID goes here */ + + lookup = EPSIRI_CONTENTS_RAW_LINKED_BEARER_ID; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 13, p->itemptr, p->itemlen); + } + + /* TFT goes here */ + + /* Handover Indication */ + + lookup = EPSIRI_CONTENTS_RAW_FAILED_BEARER_MODIFICATION_REASON; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 16, p->itemptr, p->itemlen); + } + + lookup = EPSIRI_CONTENTS_BEARER_DEACTIVATION_TYPE; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + wandder_encode_next(encoder, WANDDER_TAG_ENUM, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 21, p->itemptr, p->itemlen); + } + + lookup = EPSIRI_CONTENTS_RAW_BEARER_DEACTIVATION_CAUSE; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 22, p->itemptr, p->itemlen); + } + + END_ENCODED_SEQUENCE(encoder, 8); return wandder_encode_finish(encoder); diff --git a/src/collector/gtp.h b/src/collector/gtp.h index 3985ba5..1647c6d 100644 --- a/src/collector/gtp.h +++ b/src/collector/gtp.h @@ -57,8 +57,20 @@ enum { GTPV2_CREATE_SESSION_REQUEST = 32, GTPV2_CREATE_SESSION_RESPONSE = 33, + GTPV2_MODIFY_BEARER_REQUEST = 34, + GTPV2_MODIFY_BEARER_RESPONSE = 35, GTPV2_DELETE_SESSION_REQUEST = 36, GTPV2_DELETE_SESSION_RESPONSE = 37, + GTPV2_MODIFY_BEARER_COMMAND = 64, + GTPV2_MODIFY_BEARER_FAILURE_INDICATION = 65, + GTPV2_DELETE_BEARER_COMMAND = 66, + GTPV2_DELETE_BEARER_FAILURE_INDICATION = 67, + GTPV2_CREATE_BEARER_REQUEST = 95, + GTPV2_CREATE_BEARER_RESPONSE = 96, + GTPV2_UPDATE_BEARER_REQUEST = 97, + GTPV2_UPDATE_BEARER_RESPONSE = 98, + GTPV2_DELETE_BEARER_REQUEST = 99, + GTPV2_DELETE_BEARER_RESPONSE = 100, }; uint8_t gtp_get_parsed_version(void *parseddata); From fb397ba4c248bb50981837d2f2a28a94412fa8a3 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Thu, 15 Aug 2024 17:19:55 +1200 Subject: [PATCH 17/44] Add epsLocation and pdnType to EPS IRIs --- src/collector/accessplugins/gtp.c | 57 +++++++++++++++++++++-------- src/collector/etsiencoding/epsiri.c | 14 +++++++ 2 files changed, 55 insertions(+), 16 deletions(-) diff --git a/src/collector/accessplugins/gtp.c b/src/collector/accessplugins/gtp.c index caeae2a..8832e5c 100644 --- a/src/collector/accessplugins/gtp.c +++ b/src/collector/accessplugins/gtp.c @@ -65,6 +65,7 @@ enum { GTPV2_IE_ULI = 86, GTPV2_IE_FTEID = 87, GTPV2_IE_BEARER_CONTEXT = 93, + GTPV2_IE_PDN_TYPE = 99, }; /* TODO add more cause values here */ @@ -410,6 +411,7 @@ static inline bool interesting_info_element(uint8_t gtpv, uint8_t ietype) { case GTPV2_IE_RAT_TYPE: case GTPV2_IE_AMBR: case GTPV2_IE_BEARER_ID: + case GTPV2_IE_PDN_TYPE: return true; } } else if (gtpv == 1) { @@ -1577,6 +1579,22 @@ static access_session_t *gtp_update_session_state(access_plugin_t *p, return thissess; } + if (gparsed->msgtype == GTPV2_MODIFY_BEARER_COMMAND || + gparsed->msgtype == GTPV2_DELETE_BEARER_COMMAND) { + + /* TODO */ + gparsed->matched_session = NULL; + *action = ACCESS_ACTION_NONE; + return NULL; + } else if (gparsed->msgtype == GTPV2_MODIFY_BEARER_FAILURE_INDICATION || + gparsed->msgtype == GTPV2_DELETE_BEARER_FAILURE_INDICATION) { + + /* TODO */ + gparsed->matched_session = NULL; + *action = ACCESS_ACTION_NONE; + return NULL; + } + saved = calloc(1, sizeof(gtp_saved_pkt_t)); saved->type = gparsed->msgtype; @@ -1602,22 +1620,6 @@ static access_session_t *gtp_update_session_state(access_plugin_t *p, openli_copy_ipcontent(gparsed->origpkt, &(saved->ipcontent), &(saved->iplen)); - if (gparsed->msgtype == GTPV2_MODIFY_BEARER_COMMAND || - gparsed->msgtype == GTPV2_DELETE_BEARER_COMMAND) { - - /* TODO */ - gparsed->matched_session = NULL; - *action = ACCESS_ACTION_NONE; - return NULL; - } else if (gparsed->msgtype == GTPV2_MODIFY_BEARER_FAILURE_INDICATION || - gparsed->msgtype == GTPV2_DELETE_BEARER_FAILURE_INDICATION) { - - /* TODO */ - gparsed->matched_session = NULL; - *action = ACCESS_ACTION_NONE; - return NULL; - } - JLG(pval, glob->saved_packets, saved->reqid); if (pval == NULL) { JLI(pval, glob->saved_packets, saved->reqid); @@ -1667,6 +1669,14 @@ static access_session_t *gtp_update_session_state(access_plugin_t *p, gparsed->request = check; gparsed->response = saved; incr_refcount = 1; + } else if (saved->type == GTPV2_MODIFY_BEARER_REQUEST && + check->type == GTPV2_MODIFY_BEARER_RESPONSE) { + gparsed->request = saved; + gparsed->response = check; + } else if (check->type == GTPV2_MODIFY_BEARER_REQUEST && + saved->type == GTPV2_MODIFY_BEARER_RESPONSE) { + gparsed->request = check; + gparsed->response = saved; } else if (saved->type == GTPV2_DELETE_SESSION_REQUEST && check->type == GTPV2_DELETE_SESSION_RESPONSE) { gparsed->request = saved; @@ -2048,6 +2058,21 @@ static int gtp_create_eps_generic_iri(gtp_parsed_t *gparsed, HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), sizeof(np->itemnum), np); break; + case GTPV2_IE_ULI: + np = create_etsili_generic(freelist, + EPSIRI_CONTENTS_RAW_ULI, el->ielength, + (uint8_t *)(el->iecontent)); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), + sizeof(np->itemnum), np); + break; + case GTPV2_IE_PDN_TYPE: + np = create_etsili_generic(freelist, + EPSIRI_CONTENTS_RAW_PDN_TYPE, el->ielength, + (uint8_t *)(el->iecontent)); + HASH_ADD_KEYPTR(hh, *params, &(np->itemnum), + sizeof(np->itemnum), np); + break; + } diff --git a/src/collector/etsiencoding/epsiri.c b/src/collector/etsiencoding/epsiri.c index 543118d..a22f5bf 100644 --- a/src/collector/etsiencoding/epsiri.c +++ b/src/collector/etsiencoding/epsiri.c @@ -362,7 +362,21 @@ wandder_encoded_result_t *encode_epsiri_body(wandder_encoder_t *encoder, WANDDER_CLASS_CONTEXT_PRIMITIVE, 22, p->itemptr, p->itemlen); } + lookup = EPSIRI_CONTENTS_RAW_ULI; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + ENC_CSEQUENCE(encoder, 23); + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 1, p->itemptr, p->itemlen); + END_ENCODED_SEQUENCE(encoder, 1); + } + lookup = EPSIRI_CONTENTS_RAW_PDN_TYPE; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 24, p->itemptr, p->itemlen); + } END_ENCODED_SEQUENCE(encoder, 8); return wandder_encode_finish(encoder); From 345125f7ec74946dd1f1cc90110ced2d8b8396e8 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Fri, 16 Aug 2024 12:25:36 +1200 Subject: [PATCH 18/44] GTP worker threads now track TEIDs for GTP-U tunnels Specifically, we are tracking the TEIDs for tunnels belonging to intercept targets. I've included the endpoint IPs for the tunnel to the identifier for a given TEID, as a TEID is only unique for a particular link. If a collector is provided traffic from multiple gateways, we will hopefully avoid issues where the TEIDs clash. Note to self: it might be better to use the IP address from inside the F-TEID element but I would need to confirm how that IP maps to addresses available in the GTP-U packets. --- src/collector/accessplugins/gtp.c | 44 ++++++++ src/collector/gtp_worker.c | 167 ++++++++++++++++++++++++++++-- src/collector/gtp_worker.h | 3 + src/collector/internetaccess.c | 7 ++ src/collector/internetaccess.h | 5 + 5 files changed, 220 insertions(+), 6 deletions(-) diff --git a/src/collector/accessplugins/gtp.c b/src/collector/accessplugins/gtp.c index 8832e5c..6ddfc66 100644 --- a/src/collector/accessplugins/gtp.c +++ b/src/collector/accessplugins/gtp.c @@ -139,6 +139,8 @@ typedef struct gtp_session { uint8_t serverid[16]; uint8_t serveripfamily; + char *tunnel_endpoints; + session_state_t current; uint64_t last_reqid; @@ -188,6 +190,7 @@ typedef struct gtp_parsed { uint8_t serveripfamily; uint8_t serverid[16]; + char tunnel_endpoints[256]; char imsi[16]; char msisdn[16]; char imei[16]; @@ -227,6 +230,7 @@ static void reset_parsed_pkt(gtp_parsed_t *parsed) { parsed->bearerid = 255; parsed->serveripfamily = 0; + memset(parsed->tunnel_endpoints, 0, 256); memset(parsed->serverid, 0, 16); memset(parsed->imsi, 0, 16); memset(parsed->imei, 0, 16); @@ -267,6 +271,10 @@ static inline void destroy_gtp_session(gtp_session_t *sess) { free(sess->sessid); } + if (sess->tunnel_endpoints) { + free(sess->tunnel_endpoints); + } + if (sess->altsessid) { free(sess->altsessid); } @@ -948,6 +956,14 @@ static void *gtp_parse_packet(access_plugin_t *p, libtrace_packet_t *pkt) { /* It appears that update bearer requests are sent by the server. * Every other request so far is sent by the UE / client */ + if (ip->ip_src.s_addr < ip->ip_dst.s_addr) { + snprintf(glob->parsedpkt->tunnel_endpoints, 256, "%u-%u", + ip->ip_src.s_addr, ip->ip_dst.s_addr); + } else { + snprintf(glob->parsedpkt->tunnel_endpoints, 256, "%u-%u", + ip->ip_dst.s_addr, ip->ip_src.s_addr); + } + switch(glob->parsedpkt->msgtype) { case GTPV2_CREATE_SESSION_REQUEST: case GTPV2_DELETE_SESSION_REQUEST: @@ -984,6 +1000,20 @@ static void *gtp_parse_packet(access_plugin_t *p, libtrace_packet_t *pkt) { glob->parsedpkt->serveripfamily = 6; + if (memcmp(&(ip6->ip_src.s6_addr), &(ip6->ip_dst.s6_addr), 16) < 0) { + snprintf(glob->parsedpkt->tunnel_endpoints, 256, "%lu-%lu-%lu-%lu", + *(uint64_t *)(&(ip6->ip_src.s6_addr)), + *(uint64_t *)(&(ip6->ip_src.s6_addr[8])), + *(uint64_t *)(&(ip6->ip_dst.s6_addr)), + *(uint64_t *)(&(ip6->ip_dst.s6_addr[8]))); + } else { + snprintf(glob->parsedpkt->tunnel_endpoints, 256, "%lu-%lu-%lu-%lu", + *(uint64_t *)(&(ip6->ip_dst.s6_addr)), + *(uint64_t *)(&(ip6->ip_dst.s6_addr[8])), + *(uint64_t *)(&(ip6->ip_src.s6_addr)), + *(uint64_t *)(&(ip6->ip_src.s6_addr[8]))); + } + switch(glob->parsedpkt->msgtype) { case GTPV2_CREATE_SESSION_REQUEST: case GTPV2_DELETE_SESSION_REQUEST: @@ -1188,6 +1218,7 @@ static user_identity_t *gtp_get_userid(access_plugin_t *p, void *parsed, sess->gtpversion = gparsed->version; sess->defaultbearer = 255; memcpy(sess->serverid, gparsed->serverid, 16); + sess->tunnel_endpoints = strdup(gparsed->tunnel_endpoints); sess->serveripfamily = gparsed->serveripfamily; JSLI(pval, glob->session_map, (unsigned char *)sess->sessid); @@ -1406,6 +1437,16 @@ static void create_alt_session_entry(gtp_global_t *glob, } } +static inline void add_new_session_teids(access_session_t *sess, + gtp_session_t *gsess) { + + sess->teids[0] = gsess->data_teid[0]; + sess->teids[1] = gsess->data_teid[1]; + sess->gtp_tunnel_endpoints = strdup(gsess->tunnel_endpoints); + sess->identifier_type |= OPENLI_ACCESS_SESSION_TEID; + +} + static void apply_gtp_fsm_logic(gtp_global_t *glob, gtp_parsed_t *gparsed, access_action_t *action, access_session_t *sess, gtp_saved_pkt_t *gpkt, @@ -1456,6 +1497,7 @@ static void apply_gtp_fsm_logic(gtp_global_t *glob, if (gpkt->teid_data != 0) { gparsed->matched_session->data_teid[1] = gpkt->teid_data; } + add_new_session_teids(sess, gparsed->matched_session); } else if (gpkt->response_cause >= 64 && gpkt->response_cause <= 239) { current = SESSION_STATE_OVER; *action = ACCESS_ACTION_REJECT; @@ -1477,6 +1519,8 @@ static void apply_gtp_fsm_logic(gtp_global_t *glob, if (gpkt->teid_data != 0) { gparsed->matched_session->data_teid[1] = gpkt->teid_data; } + add_new_session_teids(sess, gparsed->matched_session); + } else if (gpkt->response_cause >= 192) { current = SESSION_STATE_OVER; *action = ACCESS_ACTION_REJECT; diff --git a/src/collector/gtp_worker.c b/src/collector/gtp_worker.c index 1437bc1..4ca084e 100644 --- a/src/collector/gtp_worker.c +++ b/src/collector/gtp_worker.c @@ -320,9 +320,103 @@ static void push_gtp_session_over(openli_gtp_worker_t *worker, } } +static void add_teid_to_session_mapping(openli_gtp_worker_t *worker, + access_session_t *sess, uint32_t teid, internet_user_t *iuser) { + + teid_to_session_t *found; + char keystr[1024]; + + memset(keystr, 0, 1024); + + if (teid == 0) { + logger(LOG_INFO, "OpenLI: called add_teid_to_session_mapping() but the assigned TEID is zero for the session?"); + return; + } + snprintf(keystr, 1024, "%s-%u", sess->gtp_tunnel_endpoints, teid); + + printf("TEID ID: %s\n", keystr); + + HASH_FIND(hh, worker->all_data_teids, keystr, strlen(keystr), found); + if (found && found->cin == sess->cin) { + found->session = realloc(found->session, + (found->sessioncount + 1) * sizeof(access_session_t *)); + found->owner = realloc(found->owner, + (found->sessioncount + 1) * sizeof(internet_user_t *)); + found->session[found->sessioncount] = sess; + found->owner[found->sessioncount] = iuser; + found->sessioncount ++; + return; + } else if (found) { + /* a silent log-off scenario? XXX do we need to generate an IRI? */ + + /* For now, just delete the old entry and fall through... */ + HASH_DELETE(hh, worker->all_data_teids, found); + free(found->idstring); + free(found->session); + free(found->owner); + free(found); + } + + found = calloc(1, sizeof(teid_to_session_t)); + found->idstring = strdup(keystr); + found->teid = teid; + found->cin = sess->cin; + found->sessioncount = 1; + found->session = calloc(1, sizeof(access_session_t *)); + found->owner = calloc(1, sizeof(internet_user_t *)); + found->session[0] = sess; + found->owner[0] = iuser; + + HASH_ADD_KEYPTR(hh, worker->all_data_teids, &(found->teid), + sizeof(found->teid), found); +} + +static void remove_teid_to_session_mapping(openli_gtp_worker_t *worker, + access_session_t *sess, uint32_t teid) { + + teid_to_session_t *found; + int nullsess = 0, i; + char keystr[1024]; + + if (!sess->teids_mapped) { + return; + } + snprintf(keystr, 1024, "%s-%u", sess->gtp_tunnel_endpoints, teid); + printf("DELETING %s\n", keystr); + + HASH_FIND(hh, worker->all_data_teids, keystr, strlen(keystr), found); + if (!found) { + /* Weird, but ok we'll just ignore this */ + return; + } + + for (i = 0; i < found->sessioncount; i++) { + if (found->session[i] == NULL) { + nullsess ++; + continue; + } + if (found->session[i] == sess) { + found->session[i] = NULL; + found->owner[i] = NULL; + nullsess ++; + } + } + if (nullsess == found->sessioncount) { + /* All sessions relating to this TEID have been removed, so + * free the entire object + */ + HASH_DELETE(hh, worker->all_data_teids, found); + free(found->idstring); + free(found->session); + free(found->owner); + free(found); + } + +} static void newly_active_gtp_session(openli_gtp_worker_t *worker, - user_intercept_list_t *userint, access_session_t *sess) { + user_intercept_list_t *userint, access_session_t *sess, + internet_user_t *iuser) { ipintercept_t *ipint, *tmp; sync_sendq_t *sendq, *tmpq; @@ -334,6 +428,11 @@ static void newly_active_gtp_session(openli_gtp_worker_t *worker, /* Save the Data TEIDs for this session as we have to now * intercept GTP-U for those TEIDs from now on -- TODO */ + if (sess->identifier_type & OPENLI_ACCESS_SESSION_TEID) { + add_teid_to_session_mapping(worker, sess, sess->teids[0], iuser); + add_teid_to_session_mapping(worker, sess, sess->teids[1], iuser); + sess->teids_mapped = 1; + } if (sess->sessipcount == 0) { return; @@ -442,9 +541,54 @@ static void generate_encoding_jobs(openli_gtp_worker_t *worker, } static void process_gtp_u_packet(openli_gtp_worker_t *worker UNUSED, - uint8_t *payload UNUSED, uint32_t plen UNUSED, - uint32_t teid UNUSED) { + libtrace_packet_t *packet, uint8_t *payload UNUSED, + uint32_t plen UNUSED, uint32_t teid) { + void *l3; + uint16_t ethertype; + uint32_t rem; + + char keystr[1024]; + + l3 = trace_get_layer3(packet, ðertype, &rem); + if (l3 == NULL || rem < sizeof(libtrace_ip_t)) { + return; + } + if (ethertype == TRACE_ETHERTYPE_IP) { + libtrace_ip_t *ip = (libtrace_ip_t *)l3; + + if (ip->ip_src.s_addr < ip->ip_dst.s_addr) { + snprintf(keystr, 1024, "%u-%u-%u", ip->ip_src.s_addr, + ip->ip_dst.s_addr, teid); + } else { + snprintf(keystr, 1024, "%u-%u-%u", ip->ip_dst.s_addr, + ip->ip_src.s_addr, teid); + } + } else if (ethertype == TRACE_ETHERTYPE_IPV6) { + libtrace_ip6_t *ip6 = (libtrace_ip6_t *)l3; + if (rem < sizeof(libtrace_ip6_t)) { + return; + } + if (memcmp(&(ip6->ip_src.s6_addr), &(ip6->ip_dst.s6_addr), 16) < 0) { + snprintf(keystr, 1024, "%lu-%lu-%lu-%lu-%u", + *(uint64_t *)(&(ip6->ip_src.s6_addr)), + *(uint64_t *)(&(ip6->ip_src.s6_addr[8])), + *(uint64_t *)(&(ip6->ip_dst.s6_addr)), + *(uint64_t *)(&(ip6->ip_dst.s6_addr[8])), + teid); + } else { + snprintf(keystr, 1024, "%lu-%lu-%lu-%lu-%u", + *(uint64_t *)(&(ip6->ip_dst.s6_addr)), + *(uint64_t *)(&(ip6->ip_dst.s6_addr[8])), + *(uint64_t *)(&(ip6->ip_src.s6_addr)), + *(uint64_t *)(&(ip6->ip_src.s6_addr[8])), + teid); + } + } else { + return; + } + + printf("GTP-U: lookup for %s\n", keystr); } @@ -498,11 +642,12 @@ static void process_gtp_c_packet(openli_gtp_worker_t *worker, if (oldstate != newstate) { if (newstate == SESSION_STATE_ACTIVE) { - newly_active_gtp_session(worker, userint, sess); + newly_active_gtp_session(worker, userint, sess, iuser); } else if (newstate == SESSION_STATE_OVER) { push_gtp_session_over(worker, userint, sess); - + remove_teid_to_session_mapping(worker, sess, sess->teids[0]); + remove_teid_to_session_mapping(worker, sess, sess->teids[1]); } } @@ -592,7 +737,7 @@ static void process_gtp_packet(openli_gtp_worker_t *worker, if (msgtype == 0xff) { /* This is GTP-U */ - process_gtp_u_packet(worker, payload, plen, teid); + process_gtp_u_packet(worker, packet, payload, plen, teid); } else { /* This is GTP-C */ process_gtp_c_packet(worker, packet); @@ -717,6 +862,7 @@ void *gtp_thread_begin(void *arg) { char sockname[256]; int zero = 0, x; openli_state_update_t recvd; + teid_to_session_t *iter, *tmp; worker->zmq_pubsocks = calloc(worker->tracker_threads, sizeof(void *)); init_zmq_socket_array(worker->zmq_pubsocks, worker->tracker_threads, @@ -766,6 +912,14 @@ void *gtp_thread_begin(void *arg) { logger(LOG_INFO, "OpenLI: halting GTP processing thread %d", worker->workerid); + HASH_ITER(hh, worker->all_data_teids, iter, tmp) { + HASH_DELETE(hh, worker->all_data_teids, iter); + free(iter->idstring); + free(iter->session); + free(iter->owner); + free(iter); + } + zmq_close(worker->zmq_ii_sock); zmq_close(worker->zmq_colthread_recvsock); free_all_users(worker->allusers); @@ -802,6 +956,7 @@ int start_gtp_worker_thread(openli_gtp_worker_t *worker, int id, worker->tracker_threads = glob->seqtracker_threads; worker->ipintercepts = NULL; worker->allusers = NULL; + worker->all_data_teids = NULL; worker->userintercepts = NULL; worker->gtpplugin = get_gtp_access_plugin(); worker->freegenerics = create_etsili_generic_freelist(1); diff --git a/src/collector/gtp_worker.h b/src/collector/gtp_worker.h index 002af27..10881df 100644 --- a/src/collector/gtp_worker.h +++ b/src/collector/gtp_worker.h @@ -81,6 +81,9 @@ typedef struct openli_gtp_worker { * sessions */ internet_user_t *allusers; + /* Set of all data TEIDs for active intercepts */ + teid_to_session_t *all_data_teids; + /* Map of user identities -> active intercepts */ user_intercept_list_t *userintercepts; diff --git a/src/collector/internetaccess.c b/src/collector/internetaccess.c index 4e27a8b..21bb445 100644 --- a/src/collector/internetaccess.c +++ b/src/collector/internetaccess.c @@ -114,6 +114,9 @@ static inline void free_session(access_session_t *sess) { if (sess->plugin) { sess->plugin->destroy_session_data(sess->plugin, sess); } + if (sess->gtp_tunnel_endpoints) { + free(sess->gtp_tunnel_endpoints); + } if (sess->sessionips) { free(sess->sessionips); } @@ -243,6 +246,10 @@ access_session_t *create_access_session(access_plugin_t *p, char *sessid, newsess->started.tv_sec = 0; newsess->started.tv_usec = 0; + newsess->teids[0] = 0; + newsess->teids[1] = 0; + newsess->teids_mapped = 0; + newsess->gtp_tunnel_endpoints = NULL; return newsess; } diff --git a/src/collector/internetaccess.h b/src/collector/internetaccess.h index c984499..3a60438 100644 --- a/src/collector/internetaccess.h +++ b/src/collector/internetaccess.h @@ -110,6 +110,7 @@ typedef struct ip_to_session { } ip_to_session_t; typedef struct teid_to_session { + char *idstring; uint32_t teid; int sessioncount; access_session_t **session; @@ -142,6 +143,10 @@ struct access_session { struct timeval started; + char *gtp_tunnel_endpoints; + uint32_t teids[2]; + uint8_t teids_mapped; + UT_hash_handle hh; } ; From 6351c9369c4106211352d9e11479f026db27ae56 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Fri, 16 Aug 2024 19:13:00 +1200 Subject: [PATCH 19/44] Remove debug output prior to merging with develop --- src/collector/gtp_worker.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/collector/gtp_worker.c b/src/collector/gtp_worker.c index 4ca084e..6c3db61 100644 --- a/src/collector/gtp_worker.c +++ b/src/collector/gtp_worker.c @@ -334,7 +334,7 @@ static void add_teid_to_session_mapping(openli_gtp_worker_t *worker, } snprintf(keystr, 1024, "%s-%u", sess->gtp_tunnel_endpoints, teid); - printf("TEID ID: %s\n", keystr); + //printf("TEID ID: %s\n", keystr); HASH_FIND(hh, worker->all_data_teids, keystr, strlen(keystr), found); if (found && found->cin == sess->cin) { @@ -382,7 +382,7 @@ static void remove_teid_to_session_mapping(openli_gtp_worker_t *worker, return; } snprintf(keystr, 1024, "%s-%u", sess->gtp_tunnel_endpoints, teid); - printf("DELETING %s\n", keystr); + //printf("DELETING %s\n", keystr); HASH_FIND(hh, worker->all_data_teids, keystr, strlen(keystr), found); if (!found) { @@ -588,7 +588,7 @@ static void process_gtp_u_packet(openli_gtp_worker_t *worker UNUSED, return; } - printf("GTP-U: lookup for %s\n", keystr); + //printf("GTP-U: lookup for %s\n", keystr); } From d7d42a00cd1bf1485faca68ce2e7ba6067dda817 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Mon, 19 Aug 2024 11:55:33 +1200 Subject: [PATCH 20/44] GTP: TEIDs are not bidirectionally unique The only entity that matters for a TEID's uniqueness is the destination IP. This means that the same TEID can be used for both A->B and B->A paths, which would have broken our previous approach. This change should fix that problem, but needs to be properly tested with traffic for the GTP-C and GTP-U channels from the same session to confirm. --- src/collector/accessplugins/gtp.c | 119 +++++++++++++++++++++--------- src/collector/gtp_worker.c | 61 +++++++-------- src/collector/internetaccess.c | 10 ++- src/collector/internetaccess.h | 2 +- 4 files changed, 120 insertions(+), 72 deletions(-) diff --git a/src/collector/accessplugins/gtp.c b/src/collector/accessplugins/gtp.c index 6ddfc66..37bbc0c 100644 --- a/src/collector/accessplugins/gtp.c +++ b/src/collector/accessplugins/gtp.c @@ -129,6 +129,7 @@ typedef struct gtp_session { int idstr_imei_len; uint32_t control_teid[2]; uint32_t data_teid[2]; + char *tunnel_endpoints[2]; internetaccess_ip_t *pdpaddrs; uint8_t pdpaddrcount; @@ -139,8 +140,6 @@ typedef struct gtp_session { uint8_t serverid[16]; uint8_t serveripfamily; - char *tunnel_endpoints; - session_state_t current; uint64_t last_reqid; @@ -165,6 +164,7 @@ struct gtp_saved_packet { uint32_t teid_ctl; uint32_t teid_data; uint32_t teid; + char *endpoint_ip; uint8_t *ipcontent; uint16_t iplen; @@ -190,7 +190,7 @@ typedef struct gtp_parsed { uint8_t serveripfamily; uint8_t serverid[16]; - char tunnel_endpoints[256]; + char tunnel_endpoint[256]; char imsi[16]; char msisdn[16]; char imei[16]; @@ -230,7 +230,7 @@ static void reset_parsed_pkt(gtp_parsed_t *parsed) { parsed->bearerid = 255; parsed->serveripfamily = 0; - memset(parsed->tunnel_endpoints, 0, 256); + memset(parsed->tunnel_endpoint, 0, 256); memset(parsed->serverid, 0, 16); memset(parsed->imsi, 0, 16); memset(parsed->imei, 0, 16); @@ -271,8 +271,11 @@ static inline void destroy_gtp_session(gtp_session_t *sess) { free(sess->sessid); } - if (sess->tunnel_endpoints) { - free(sess->tunnel_endpoints); + if (sess->tunnel_endpoints[0]) { + free(sess->tunnel_endpoints[0]); + } + if (sess->tunnel_endpoints[1]) { + free(sess->tunnel_endpoints[1]); } if (sess->altsessid) { @@ -383,6 +386,9 @@ static void gtp_destroy_parsed_data(access_plugin_t *p UNUSED, void *parsed) { if (gparsed->request->ipcontent) { free(gparsed->request->ipcontent); } + if (gparsed->request->endpoint_ip) { + free(gparsed->request->endpoint_ip); + } gtp_free_ie_list(gparsed->request->ies); free(gparsed->request); } @@ -391,6 +397,9 @@ static void gtp_destroy_parsed_data(access_plugin_t *p UNUSED, void *parsed) { if (gparsed->response->ipcontent) { free(gparsed->response->ipcontent); } + if (gparsed->response->endpoint_ip) { + free(gparsed->response->endpoint_ip); + } gtp_free_ie_list(gparsed->response->ies); free(gparsed->response); } @@ -809,6 +818,9 @@ static void flush_old_gtp_packets(gtp_global_t *glob, double ts) { if (pkt->ipcontent) { free(pkt->ipcontent); } + if (pkt->endpoint_ip) { + free(pkt->endpoint_ip); + } JLD(rc, glob->saved_packets, pkt->reqid); free(pkt); purged ++; @@ -955,17 +967,18 @@ static void *gtp_parse_packet(access_plugin_t *p, libtrace_packet_t *pkt) { /* It appears that update bearer requests are sent by the server. * Every other request so far is sent by the UE / client */ - - if (ip->ip_src.s_addr < ip->ip_dst.s_addr) { - snprintf(glob->parsedpkt->tunnel_endpoints, 256, "%u-%u", - ip->ip_src.s_addr, ip->ip_dst.s_addr); - } else { - snprintf(glob->parsedpkt->tunnel_endpoints, 256, "%u-%u", - ip->ip_dst.s_addr, ip->ip_src.s_addr); - } - switch(glob->parsedpkt->msgtype) { case GTPV2_CREATE_SESSION_REQUEST: + case GTPV1_CREATE_PDP_CONTEXT_REQUEST: + /* Use source IP because the TEID to use is announced by the + * intended recipient. + */ + snprintf(glob->parsedpkt->tunnel_endpoint, 256, "%u", + ip->ip_src.s_addr); + + memcpy(glob->parsedpkt->serverid, &(ip->ip_dst.s_addr), 4); + break; + case GTPV2_DELETE_SESSION_REQUEST: case GTPV2_MODIFY_BEARER_REQUEST: case GTPV2_CREATE_BEARER_REQUEST: @@ -973,12 +986,21 @@ static void *gtp_parse_packet(access_plugin_t *p, libtrace_packet_t *pkt) { case GTPV2_UPDATE_BEARER_RESPONSE: case GTPV2_MODIFY_BEARER_COMMAND: case GTPV2_DELETE_BEARER_COMMAND: - case GTPV1_CREATE_PDP_CONTEXT_REQUEST: case GTPV1_UPDATE_PDP_CONTEXT_REQUEST: case GTPV1_DELETE_PDP_CONTEXT_REQUEST: memcpy(glob->parsedpkt->serverid, &(ip->ip_dst.s_addr), 4); break; case GTPV2_CREATE_SESSION_RESPONSE: + case GTPV1_CREATE_PDP_CONTEXT_RESPONSE: + /* Use source IP because the TEID to use is announced by the + * intended recipient. + */ + snprintf(glob->parsedpkt->tunnel_endpoint, 256, "%u", + ip->ip_src.s_addr); + + memcpy(glob->parsedpkt->serverid, &(ip->ip_src.s_addr), 4); + break; + case GTPV2_DELETE_SESSION_RESPONSE: case GTPV2_MODIFY_BEARER_RESPONSE: case GTPV2_CREATE_BEARER_RESPONSE: @@ -986,7 +1008,6 @@ static void *gtp_parse_packet(access_plugin_t *p, libtrace_packet_t *pkt) { case GTPV2_DELETE_BEARER_RESPONSE: case GTPV2_MODIFY_BEARER_FAILURE_INDICATION: case GTPV2_DELETE_BEARER_FAILURE_INDICATION: - case GTPV1_CREATE_PDP_CONTEXT_RESPONSE: case GTPV1_UPDATE_PDP_CONTEXT_RESPONSE: case GTPV1_DELETE_PDP_CONTEXT_RESPONSE: memcpy(glob->parsedpkt->serverid, &(ip->ip_src.s_addr), 4); @@ -1000,22 +1021,20 @@ static void *gtp_parse_packet(access_plugin_t *p, libtrace_packet_t *pkt) { glob->parsedpkt->serveripfamily = 6; - if (memcmp(&(ip6->ip_src.s6_addr), &(ip6->ip_dst.s6_addr), 16) < 0) { - snprintf(glob->parsedpkt->tunnel_endpoints, 256, "%lu-%lu-%lu-%lu", - *(uint64_t *)(&(ip6->ip_src.s6_addr)), - *(uint64_t *)(&(ip6->ip_src.s6_addr[8])), - *(uint64_t *)(&(ip6->ip_dst.s6_addr)), - *(uint64_t *)(&(ip6->ip_dst.s6_addr[8]))); - } else { - snprintf(glob->parsedpkt->tunnel_endpoints, 256, "%lu-%lu-%lu-%lu", - *(uint64_t *)(&(ip6->ip_dst.s6_addr)), - *(uint64_t *)(&(ip6->ip_dst.s6_addr[8])), - *(uint64_t *)(&(ip6->ip_src.s6_addr)), - *(uint64_t *)(&(ip6->ip_src.s6_addr[8]))); - } - switch(glob->parsedpkt->msgtype) { case GTPV2_CREATE_SESSION_REQUEST: + case GTPV1_CREATE_PDP_CONTEXT_REQUEST: + /* Use source IP because the TEID to use is announced by the + * intended recipient. + */ + snprintf(glob->parsedpkt->tunnel_endpoint, 256, "%lu-%lu", + *(uint64_t *)(&(ip6->ip_src.s6_addr)), + *(uint64_t *)(&(ip6->ip_src.s6_addr[8]))); + + memcpy(glob->parsedpkt->serverid, &(ip6->ip_dst.s6_addr), + 16); + break; + case GTPV2_DELETE_SESSION_REQUEST: case GTPV2_MODIFY_BEARER_REQUEST: case GTPV2_CREATE_BEARER_REQUEST: @@ -1023,13 +1042,25 @@ static void *gtp_parse_packet(access_plugin_t *p, libtrace_packet_t *pkt) { case GTPV2_DELETE_BEARER_REQUEST: case GTPV2_MODIFY_BEARER_COMMAND: case GTPV2_DELETE_BEARER_COMMAND: - case GTPV1_CREATE_PDP_CONTEXT_REQUEST: case GTPV1_UPDATE_PDP_CONTEXT_REQUEST: case GTPV1_DELETE_PDP_CONTEXT_REQUEST: memcpy(glob->parsedpkt->serverid, &(ip6->ip_dst.s6_addr), 16); break; + case GTPV2_CREATE_SESSION_RESPONSE: + case GTPV1_CREATE_PDP_CONTEXT_RESPONSE: + /* Use source IP because the TEID to use is announced by the + * intended recipient. + */ + snprintf(glob->parsedpkt->tunnel_endpoint, 256, "%lu-%lu", + *(uint64_t *)(&(ip6->ip_src.s6_addr)), + *(uint64_t *)(&(ip6->ip_src.s6_addr[8]))); + + memcpy(glob->parsedpkt->serverid, &(ip6->ip_src.s6_addr), + 16); + break; + case GTPV2_DELETE_SESSION_RESPONSE: case GTPV2_MODIFY_BEARER_RESPONSE: case GTPV2_CREATE_BEARER_RESPONSE: @@ -1037,7 +1068,6 @@ static void *gtp_parse_packet(access_plugin_t *p, libtrace_packet_t *pkt) { case GTPV2_DELETE_BEARER_RESPONSE: case GTPV2_MODIFY_BEARER_FAILURE_INDICATION: case GTPV2_DELETE_BEARER_FAILURE_INDICATION: - case GTPV1_CREATE_PDP_CONTEXT_RESPONSE: case GTPV1_UPDATE_PDP_CONTEXT_RESPONSE: case GTPV1_DELETE_PDP_CONTEXT_RESPONSE: memcpy(glob->parsedpkt->serverid, &(ip6->ip_src.s6_addr), @@ -1188,6 +1218,9 @@ static user_identity_t *gtp_get_userid(access_plugin_t *p, void *parsed, saved->iplen = 0; saved->response_cause = gparsed->response_cause; saved->bearerid = gparsed->bearerid; + if (gparsed->tunnel_endpoint[0] != '\0') { + saved->endpoint_ip = strdup(gparsed->tunnel_endpoint); + } gparsed->ies = NULL; openli_copy_ipcontent(gparsed->origpkt, &(saved->ipcontent), @@ -1202,6 +1235,9 @@ static user_identity_t *gtp_get_userid(access_plugin_t *p, void *parsed, if (saved->ipcontent) { free(saved->ipcontent); } + if (saved->endpoint_ip) { + free(saved->endpoint_ip); + } free(saved); } return NULL; @@ -1218,7 +1254,7 @@ static user_identity_t *gtp_get_userid(access_plugin_t *p, void *parsed, sess->gtpversion = gparsed->version; sess->defaultbearer = 255; memcpy(sess->serverid, gparsed->serverid, 16); - sess->tunnel_endpoints = strdup(gparsed->tunnel_endpoints); + sess->tunnel_endpoints[0] = strdup(gparsed->tunnel_endpoint); sess->serveripfamily = gparsed->serveripfamily; JSLI(pval, glob->session_map, (unsigned char *)sess->sessid); @@ -1442,7 +1478,11 @@ static inline void add_new_session_teids(access_session_t *sess, sess->teids[0] = gsess->data_teid[0]; sess->teids[1] = gsess->data_teid[1]; - sess->gtp_tunnel_endpoints = strdup(gsess->tunnel_endpoints); + sess->gtp_tunnel_endpoints[0] = gsess->tunnel_endpoints[0]; + sess->gtp_tunnel_endpoints[1] = gsess->tunnel_endpoints[1]; + + gsess->tunnel_endpoints[0] = NULL; + gsess->tunnel_endpoints[1] = NULL; sess->identifier_type |= OPENLI_ACCESS_SESSION_TEID; } @@ -1496,6 +1536,9 @@ static void apply_gtp_fsm_logic(gtp_global_t *glob, } if (gpkt->teid_data != 0) { gparsed->matched_session->data_teid[1] = gpkt->teid_data; + gparsed->matched_session->tunnel_endpoints[1] = + gpkt->endpoint_ip; + gpkt->endpoint_ip = NULL; } add_new_session_teids(sess, gparsed->matched_session); } else if (gpkt->response_cause >= 64 && gpkt->response_cause <= 239) { @@ -1518,6 +1561,9 @@ static void apply_gtp_fsm_logic(gtp_global_t *glob, } if (gpkt->teid_data != 0) { gparsed->matched_session->data_teid[1] = gpkt->teid_data; + gparsed->matched_session->tunnel_endpoints[1] = + gpkt->endpoint_ip; + gpkt->endpoint_ip = NULL; } add_new_session_teids(sess, gparsed->matched_session); @@ -1765,6 +1811,9 @@ static access_session_t *gtp_update_session_state(access_plugin_t *p, if (check->ipcontent) { free(check->ipcontent); } + if (check->endpoint_ip) { + free(check->endpoint_ip); + } gtp_free_ie_list(check->ies); free(check); return NULL; diff --git a/src/collector/gtp_worker.c b/src/collector/gtp_worker.c index 6c3db61..85cfc35 100644 --- a/src/collector/gtp_worker.c +++ b/src/collector/gtp_worker.c @@ -321,7 +321,8 @@ static void push_gtp_session_over(openli_gtp_worker_t *worker, } static void add_teid_to_session_mapping(openli_gtp_worker_t *worker, - access_session_t *sess, uint32_t teid, internet_user_t *iuser) { + access_session_t *sess, uint32_t teid, char *endpoint_ip, + internet_user_t *iuser) { teid_to_session_t *found; char keystr[1024]; @@ -332,7 +333,11 @@ static void add_teid_to_session_mapping(openli_gtp_worker_t *worker, logger(LOG_INFO, "OpenLI: called add_teid_to_session_mapping() but the assigned TEID is zero for the session?"); return; } - snprintf(keystr, 1024, "%s-%u", sess->gtp_tunnel_endpoints, teid); + if (endpoint_ip == NULL) { + logger(LOG_INFO, "OpenLI: called add_teid_to_session_mapping() but the endpoint IP is NULL for the session?"); + return; + } + snprintf(keystr, 1024, "%s-%u", endpoint_ip, teid); //printf("TEID ID: %s\n", keystr); @@ -372,7 +377,7 @@ static void add_teid_to_session_mapping(openli_gtp_worker_t *worker, } static void remove_teid_to_session_mapping(openli_gtp_worker_t *worker, - access_session_t *sess, uint32_t teid) { + access_session_t *sess, uint32_t teid, char *endpoint_ip) { teid_to_session_t *found; int nullsess = 0, i; @@ -381,8 +386,11 @@ static void remove_teid_to_session_mapping(openli_gtp_worker_t *worker, if (!sess->teids_mapped) { return; } - snprintf(keystr, 1024, "%s-%u", sess->gtp_tunnel_endpoints, teid); - //printf("DELETING %s\n", keystr); + if (endpoint_ip == NULL) { + return; + } + snprintf(keystr, 1024, "%s-%u", endpoint_ip, teid); + printf("DELETING %s\n", keystr); HASH_FIND(hh, worker->all_data_teids, keystr, strlen(keystr), found); if (!found) { @@ -425,12 +433,14 @@ static void newly_active_gtp_session(openli_gtp_worker_t *worker, return; } - /* Save the Data TEIDs for this session as we have to now - * intercept GTP-U for those TEIDs from now on -- TODO + /* Save the Data TEIDs for this session as we have to + * intercept GTP-U for those TEIDs from now on */ if (sess->identifier_type & OPENLI_ACCESS_SESSION_TEID) { - add_teid_to_session_mapping(worker, sess, sess->teids[0], iuser); - add_teid_to_session_mapping(worker, sess, sess->teids[1], iuser); + add_teid_to_session_mapping(worker, sess, sess->teids[0], + sess->gtp_tunnel_endpoints[0], iuser); + add_teid_to_session_mapping(worker, sess, sess->teids[1], + sess->gtp_tunnel_endpoints[1], iuser); sess->teids_mapped = 1; } @@ -557,33 +567,16 @@ static void process_gtp_u_packet(openli_gtp_worker_t *worker UNUSED, if (ethertype == TRACE_ETHERTYPE_IP) { libtrace_ip_t *ip = (libtrace_ip_t *)l3; - if (ip->ip_src.s_addr < ip->ip_dst.s_addr) { - snprintf(keystr, 1024, "%u-%u-%u", ip->ip_src.s_addr, - ip->ip_dst.s_addr, teid); - } else { - snprintf(keystr, 1024, "%u-%u-%u", ip->ip_dst.s_addr, - ip->ip_src.s_addr, teid); - } + snprintf(keystr, 1024, "%u-%u", ip->ip_dst.s_addr, teid); } else if (ethertype == TRACE_ETHERTYPE_IPV6) { libtrace_ip6_t *ip6 = (libtrace_ip6_t *)l3; if (rem < sizeof(libtrace_ip6_t)) { return; } - if (memcmp(&(ip6->ip_src.s6_addr), &(ip6->ip_dst.s6_addr), 16) < 0) { - snprintf(keystr, 1024, "%lu-%lu-%lu-%lu-%u", - *(uint64_t *)(&(ip6->ip_src.s6_addr)), - *(uint64_t *)(&(ip6->ip_src.s6_addr[8])), - *(uint64_t *)(&(ip6->ip_dst.s6_addr)), - *(uint64_t *)(&(ip6->ip_dst.s6_addr[8])), - teid); - } else { - snprintf(keystr, 1024, "%lu-%lu-%lu-%lu-%u", - *(uint64_t *)(&(ip6->ip_dst.s6_addr)), - *(uint64_t *)(&(ip6->ip_dst.s6_addr[8])), - *(uint64_t *)(&(ip6->ip_src.s6_addr)), - *(uint64_t *)(&(ip6->ip_src.s6_addr[8])), - teid); - } + snprintf(keystr, 1024, "%lu-%lu-%u", + *(uint64_t *)(&(ip6->ip_dst.s6_addr)), + *(uint64_t *)(&(ip6->ip_dst.s6_addr[8])), + teid); } else { return; } @@ -646,8 +639,10 @@ static void process_gtp_c_packet(openli_gtp_worker_t *worker, } else if (newstate == SESSION_STATE_OVER) { push_gtp_session_over(worker, userint, sess); - remove_teid_to_session_mapping(worker, sess, sess->teids[0]); - remove_teid_to_session_mapping(worker, sess, sess->teids[1]); + remove_teid_to_session_mapping(worker, sess, sess->teids[0], + sess->gtp_tunnel_endpoints[0]); + remove_teid_to_session_mapping(worker, sess, sess->teids[1], + sess->gtp_tunnel_endpoints[1]); } } diff --git a/src/collector/internetaccess.c b/src/collector/internetaccess.c index 21bb445..1cb7754 100644 --- a/src/collector/internetaccess.c +++ b/src/collector/internetaccess.c @@ -114,8 +114,11 @@ static inline void free_session(access_session_t *sess) { if (sess->plugin) { sess->plugin->destroy_session_data(sess->plugin, sess); } - if (sess->gtp_tunnel_endpoints) { - free(sess->gtp_tunnel_endpoints); + if (sess->gtp_tunnel_endpoints[0]) { + free(sess->gtp_tunnel_endpoints[0]); + } + if (sess->gtp_tunnel_endpoints[1]) { + free(sess->gtp_tunnel_endpoints[1]); } if (sess->sessionips) { free(sess->sessionips); @@ -249,7 +252,8 @@ access_session_t *create_access_session(access_plugin_t *p, char *sessid, newsess->teids[0] = 0; newsess->teids[1] = 0; newsess->teids_mapped = 0; - newsess->gtp_tunnel_endpoints = NULL; + newsess->gtp_tunnel_endpoints[0] = NULL; + newsess->gtp_tunnel_endpoints[1] = NULL; return newsess; } diff --git a/src/collector/internetaccess.h b/src/collector/internetaccess.h index 3a60438..5c1ed33 100644 --- a/src/collector/internetaccess.h +++ b/src/collector/internetaccess.h @@ -143,7 +143,7 @@ struct access_session { struct timeval started; - char *gtp_tunnel_endpoints; + char *gtp_tunnel_endpoints[2]; uint32_t teids[2]; uint8_t teids_mapped; From 0a0d038e17faf01f55bbb0d1b0b754e725a3cbd3 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Mon, 19 Aug 2024 18:02:25 +1200 Subject: [PATCH 21/44] Partial progress towards EPSCC encoding implementation Mostly just setting up the encoding job and ensuring it gets to the encoder worker. The actual encoding is still to come, but I think I have all the info I need to encode a complete and valid CC record. --- src/Makefile.am | 1 + src/collector/collector_publish.c | 11 +- src/collector/collector_publish.h | 35 ++ src/collector/collector_seqtracker.c | 8 +- src/collector/encoder_worker.c | 60 +++- src/collector/encoder_worker.h | 4 + src/collector/epscc.h | 48 +++ src/collector/etsiencoding/epscc.c | 66 ++++ src/collector/etsiencoding/epsiri.c | 13 - src/collector/etsiencoding/etsiencoding.c | 1 + src/collector/gtp_worker.c | 389 ++++++++++++++-------- src/collector/internetaccess.h | 1 + 12 files changed, 470 insertions(+), 167 deletions(-) create mode 100644 src/collector/epscc.h create mode 100644 src/collector/etsiencoding/epscc.c diff --git a/src/Makefile.am b/src/Makefile.am index 4837936..f6e314e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -72,6 +72,7 @@ openlicollector_SOURCES=collector/collector.c configparser.c configparser.h \ collector/etsiencoding/encryptcontainer.c \ collector/etsiencoding/ipmmiri.c \ collector/etsiencoding/epsiri.c collector/epsiri.h \ + collector/etsiencoding/epscc.c collector/epscc.h \ collector/sms_worker.c collector/sms_worker.h \ collector/gtp_worker.c collector/gtp_worker.h \ collector/gtp.h \ diff --git a/src/collector/collector_publish.c b/src/collector/collector_publish.c index 7123181..2a90235 100644 --- a/src/collector/collector_publish.c +++ b/src/collector/collector_publish.c @@ -88,7 +88,14 @@ void free_published_message(openli_export_recv_t *msg) { if (msg->data.ipcc.ipcontent) { free(msg->data.ipcc.ipcontent); } - } else if (msg->type == OPENLI_EXPORT_EMAILCC) { + } else if (msg->type == OPENLI_EXPORT_EPSCC) { + if (msg->data.mobcc.liid) { + free(msg->data.mobcc.liid); + } + if (msg->data.mobcc.ipcontent) { + free(msg->data.mobcc.ipcontent); + } + }else if (msg->type == OPENLI_EXPORT_EMAILCC) { if (msg->data.emailcc.liid) { free(msg->data.emailcc.liid); } @@ -139,7 +146,7 @@ void free_published_message(openli_export_recv_t *msg) { free(msg); } -static openli_export_recv_t *create_rawip_job_from_ip(char *liid, +openli_export_recv_t *create_rawip_job_from_ip(char *liid, uint32_t destid, void *l3, uint32_t l3_len, struct timeval tv, uint8_t msgtype) { diff --git a/src/collector/collector_publish.h b/src/collector/collector_publish.h index c234b8f..c084d73 100644 --- a/src/collector/collector_publish.h +++ b/src/collector/collector_publish.h @@ -78,6 +78,15 @@ typedef struct openli_ipcc_job { uint8_t dir; } PACKED openli_ipcc_job_t; +typedef struct openli_mobcc_job { + char *liid; + uint32_t cin; + uint8_t dir; + uint8_t *ipcontent; + uint32_t ipclen; + uint8_t icetype; +} PACKED openli_mobcc_job_t; + typedef struct openli_emailiri_job { char *liid; uint32_t cin; @@ -119,6 +128,7 @@ typedef struct openli_mobiri_job { etsili_generic_t *customparams; } openli_mobiri_job_t; + typedef struct openli_ipiri_job { char *liid; uint32_t cin; @@ -188,6 +198,7 @@ struct openli_export_recv { openli_ipmmiri_job_t ipmmiri; openli_ipiri_job_t ipiri; openli_mobiri_job_t mobiri; + openli_mobcc_job_t mobcc; openli_rawip_job_t rawip; openli_emailiri_job_t emailiri; openli_emailcc_job_t emailcc; @@ -203,6 +214,30 @@ openli_export_recv_t *create_ipcc_job( uint32_t cin, char *liid, uint32_t destid, libtrace_packet_t *pkt, uint8_t dir); +/** Creates a raw IP packet encoding job from a pointer to an IP header. + * Supports creating messages using both the OPENLI_EXPORT_RAW_CC type and + * the OPENLI_EXPORT_RAW_IRI type. + * + * Used to export IP packets that are being intercepted by pcapdisk + * IP data intercepts. + * + * @param liid The LIID that this packet has been intercepted for + * @param destid The mediator that should receive the raw IP packet + * @param l3 Pointer to the start of the IP header from the packet + * that is being intercepted + * @param l3_len The number of bytes in the intercepted packet, starting + * from the pointer given as `l3` + * @param tv The timestamp for the intercepted packet + * @param msgtype The type of job to encode (either OPENLI_EXPORT_RAW_CC + * or OPENLI_EXPORT_RAW_IRI) + * + * @return an encoding job that is ready to be published using + * publish_openli_msg() + */ +openli_export_recv_t *create_rawip_job_from_ip(char *liid, + uint32_t destid, void *l3, uint32_t l3_len, struct timeval tv, + uint8_t msgtype); + /** Creates a raw IP packet encoding job using the OPENLI_EXPORT_RAW_CC type. * * Used to export IP packets that are being intercepted by pcapdisk diff --git a/src/collector/collector_seqtracker.c b/src/collector/collector_seqtracker.c index 4f9add5..88bae4b 100644 --- a/src/collector/collector_seqtracker.c +++ b/src/collector/collector_seqtracker.c @@ -83,6 +83,8 @@ static inline char *extract_liid_from_job(openli_export_recv_t *recvd) { return recvd->data.emailiri.liid; case OPENLI_EXPORT_EMAILCC: return recvd->data.emailcc.liid; + case OPENLI_EXPORT_EPSCC: + return recvd->data.mobcc.liid; } return NULL; } @@ -109,6 +111,8 @@ static inline uint32_t extract_cin_from_job(openli_export_recv_t *recvd) { return recvd->data.emailiri.cin; case OPENLI_EXPORT_EMAILCC: return recvd->data.emailcc.cin; + case OPENLI_EXPORT_EPSCC: + return recvd->data.mobcc.cin; } logger(LOG_INFO, "OpenLI: invalid message type in extract_cin_from_job: %u", @@ -396,7 +400,8 @@ static int run_encoding_job(seqtracker_thread_data_t *seqdata, recvd->type == OPENLI_EXPORT_IPCC || recvd->type == OPENLI_EXPORT_UMTSCC || recvd->type == OPENLI_EXPORT_EMAILCC || - recvd->type == OPENLI_EXPORT_RAW_CC) { + recvd->type == OPENLI_EXPORT_RAW_CC || + recvd->type == OPENLI_EXPORT_EPSCC ) { job.seqno = cinseq->cc_seqno; cinseq->cc_seqno ++; @@ -482,6 +487,7 @@ static void seqtracker_main(seqtracker_thread_data_t *seqdata) { case OPENLI_EXPORT_RAW_CC: case OPENLI_EXPORT_RAW_IRI: case OPENLI_EXPORT_IPCC: + case OPENLI_EXPORT_EPSCC: run_encoding_job(seqdata, job); sincepurge ++; break; diff --git a/src/collector/encoder_worker.c b/src/collector/encoder_worker.c index 293f41a..c6de306 100644 --- a/src/collector/encoder_worker.c +++ b/src/collector/encoder_worker.c @@ -34,6 +34,7 @@ #include "umtsiri.h" #include "epsiri.h" #include "emailiri.h" +#include "epscc.h" #include "collector_base.h" #include "logger.h" #include "etsili_core.h" @@ -226,11 +227,8 @@ void destroy_encoder_worker(openli_encoder_t *enc) { } break; } - - if (job.origreq->type == OPENLI_EXPORT_IPCC) { + if (job.origreq) { free_published_message(job.origreq); - } else { - free(job.origreq); } if (job.liid) { free(job.liid); @@ -511,6 +509,56 @@ static inline void create_mobile_operator_identifier(openli_encoder_t *enc, } +static int encode_templated_epscc(openli_encoder_t *enc, + openli_encoding_job_t *job, encoded_header_template_t *hdr_tplate, + openli_encoded_result_t *res) { + + wandder_encoded_result_t *body = NULL; + openli_mobcc_job_t *epsccjob; + + epsccjob = (openli_mobcc_job_t *)&(job->origreq->data.mobcc); + + /* Templating is going to be difficult because of the timestamp and + * sequence number fields in the ULIC header + */ + reset_wandder_encoder(enc->encoder); + + body = encode_epscc_body(enc->encoder, job->preencoded, + job->cin, job->seqno, epsccjob->dir, job->origreq->ts, + epsccjob->icetype); + + if (body == NULL || body->len == 0 || body->encoded == NULL) { + logger(LOG_INFO, "OpenLI: failed to encode ETSI EPSCC body"); + if (body) { + wandder_release_encoded_result(enc->encoder, body); + } + return -1; + } + + if (job->encryptmethod != OPENLI_PAYLOAD_ENCRYPTION_NONE) { + if (create_encrypted_message_body(enc->encoder, &enc->encrypt, + res, hdr_tplate, + body->encoded, body->len, epsccjob->ipcontent, + epsccjob->ipclen, job) < 0) { + + wandder_release_encoded_result(enc->encoder, body); + return -1; + } + } else { + if (create_etsi_encoded_result(res, hdr_tplate, body->encoded, + body->len, epsccjob->ipcontent, epsccjob->ipclen, job) < 0) { + wandder_release_encoded_result(enc->encoder, body); + return -1; + } + } + + wandder_release_encoded_result(enc->encoder, body); + /* Success */ + return 1; + +} + + static int encode_templated_epsiri(openli_encoder_t *enc, openli_encoding_job_t *job, encoded_header_template_t *hdr_tplate, openli_encoded_result_t *res) { @@ -667,6 +715,7 @@ static int encode_templated_umtscc(openli_encoder_t *enc, } + static int encode_templated_emailcc(openli_encoder_t *enc, openli_encoding_job_t *job, encoded_header_template_t *hdr_tplate, openli_encoded_result_t *res) { @@ -893,6 +942,9 @@ static int encode_etsi(openli_encoder_t *enc, openli_encoding_job_t *job, case OPENLI_EXPORT_EMAILCC: ret = encode_templated_emailcc(enc, job, hdr_tplate, res); break; + case OPENLI_EXPORT_EPSCC: + ret = encode_templated_epscc(enc, job, hdr_tplate, res); + break; default: ret = 0; } diff --git a/src/collector/encoder_worker.h b/src/collector/encoder_worker.h index 7f4a6b7..d25c703 100644 --- a/src/collector/encoder_worker.h +++ b/src/collector/encoder_worker.h @@ -58,6 +58,10 @@ enum { TEMPLATE_TYPE_EMAILCC_APP_DIRFROM, TEMPLATE_TYPE_EMAILCC_IP_DIROTHER, TEMPLATE_TYPE_EMAILCC_APP_DIROTHER, + + TEMPLATE_TYPE_EPSCC_DIRFROM, + TEMPLATE_TYPE_EPSCC_DIRTO, + TEMPLATE_TYPE_EPSCC_DIROTHER, }; typedef struct saved_encoding_templates { diff --git a/src/collector/epscc.h b/src/collector/epscc.h new file mode 100644 index 0000000..0ed2bb1 --- /dev/null +++ b/src/collector/epscc.h @@ -0,0 +1,48 @@ +/* + * + * Copyright (c) 2024 SearchLight New Zealand. + * All rights reserved. + * + * This file is part of OpenLI. + * + * OpenLI was originally developed by the University of Waikato WAND + * research group. For further information please see http://www.wand.net.nz/ + * + * OpenLI is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenLI 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, see . + * + * + */ + +#ifndef OPENLI_EPSCC_H_ +#define OPENLI_EPSCC_H_ + +#include +#include +#include "collector.h" +#include "intercept.h" +#include "internetaccess.h" +#include "etsili_core.h" +#include "collector_sync.h" + +openli_export_recv_t *create_epscc_job(char *liid, uint32_t cin, + uint32_t destid, uint8_t dir, uint8_t *ipcontent, uint32_t ipclen, + uint8_t icetype); + +wandder_encoded_result_t *encode_epscc_body(wandder_encoder_t *encoder, + wandder_encode_job_t *precomputed, uint32_t cin, uint32_t seqno, + uint8_t dir, struct timeval tv, uint8_t icetype); + +#endif +// vim: set sw=4 tabstop=4 softtabstop=4 expandtab : + diff --git a/src/collector/etsiencoding/epscc.c b/src/collector/etsiencoding/epscc.c new file mode 100644 index 0000000..6e26890 --- /dev/null +++ b/src/collector/etsiencoding/epscc.c @@ -0,0 +1,66 @@ +/* + * + * Copyright (c) 2024 SearchLight NZ + * All rights reserved. + * + * This file is part of OpenLI. + * + * OpenLI was originally developed by the University of Waikato WAND + * research group. For further information please see http://www.wand.net.nz/ + * + * OpenLI is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * OpenLI 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, see . + * + * + */ + +#include +#include "etsiencoding.h" +#include "logger.h" +#include "intercept.h" +#include "etsili_core.h" +#include "epscc.h" + +openli_export_recv_t *create_epscc_job(char *liid, uint32_t cin, + uint32_t destid, uint8_t dir, uint8_t *ipcontent, uint32_t ipclen, + uint8_t icetype) { + + openli_export_recv_t *msg = NULL; + + msg = (openli_export_recv_t *)calloc(1, sizeof(openli_export_recv_t)); + if (msg == NULL) { + return msg; + } + + msg->type = OPENLI_EXPORT_EPSCC; + msg->destid = destid; + gettimeofday(&(msg->ts), NULL); + + msg->data.mobcc.liid = strdup(liid); + msg->data.mobcc.cin = cin; + msg->data.mobcc.dir = dir; + msg->data.mobcc.ipcontent = calloc(ipclen, sizeof(uint8_t)); + memcpy(msg->data.mobcc.ipcontent, ipcontent, ipclen); + msg->data.mobcc.ipclen = ipclen; + msg->data.mobcc.icetype = icetype; + + return msg; +} + +wandder_encoded_result_t *encode_epscc_body(wandder_encoder_t *encoder, + wandder_encode_job_t *precomputed UNUSED, uint32_t cin UNUSED, + uint32_t seqno UNUSED, uint8_t dir UNUSED, struct timeval tv UNUSED, + uint8_t icetype UNUSED) { + + return wandder_encode_finish(encoder); +} diff --git a/src/collector/etsiencoding/epsiri.c b/src/collector/etsiencoding/epsiri.c index a22f5bf..04de0a6 100644 --- a/src/collector/etsiencoding/epsiri.c +++ b/src/collector/etsiencoding/epsiri.c @@ -181,19 +181,6 @@ wandder_encoded_result_t *encode_epsiri_body(wandder_encoder_t *encoder, END_ENCODED_SEQUENCE(encoder, 3); /* gprs correlation number (18) */ - lookup = EPSIRI_CONTENTS_GPRS_CORRELATION; - HASH_FIND(hh, params, &lookup, sizeof(lookup), p); - if (!p) { - logger(LOG_INFO, - "OpenLI: warning, no GPRS correlation number available for building EPS IRI"); - logger(LOG_INFO, "OpenLI: EPS IRI record may be invalid..."); - } else { - char space[24]; - snprintf(space, 24, "%lu", *((uint64_t *)(p->itemptr))); - - wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, - WANDDER_CLASS_CONTEXT_PRIMITIVE, 18, space, strlen(space)); - } /* EPS event (20) */ lookup = EPSIRI_CONTENTS_EVENT_TYPE; diff --git a/src/collector/etsiencoding/etsiencoding.c b/src/collector/etsiencoding/etsiencoding.c index 0ba0dae..7097567 100644 --- a/src/collector/etsiencoding/etsiencoding.c +++ b/src/collector/etsiencoding/etsiencoding.c @@ -166,6 +166,7 @@ int create_etsi_encoded_result(openli_encoded_result_t *res, case OPENLI_EXPORT_IPMMCC: case OPENLI_EXPORT_UMTSCC: case OPENLI_EXPORT_EMAILCC: + case OPENLI_EXPORT_EPSCC: res->header.intercepttype = htons(OPENLI_PROTO_ETSI_CC); break; case OPENLI_EXPORT_IPIRI: diff --git a/src/collector/gtp_worker.c b/src/collector/gtp_worker.c index 85cfc35..b3203a4 100644 --- a/src/collector/gtp_worker.c +++ b/src/collector/gtp_worker.c @@ -36,6 +36,7 @@ #include "util.h" #include "intercept.h" #include "netcomms.h" +#include "epscc.h" static void remove_gtp_intercept(openli_gtp_worker_t *worker, ipintercept_t *ipint) { @@ -77,6 +78,192 @@ static void push_existing_ip_sessions(openli_gtp_worker_t *worker UNUSED, /* TODO */ } +static void add_teid_to_session_mapping(openli_gtp_worker_t *worker, + access_session_t *sess, uint8_t dir, internet_user_t *iuser) { + + teid_to_session_t *found; + char keystr[1024]; + uint8_t etsidir = ETSI_DIR_INDETERMINATE; + + memset(keystr, 0, 1024); + + if (sess->teids[dir] == 0) { + logger(LOG_INFO, "OpenLI: called add_teid_to_session_mapping() but the assigned TEID is zero for the session?"); + return; + } + if (sess->gtp_tunnel_endpoints[dir] == NULL) { + logger(LOG_INFO, "OpenLI: called add_teid_to_session_mapping() but the endpoint IP is NULL for the session?"); + return; + } + snprintf(keystr, 1024, "%s-%u", sess->gtp_tunnel_endpoints[dir], + sess->teids[dir]); + + /* Direction values for EPS CCs are {1, 2, 3} where 1 == from-target + * (i.e. teid[0]) and 2 == to-target (i.e. teid[1]). + */ + if (dir == 0) { + etsidir = ETSI_DIR_FROM_TARGET; + } else if (dir == 1) { + etsidir = ETSI_DIR_TO_TARGET; + } + + printf("TEID ID: %s\n", keystr); + + HASH_FIND(hh, worker->all_data_teids, keystr, strlen(keystr), found); + if (found && found->cin == sess->cin && found->dir == etsidir) { + found->session = realloc(found->session, + (found->sessioncount + 1) * sizeof(access_session_t *)); + found->owner = realloc(found->owner, + (found->sessioncount + 1) * sizeof(internet_user_t *)); + found->session[found->sessioncount] = sess; + found->owner[found->sessioncount] = iuser; + found->sessioncount ++; + return; + } else if (found) { + /* a silent log-off scenario? XXX do we need to generate an IRI? */ + + /* For now, just delete the old entry and fall through... */ + HASH_DELETE(hh, worker->all_data_teids, found); + free(found->idstring); + free(found->session); + free(found->owner); + free(found); + } + + found = calloc(1, sizeof(teid_to_session_t)); + found->idstring = strdup(keystr); + found->teid = sess->teids[dir]; + found->cin = sess->cin; + found->dir = etsidir; + found->sessioncount = 1; + found->session = calloc(1, sizeof(access_session_t *)); + found->owner = calloc(1, sizeof(internet_user_t *)); + found->session[0] = sess; + found->owner[0] = iuser; + + HASH_ADD_KEYPTR(hh, worker->all_data_teids, found->idstring, + strlen(found->idstring), found); +} + +static void remove_teid_to_session_mapping(openli_gtp_worker_t *worker, + access_session_t *sess, uint32_t teid, char *endpoint_ip) { + + teid_to_session_t *found; + int nullsess = 0, i; + char keystr[1024]; + + if (!sess->teids_mapped) { + return; + } + if (endpoint_ip == NULL) { + return; + } + snprintf(keystr, 1024, "%s-%u", endpoint_ip, teid); + printf("DELETING %s\n", keystr); + + HASH_FIND(hh, worker->all_data_teids, keystr, strlen(keystr), found); + if (!found) { + /* Weird, but ok we'll just ignore this */ + return; + } + + for (i = 0; i < found->sessioncount; i++) { + if (found->session[i] == NULL) { + nullsess ++; + continue; + } + if (found->session[i] == sess) { + found->session[i] = NULL; + found->owner[i] = NULL; + nullsess ++; + } + } + if (nullsess == found->sessioncount) { + /* All sessions relating to this TEID have been removed, so + * free the entire object + */ + HASH_DELETE(hh, worker->all_data_teids, found); + free(found->idstring); + free(found->session); + free(found->owner); + free(found); + } + +} + +static void newly_active_gtp_session(openli_gtp_worker_t *worker, + user_intercept_list_t *userint, access_session_t *sess, + internet_user_t *iuser) { + + ipintercept_t *ipint, *tmp; + sync_sendq_t *sendq, *tmpq; + + if (userint == NULL || sess == NULL) { + return; + } + + /* Save the Data TEIDs for this session as we have to + * intercept GTP-U for those TEIDs from now on + */ + if (sess->identifier_type & OPENLI_ACCESS_SESSION_TEID) { + add_teid_to_session_mapping(worker, sess, 0, iuser); + add_teid_to_session_mapping(worker, sess, 1, iuser); + sess->teids_mapped = 1; + } + + if (sess->sessipcount == 0) { + return; + } + + /* Tell the collector threads about any IPs associated with this + * newly active session. + */ + HASH_ITER(hh_user, userint->intlist, ipint, tmp) { + HASH_ITER(hh, (sync_sendq_t *)(worker->collector_queues), sendq, + tmpq) { + push_session_ips_to_collector_queue(sendq->q, ipint, sess); + } + } + +} + +static void setup_gtpu_testing_intercept(openli_gtp_worker_t *worker, + ipintercept_t *ipint) { + + internet_user_t *iuser; + user_intercept_list_t *userint; + access_session_t *sess; + user_identity_t newid; + + newid.method = USER_IDENT_GTP_MSISDN; + newid.idstr = "foobar"; + newid.idlength = strlen(newid.idstr); + + iuser = calloc(1, sizeof(internet_user_t)); + + add_userid_to_allusers_map(&worker->allusers, iuser, &newid); + + printf("iuser->userid: %s\n", iuser->userid); + HASH_FIND(hh, worker->userintercepts, iuser->userid, + strlen(iuser->userid), userint); + if (userint == NULL) { + logger(LOG_INFO, "NO USER INTERCEPT LIST for %s?", ipint->common.liid); + return; + } + + sess = create_access_session(worker->gtpplugin, "foobar", strlen("foobar")); + sess->identifier_type = OPENLI_ACCESS_SESSION_TEID; + sess->cin = 240; + sess->teids[0] = 1; + sess->teids[1] = 1; + sess->gtp_tunnel_endpoints[0] = strdup("2989009088"); + sess->gtp_tunnel_endpoints[1] = strdup("3005786304"); + sess->teids_mapped = 0; + + newly_active_gtp_session(worker, userint, sess, iuser); + +} + static int init_gtp_intercept(openli_gtp_worker_t *worker, ipintercept_t *ipint) { @@ -103,6 +290,12 @@ static int init_gtp_intercept(openli_gtp_worker_t *worker, HASH_ADD_KEYPTR(hh_liid, worker->ipintercepts, ipint->common.liid, ipint->common.liid_len, ipint); ipint->awaitingconfirm = 0; + + + // XXX VERY TEMPORARY for testing and dev + if (strcmp(ipint->common.liid, "gtpv2test") == 0) { + setup_gtpu_testing_intercept(worker, ipint); + } return 1; } @@ -320,146 +513,6 @@ static void push_gtp_session_over(openli_gtp_worker_t *worker, } } -static void add_teid_to_session_mapping(openli_gtp_worker_t *worker, - access_session_t *sess, uint32_t teid, char *endpoint_ip, - internet_user_t *iuser) { - - teid_to_session_t *found; - char keystr[1024]; - - memset(keystr, 0, 1024); - - if (teid == 0) { - logger(LOG_INFO, "OpenLI: called add_teid_to_session_mapping() but the assigned TEID is zero for the session?"); - return; - } - if (endpoint_ip == NULL) { - logger(LOG_INFO, "OpenLI: called add_teid_to_session_mapping() but the endpoint IP is NULL for the session?"); - return; - } - snprintf(keystr, 1024, "%s-%u", endpoint_ip, teid); - - //printf("TEID ID: %s\n", keystr); - - HASH_FIND(hh, worker->all_data_teids, keystr, strlen(keystr), found); - if (found && found->cin == sess->cin) { - found->session = realloc(found->session, - (found->sessioncount + 1) * sizeof(access_session_t *)); - found->owner = realloc(found->owner, - (found->sessioncount + 1) * sizeof(internet_user_t *)); - found->session[found->sessioncount] = sess; - found->owner[found->sessioncount] = iuser; - found->sessioncount ++; - return; - } else if (found) { - /* a silent log-off scenario? XXX do we need to generate an IRI? */ - - /* For now, just delete the old entry and fall through... */ - HASH_DELETE(hh, worker->all_data_teids, found); - free(found->idstring); - free(found->session); - free(found->owner); - free(found); - } - - found = calloc(1, sizeof(teid_to_session_t)); - found->idstring = strdup(keystr); - found->teid = teid; - found->cin = sess->cin; - found->sessioncount = 1; - found->session = calloc(1, sizeof(access_session_t *)); - found->owner = calloc(1, sizeof(internet_user_t *)); - found->session[0] = sess; - found->owner[0] = iuser; - - HASH_ADD_KEYPTR(hh, worker->all_data_teids, &(found->teid), - sizeof(found->teid), found); -} - -static void remove_teid_to_session_mapping(openli_gtp_worker_t *worker, - access_session_t *sess, uint32_t teid, char *endpoint_ip) { - - teid_to_session_t *found; - int nullsess = 0, i; - char keystr[1024]; - - if (!sess->teids_mapped) { - return; - } - if (endpoint_ip == NULL) { - return; - } - snprintf(keystr, 1024, "%s-%u", endpoint_ip, teid); - printf("DELETING %s\n", keystr); - - HASH_FIND(hh, worker->all_data_teids, keystr, strlen(keystr), found); - if (!found) { - /* Weird, but ok we'll just ignore this */ - return; - } - - for (i = 0; i < found->sessioncount; i++) { - if (found->session[i] == NULL) { - nullsess ++; - continue; - } - if (found->session[i] == sess) { - found->session[i] = NULL; - found->owner[i] = NULL; - nullsess ++; - } - } - if (nullsess == found->sessioncount) { - /* All sessions relating to this TEID have been removed, so - * free the entire object - */ - HASH_DELETE(hh, worker->all_data_teids, found); - free(found->idstring); - free(found->session); - free(found->owner); - free(found); - } - -} - -static void newly_active_gtp_session(openli_gtp_worker_t *worker, - user_intercept_list_t *userint, access_session_t *sess, - internet_user_t *iuser) { - - ipintercept_t *ipint, *tmp; - sync_sendq_t *sendq, *tmpq; - - if (userint == NULL || sess == NULL) { - return; - } - - /* Save the Data TEIDs for this session as we have to - * intercept GTP-U for those TEIDs from now on - */ - if (sess->identifier_type & OPENLI_ACCESS_SESSION_TEID) { - add_teid_to_session_mapping(worker, sess, sess->teids[0], - sess->gtp_tunnel_endpoints[0], iuser); - add_teid_to_session_mapping(worker, sess, sess->teids[1], - sess->gtp_tunnel_endpoints[1], iuser); - sess->teids_mapped = 1; - } - - if (sess->sessipcount == 0) { - return; - } - - /* Tell the collector threads about any IPs associated with this - * newly active session. - */ - HASH_ITER(hh_user, userint->intlist, ipint, tmp) { - HASH_ITER(hh, (sync_sendq_t *)(worker->collector_queues), sendq, - tmpq) { - push_session_ips_to_collector_queue(sendq->q, ipint, sess); - } - } - -} - static void export_raw_gtp_c_packet_content(openli_gtp_worker_t *worker UNUSED, ipintercept_t *ipint UNUSED, void *parseddata UNUSED, uint32_t seqno UNUSED, uint32_t cin UNUSED) { @@ -550,15 +603,19 @@ static void generate_encoding_jobs(openli_gtp_worker_t *worker, } } -static void process_gtp_u_packet(openli_gtp_worker_t *worker UNUSED, - libtrace_packet_t *packet, uint8_t *payload UNUSED, - uint32_t plen UNUSED, uint32_t teid) { +static void process_gtp_u_packet(openli_gtp_worker_t *worker, + libtrace_packet_t *packet, uint8_t *payload, + uint32_t plen, uint32_t teid) { void *l3; uint16_t ethertype; uint32_t rem; - + teid_to_session_t *found = NULL; char keystr[1024]; + openli_export_recv_t *expmsg; + struct timeval tv; + int i; + ipintercept_t *ipint, *tmp; l3 = trace_get_layer3(packet, ðertype, &rem); if (l3 == NULL || rem < sizeof(libtrace_ip_t)) { @@ -581,8 +638,46 @@ static void process_gtp_u_packet(openli_gtp_worker_t *worker UNUSED, return; } - //printf("GTP-U: lookup for %s\n", keystr); + printf("\nGTP-U: lookup for %s\n", keystr); + + HASH_FIND(hh, worker->all_data_teids, keystr, strlen(keystr), found); + if (!found) { + return; + } + + tv = trace_get_timeval(packet); + for (i = 0; i < found->sessioncount; i++) { + internet_user_t *owner = found->owner[i]; + user_intercept_list_t *userint; + + printf("%d %s\n", i, owner->userid); + HASH_FIND(hh, worker->userintercepts, owner->userid, + strlen(owner->userid), userint); + + if (!userint) { + continue; + } + + HASH_ITER(hh_user, userint->intlist, ipint, tmp) { + printf("%s-%s\n", ipint->common.liid, ipint->common.targetagency); + if (ipint->common.targetagency == NULL || + strcmp(ipint->common.targetagency, "pcapdisk") == 0) { + expmsg = create_rawip_job_from_ip(ipint->common.liid, + ipint->common.destid, payload, plen, tv, + OPENLI_EXPORT_RAW_CC); + + } else { + /* TODO define ICE types and figure out how we decide what + * value to use here... + */ + expmsg = create_epscc_job(ipint->common.liid, found->cin, + ipint->common.destid, found->dir, payload, plen, 0); + } + publish_openli_msg(worker->zmq_pubsocks[ipint->common.seqtrackerid], + expmsg); + } + } } static void process_gtp_c_packet(openli_gtp_worker_t *worker, @@ -710,7 +805,7 @@ static void process_gtp_packet(openli_gtp_worker_t *worker, } msgtype = v2hdr->msgtype; - teid = v2hdr->teid; + teid = ntohl(v2hdr->teid); payload += sizeof(gtpv2_header_teid_t); plen -= sizeof(gtpv2_header_teid_t); @@ -723,7 +818,7 @@ static void process_gtp_packet(openli_gtp_worker_t *worker, } msgtype = v1hdr->msgtype; - teid = v1hdr->teid; + teid = ntohl(v1hdr->teid); payload += sizeof(gtpv1_header_t); plen -= sizeof(gtpv1_header_t); } else { diff --git a/src/collector/internetaccess.h b/src/collector/internetaccess.h index 5c1ed33..5a34ab6 100644 --- a/src/collector/internetaccess.h +++ b/src/collector/internetaccess.h @@ -116,6 +116,7 @@ typedef struct teid_to_session { access_session_t **session; internet_user_t **owner; uint32_t cin; + uint8_t dir; UT_hash_handle hh; } teid_to_session_t; From 475dfc06a72e615dc411066b8426b71cc9035e21 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Mon, 19 Aug 2024 18:12:25 +1200 Subject: [PATCH 22/44] Save GTP sequence number for EPSCC construction. The sequence number in the ULIC header is meant to be the sequence number from the GTP header (so the LEA can tell if we missed a GTP-U packet presumably). --- src/collector/collector_publish.h | 1 + src/collector/encoder_worker.c | 2 +- src/collector/epscc.h | 4 ++-- src/collector/etsiencoding/epscc.c | 5 +++-- src/collector/gtp_worker.c | 10 +++++++--- 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/collector/collector_publish.h b/src/collector/collector_publish.h index c084d73..6105aa8 100644 --- a/src/collector/collector_publish.h +++ b/src/collector/collector_publish.h @@ -85,6 +85,7 @@ typedef struct openli_mobcc_job { uint8_t *ipcontent; uint32_t ipclen; uint8_t icetype; + uint16_t gtpseqno; } PACKED openli_mobcc_job_t; typedef struct openli_emailiri_job { diff --git a/src/collector/encoder_worker.c b/src/collector/encoder_worker.c index c6de306..28c3632 100644 --- a/src/collector/encoder_worker.c +++ b/src/collector/encoder_worker.c @@ -524,7 +524,7 @@ static int encode_templated_epscc(openli_encoder_t *enc, reset_wandder_encoder(enc->encoder); body = encode_epscc_body(enc->encoder, job->preencoded, - job->cin, job->seqno, epsccjob->dir, job->origreq->ts, + job->cin, epsccjob->gtpseqno, epsccjob->dir, job->origreq->ts, epsccjob->icetype); if (body == NULL || body->len == 0 || body->encoded == NULL) { diff --git a/src/collector/epscc.h b/src/collector/epscc.h index 0ed2bb1..17b0787 100644 --- a/src/collector/epscc.h +++ b/src/collector/epscc.h @@ -37,10 +37,10 @@ openli_export_recv_t *create_epscc_job(char *liid, uint32_t cin, uint32_t destid, uint8_t dir, uint8_t *ipcontent, uint32_t ipclen, - uint8_t icetype); + uint8_t icetype, uint16_t gtpseqno); wandder_encoded_result_t *encode_epscc_body(wandder_encoder_t *encoder, - wandder_encode_job_t *precomputed, uint32_t cin, uint32_t seqno, + wandder_encode_job_t *precomputed, uint32_t cin, uint16_t gtpseqno, uint8_t dir, struct timeval tv, uint8_t icetype); #endif diff --git a/src/collector/etsiencoding/epscc.c b/src/collector/etsiencoding/epscc.c index 6e26890..d17e5e5 100644 --- a/src/collector/etsiencoding/epscc.c +++ b/src/collector/etsiencoding/epscc.c @@ -33,7 +33,7 @@ openli_export_recv_t *create_epscc_job(char *liid, uint32_t cin, uint32_t destid, uint8_t dir, uint8_t *ipcontent, uint32_t ipclen, - uint8_t icetype) { + uint8_t icetype, uint16_t gtpseqno) { openli_export_recv_t *msg = NULL; @@ -53,13 +53,14 @@ openli_export_recv_t *create_epscc_job(char *liid, uint32_t cin, memcpy(msg->data.mobcc.ipcontent, ipcontent, ipclen); msg->data.mobcc.ipclen = ipclen; msg->data.mobcc.icetype = icetype; + msg->data.mobcc.gtpseqno = gtpseqno; return msg; } wandder_encoded_result_t *encode_epscc_body(wandder_encoder_t *encoder, wandder_encode_job_t *precomputed UNUSED, uint32_t cin UNUSED, - uint32_t seqno UNUSED, uint8_t dir UNUSED, struct timeval tv UNUSED, + uint16_t gtpseqno UNUSED, uint8_t dir UNUSED, struct timeval tv UNUSED, uint8_t icetype UNUSED) { return wandder_encode_finish(encoder); diff --git a/src/collector/gtp_worker.c b/src/collector/gtp_worker.c index b3203a4..cb282c3 100644 --- a/src/collector/gtp_worker.c +++ b/src/collector/gtp_worker.c @@ -605,7 +605,7 @@ static void generate_encoding_jobs(openli_gtp_worker_t *worker, static void process_gtp_u_packet(openli_gtp_worker_t *worker, libtrace_packet_t *packet, uint8_t *payload, - uint32_t plen, uint32_t teid) { + uint32_t plen, uint32_t teid, uint16_t gtpseqno) { void *l3; uint16_t ethertype; @@ -672,7 +672,8 @@ static void process_gtp_u_packet(openli_gtp_worker_t *worker, * value to use here... */ expmsg = create_epscc_job(ipint->common.liid, found->cin, - ipint->common.destid, found->dir, payload, plen, 0); + ipint->common.destid, found->dir, payload, plen, 0, + gtpseqno); } publish_openli_msg(worker->zmq_pubsocks[ipint->common.seqtrackerid], expmsg); @@ -775,6 +776,7 @@ static void process_gtp_packet(openli_gtp_worker_t *worker, void *transport; uint8_t msgtype; uint32_t teid; + uint16_t seqno = 0; if (packet == NULL) { return; @@ -806,6 +808,7 @@ static void process_gtp_packet(openli_gtp_worker_t *worker, msgtype = v2hdr->msgtype; teid = ntohl(v2hdr->teid); + seqno = ntohs(v2hdr->seqno); payload += sizeof(gtpv2_header_teid_t); plen -= sizeof(gtpv2_header_teid_t); @@ -819,6 +822,7 @@ static void process_gtp_packet(openli_gtp_worker_t *worker, msgtype = v1hdr->msgtype; teid = ntohl(v1hdr->teid); + seqno = ntohs(v1hdr->seqno); payload += sizeof(gtpv1_header_t); plen -= sizeof(gtpv1_header_t); } else { @@ -827,7 +831,7 @@ static void process_gtp_packet(openli_gtp_worker_t *worker, if (msgtype == 0xff) { /* This is GTP-U */ - process_gtp_u_packet(worker, packet, payload, plen, teid); + process_gtp_u_packet(worker, packet, payload, plen, teid, seqno); } else { /* This is GTP-C */ process_gtp_c_packet(worker, packet); From 6c124e4107a80ea2b898cff278e9c92aaeec6b29 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Tue, 20 Aug 2024 15:04:23 +1200 Subject: [PATCH 23/44] First pass at encoding the EPSCC body --- src/collector/encoder_worker.c | 4 +- src/collector/epscc.h | 5 ++- src/collector/etsiencoding/epscc.c | 70 +++++++++++++++++++++++++++-- src/collector/etsiencoding/epsiri.c | 25 +++-------- src/collector/gtp_worker.c | 2 +- src/etsili_core.c | 14 ++++++ src/etsili_core.h | 2 + 7 files changed, 95 insertions(+), 27 deletions(-) diff --git a/src/collector/encoder_worker.c b/src/collector/encoder_worker.c index 28c3632..62e6ced 100644 --- a/src/collector/encoder_worker.c +++ b/src/collector/encoder_worker.c @@ -523,9 +523,9 @@ static int encode_templated_epscc(openli_encoder_t *enc, */ reset_wandder_encoder(enc->encoder); - body = encode_epscc_body(enc->encoder, job->preencoded, + body = encode_epscc_body(enc->encoder, job->preencoded, job->liid, job->cin, epsccjob->gtpseqno, epsccjob->dir, job->origreq->ts, - epsccjob->icetype); + epsccjob->icetype, epsccjob->ipclen); if (body == NULL || body->len == 0 || body->encoded == NULL) { logger(LOG_INFO, "OpenLI: failed to encode ETSI EPSCC body"); diff --git a/src/collector/epscc.h b/src/collector/epscc.h index 17b0787..720a3b7 100644 --- a/src/collector/epscc.h +++ b/src/collector/epscc.h @@ -40,8 +40,9 @@ openli_export_recv_t *create_epscc_job(char *liid, uint32_t cin, uint8_t icetype, uint16_t gtpseqno); wandder_encoded_result_t *encode_epscc_body(wandder_encoder_t *encoder, - wandder_encode_job_t *precomputed, uint32_t cin, uint16_t gtpseqno, - uint8_t dir, struct timeval tv, uint8_t icetype); + wandder_encode_job_t *precomputed, const char *liid, uint32_t cin, + uint16_t gtpseqno, uint8_t dir, struct timeval tv, uint8_t icetype, + uint32_t ipclen); #endif // vim: set sw=4 tabstop=4 softtabstop=4 expandtab : diff --git a/src/collector/etsiencoding/epscc.c b/src/collector/etsiencoding/epscc.c index d17e5e5..f9acd7d 100644 --- a/src/collector/etsiencoding/epscc.c +++ b/src/collector/etsiencoding/epscc.c @@ -59,9 +59,73 @@ openli_export_recv_t *create_epscc_job(char *liid, uint32_t cin, } wandder_encoded_result_t *encode_epscc_body(wandder_encoder_t *encoder, - wandder_encode_job_t *precomputed UNUSED, uint32_t cin UNUSED, - uint16_t gtpseqno UNUSED, uint8_t dir UNUSED, struct timeval tv UNUSED, - uint8_t icetype UNUSED) { + wandder_encode_job_t *precomputed, const char *liid, uint32_t cin, + uint16_t gtpseqno, uint8_t dir, struct timeval tv, uint8_t icetype, + uint32_t ipclen) { + wandder_encode_job_t *jobarray[8]; + char correlation[32]; + uint32_t seqno = gtpseqno; + uint32_t tpdudir; + uint32_t ice32 = icetype; + + jobarray[0] = &(precomputed[OPENLI_PREENCODE_CSEQUENCE_2]); + jobarray[1] = &(precomputed[OPENLI_PREENCODE_CSEQUENCE_1]); + jobarray[2] = &(precomputed[OPENLI_PREENCODE_USEQUENCE]); + + if (dir == ETSI_DIR_FROM_TARGET) { + jobarray[3] = &(precomputed[OPENLI_PREENCODE_DIRFROM]); + } else if (dir == ETSI_DIR_TO_TARGET) { + jobarray[3] = &(precomputed[OPENLI_PREENCODE_DIRTO]); + } else { + jobarray[3] = &(precomputed[OPENLI_PREENCODE_DIRUNKNOWN]); + } + jobarray[4] = &(precomputed[OPENLI_PREENCODE_CSEQUENCE_2]); // ccContents + jobarray[5] = &(precomputed[OPENLI_PREENCODE_CSEQUENCE_17]); // EPSCC-PDU + jobarray[6] = &(precomputed[OPENLI_PREENCODE_CSEQUENCE_1]); // ULIC-header + jobarray[7] = &(precomputed[OPENLI_PREENCODE_EPSCCOID]); // hi3DomainID + wandder_encode_next_preencoded(encoder, jobarray, 8); + + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 2, (void *)liid, strlen(liid)); + + snprintf(correlation, 32, "%u", cin); + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 3, correlation, + strlen(correlation)); + + ENC_CSEQUENCE(encoder, 4); + wandder_encode_next(encoder, WANDDER_TAG_UTCTIME, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 1, &tv, sizeof(tv)); + wandder_encode_endseq(encoder); + + // sequenceNumber + wandder_encode_next(encoder, WANDDER_TAG_INTEGER, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 5, &seqno, sizeof(seqno)); + + // tpdu-direction + if (dir == ETSI_DIR_FROM_TARGET) { + tpdudir = 1; + } else if (dir == ETSI_DIR_TO_TARGET) { + tpdudir = 2; + } else { + tpdudir = 3; + } + wandder_encode_next(encoder, WANDDER_TAG_ENUM, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 6, &(tpdudir), sizeof(tpdudir)); + + // national parameters go here (7) + + // ice-type + if (icetype != 0) { + wandder_encode_next(encoder, WANDDER_TAG_ENUM, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 8, &(ice32), sizeof(ice32)); + } + + END_ENCODED_SEQUENCE(encoder, 1); + + // payload + wandder_encode_next(encoder, WANDDER_TAG_IPPACKET, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 2, NULL, ipclen); return wandder_encode_finish(encoder); } diff --git a/src/collector/etsiencoding/epsiri.c b/src/collector/etsiencoding/epsiri.c index 04de0a6..d31f4ba 100644 --- a/src/collector/etsiencoding/epsiri.c +++ b/src/collector/etsiencoding/epsiri.c @@ -37,7 +37,7 @@ wandder_encoded_result_t *encode_epsiri_body(wandder_encoder_t *encoder, etsili_iri_type_t iritype, etsili_generic_t *params) { wandder_encode_job_t *jobarray[6]; - etsili_generic_t *p, *savedtime; + etsili_generic_t *p; uint8_t lookup; //uint32_t iriversion = 8; uint32_t gprstarget = 3; @@ -51,21 +51,6 @@ wandder_encoded_result_t *encode_epsiri_body(wandder_encoder_t *encoder, WANDDER_CLASS_CONTEXT_PRIMITIVE, 0, &iritype, sizeof(iritype)); - /* timeStamp -- as generalized time */ - lookup = EPSIRI_CONTENTS_EVENT_TIME; - HASH_FIND(hh, params, &lookup, sizeof(lookup), p); - if (p) { - wandder_encode_next(encoder, WANDDER_TAG_GENERALTIME, - WANDDER_CLASS_CONTEXT_PRIMITIVE, 1, - p->itemptr, p->itemlen); - savedtime = p; - } else { - savedtime = NULL; - logger(LOG_INFO, - "OpenLI: warning, no timestamp available for building EPS IRI"); - logger(LOG_INFO, "OpenLI: EPS IRI record may be invalid..."); - } - jobarray[0] = &(precomputed[OPENLI_PREENCODE_CSEQUENCE_2]); jobarray[1] = &(precomputed[OPENLI_PREENCODE_CSEQUENCE_15]); jobarray[2] = &(precomputed[OPENLI_PREENCODE_CSEQUENCE_0]); @@ -81,14 +66,16 @@ wandder_encoded_result_t *encode_epsiri_body(wandder_encoder_t *encoder, jobarray[4] = &(precomputed[OPENLI_PREENCODE_LIID]); - /* timeStamp again (3) -- different format, use UTCTime */ + /* timeStamp (3) -- use UTCTime */ jobarray[5] = &(precomputed[OPENLI_PREENCODE_CSEQUENCE_3]); wandder_encode_next_preencoded(encoder, jobarray, 6); - if (savedtime) { + lookup = EPSIRI_CONTENTS_EVENT_TIME; + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { wandder_encode_next(encoder, WANDDER_TAG_UTCTIME, WANDDER_CLASS_CONTEXT_PRIMITIVE, 1, - savedtime->itemptr, savedtime->itemlen); + p->itemptr, p->itemlen); } END_ENCODED_SEQUENCE(encoder, 1); diff --git a/src/collector/gtp_worker.c b/src/collector/gtp_worker.c index cb282c3..2dfdda3 100644 --- a/src/collector/gtp_worker.c +++ b/src/collector/gtp_worker.c @@ -236,7 +236,7 @@ static void setup_gtpu_testing_intercept(openli_gtp_worker_t *worker, user_identity_t newid; newid.method = USER_IDENT_GTP_MSISDN; - newid.idstr = "foobar"; + newid.idstr = "5511950140000"; newid.idlength = strlen(newid.idstr); iuser = calloc(1, sizeof(internet_user_t)); diff --git a/src/etsili_core.c b/src/etsili_core.c index 612b7be..0a7f2ae 100644 --- a/src/etsili_core.c +++ b/src/etsili_core.c @@ -43,6 +43,7 @@ uint8_t etsi_emailccoid[4] = {0x05, 0x02, 0x0f, 0x02}; uint8_t etsi_umtsirioid[9] = {0x00, 0x04, 0x00, 0x02, 0x02, 0x04, 0x01, 0x0f, 0x05}; uint8_t etsi_hi1operationoid[8] = {0x00, 0x04, 0x00, 0x02, 0x02, 0x00, 0x01, 0x06}; uint8_t etsi_epsirioid[9] = {0x00, 0x04, 0x00, 0x02, 0x02, 0x04, 0x08, 0x11, 0x00}; +uint8_t etsi_epsccoid[9] = {0x00, 0x04, 0x00, 0x02, 0x02, 0x04, 0x09, 0x11, 0x00}; static inline void encode_tri_body(wandder_encoder_t *encoder) { ENC_CSEQUENCE(encoder, 2); // Payload @@ -1164,6 +1165,13 @@ void etsili_preencode_static_fields( p->valspace = NULL; p->vallen = 0; + p = &(pendarray[OPENLI_PREENCODE_CSEQUENCE_17]); + p->identclass = WANDDER_CLASS_CONTEXT_CONSTRUCT; + p->identifier = 17; + p->encodeas = WANDDER_TAG_SEQUENCE; + p->valspace = NULL; + p->vallen = 0; + p = &(pendarray[OPENLI_PREENCODE_PSDOMAINID]); p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; p->identifier = 0; @@ -1267,6 +1275,12 @@ void etsili_preencode_static_fields( p->encodeas = WANDDER_TAG_OID; wandder_encode_preencoded_value(p, etsi_epsirioid, sizeof(etsi_epsirioid)); + p = &(pendarray[OPENLI_PREENCODE_EPSCCOID]); + p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; + p->identifier = 0; + p->encodeas = WANDDER_TAG_OID; + wandder_encode_preencoded_value(p, etsi_epsccoid, sizeof(etsi_epsccoid)); + p = &(pendarray[OPENLI_PREENCODE_IPMMCCOID]); p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; p->identifier = 0; diff --git a/src/etsili_core.h b/src/etsili_core.h index c0ac155..6c0fb11 100644 --- a/src/etsili_core.h +++ b/src/etsili_core.h @@ -173,6 +173,7 @@ typedef enum { OPENLI_PREENCODE_CSEQUENCE_11, /* IPMMIRI */ OPENLI_PREENCODE_CSEQUENCE_12, /* IPMMCC */ OPENLI_PREENCODE_CSEQUENCE_15, /* EPSIRI */ + OPENLI_PREENCODE_CSEQUENCE_17, /* EPSCC-PDU */ OPENLI_PREENCODE_PSDOMAINID, OPENLI_PREENCODE_LIID, OPENLI_PREENCODE_AUTHCC, @@ -194,6 +195,7 @@ typedef enum { OPENLI_PREENCODE_DIRUNKNOWN, OPENLI_PREENCODE_NO_ENCRYPTION, OPENLI_PREENCODE_AES_192_CBC, + OPENLI_PREENCODE_EPSCCOID, OPENLI_PREENCODE_LAST } preencode_index_t; From 0bad6503655639eeb65e3176fb8a20ae0414a08a Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Wed, 21 Aug 2024 19:41:07 +1200 Subject: [PATCH 24/44] Resolve very rare RADIUS segfault The core change here is to not automatically delete RADIUS users who have no more active sessions. The underlying explanation is a lot more complex... The actual problem occurs when you have a combination of conditions: * A RADIUS CSID that is used for more than one RADIUS username (or vice versa). * A little bit of packet loss on the RADIUS feed into the collector. * The Framed IP address for an affected shared CSID being re-assigned to another CSID without seeing the corresponding RADIUS session ending and start messages (either because of the packet loss, or because they were never mirrored in the first place). What happens is that the IP reassignment triggers the sync thread's "silent logoff" code branch. As part of that, all of the identities previously attached to that IP address are detached, and if that detached session was the last session for a user then we would trigger the "delete user" code from the RADIUS plugin. Which make sense BUT the silent logoff removes ALL users as soon as it is detected, and the silent logoff detection happens inside a loop that is iterating over all users that have been reported as belonging to that session. So what if the user we just deleted is somehow in that list of users that we are iterating over? Then we start playing around with a user entity that we just freed and bad memory things will happen. But how does that user appear in the list if the IP has been reassigned to another user? That's where the non-unitary mapping of CSID to username comes into play. The RADIUS plugin maintains a list of unanswered requests, keyed by a combination of source port, request ID (8 bits) and request type. Requests are only deleted if they are answered or if all the users involved in the request are deleted. Normally, most requests are answered pretty promptly but if there is packet loss then some responses may never be seen. Now if the CSID has more sessions than the Username, any unanswered requests associated with both the CSID AND the username will persist, even if the username has no more sessions and was therefore deleted. If we then later on get an orphaned response (i.e. its original request was also lost) that happens to match the key of one of the old persisting requests then, guess what, we're going to dig up the old request and start trying to update the session state for the users that were originally involved with it. Of course, if we happen to have deleted one of the users in the interim (e.g. due to silent logoff, or just a regular session ending) then bad things are going to happen again. So ideally, we might want to think about having a way to expire old requests (or at least ignore them when we're trying to match a response) but this wouldn't help us with cases where we delete a user early due to silent logoff. For now, the "safe" option is not delete any users -- they're probably going to appear again soon anyway -- with an eye towards instituting an expiry process for seriously inactive users (and purging any requests still associated with them, regardless of any other active users who are also attached to those requests). --- src/collector/accessplugins/radius.c | 37 +++++++++++++++++----------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/collector/accessplugins/radius.c b/src/collector/accessplugins/radius.c index a7f1632..4c6b4ea 100644 --- a/src/collector/accessplugins/radius.c +++ b/src/collector/accessplugins/radius.c @@ -106,6 +106,8 @@ struct radius_user { Pvoid_t sessions; Pvoid_t savedrequests; radius_nas_t *parent_nas; + + time_t inactive_since; }; typedef struct radius_v6_prefix_attr { @@ -129,7 +131,7 @@ struct radius_saved_request { uint32_t reqid; uint32_t statustype; - uint32_t acctsess; + uint32_t acctsess_hash; double tvsec; radius_attribute_t *attrs; @@ -175,7 +177,7 @@ typedef struct radius_parsed { uint8_t msgident; uint8_t *authptr; uint32_t accttype; - uint32_t acctsess; + uint32_t acctsess_hash; uint32_t nasport; double tvsec; radius_attribute_t *attrs; @@ -235,7 +237,7 @@ static inline void reset_parsed_packet(radius_parsed_t *parsed) { parsed->savedreq = NULL; parsed->savedresp = NULL; parsed->muser_count = 0; - parsed->acctsess = 0; + parsed->acctsess_hash = 0; memset(parsed->matchedusers, 0, sizeof(radius_user_t *) * USER_IDENT_MAX); memset(&(parsed->nasip), 0, sizeof(struct sockaddr_storage)); memset(&(parsed->radiusip), 0, sizeof(struct sockaddr_storage)); @@ -391,7 +393,6 @@ static void destroy_radius_user(radius_user_t *user, unsigned char *userind) { JLF(pval, user->savedrequests, index); while (pval) { radius_saved_req_t *req = (radius_saved_req_t *)(*pval); - for (i = 0; i < req->targetuser_count; i++) { if (req->targetusers[i] == NULL) { continue; @@ -884,7 +885,8 @@ static void *radius_parse_packet(access_plugin_t *p, libtrace_packet_t *pkt) { memcpy(sessstr, newattr->att_val, att_len - 2); } - parsed->acctsess = strtoul(sessstr, NULL, 10); + parsed->acctsess_hash = hashlittle(sessstr, strlen(sessstr), + 0x85F8B41B); } } @@ -921,8 +923,8 @@ static radius_user_t *add_user_identity(uint8_t att_type, uint8_t *att_val, } assert(keyrem > att_len); - memcpy(nextchar, att_val, att_len); + memcpy(nextchar, att_val, att_len); nextchar += att_len; keyrem -= att_len; @@ -934,6 +936,7 @@ static radius_user_t *add_user_identity(uint8_t att_type, uint8_t *att_val, index = raddata->muser_count; raddata->muser_count ++; raddata->matchedusers[index] = (radius_user_t *)(*pval); + raddata->matchedusers[index]->inactive_since = 0; return raddata->matchedusers[index]; } @@ -946,6 +949,7 @@ static radius_user_t *add_user_identity(uint8_t att_type, uint8_t *att_val, user->sessions = NULL; user->savedrequests = NULL; user->parent_nas = raddata->matchednas; + user->inactive_since = 0; //user->current = SESSION_STATE_NEW; JSLI(pval, raddata->matchednas->user_map, (unsigned char *)user->userid); @@ -1013,7 +1017,7 @@ static uint32_t assign_cin(radius_parsed_t *raddata) { /* Modulo 2^31 to avoid possible issues with the CIN * being treated as a negative number by the recipient. */ - hashval = raddata->acctsess % (uint32_t)(pow(2, 31)); + hashval = raddata->acctsess_hash % (uint32_t)(pow(2, 31)); return hashval; } attr = attr->next; @@ -1222,7 +1226,7 @@ static inline void find_matching_request(radius_parsed_t *raddata) { raddata->savedreq = req; raddata->accttype = raddata->savedreq->statustype; - raddata->acctsess = raddata->savedreq->acctsess; + raddata->acctsess_hash = raddata->savedreq->acctsess_hash; memcpy(raddata->matchedusers, raddata->savedreq->targetusers, sizeof(radius_user_t *) * USER_IDENT_MAX); @@ -1630,7 +1634,7 @@ static access_session_t *radius_update_session_state(access_plugin_t *p, ptr = quickcat(ptr, &rem, raduser->nasidentifier, raduser->nasid_len); ptr = quickcat(ptr, &rem, "-", 1); - snprintf(tempstr, 24, "%u", raddata->acctsess); + snprintf(tempstr, 24, "%u", raddata->acctsess_hash); ptr = quickcat(ptr, &rem, tempstr, strlen(tempstr)); HASH_FIND(hh, *sesslist, sessionid, strlen(sessionid), thissess); @@ -1665,7 +1669,7 @@ static access_session_t *radius_update_session_state(access_plugin_t *p, HASH_FIND(hh, raddata->matchednas->request_map, &(reqid), sizeof(reqid), check); if (check && raddata->tvsec == check->tvsec && - raddata->acctsess == check->acctsess) { + raddata->acctsess_hash == check->acctsess_hash) { /* This *is* the same request -- we've already inserted it, * probably due to having both CSID and username in the * AVP list. @@ -1701,7 +1705,7 @@ static access_session_t *radius_update_session_state(access_plugin_t *p, req->reqid = reqid; req->statustype = raddata->accttype; - req->acctsess = raddata->acctsess; + req->acctsess_hash = raddata->acctsess_hash; req->tvsec = raddata->tvsec; req->next = NULL; req->attrs = raddata->attrs; @@ -1721,12 +1725,12 @@ static access_session_t *radius_update_session_state(access_plugin_t *p, } } - JLG(pval, raduser->sessions, raddata->acctsess); + JLG(pval, raduser->sessions, raddata->acctsess_hash); if (pval == NULL) { usess = calloc(1, sizeof(radius_user_session_t)); usess->current = SESSION_STATE_NEW; - usess->session_id = raddata->acctsess; + usess->session_id = raddata->acctsess_hash; usess->nasidentifier = NULL; usess->nas_port = 0; usess->nas_ip = NULL; @@ -2154,8 +2158,11 @@ static void radius_destroy_session_data(access_plugin_t *p UNUSED, JLD(rcint, usess->parent->sessions, usess->session_id); JLC(rcw, usess->parent->sessions, 0, -1); if (rcw == 0) { - destroy_radius_user(usess->parent, - (unsigned char *)usess->parent->userid); + struct timeval tv; + gettimeofday(&tv, NULL); + usess->parent->inactive_since = tv.tv_sec; + + // TODO expire users who have been inactive for a long time? } } From 65ae089afce923a0906faa02df21067b05c64299 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Wed, 21 Aug 2024 20:06:44 +1200 Subject: [PATCH 25/44] Collector: don't exit(1) if we cannot copy a packet for some reason --- src/collector/collector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/collector/collector.c b/src/collector/collector.c index 5a034c4..fe14b72 100644 --- a/src/collector/collector.c +++ b/src/collector/collector.c @@ -512,7 +512,7 @@ static inline void send_packet_to_sync(libtrace_packet_t *pkt, * doing this a lot and don't want to be wasteful */ copy = openli_copy_packet(pkt); if (copy == NULL) { - exit(1); + return; } syncup.type = updatetype; From 27166a0c1a38e827e0eadd340b71b009748fcee5 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Thu, 22 Aug 2024 07:47:53 +1200 Subject: [PATCH 26/44] Update debian changelog for hotfix package --- debian/changelog | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/debian/changelog b/debian/changelog index c5fcc20..42b1232 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,14 @@ +openli (1.1.9-1~hotfixes01) unstable; urgency=medium + + * Fix RADIUS crash that can occur under very rare circumstances due to + a dangling user record pointer in an old unmatched request. + * Fix bug where CINs for all RADIUS sessions were zero. + * Fix potential silent exit in collector if a packet cannot be + copied to be sent to another thread. + + -- Shane Alcock Wed, 21 Aug 2024 23:46:18 +1200 + + openli (1.1.8-1) unstable; urgency=medium * Collector: fix crash in sync_voip thread if an invalid SIP packet From 56dc79f7af8e1b5de2ba13dde738c55d5d4f8f18 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Wed, 11 Sep 2024 17:08:45 +1200 Subject: [PATCH 27/44] Fix potential double-frees when reassembling TCP SIP segments * do not free SIP packets if they have been "kept" by the TCP reassembler; they will be freed later on when the reassembly has completed successfully. * reassembler now always zero-copies packets that it is keeping. * always use a copy of the packet for the SMS check, so that the reassembler can own it if reassembly is required for some reason. * apply the same logic to the SMS check for consistency and maintainability (i.e. do not free packets if the reassembler keeps them). * recognise yet another keep alive pattern for SIP sessions, so we don't report it as "invalid" SIP. --- src/collector/collector.c | 18 ++++++++++++------ src/collector/collector_sync_voip.c | 1 + src/collector/reassembler.c | 2 +- src/collector/sipparsing.c | 9 +++++++++ 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/collector/collector.c b/src/collector/collector.c index 5f7af31..d28f247 100644 --- a/src/collector/collector.c +++ b/src/collector/collector.c @@ -779,20 +779,26 @@ static uint8_t sms_check_slow_path(colthread_local_t *loc, static uint8_t is_sms_over_sip(libtrace_packet_t *pkt, colthread_local_t *loc, collector_global_t *glob) { - uint8_t x = 0; + uint8_t x = 0, ret = 0; - x = add_sip_packet_to_parser(&(loc->sipparser), pkt, 0); + libtrace_packet_t *copy = openli_copy_packet(pkt); + + x = add_sip_packet_to_parser(&(loc->sipparser), copy, 0); if (x == SIP_ACTION_USE_PACKET) { /* No fragments, no TCP reassembly required */ - return sms_check_fast_path(loc, pkt, glob); + ret = sms_check_fast_path(loc, copy, glob); } else if (x == SIP_ACTION_REASSEMBLE_TCP) { /* Reassembled TCP, could contain multiple messages */ - return sms_check_slow_path(loc, glob, 0); + ret = sms_check_slow_path(loc, glob, 0); + copy = NULL; // consumed by the reassembler } else if (x == SIP_ACTION_REASSEMBLE_IPFRAG) { /* Reassembled IP/UDP fragment */ - return sms_check_slow_path(loc, glob, 1); + ret = sms_check_slow_path(loc, glob, 1); } - return 0; + if (copy) { + trace_destroy_packet(copy); + } + return ret; } static inline uint8_t check_for_invalid_sip(packet_info_t *pinfo, diff --git a/src/collector/collector_sync_voip.c b/src/collector/collector_sync_voip.c index e49748c..b054350 100644 --- a/src/collector/collector_sync_voip.c +++ b/src/collector/collector_sync_voip.c @@ -2054,6 +2054,7 @@ static void examine_sip_update(collector_sync_voip_t *sync, sip_update_fast_path(sync, recvdpkt); } else if (ret == SIP_ACTION_REASSEMBLE_TCP) { sip_update_slow_path(sync, recvdpkt, 0); + recvdpkt = NULL; // consumed by the reassembler } else if (ret == SIP_ACTION_REASSEMBLE_IPFRAG) { sip_update_slow_path(sync, recvdpkt, 1); } diff --git a/src/collector/reassembler.c b/src/collector/reassembler.c index 53dc379..544fb7b 100644 --- a/src/collector/reassembler.c +++ b/src/collector/reassembler.c @@ -562,7 +562,7 @@ int update_tcp_reassemble_stream(tcp_reassemble_stream_t *stream, (stream->pkt_alloc + 4) * sizeof(libtrace_packet_t *)); stream->pkt_alloc += 4; } - stream->packets[stream->pkt_cnt] = openli_copy_packet(pkt); + stream->packets[stream->pkt_cnt] = pkt; stream->pkt_cnt ++; } diff --git a/src/collector/sipparsing.c b/src/collector/sipparsing.c index 9508227..a380a3a 100644 --- a/src/collector/sipparsing.c +++ b/src/collector/sipparsing.c @@ -69,6 +69,11 @@ static int parse_tcp_sip_packet(openli_sip_parser_t *p, libtrace_packet_t *pkt, return -1; } + if (tcprem == 8 && memcmp(payload, "\x00\x00\x00\x00\x00\x00\x00\x00", + 8) == 0) { + return -1; + } + /* Yet another keep alive pattern */ if (tcprem == 1 && memcmp(payload, "\x00", 1) == 0) { return -1; @@ -118,6 +123,10 @@ static int parse_udp_sip_packet(libtrace_udp_t *udp, uint32_t udprem) { return -1; } + if (udprem == 8 && memcmp(payload, "\x00\x00\x00\x00\x00\x00\x00\x00", + 8) == 0) { + return -1; + } return 1; } From 9bc122c6948a3dfd93a6ee4d96eb9b569378c00c Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Thu, 12 Sep 2024 11:58:12 +1200 Subject: [PATCH 28/44] Fix assertion failure bug when doing TCP SIP reassembly The crash was due to some slightly incorrect pointer arithmetic in cases where a TCP SIP segment had some trailing bytes (e.g. an extra '\r\n' sequence). --- src/collector/reassembler.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/collector/reassembler.c b/src/collector/reassembler.c index 544fb7b..ec37531 100644 --- a/src/collector/reassembler.c +++ b/src/collector/reassembler.c @@ -739,9 +739,8 @@ int get_next_tcp_reassembled(tcp_reassemble_stream_t *stream, char **content, assert(endfound <= contstart + iter->length); assert(endfound > contstart); - used = endfound - (uint8_t *)(*content); - - stream->expectedseqno += used; + used = endfound - contstart; + stream->expectedseqno += (used + contused); /* give all of the packets thus far back to the caller, so * they can decide if they need to "intercept" them -- the From f3fe7624c1d310cb60e6e39ea63aca3975a63755 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Thu, 12 Sep 2024 20:24:13 +1200 Subject: [PATCH 29/44] Fix RTP intercept failures if SIP is proxied back to the source IP Bug was introduced by https://github.com/OpenLI-NZ/openli/commit/0049127c86ec813252f02778a12e074f751dfc14 In certain setups, a SIP proxy may end up proxying a SIP session back to the exact same IP address that sent the initial SIP messages in the first place. In other words, we see an INVITE from IP A -> proxy B, followed by the same (mostly) INVITE going back from proxy B to IP A. In that case, we were erroneously determining that the proxied INVITE was a "reverse INVITE" and acting as though the SDP info in that INVITE applied to the other direction of the corresponding RTP stream. If the proxy had forwarded that INVITE anywhere else then there wouldn't be a problem, but the destination IP matching the source of the initial INVITE would trigger the "reverse INVITE" logic. This change simply forces any INVITE seen prior to the RTP stream becoming "active", i.e. the 200 OK being seen for the most recent INVITE, to be treated as an initial INVITE regardless of its destination IP address. Note to self: I guess there is still potential for things to go haywire if a proxy is sending back to the same source IP AND a genuine reverse INVITE occurs.... --- src/collector/collector_sync_voip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/collector/collector_sync_voip.c b/src/collector/collector_sync_voip.c index b054350..b007311 100644 --- a/src/collector/collector_sync_voip.c +++ b/src/collector/collector_sync_voip.c @@ -1271,7 +1271,7 @@ static int process_sip_invite(collector_sync_voip_t *sync, char *callid, portstr = get_sip_media_port(sync->sipparser, 0); mediatype = get_sip_media_type(sync->sipparser, 0); - if (iritype == ETSILI_IRI_BEGIN) { + if (iritype == ETSILI_IRI_BEGIN || thisrtp->active == 0) { memcpy(thisrtp->inviter, irimsg->data.ipmmiri.ipsrc, 16); dir = 0; } else if (memcmp(thisrtp->inviter, irimsg->data.ipmmiri.ipsrc, From aaa58c6eb0085441509137998343e9db3618da93 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Mon, 16 Sep 2024 10:58:45 +1200 Subject: [PATCH 30/44] config: fix "RMQlocalpass" and "RMQinternalpass" discrepancy Our documentation says that the config option for specifying the mediator RMQ password is called "RMQinternalpass", but the code itself expects "RMQlocalpass". This commit updates the config parser to support both option names. I've also replaced all strcmp() calls for checking mediator config option names with strcasecmp() calls, so users don't have to worry about whether the option names are camel case or some other arbitrary schema. --- src/configparser.c | 256 +++++++++++++++++++++++---------------------- 1 file changed, 129 insertions(+), 127 deletions(-) diff --git a/src/configparser.c b/src/configparser.c index c74e2e4..9ea6199 100644 --- a/src/configparser.c +++ b/src/configparser.c @@ -120,19 +120,19 @@ static int parse_input_config(collector_global_t *glob, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "uri") == 0) { + strcasecmp((char *)key->data.scalar.value, "uri") == 0) { SET_CONFIG_STRING_OPTION(inp->uri, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "filter") == 0) { + strcasecmp((char *)key->data.scalar.value, "filter") == 0) { SET_CONFIG_STRING_OPTION(inp->filterstring, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, + strcasecmp((char *)key->data.scalar.value, "reportdrops") == 0) { if (check_onoff((char *)value->data.scalar.value) == 0) { inp->report_drops = 0; @@ -143,14 +143,14 @@ static int parse_input_config(collector_global_t *glob, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "threads") == 0) { + strcasecmp((char *)key->data.scalar.value, "threads") == 0) { inp->threadcount = strtoul( (char *)value->data.scalar.value, NULL, 10); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "hasher") == 0) { + strcasecmp((char *)key->data.scalar.value, "hasher") == 0) { if (strcasecmp((char *)value->data.scalar.value, "balanced") == 0) { inp->hasher_apply = OPENLI_HASHER_BALANCE; @@ -190,34 +190,34 @@ static int parse_email_ingest_config(collector_global_t *glob, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "enabled") == 0) { + strcasecmp((char *)key->data.scalar.value, "enabled") == 0) { glob->emailconf.enabled = check_onoff((char *)value->data.scalar.value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "requiretls") == 0) { + strcasecmp((char *)key->data.scalar.value, "requiretls") == 0) { glob->emailconf.tlsrequired = check_onoff((char *)value->data.scalar.value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "authpassword") == 0) { + strcasecmp((char *)key->data.scalar.value, "authpassword") == 0) { glob->emailconf.authrequired = true; SET_CONFIG_STRING_OPTION(glob->emailconf.authpassword, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "listenaddress") == 0) { + strcasecmp((char *)key->data.scalar.value, "listenaddress") == 0) { SET_CONFIG_STRING_OPTION(glob->emailconf.listenaddr, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "listenport") == 0) { + strcasecmp((char *)key->data.scalar.value, "listenport") == 0) { SET_CONFIG_STRING_OPTION(glob->emailconf.listenport, value); } } @@ -314,7 +314,7 @@ static void parse_email_targets(email_target_t **targets, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "address") == 0) { + strcasecmp((char *)key->data.scalar.value, "address") == 0) { SET_CONFIG_STRING_OPTION(newtgt->address, value); } else if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && @@ -355,7 +355,7 @@ static void parse_col_thread_count(int *toset, const char *expectedkey, return; } - if (strcmp(expectedkey, (const char *)key->data.scalar.value) != 0) { + if (strcasecmp(expectedkey, (const char *)key->data.scalar.value) != 0) { return; } @@ -392,7 +392,7 @@ static void parse_sip_targets(libtrace_list_t *targets, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "username") == 0) { + strcasecmp((char *)key->data.scalar.value, "username") == 0) { SET_CONFIG_STRING_OPTION(newtgt->username, value); newtgt->username_len = strlen(newtgt->username); @@ -401,7 +401,7 @@ static void parse_sip_targets(libtrace_list_t *targets, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "realm") == 0) { + strcasecmp((char *)key->data.scalar.value, "realm") == 0) { SET_CONFIG_STRING_OPTION(newtgt->realm, value); newtgt->realm_len = strlen(newtgt->realm); } @@ -499,25 +499,25 @@ static int parse_core_server_list(coreserver_t **servlist, uint8_t cstype, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "ip") == 0) { + strcasecmp((char *)key->data.scalar.value, "ip") == 0) { SET_CONFIG_STRING_OPTION(cs->ipstr, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "port") == 0) { + strcasecmp((char *)key->data.scalar.value, "port") == 0) { SET_CONFIG_STRING_OPTION(cs->portstr, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "port_lower") == 0) { + strcasecmp((char *)key->data.scalar.value, "port_lower") == 0) { SET_CONFIG_STRING_OPTION(cs->lower_portstr, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "port_upper") == 0) { + strcasecmp((char *)key->data.scalar.value, "port_upper") == 0) { SET_CONFIG_STRING_OPTION(cs->upper_portstr, value); } } @@ -561,7 +561,7 @@ static int add_intercept_static_ips(static_ipranges_t **statics, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "iprange") == 0 && + strcasecmp((char *)key->data.scalar.value, "iprange") == 0 && newr->rangestr == NULL) { newr->rangestr = parse_iprange_string((char *)value->data.scalar.value); @@ -569,7 +569,7 @@ static int add_intercept_static_ips(static_ipranges_t **statics, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "sessionid") == 0) { + strcasecmp((char *)key->data.scalar.value, "sessionid") == 0) { newr->cin = strtoul((char *)value->data.scalar.value, NULL, 10); } } @@ -631,49 +631,49 @@ static int parse_agency_list(prov_intercept_conf_t *state, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, + strcasecmp((char *)key->data.scalar.value, "hi2address") == 0) { SET_CONFIG_STRING_OPTION(newag->hi2_ipstr, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, + strcasecmp((char *)key->data.scalar.value, "hi2port") == 0) { SET_CONFIG_STRING_OPTION(newag->hi2_portstr, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, + strcasecmp((char *)key->data.scalar.value, "hi3address") == 0) { SET_CONFIG_STRING_OPTION(newag->hi3_ipstr, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, + strcasecmp((char *)key->data.scalar.value, "hi3port") == 0) { SET_CONFIG_STRING_OPTION(newag->hi3_portstr, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, + strcasecmp((char *)key->data.scalar.value, "agencyid") == 0) { SET_CONFIG_STRING_OPTION(newag->agencyid, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, + strcasecmp((char *)key->data.scalar.value, "agencycountrycode") == 0) { SET_CONFIG_STRING_OPTION(newag->agencycc, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, + strcasecmp((char *)key->data.scalar.value, "keepalivefreq") == 0) { newag->keepalivefreq = strtoul( (char *)value->data.scalar.value, NULL, 10); @@ -681,7 +681,7 @@ static int parse_agency_list(prov_intercept_conf_t *state, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, + strcasecmp((char *)key->data.scalar.value, "keepalivewait") == 0) { newag->keepalivewait = strtoul( (char *)value->data.scalar.value, NULL, 10); @@ -691,7 +691,7 @@ static int parse_agency_list(prov_intercept_conf_t *state, yaml_document_t *doc, /* 'pcapdisk' is reserved for the intercepts that need to * be written to pcap files instead of live streamed to an * ETSI-capable agency. */ - if (strcmp(newag->agencyid, "pcapdisk") == 0) { + if (strcasecmp(newag->agencyid, "pcapdisk") == 0) { logger(LOG_INFO, "OpenLI: 'pcapdisk' is a reserved agencyid, please rename to something else."); free(newag->agencyid); @@ -736,20 +736,20 @@ static void parse_intercept_common_fields(intercept_common_t *common, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "liid") == 0) { + strcasecmp((char *)key->data.scalar.value, "liid") == 0) { SET_CONFIG_STRING_OPTION(common->liid, value); common->liid_len = strlen(common->liid); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, + strcasecmp((char *)key->data.scalar.value, "authcountrycode") == 0) { SET_CONFIG_STRING_OPTION(common->authcc, value); common->authcc_len = strlen(common->authcc); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, + strcasecmp((char *)key->data.scalar.value, "deliverycountrycode") == 0) { SET_CONFIG_STRING_OPTION(common->delivcc, value); common->delivcc_len = strlen(common->delivcc); @@ -757,7 +757,7 @@ static void parse_intercept_common_fields(intercept_common_t *common, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "mediator") == 0 + strcasecmp((char *)key->data.scalar.value, "mediator") == 0 && common->destid == 0) { common->destid = strtoul( (char *)value->data.scalar.value, NULL, 10); @@ -767,27 +767,27 @@ static void parse_intercept_common_fields(intercept_common_t *common, } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "starttime") == 0) { + strcasecmp((char *)key->data.scalar.value, "starttime") == 0) { common->tostart_time = strtoul( (char *)value->data.scalar.value, NULL, 10); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "endtime") == 0) { + strcasecmp((char *)key->data.scalar.value, "endtime") == 0) { common->toend_time = strtoul( (char *)value->data.scalar.value, NULL, 10); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "agencyid") == 0) { + strcasecmp((char *)key->data.scalar.value, "agencyid") == 0) { SET_CONFIG_STRING_OPTION(common->targetagency, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "payloadencryption") == 0) { + strcasecmp((char *)key->data.scalar.value, "payloadencryption") == 0) { if (strcasecmp((char *)value->data.scalar.value, "none") == 0) { common->encrypt = OPENLI_PAYLOAD_ENCRYPTION_NONE; } else if (strcasecmp((char *)value->data.scalar.value, "aes-192-cbc") == 0) { @@ -797,13 +797,13 @@ static void parse_intercept_common_fields(intercept_common_t *common, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "encryptionkey") == 0) { + strcasecmp((char *)key->data.scalar.value, "encryptionkey") == 0) { SET_CONFIG_STRING_OPTION(common->encryptkey, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "outputhandovers") == 0) { + strcasecmp((char *)key->data.scalar.value, "outputhandovers") == 0) { if (strcasecmp((char *)value->data.scalar.value, "irionly") == 0) { common->tomediate = OPENLI_INTERCEPT_OUTPUTS_IRIONLY; @@ -870,23 +870,23 @@ static int parse_emailintercept_list(emailintercept_t **mailints, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SEQUENCE_NODE && - strcmp((char *)key->data.scalar.value, "targets") == 0) { + strcasecmp((char *)key->data.scalar.value, "targets") == 0) { parse_email_targets(&(newcept->targets), doc, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, + strcasecmp((char *)key->data.scalar.value, "delivercompressed") == 0) { - if (strcmp((char *)value->data.scalar.value, "as-is") == 0) { + if (strcasecmp((char *)value->data.scalar.value, "as-is") == 0) { newcept->delivercompressed = OPENLI_EMAILINT_DELIVER_COMPRESSED_ASIS; - } else if (strcmp((char *)value->data.scalar.value, + } else if (strcasecmp((char *)value->data.scalar.value, "decompressed") == 0) { newcept->delivercompressed = OPENLI_EMAILINT_DELIVER_COMPRESSED_INFLATED; - } else if (strcmp((char *)value->data.scalar.value, + } else if (strcasecmp((char *)value->data.scalar.value, "inflated") == 0) { newcept->delivercompressed = OPENLI_EMAILINT_DELIVER_COMPRESSED_INFLATED; @@ -960,7 +960,7 @@ static int parse_voipintercept_list(voipintercept_t **voipints, parse_intercept_common_fields(&(newcept->common), key, value); if (key->type == YAML_SCALAR_NODE && value->type == YAML_SEQUENCE_NODE && - strcmp((char *)key->data.scalar.value, "siptargets") == 0) { + strcasecmp((char *)key->data.scalar.value, "siptargets") == 0) { parse_sip_targets(newcept->targets, doc, value); } @@ -1033,21 +1033,21 @@ static int parse_ipintercept_list(ipintercept_t **ipints, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SEQUENCE_NODE && - strcmp((char *)key->data.scalar.value, + strcasecmp((char *)key->data.scalar.value, "staticips") == 0) { add_intercept_static_ips(&(newcept->statics), doc, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "user") == 0) { + strcasecmp((char *)key->data.scalar.value, "user") == 0) { SET_CONFIG_STRING_OPTION(newcept->username, value); newcept->username_len = strlen(newcept->username); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "alushimid") == 0) { + strcasecmp((char *)key->data.scalar.value, "alushimid") == 0) { newcept->vendmirrorid = strtoul( (char *)value->data.scalar.value, NULL, 0); newcept->vendmirrorid &= 0x3fffffff; @@ -1055,7 +1055,7 @@ static int parse_ipintercept_list(ipintercept_t **ipints, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, + strcasecmp((char *)key->data.scalar.value, "vendmirrorid") == 0) { newcept->vendmirrorid = strtoul( (char *)value->data.scalar.value, @@ -1065,7 +1065,7 @@ static int parse_ipintercept_list(ipintercept_t **ipints, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "accesstype") == 0) { + strcasecmp((char *)key->data.scalar.value, "accesstype") == 0) { newcept->accesstype = map_access_type_string( (char *)value->data.scalar.value); if (newcept->accesstype == INTERNET_ACCESS_TYPE_UNDEFINED) { @@ -1077,7 +1077,7 @@ static int parse_ipintercept_list(ipintercept_t **ipints, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "radiusident") + strcasecmp((char *)key->data.scalar.value, "radiusident") == 0) { if (strcasecmp((char *)value->data.scalar.value, "csid") == 0) { @@ -1093,7 +1093,7 @@ static int parse_ipintercept_list(ipintercept_t **ipints, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "mobileident") + strcasecmp((char *)key->data.scalar.value, "mobileident") == 0) { newcept->mobileident = map_mobile_ident_string( (char *)value->data.scalar.value); @@ -1206,7 +1206,7 @@ static int global_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SEQUENCE_NODE && - strcmp((char *)key->data.scalar.value, "inputs") == 0) { + strcasecmp((char *)key->data.scalar.value, "inputs") == 0) { if (parse_input_config(glob, doc, value) == -1) { return -1; } @@ -1214,7 +1214,7 @@ static int global_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "operatorid") == 0) { + strcasecmp((char *)key->data.scalar.value, "operatorid") == 0) { SET_CONFIG_STRING_OPTION(glob->sharedinfo.operatorid, value); glob->sharedinfo.operatorid_len = strlen(glob->sharedinfo.operatorid); @@ -1227,7 +1227,7 @@ static int global_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "networkelementid") + strcasecmp((char *)key->data.scalar.value, "networkelementid") == 0) { SET_CONFIG_STRING_OPTION(glob->sharedinfo.networkelemid, value); glob->sharedinfo.networkelemid_len = strlen(glob->sharedinfo.networkelemid); @@ -1241,7 +1241,7 @@ static int global_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "interceptpointid") + strcasecmp((char *)key->data.scalar.value, "interceptpointid") == 0) { SET_CONFIG_STRING_OPTION(glob->sharedinfo.intpointid, value); glob->sharedinfo.intpointid_len = strlen(glob->sharedinfo.intpointid); @@ -1255,26 +1255,26 @@ static int global_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "provisionerport") == 0) { + strcasecmp((char *)key->data.scalar.value, "provisionerport") == 0) { SET_CONFIG_STRING_OPTION(glob->sharedinfo.provisionerport, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "provisioneraddr") == 0) { + strcasecmp((char *)key->data.scalar.value, "provisioneraddr") == 0) { SET_CONFIG_STRING_OPTION(glob->sharedinfo.provisionerip, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "sipdebugfile") == 0) { + strcasecmp((char *)key->data.scalar.value, "sipdebugfile") == 0) { SET_CONFIG_STRING_OPTION(glob->sipdebugfile, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_MAPPING_NODE && - strcmp((char *)key->data.scalar.value, "emailingest") == 0) { + strcasecmp((char *)key->data.scalar.value, "emailingest") == 0) { if (parse_email_ingest_config(glob, doc, value) == -1) { return -1; } @@ -1282,7 +1282,7 @@ static int global_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SEQUENCE_NODE && - strcmp((char *)key->data.scalar.value, "alumirrors") == 0) { + strcasecmp((char *)key->data.scalar.value, "alumirrors") == 0) { if (parse_core_server_list(&glob->alumirrors, OPENLI_CORE_SERVER_ALUMIRROR, doc, value) == -1) { return -1; @@ -1291,7 +1291,7 @@ static int global_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SEQUENCE_NODE && - strcmp((char *)key->data.scalar.value, "jmirrors") == 0) { + strcasecmp((char *)key->data.scalar.value, "jmirrors") == 0) { if (parse_core_server_list(&glob->jmirrors, OPENLI_CORE_SERVER_ALUMIRROR, doc, value) == -1) { return -1; @@ -1300,7 +1300,7 @@ static int global_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SEQUENCE_NODE && - strcmp((char *)key->data.scalar.value, "ciscomirrors") == 0) { + strcasecmp((char *)key->data.scalar.value, "ciscomirrors") == 0) { if (parse_core_server_list(&glob->ciscomirrors, OPENLI_CORE_SERVER_ALUMIRROR, doc, value) == -1) { return -1; @@ -1322,44 +1322,44 @@ static int global_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "logstatfrequency") == 0) { + strcasecmp((char *)key->data.scalar.value, "logstatfrequency") == 0) { glob->stat_frequency = strtoul((char *) value->data.scalar.value, NULL, 10); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "tlscert") == 0) { + strcasecmp((char *)key->data.scalar.value, "tlscert") == 0) { SET_CONFIG_STRING_OPTION(glob->sslconf.certfile, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "tlskey") == 0) { + strcasecmp((char *)key->data.scalar.value, "tlskey") == 0) { SET_CONFIG_STRING_OPTION(glob->sslconf.keyfile, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "tlsca") == 0) { + strcasecmp((char *)key->data.scalar.value, "tlsca") == 0) { SET_CONFIG_STRING_OPTION(glob->sslconf.cacertfile, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "etsitls") == 0) { + strcasecmp((char *)key->data.scalar.value, "etsitls") == 0) { glob->etsitls = check_onoff((char *)value->data.scalar.value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "sipignoresdpo") == 0) { + strcasecmp((char *)key->data.scalar.value, "sipignoresdpo") == 0) { glob->ignore_sdpo_matches = check_onoff((char *)value->data.scalar.value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "encoding") == 0) { + strcasecmp((char *)key->data.scalar.value, "encoding") == 0) { /* We're back to only having one encoding method now, but * allow users to choose "BER" without breaking anything. @@ -1416,7 +1416,7 @@ static int global_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SEQUENCE_NODE && - strcmp((char *)key->data.scalar.value, + strcasecmp((char *)key->data.scalar.value, "emailsessiontimeouts") == 0) { if (parse_email_timeouts_config(glob, doc, value) == -1) { return -1; @@ -1425,13 +1425,13 @@ static int global_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "defaultemaildomain") == 0) { + strcasecmp((char *)key->data.scalar.value, "defaultemaildomain") == 0) { SET_CONFIG_STRING_OPTION(glob->default_email_domain, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SEQUENCE_NODE && - strcmp((char *)key->data.scalar.value, "emailforwardingheaders") + strcasecmp((char *)key->data.scalar.value, "emailforwardingheaders") == 0) { if (parse_email_forwarding_headers(glob, doc, value) == -1) { return -1; @@ -1440,38 +1440,38 @@ static int global_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "RMQname") == 0) { + strcasecmp((char *)key->data.scalar.value, "RMQname") == 0) { SET_CONFIG_STRING_OPTION(glob->RMQ_conf.name, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "RMQpass") == 0) { + strcasecmp((char *)key->data.scalar.value, "RMQpass") == 0) { SET_CONFIG_STRING_OPTION(glob->RMQ_conf.pass, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "RMQhostname") == 0) { + strcasecmp((char *)key->data.scalar.value, "RMQhostname") == 0) { SET_CONFIG_STRING_OPTION(glob->RMQ_conf.hostname, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "RMQheartbeatfreq") == 0) { + strcasecmp((char *)key->data.scalar.value, "RMQheartbeatfreq") == 0) { glob->RMQ_conf.heartbeatFreq = strtoul((char *)value->data.scalar.value, NULL, 10); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "RMQenabled") == 0) { + strcasecmp((char *)key->data.scalar.value, "RMQenabled") == 0) { glob->RMQ_conf.enabled = check_onoff((char *)value->data.scalar.value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "RMQport") == 0) { + strcasecmp((char *)key->data.scalar.value, "RMQport") == 0) { glob->RMQ_conf.port = strtoul((char *)value->data.scalar.value, NULL, 10); } @@ -1484,46 +1484,47 @@ static int mediator_parser(void *arg, yaml_document_t *doc UNUSED, yaml_node_t *key, yaml_node_t *value) { mediator_state_t *state = (mediator_state_t *)arg; + char *keyname = (char *)key->data.scalar.value; if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "listenport") == 0) { + strcasecmp(keyname, "listenport") == 0) { SET_CONFIG_STRING_OPTION(state->listenport, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "listenaddr") == 0) { + strcasecmp(keyname, "listenaddr") == 0) { SET_CONFIG_STRING_OPTION(state->listenaddr, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "provisionerport") == 0) { + strcasecmp(keyname, "provisionerport") == 0) { SET_CONFIG_STRING_OPTION(state->provisioner.provport, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "provisioneraddr") == 0) { + strcasecmp(keyname, "provisioneraddr") == 0) { SET_CONFIG_STRING_OPTION(state->provisioner.provaddr, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "pcapdirectory") == 0) { + strcasecmp(keyname, "pcapdirectory") == 0) { SET_CONFIG_STRING_OPTION(state->pcapdirectory, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "pcapfilename") == 0) { + strcasecmp(keyname, "pcapfilename") == 0) { SET_CONFIG_STRING_OPTION(state->pcaptemplate, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "operatorid") == 0) { + strcasecmp(keyname, "operatorid") == 0) { SET_CONFIG_STRING_OPTION(state->operatorid, value); /* 16 chars max allowed for this field (defined in * ETSI LI-PS-PDU spec) */ @@ -1535,7 +1536,7 @@ static int mediator_parser(void *arg, yaml_document_t *doc UNUSED, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "altoperatorid") == 0) { + strcasecmp(keyname, "altoperatorid") == 0) { SET_CONFIG_STRING_OPTION(state->shortoperatorid, value); /* 5 chars max allowed for this field (defined in ETSI HI2 spec) */ @@ -1547,7 +1548,7 @@ static int mediator_parser(void *arg, yaml_document_t *doc UNUSED, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "mediatorid") == 0) { + strcasecmp(keyname, "mediatorid") == 0) { state->mediatorid = strtoul((char *)value->data.scalar.value, NULL, 10); if (state->mediatorid == 0) { @@ -1558,7 +1559,7 @@ static int mediator_parser(void *arg, yaml_document_t *doc UNUSED, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "pcapcompress") == 0) { + strcasecmp(keyname, "pcapcompress") == 0) { state->pcapcompress = strtoul((char *)value->data.scalar.value, NULL, 10); if (state->pcapcompress > 9) { @@ -1569,7 +1570,7 @@ static int mediator_parser(void *arg, yaml_document_t *doc UNUSED, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "pcaprotatefreq") == 0) { + strcasecmp(keyname, "pcaprotatefreq") == 0) { state->pcaprotatefreq = strtoul((char *)value->data.scalar.value, NULL, 10); if (state->pcaprotatefreq == 0) { @@ -1580,74 +1581,75 @@ static int mediator_parser(void *arg, yaml_document_t *doc UNUSED, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "tlscert") == 0) { + strcasecmp(keyname, "tlscert") == 0) { SET_CONFIG_STRING_OPTION(state->sslconf.certfile, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "tlskey") == 0) { + strcasecmp(keyname, "tlskey") == 0) { SET_CONFIG_STRING_OPTION(state->sslconf.keyfile, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "tlsca") == 0) { + strcasecmp(keyname, "tlsca") == 0) { SET_CONFIG_STRING_OPTION(state->sslconf.cacertfile, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "etsitls") == 0) { + strcasecmp(keyname, "etsitls") == 0) { state->etsitls = check_onoff((char *)value->data.scalar.value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "RMQname") == 0) { + strcasecmp(keyname, "RMQname") == 0) { SET_CONFIG_STRING_OPTION(state->RMQ_conf.name, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "RMQpass") == 0) { + strcasecmp(keyname, "RMQpass") == 0) { SET_CONFIG_STRING_OPTION(state->RMQ_conf.pass, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "RMQlocalpass") == 0) { + (strcasecmp(keyname, "RMQlocalpass") == 0 || + strcasecmp(keyname, "RMQinternalpass") == 0)) { SET_CONFIG_STRING_OPTION(state->RMQ_conf.internalpass, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "RMQhostname") == 0) { + strcasecmp(keyname, "RMQhostname") == 0) { SET_CONFIG_STRING_OPTION(state->RMQ_conf.hostname, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "RMQheartbeatfreq") == 0) { + strcasecmp(keyname, "RMQheartbeatfreq") == 0) { state->RMQ_conf.heartbeatFreq = strtoul((char *)value->data.scalar.value, NULL, 10); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "RMQenabled") == 0) { + strcasecmp(keyname, "RMQenabled") == 0) { state->RMQ_conf.enabled = check_onoff((char *)value->data.scalar.value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "RMQSSL") == 0) { + strcasecmp(keyname, "RMQSSL") == 0) { state->RMQ_conf.SSLenabled = check_onoff((char *)value->data.scalar.value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "RMQport") == 0) { + strcasecmp(keyname, "RMQport") == 0) { state->RMQ_conf.port = strtoul((char *)value->data.scalar.value, NULL, 10); } @@ -1663,7 +1665,7 @@ static int intercept_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SEQUENCE_NODE && - strcmp((char *)key->data.scalar.value, "ipintercepts") == 0) { + strcasecmp((char *)key->data.scalar.value, "ipintercepts") == 0) { if (parse_ipintercept_list(&state->ipintercepts, doc, value) == -1) { return -1; } @@ -1671,7 +1673,7 @@ static int intercept_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SEQUENCE_NODE && - strcmp((char *)key->data.scalar.value, "voipintercepts") == 0) { + strcasecmp((char *)key->data.scalar.value, "voipintercepts") == 0) { if (parse_voipintercept_list(&state->voipintercepts, doc, value) == -1) { return -1; @@ -1680,7 +1682,7 @@ static int intercept_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SEQUENCE_NODE && - strcmp((char *)key->data.scalar.value, "emailintercepts") == 0) { + strcasecmp((char *)key->data.scalar.value, "emailintercepts") == 0) { if (parse_emailintercept_list(&state->emailintercepts, doc, value) == -1) { return -1; @@ -1689,7 +1691,7 @@ static int intercept_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SEQUENCE_NODE && - strcmp((char *)key->data.scalar.value, "agencies") == 0) { + strcasecmp((char *)key->data.scalar.value, "agencies") == 0) { if (parse_agency_list(state, doc, value) == -1) { return -1; } @@ -1697,7 +1699,7 @@ static int intercept_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SEQUENCE_NODE && - strcmp((char *)key->data.scalar.value, "defaultradiususers") == 0) { + strcasecmp((char *)key->data.scalar.value, "defaultradiususers") == 0) { if (parse_defradusers_list(state, doc, value) == -1) { return -1; } @@ -1705,7 +1707,7 @@ static int intercept_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SEQUENCE_NODE && - strcmp((char *)key->data.scalar.value, "radiusservers") == 0) { + strcasecmp((char *)key->data.scalar.value, "radiusservers") == 0) { if (parse_core_server_list(&state->radiusservers, OPENLI_CORE_SERVER_RADIUS, doc, value) == -1) { return -1; @@ -1714,7 +1716,7 @@ static int intercept_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SEQUENCE_NODE && - strcmp((char *)key->data.scalar.value, "gtpservers") == 0) { + strcasecmp((char *)key->data.scalar.value, "gtpservers") == 0) { if (parse_core_server_list(&state->gtpservers, OPENLI_CORE_SERVER_GTP, doc, value) == -1) { return -1; @@ -1723,7 +1725,7 @@ static int intercept_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SEQUENCE_NODE && - strcmp((char *)key->data.scalar.value, "sipservers") == 0) { + strcasecmp((char *)key->data.scalar.value, "sipservers") == 0) { if (parse_core_server_list(&state->sipservers, OPENLI_CORE_SERVER_SIP, doc, value) == -1) { return -1; @@ -1732,7 +1734,7 @@ static int intercept_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SEQUENCE_NODE && - strcmp((char *)key->data.scalar.value, "smtpservers") == 0) { + strcasecmp((char *)key->data.scalar.value, "smtpservers") == 0) { if (parse_core_server_list(&state->smtpservers, OPENLI_CORE_SERVER_SMTP, doc, value) == -1) { return -1; @@ -1741,7 +1743,7 @@ static int intercept_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SEQUENCE_NODE && - strcmp((char *)key->data.scalar.value, "imapservers") == 0) { + strcasecmp((char *)key->data.scalar.value, "imapservers") == 0) { if (parse_core_server_list(&state->imapservers, OPENLI_CORE_SERVER_IMAP, doc, value) == -1) { return -1; @@ -1750,7 +1752,7 @@ static int intercept_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SEQUENCE_NODE && - strcmp((char *)key->data.scalar.value, "pop3servers") == 0) { + strcasecmp((char *)key->data.scalar.value, "pop3servers") == 0) { if (parse_core_server_list(&state->pop3servers, OPENLI_CORE_SERVER_POP3, doc, value) == -1) { return -1; @@ -1759,7 +1761,7 @@ static int intercept_parser(void *arg, yaml_document_t *doc, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, + strcasecmp((char *)key->data.scalar.value, "email-defaultdelivercompressed") == 0) { if (strcasecmp((char *)value->data.scalar.value, "as-is") == 0) { state->default_email_deliver_compress = @@ -1792,80 +1794,80 @@ static int provisioning_parser(void *arg, yaml_document_t *doc UNUSED, if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "voip-ignorecomfort") == 0) { + strcasecmp((char *)key->data.scalar.value, "voip-ignorecomfort") == 0) { state->ignorertpcomfort = check_onoff((char *)(value->data.scalar.value)); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "clientport") == 0) { + strcasecmp((char *)key->data.scalar.value, "clientport") == 0) { SET_CONFIG_STRING_OPTION(state->listenport, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "clientaddr") == 0) { + strcasecmp((char *)key->data.scalar.value, "clientaddr") == 0) { SET_CONFIG_STRING_OPTION(state->listenaddr, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "updateport") == 0) { + strcasecmp((char *)key->data.scalar.value, "updateport") == 0) { SET_CONFIG_STRING_OPTION(state->pushport, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "updateaddr") == 0) { + strcasecmp((char *)key->data.scalar.value, "updateaddr") == 0) { SET_CONFIG_STRING_OPTION(state->pushaddr, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "mediationport") == 0) { + strcasecmp((char *)key->data.scalar.value, "mediationport") == 0) { SET_CONFIG_STRING_OPTION(state->mediateport, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "mediationaddr") == 0) { + strcasecmp((char *)key->data.scalar.value, "mediationaddr") == 0) { SET_CONFIG_STRING_OPTION(state->mediateaddr, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "intercept-config-file") == 0) { + strcasecmp((char *)key->data.scalar.value, "intercept-config-file") == 0) { SET_CONFIG_STRING_OPTION(state->interceptconffile, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "tlscert") == 0) { + strcasecmp((char *)key->data.scalar.value, "tlscert") == 0) { SET_CONFIG_STRING_OPTION(state->sslconf.certfile, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "tlskey") == 0) { + strcasecmp((char *)key->data.scalar.value, "tlskey") == 0) { SET_CONFIG_STRING_OPTION(state->sslconf.keyfile, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "tlsca") == 0) { + strcasecmp((char *)key->data.scalar.value, "tlsca") == 0) { SET_CONFIG_STRING_OPTION(state->sslconf.cacertfile, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "restauthdb") == 0) { + strcasecmp((char *)key->data.scalar.value, "restauthdb") == 0) { SET_CONFIG_STRING_OPTION(state->restauthdbfile, value); } if (key->type == YAML_SCALAR_NODE && value->type == YAML_SCALAR_NODE && - strcmp((char *)key->data.scalar.value, "restauthkey") == 0) { + strcasecmp((char *)key->data.scalar.value, "restauthkey") == 0) { SET_CONFIG_STRING_OPTION(state->restauthkey, value); } From 740f4bc89bf1a6ef1af271f084949120052784eb Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Wed, 18 Sep 2024 09:02:08 +1200 Subject: [PATCH 31/44] Fix various issues found during EPSCC testing * forwarder: add EPSCC to list of CC types * encoding: add missing sequence endings for EPSCC content * remove duplicate declarations of OIDs that are now part of libwandder * when pre-encoding OIDS, cast away the `const` that is part of their definition in libwandder.h * fix bug where PS header template would modify the timestamp for a job, so it can't be re-used in later encoding tasks (i.e. if the timestamp appears elsewhere in the record). * remove debug output in gtp_worker.c --- src/collector/collector_forwarder.c | 3 +- src/collector/etsiencoding/epscc.c | 1 + src/collector/gtp_worker.c | 4 --- src/etsili_core.c | 44 +++++++++++++++-------------- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/collector/collector_forwarder.c b/src/collector/collector_forwarder.c index f10a7ca..6ee39f5 100644 --- a/src/collector/collector_forwarder.c +++ b/src/collector/collector_forwarder.c @@ -365,7 +365,8 @@ static inline int enqueue_result(forwarding_thread_data_t *fwd, res->origreq->type == OPENLI_EXPORT_IPMMCC || res->origreq->type == OPENLI_EXPORT_UMTSCC || res->origreq->type == OPENLI_EXPORT_EMAILCC || - res->origreq->type == OPENLI_EXPORT_RAW_CC) { + res->origreq->type == OPENLI_EXPORT_RAW_CC || + res->origreq->type == OPENLI_EXPORT_EPSCC) { reorderer = &(fwd->intreorderer_cc); } else { diff --git a/src/collector/etsiencoding/epscc.c b/src/collector/etsiencoding/epscc.c index f9acd7d..9a98063 100644 --- a/src/collector/etsiencoding/epscc.c +++ b/src/collector/etsiencoding/epscc.c @@ -127,5 +127,6 @@ wandder_encoded_result_t *encode_epscc_body(wandder_encoder_t *encoder, // payload wandder_encode_next(encoder, WANDDER_TAG_IPPACKET, WANDDER_CLASS_CONTEXT_PRIMITIVE, 2, NULL, ipclen); + END_ENCODED_SEQUENCE(encoder, 6); return wandder_encode_finish(encoder); } diff --git a/src/collector/gtp_worker.c b/src/collector/gtp_worker.c index 2dfdda3..2dd7b4c 100644 --- a/src/collector/gtp_worker.c +++ b/src/collector/gtp_worker.c @@ -638,8 +638,6 @@ static void process_gtp_u_packet(openli_gtp_worker_t *worker, return; } - printf("\nGTP-U: lookup for %s\n", keystr); - HASH_FIND(hh, worker->all_data_teids, keystr, strlen(keystr), found); if (!found) { return; @@ -651,7 +649,6 @@ static void process_gtp_u_packet(openli_gtp_worker_t *worker, internet_user_t *owner = found->owner[i]; user_intercept_list_t *userint; - printf("%d %s\n", i, owner->userid); HASH_FIND(hh, worker->userintercepts, owner->userid, strlen(owner->userid), userint); @@ -660,7 +657,6 @@ static void process_gtp_u_packet(openli_gtp_worker_t *worker, } HASH_ITER(hh_user, userint->intlist, ipint, tmp) { - printf("%s-%s\n", ipint->common.liid, ipint->common.targetagency); if (ipint->common.targetagency == NULL || strcmp(ipint->common.targetagency, "pcapdisk") == 0) { expmsg = create_rawip_job_from_ip(ipint->common.liid, diff --git a/src/etsili_core.c b/src/etsili_core.c index 0a7f2ae..c1af4bb 100644 --- a/src/etsili_core.c +++ b/src/etsili_core.c @@ -34,16 +34,9 @@ #include "collector/emailiri.h" #include "logger.h" -uint8_t etsi_ipccoid[4] = {0x05, 0x03, 0x0a, 0x02}; -uint8_t etsi_ipirioid[4] = {0x05, 0x03, 0x0a, 0x01}; -uint8_t etsi_ipmmccoid[4] = {0x05, 0x05, 0x06, 0x02}; -uint8_t etsi_ipmmirioid[4] = {0x05, 0x05, 0x06, 0x01}; +uint8_t etsi_hi1operationoid[8] = {0x00, 0x04, 0x00, 0x02, 0x02, 0x00, 0x01, 0x06}; uint8_t etsi_emailirioid[4] = {0x05, 0x02, 0x0f, 0x01}; uint8_t etsi_emailccoid[4] = {0x05, 0x02, 0x0f, 0x02}; -uint8_t etsi_umtsirioid[9] = {0x00, 0x04, 0x00, 0x02, 0x02, 0x04, 0x01, 0x0f, 0x05}; -uint8_t etsi_hi1operationoid[8] = {0x00, 0x04, 0x00, 0x02, 0x02, 0x00, 0x01, 0x06}; -uint8_t etsi_epsirioid[9] = {0x00, 0x04, 0x00, 0x02, 0x02, 0x04, 0x08, 0x11, 0x00}; -uint8_t etsi_epsccoid[9] = {0x00, 0x04, 0x00, 0x02, 0x02, 0x04, 0x09, 0x11, 0x00}; static inline void encode_tri_body(wandder_encoder_t *encoder) { ENC_CSEQUENCE(encoder, 2); // Payload @@ -1235,57 +1228,64 @@ void etsili_preencode_static_fields( p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; p->identifier = 0; p->encodeas = WANDDER_TAG_RELATIVEOID; - wandder_encode_preencoded_value(p, etsi_ipmmirioid, sizeof(etsi_ipmmirioid)); + wandder_encode_preencoded_value(p, (uint8_t *)etsi_ipmmirioid, + sizeof(etsi_ipmmirioid)); p = &(pendarray[OPENLI_PREENCODE_IPCCOID]); p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; p->identifier = 0; p->encodeas = WANDDER_TAG_RELATIVEOID; - wandder_encode_preencoded_value(p, etsi_ipccoid, sizeof(etsi_ipccoid)); + wandder_encode_preencoded_value(p, (uint8_t *)etsi_ipccoid, + sizeof(etsi_ipccoid)); p = &(pendarray[OPENLI_PREENCODE_IPIRIOID]); p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; p->identifier = 0; p->encodeas = WANDDER_TAG_RELATIVEOID; - wandder_encode_preencoded_value(p, etsi_ipirioid, sizeof(etsi_ipirioid)); + wandder_encode_preencoded_value(p, (uint8_t *)etsi_ipirioid, + sizeof(etsi_ipirioid)); p = &(pendarray[OPENLI_PREENCODE_EMAILIRIOID]); p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; p->identifier = 0; p->encodeas = WANDDER_TAG_RELATIVEOID; - wandder_encode_preencoded_value(p, etsi_emailirioid, + wandder_encode_preencoded_value(p, (uint8_t *)etsi_emailirioid, sizeof(etsi_emailirioid)); p = &(pendarray[OPENLI_PREENCODE_EMAILCCOID]); p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; p->identifier = 0; p->encodeas = WANDDER_TAG_RELATIVEOID; - wandder_encode_preencoded_value(p, etsi_emailccoid, + wandder_encode_preencoded_value(p, (uint8_t *)etsi_emailccoid, sizeof(etsi_emailccoid)); p = &(pendarray[OPENLI_PREENCODE_UMTSIRIOID]); p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; p->identifier = 0; p->encodeas = WANDDER_TAG_OID; - wandder_encode_preencoded_value(p, etsi_umtsirioid, sizeof(etsi_umtsirioid)); + wandder_encode_preencoded_value(p, (uint8_t *)etsi_umtsirioid, + sizeof(etsi_umtsirioid)); p = &(pendarray[OPENLI_PREENCODE_EPSIRIOID]); p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; p->identifier = 0; p->encodeas = WANDDER_TAG_OID; - wandder_encode_preencoded_value(p, etsi_epsirioid, sizeof(etsi_epsirioid)); + wandder_encode_preencoded_value(p, (uint8_t *)etsi_epsirioid, + sizeof(etsi_epsirioid)); p = &(pendarray[OPENLI_PREENCODE_EPSCCOID]); p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; p->identifier = 0; p->encodeas = WANDDER_TAG_OID; - wandder_encode_preencoded_value(p, etsi_epsccoid, sizeof(etsi_epsccoid)); + wandder_encode_preencoded_value(p, (uint8_t *)etsi_epsccoid, + sizeof(etsi_epsccoid)); p = &(pendarray[OPENLI_PREENCODE_IPMMCCOID]); p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; p->identifier = 0; p->encodeas = WANDDER_TAG_RELATIVEOID; - wandder_encode_preencoded_value(p, etsi_ipmmccoid, sizeof(etsi_ipmmccoid)); + wandder_encode_preencoded_value(p, (uint8_t *)etsi_ipmmccoid, + sizeof(etsi_ipmmccoid)); p = &(pendarray[OPENLI_PREENCODE_DIRFROM]); p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; @@ -1473,6 +1473,8 @@ int etsili_create_header_template(wandder_encoder_t *encoder, int etsili_update_header_template(encoded_header_template_t *tplate, int64_t seqno, struct timeval *tv) { int i; + time_t tvsec = tv->tv_sec; + time_t tvusec = tv->tv_usec; /* Assume that we've been provided the right template with sufficient * space to fit the sequence number and timestamps -- ideally we would @@ -1487,13 +1489,13 @@ int etsili_update_header_template(encoded_header_template_t *tplate, } for (i = tplate->tssec_size - 1; i >= 0; i--) { - *(tplate->tssec_ptr + i) = (tv->tv_sec & 0xff); - tv->tv_sec = tv->tv_sec >> 8; + *(tplate->tssec_ptr + i) = (tvsec & 0xff); + tvsec = tvsec >> 8; } for (i = tplate->tsusec_size - 1; i >= 0; i--) { - *(tplate->tsusec_ptr + i) = (tv->tv_usec & 0xff); - tv->tv_usec = tv->tv_usec >> 8; + *(tplate->tsusec_ptr + i) = (tvusec & 0xff); + tvusec = tvusec >> 8; } return 0; From 3bcc8c8bbd60a4b925e2ff7439a400b3a7942363 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Wed, 18 Sep 2024 09:50:55 +1200 Subject: [PATCH 32/44] Only generate EPS CCs for GTPv2 sessions GTPv1 sessions should be generating UMTS CCs, but that's getting to be somewhat legacy now so we don't want to have to support that any more than we need to. Also tidy up some extraneous debug output and testing code that was accidentally left behind prior to the latest merge. --- src/collector/accessplugins/gtp.c | 1 + src/collector/gtp_worker.c | 51 +++---------------------------- src/collector/internetaccess.h | 1 + 3 files changed, 7 insertions(+), 46 deletions(-) diff --git a/src/collector/accessplugins/gtp.c b/src/collector/accessplugins/gtp.c index 37bbc0c..abe76e5 100644 --- a/src/collector/accessplugins/gtp.c +++ b/src/collector/accessplugins/gtp.c @@ -1480,6 +1480,7 @@ static inline void add_new_session_teids(access_session_t *sess, sess->teids[1] = gsess->data_teid[1]; sess->gtp_tunnel_endpoints[0] = gsess->tunnel_endpoints[0]; sess->gtp_tunnel_endpoints[1] = gsess->tunnel_endpoints[1]; + sess->gtp_version = gsess->gtpversion; gsess->tunnel_endpoints[0] = NULL; gsess->tunnel_endpoints[1] = NULL; diff --git a/src/collector/gtp_worker.c b/src/collector/gtp_worker.c index 2dd7b4c..9ba7f5b 100644 --- a/src/collector/gtp_worker.c +++ b/src/collector/gtp_worker.c @@ -107,8 +107,6 @@ static void add_teid_to_session_mapping(openli_gtp_worker_t *worker, etsidir = ETSI_DIR_TO_TARGET; } - printf("TEID ID: %s\n", keystr); - HASH_FIND(hh, worker->all_data_teids, keystr, strlen(keystr), found); if (found && found->cin == sess->cin && found->dir == etsidir) { found->session = realloc(found->session, @@ -159,7 +157,6 @@ static void remove_teid_to_session_mapping(openli_gtp_worker_t *worker, return; } snprintf(keystr, 1024, "%s-%u", endpoint_ip, teid); - printf("DELETING %s\n", keystr); HASH_FIND(hh, worker->all_data_teids, keystr, strlen(keystr), found); if (!found) { @@ -227,43 +224,6 @@ static void newly_active_gtp_session(openli_gtp_worker_t *worker, } -static void setup_gtpu_testing_intercept(openli_gtp_worker_t *worker, - ipintercept_t *ipint) { - - internet_user_t *iuser; - user_intercept_list_t *userint; - access_session_t *sess; - user_identity_t newid; - - newid.method = USER_IDENT_GTP_MSISDN; - newid.idstr = "5511950140000"; - newid.idlength = strlen(newid.idstr); - - iuser = calloc(1, sizeof(internet_user_t)); - - add_userid_to_allusers_map(&worker->allusers, iuser, &newid); - - printf("iuser->userid: %s\n", iuser->userid); - HASH_FIND(hh, worker->userintercepts, iuser->userid, - strlen(iuser->userid), userint); - if (userint == NULL) { - logger(LOG_INFO, "NO USER INTERCEPT LIST for %s?", ipint->common.liid); - return; - } - - sess = create_access_session(worker->gtpplugin, "foobar", strlen("foobar")); - sess->identifier_type = OPENLI_ACCESS_SESSION_TEID; - sess->cin = 240; - sess->teids[0] = 1; - sess->teids[1] = 1; - sess->gtp_tunnel_endpoints[0] = strdup("2989009088"); - sess->gtp_tunnel_endpoints[1] = strdup("3005786304"); - sess->teids_mapped = 0; - - newly_active_gtp_session(worker, userint, sess, iuser); - -} - static int init_gtp_intercept(openli_gtp_worker_t *worker, ipintercept_t *ipint) { @@ -291,11 +251,6 @@ static int init_gtp_intercept(openli_gtp_worker_t *worker, ipint->common.liid_len, ipint); ipint->awaitingconfirm = 0; - - // XXX VERY TEMPORARY for testing and dev - if (strcmp(ipint->common.liid, "gtpv2test") == 0) { - setup_gtpu_testing_intercept(worker, ipint); - } return 1; } @@ -647,6 +602,7 @@ static void process_gtp_u_packet(openli_gtp_worker_t *worker, for (i = 0; i < found->sessioncount; i++) { internet_user_t *owner = found->owner[i]; + access_session_t *sess = found->session[i]; user_intercept_list_t *userint; HASH_FIND(hh, worker->userintercepts, owner->userid, @@ -663,13 +619,16 @@ static void process_gtp_u_packet(openli_gtp_worker_t *worker, ipint->common.destid, payload, plen, tv, OPENLI_EXPORT_RAW_CC); - } else { + } else if (sess->gtp_version == 2) { /* TODO define ICE types and figure out how we decide what * value to use here... */ expmsg = create_epscc_job(ipint->common.liid, found->cin, ipint->common.destid, found->dir, payload, plen, 0, gtpseqno); + } else { + /* XXX don't bother with UMTSCC right now */ + continue; } publish_openli_msg(worker->zmq_pubsocks[ipint->common.seqtrackerid], expmsg); diff --git a/src/collector/internetaccess.h b/src/collector/internetaccess.h index 5a34ab6..ac82bdf 100644 --- a/src/collector/internetaccess.h +++ b/src/collector/internetaccess.h @@ -145,6 +145,7 @@ struct access_session { struct timeval started; char *gtp_tunnel_endpoints[2]; + uint8_t gtp_version; uint32_t teids[2]; uint8_t teids_mapped; From 768230f34b8089b486c4997168dba685eab4dc97 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Wed, 18 Sep 2024 10:09:31 +1200 Subject: [PATCH 33/44] Bump version to 1.1.9 * update debian changelog * require latest version of libwandder --- README.md | 2 +- configure.ac | 2 +- debian/changelog | 35 +++++++++++++++++++++++------------ debian/control | 2 +- rpm/openli.spec | 7 +++++-- 5 files changed, 31 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 7d93660..8c141f6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ OpenLI -- open source ETSI-compliant Lawful Intercept software -Version: 1.1.8 +Version: 1.1.9 --------------------------------------------------------------------------- diff --git a/configure.ac b/configure.ac index 16a4f3d..2d61f20 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # Super primitive configure script -AC_INIT([openli],[1.1.8],[shane@alcock.co.nz]) +AC_INIT([openli],[1.1.9],[shane@alcock.co.nz]) AM_INIT_AUTOMAKE([subdir-objects]) AC_CONFIG_SRCDIR(src/collector/collector.c) diff --git a/debian/changelog b/debian/changelog index e4b0ada..03e7084 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,12 +1,30 @@ -openli (1.1.9-1~hotfixes01) unstable; urgency=medium +openli (1.1.9-1) unstable; urgency=medium - * Fix RADIUS crash that can occur under very rare circumstances due to + * RADIUS: fix crash that can occur under very rare circumstances due to a dangling user record pointer in an old unmatched request. - * Fix bug where CINs for all RADIUS sessions were zero. + * RADIUS: fix bug where CINs for all RADIUS sessions were zero. * Fix potential silent exit in collector if a packet cannot be copied to be sent to another thread. - - -- Shane Alcock Wed, 21 Aug 2024 23:46:18 +1200 + * Mobile data: move processing of GTP traffic / sessions into separate worker + threads. + * Mobile data: add (experimental) support for intercepting GTP-U traffic for + sessions where the GTP-C identity matches an intercept target. + Only applies to GTPv2 sessions -- no CC interception is performed for + GTPv1 sessions (i.e UMTS-CCs). + * Mobile data: add support for intercepting GTP-C traffic for intercept + targets and encoding it as either EPS-IRIs (for GTPv2) or UMTS-IRIs + (for GTPv1). + * Mediator: allow RabbitMQ internal password to be specified using + either "RMQlocalpass" OR "RMQinternalpass" config options, so + as to match the existing documentation. + * SIP: fix bug where RTP would not be intercepted if the SIP traffic + is proxied back to the original source IP. + * SIP: fix assertion failure when reassembling TCP SIP traffic that + happens to have trailing bytes (such as an extra '\r\n' sequence. + * SIP: fix double frees that could occur when reassembling TCP SIP + traffic. + + -- Shane Alcock Wed, 18 Sep 2024 09:10:41 +1200 openli (1.1.8-1) unstable; urgency=medium @@ -55,12 +73,6 @@ openli (1.1.6-1) unstable; urgency=medium * Added new parameter for IP intercepts: mobileident -- this is used to indicate whether the user identifier for a mobile data intercept is an MSISDN, IMEI or IMSI. -<<<<<<< HEAD - * VOIP intercepts that are written to pcap files will now include - their corresponding SIP packets alongside the RTP streams. - - -- Shane Alcock Wed, 22 May 2024 11:08:41 +1200 -======= * Add support for including SIP packets in pcapdisk output for VoIP intercepts. * Fix bug where mediators receiving message from a collector via @@ -74,7 +86,6 @@ openli (1.1.6-1) unstable; urgency=medium blocked. -- Shane Alcock Mon, 1 Jul 2024 09:57:07 +1200 ->>>>>>> master openli (1.1.5-1) unstable; urgency=medium diff --git a/debian/control b/debian/control index a9ea854..dd44dca 100644 --- a/debian/control +++ b/debian/control @@ -3,7 +3,7 @@ Section: net Priority: optional Maintainer: Shane Alcock Build-Depends: debhelper-compat (= 12), dh-autoreconf, dh-systemd (>=1.5), - libtrace4-dev (>= 4.0.24), libyaml-dev, uthash-dev, libwandder2-dev (>=2.0.10), + libtrace4-dev (>= 4.0.24), libyaml-dev, uthash-dev, libwandder2-dev (>=2.0.13), libjudy-dev, libzmq3-dev, libgoogle-perftools-dev, libosip2-dev (>=5.0.0), libssl1.0-dev (>=1.0.2r) | libssl-dev, librabbitmq-dev, libb64-dev, libmicrohttpd-dev, libjson-c-dev, libsqlcipher-dev, zlib1g-dev diff --git a/rpm/openli.spec b/rpm/openli.spec index 4784536..9ddfe0b 100644 --- a/rpm/openli.spec +++ b/rpm/openli.spec @@ -1,5 +1,5 @@ Name: openli -Version: 1.1.8 +Version: 1.1.9 Release: 1%{?dist} Summary: Software for performing ETSI-compliant lawful intercept @@ -17,7 +17,7 @@ BuildRequires: libyaml-devel BuildRequires: libtrace4-devel >= 4.0.24 BuildRequires: Judy-devel BuildRequires: uthash-devel -BuildRequires: libwandder2-devel >= 2.0.10 +BuildRequires: libwandder2-devel >= 2.0.13 BuildRequires: zeromq-devel BuildRequires: gperftools-devel BuildRequires: libosip2-devel >= 5.0.0 @@ -283,6 +283,9 @@ fi %changelog +* Wed Sep 18 2024 Shane Alcock - 1.1.9-1 +- Updated for 1.1.9 release + * Thu Jul 25 2024 Shane Alcock - 1.1.8-1 - Updated for 1.1.8 release From f98fec02d77a11bbcc6a6b9de0d24cd1b0c856a7 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Wed, 18 Sep 2024 11:25:41 +1200 Subject: [PATCH 34/44] Fix missing endpoint IP for GTP sessions Resolves issue where the GTP worker would print warnings for new sessions that an endpoint IP was missing. --- src/collector/accessplugins/gtp.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/collector/accessplugins/gtp.c b/src/collector/accessplugins/gtp.c index abe76e5..12ae3cb 100644 --- a/src/collector/accessplugins/gtp.c +++ b/src/collector/accessplugins/gtp.c @@ -997,7 +997,6 @@ static void *gtp_parse_packet(access_plugin_t *p, libtrace_packet_t *pkt) { */ snprintf(glob->parsedpkt->tunnel_endpoint, 256, "%u", ip->ip_src.s_addr); - memcpy(glob->parsedpkt->serverid, &(ip->ip_src.s_addr), 4); break; @@ -1530,8 +1529,7 @@ static void apply_gtp_fsm_logic(gtp_global_t *glob, extract_gtp_assigned_ip_address(gpkt, sess, gparsed->matched_session); - /* TODO: set up GTP-U data sessions */ - + /* set up GTP-U data sessions */ if (gpkt->teid_ctl != 0) { create_alt_session_entry(glob, gparsed, gpkt->teid_ctl); } @@ -1556,7 +1554,7 @@ static void apply_gtp_fsm_logic(gtp_global_t *glob, extract_gtp_assigned_ip_address(gpkt, sess, gparsed->matched_session); - /* TODO: set up GTP-U data sessions */ + /* set up GTP-U data sessions */ if (gpkt->teid_ctl != 0) { create_alt_session_entry(glob, gparsed, gpkt->teid_ctl); } @@ -1702,6 +1700,7 @@ static access_session_t *gtp_update_session_state(access_plugin_t *p, saved->teid = gparsed->teid; saved->teid_ctl = gparsed->teid_ctl; saved->teid_data = gparsed->teid_data; + saved->endpoint_ip = strdup(gparsed->tunnel_endpoint); gparsed->ies = NULL; gparsed->matched_session->last_reqid = reqid; From cda99eb5fa2c398b7755e4b45abbabe671782973 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Wed, 18 Sep 2024 11:27:13 +1200 Subject: [PATCH 35/44] IP-based mobile intercepts are now encoded as EPSCCs Previously, these were UMTSCCs which I'm trying to get away from supporting. --- src/collector/collector_publish.c | 36 +++++++++++++++++++++++++++++++ src/collector/collector_publish.h | 3 +++ src/collector/ipcc.c | 21 +++++++++--------- 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/src/collector/collector_publish.c b/src/collector/collector_publish.c index 2a90235..1a4e6ab 100644 --- a/src/collector/collector_publish.c +++ b/src/collector/collector_publish.c @@ -254,6 +254,42 @@ int push_vendor_mirrored_ipcc_job(void *pubqueue, return 0; } +openli_export_recv_t *create_epscc_job_from_ip(uint32_t cin, char *liid, + uint32_t destid, libtrace_packet_t *pkt, uint8_t dir) { + + void *l3; + uint32_t rem; + uint16_t ethertype; + openli_export_recv_t *msg = NULL; + + msg = (openli_export_recv_t *)calloc(1, sizeof(openli_export_recv_t)); + if (msg == NULL) { + return msg; + } + + l3 = trace_get_layer3(pkt, ðertype, &rem); + + if (l3 == NULL || rem == 0) { + free(msg); + return NULL; + } + + msg->type = OPENLI_EXPORT_EPSCC; + msg->destid = destid; + msg->ts = trace_get_timeval(pkt); + msg->data.mobcc.liid = strdup(liid); + msg->data.mobcc.ipcontent = calloc(rem, sizeof(uint8_t)); + memcpy(msg->data.mobcc.ipcontent, l3, rem); + msg->data.mobcc.ipclen = rem; + msg->data.mobcc.cin = cin; + msg->data.mobcc.dir = dir; + + msg->data.mobcc.icetype = 0; + msg->data.mobcc.gtpseqno = 0; + + return msg; +} + openli_export_recv_t *create_ipcc_job(uint32_t cin, char *liid, uint32_t destid, libtrace_packet_t *pkt, uint8_t dir) { diff --git a/src/collector/collector_publish.h b/src/collector/collector_publish.h index 6105aa8..5c62f5a 100644 --- a/src/collector/collector_publish.h +++ b/src/collector/collector_publish.h @@ -215,6 +215,9 @@ openli_export_recv_t *create_ipcc_job( uint32_t cin, char *liid, uint32_t destid, libtrace_packet_t *pkt, uint8_t dir); +openli_export_recv_t *create_epscc_job_from_ip(uint32_t cin, char *liid, + uint32_t destid, libtrace_packet_t *pkt, uint8_t dir); + /** Creates a raw IP packet encoding job from a pointer to an IP header. * Supports creating messages using both the OPENLI_EXPORT_RAW_CC type and * the OPENLI_EXPORT_RAW_IRI type. diff --git a/src/collector/ipcc.c b/src/collector/ipcc.c index 08a285a..a5ecac7 100644 --- a/src/collector/ipcc.c +++ b/src/collector/ipcc.c @@ -213,13 +213,14 @@ static void singlev6_conn_contents(struct sockaddr_in6 *cmp, strcmp(sess->common.targetagency,"pcapdisk") == 0) { msg = create_rawip_cc_job(sess->common.liid, sess->common.destid, pkt); + } else if (sess->accesstype == + INTERNET_ACCESS_TYPE_MOBILE) { + + msg = create_epscc_job_from_ip(sess->cin, + sess->common.liid, sess->common.destid, pkt, 0); } else { msg = create_ipcc_job(sess->cin, sess->common.liid, sess->common.destid, pkt, 0); - if (sess->accesstype == INTERNET_ACCESS_TYPE_MOBILE && - msg) { - msg->type = OPENLI_EXPORT_UMTSCC; - } } if (msg != NULL) { publish_openli_msg(loc->zmq_pubsocks[0], msg); //FIXME @@ -303,12 +304,12 @@ int ipv4_comm_contents(libtrace_packet_t *pkt, packet_info_t *pinfo, strcmp(sess->common.targetagency, "pcapdisk") == 0) { msg = create_rawip_cc_job(sess->common.liid, sess->common.destid, pkt); + } else if (sess->accesstype == INTERNET_ACCESS_TYPE_MOBILE) { + msg = create_epscc_job_from_ip(sess->cin, + sess->common.liid, sess->common.destid, pkt, 0); } else { msg = create_ipcc_job(sess->cin, sess->common.liid, sess->common.destid, pkt, 0); - if (sess->accesstype == INTERNET_ACCESS_TYPE_MOBILE && msg) { - msg->type = OPENLI_EXPORT_UMTSCC; - } } if (msg != NULL) { publish_openli_msg(loc->zmq_pubsocks[0], msg); //FIXME @@ -339,12 +340,12 @@ int ipv4_comm_contents(libtrace_packet_t *pkt, packet_info_t *pinfo, strcmp(sess->common.targetagency, "pcapdisk") == 0) { msg = create_rawip_cc_job(sess->common.liid, sess->common.destid, pkt); + } else if (sess->accesstype == INTERNET_ACCESS_TYPE_MOBILE) { + msg = create_epscc_job_from_ip(sess->cin, + sess->common.liid, sess->common.destid, pkt, 1); } else { msg = create_ipcc_job(sess->cin, sess->common.liid, sess->common.destid, pkt, 1); - if (sess->accesstype == INTERNET_ACCESS_TYPE_MOBILE && msg) { - msg->type = OPENLI_EXPORT_UMTSCC; - } } if (msg != NULL) { publish_openli_msg(loc->zmq_pubsocks[0], msg); //FIXME From ba56dbda8c0f4a886d98f004ad4131532ed4dd41 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Wed, 18 Sep 2024 12:00:36 +1200 Subject: [PATCH 36/44] Update debian changelog --- debian/changelog | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 03e7084..18c71ba 100644 --- a/debian/changelog +++ b/debian/changelog @@ -14,19 +14,20 @@ openli (1.1.9-1) unstable; urgency=medium * Mobile data: add support for intercepting GTP-C traffic for intercept targets and encoding it as either EPS-IRIs (for GTPv2) or UMTS-IRIs (for GTPv1). + * Mobile data: IP-based mobile intercepts are now encoded as EPS-CCs, + instead of UMTS-CCs. * Mediator: allow RabbitMQ internal password to be specified using either "RMQlocalpass" OR "RMQinternalpass" config options, so as to match the existing documentation. * SIP: fix bug where RTP would not be intercepted if the SIP traffic is proxied back to the original source IP. * SIP: fix assertion failure when reassembling TCP SIP traffic that - happens to have trailing bytes (such as an extra '\r\n' sequence. + happens to have trailing bytes (such as an extra '\r\n' sequence). * SIP: fix double frees that could occur when reassembling TCP SIP traffic. -- Shane Alcock Wed, 18 Sep 2024 09:10:41 +1200 - openli (1.1.8-1) unstable; urgency=medium * Collector: fix crash in sync_voip thread if an invalid SIP packet From 39e3b8da068b0c3c2b58831471ba52d39a7cd0a9 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Wed, 18 Sep 2024 12:40:42 +1200 Subject: [PATCH 37/44] Use renamed OIDs from libwandder The new OIDs in libwandder were renamed to avoid issues with multiple declarations if new libwandder is used alongside older OpenLI. This commit updates OpenLI to use the new OID names and create a clean break. --- src/etsili_core.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/etsili_core.c b/src/etsili_core.c index c1af4bb..a6ac3ab 100644 --- a/src/etsili_core.c +++ b/src/etsili_core.c @@ -1228,22 +1228,22 @@ void etsili_preencode_static_fields( p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; p->identifier = 0; p->encodeas = WANDDER_TAG_RELATIVEOID; - wandder_encode_preencoded_value(p, (uint8_t *)etsi_ipmmirioid, - sizeof(etsi_ipmmirioid)); + wandder_encode_preencoded_value(p, (uint8_t *)wandder_etsi_ipmmirioid, + sizeof(wandder_etsi_ipmmirioid)); p = &(pendarray[OPENLI_PREENCODE_IPCCOID]); p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; p->identifier = 0; p->encodeas = WANDDER_TAG_RELATIVEOID; - wandder_encode_preencoded_value(p, (uint8_t *)etsi_ipccoid, - sizeof(etsi_ipccoid)); + wandder_encode_preencoded_value(p, (uint8_t *)wandder_etsi_ipccoid, + sizeof(wandder_etsi_ipccoid)); p = &(pendarray[OPENLI_PREENCODE_IPIRIOID]); p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; p->identifier = 0; p->encodeas = WANDDER_TAG_RELATIVEOID; - wandder_encode_preencoded_value(p, (uint8_t *)etsi_ipirioid, - sizeof(etsi_ipirioid)); + wandder_encode_preencoded_value(p, (uint8_t *)wandder_etsi_ipirioid, + sizeof(wandder_etsi_ipirioid)); p = &(pendarray[OPENLI_PREENCODE_EMAILIRIOID]); p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; @@ -1263,29 +1263,29 @@ void etsili_preencode_static_fields( p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; p->identifier = 0; p->encodeas = WANDDER_TAG_OID; - wandder_encode_preencoded_value(p, (uint8_t *)etsi_umtsirioid, - sizeof(etsi_umtsirioid)); + wandder_encode_preencoded_value(p, (uint8_t *)wandder_etsi_umtsirioid, + sizeof(wandder_etsi_umtsirioid)); p = &(pendarray[OPENLI_PREENCODE_EPSIRIOID]); p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; p->identifier = 0; p->encodeas = WANDDER_TAG_OID; - wandder_encode_preencoded_value(p, (uint8_t *)etsi_epsirioid, - sizeof(etsi_epsirioid)); + wandder_encode_preencoded_value(p, (uint8_t *)wandder_etsi_epsirioid, + sizeof(wandder_etsi_epsirioid)); p = &(pendarray[OPENLI_PREENCODE_EPSCCOID]); p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; p->identifier = 0; p->encodeas = WANDDER_TAG_OID; - wandder_encode_preencoded_value(p, (uint8_t *)etsi_epsccoid, - sizeof(etsi_epsccoid)); + wandder_encode_preencoded_value(p, (uint8_t *)wandder_etsi_epsccoid, + sizeof(wandder_etsi_epsccoid)); p = &(pendarray[OPENLI_PREENCODE_IPMMCCOID]); p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; p->identifier = 0; p->encodeas = WANDDER_TAG_RELATIVEOID; - wandder_encode_preencoded_value(p, (uint8_t *)etsi_ipmmccoid, - sizeof(etsi_ipmmccoid)); + wandder_encode_preencoded_value(p, (uint8_t *)wandder_etsi_ipmmccoid, + sizeof(wandder_etsi_ipmmccoid)); p = &(pendarray[OPENLI_PREENCODE_DIRFROM]); p->identclass = WANDDER_CLASS_CONTEXT_PRIMITIVE; From 2f9cb2c78c538ba447e00df9a88eedd22f6ce44b Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Thu, 19 Sep 2024 17:46:35 +1200 Subject: [PATCH 38/44] Fix a few bugs in the GTP code * fix double-free when encoding UMTS IRIs * fix bug where GTPv1 sessions would not have a valid data TEID * fix memory leak of endpoint IP strings --- src/collector/accessplugins/gtp.c | 11 ++++++++--- src/collector/collector_publish.c | 3 ++- src/collector/encoder_worker.c | 2 -- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/collector/accessplugins/gtp.c b/src/collector/accessplugins/gtp.c index 12ae3cb..7eebb2e 100644 --- a/src/collector/accessplugins/gtp.c +++ b/src/collector/accessplugins/gtp.c @@ -354,6 +354,9 @@ static void gtp_destroy_plugin_data(access_plugin_t *p) { if (pkt->ipcontent) { free(pkt->ipcontent); } + if (pkt->endpoint_ip) { + free(pkt->endpoint_ip); + } gtp_free_ie_list(pkt->ies); free(pkt); JLN(pval, glob->saved_packets, indexnum); @@ -436,6 +439,7 @@ static inline bool interesting_info_element(uint8_t gtpv, uint8_t ietype) { case GTPV1_IE_CAUSE: case GTPV1_IE_IMSI: case GTPV1_IE_TEID_CTRL: + case GTPV1_IE_TEID_DATA: case GTPV1_IE_END_USER_ADDRESS: case GTPV1_IE_APNAME: case GTPV1_IE_MSISDN: @@ -722,9 +726,10 @@ static int walk_gtpv1_ies(gtp_parsed_t *parsedpkt, uint8_t *ptr, uint32_t rem, if (ietype == GTPV1_IE_MSISDN) { get_gtpnum_from_ie(gtpel, parsedpkt->msisdn, 1); } - if (ietype == GTPV1_IE_TEID_DATA) { - parsedpkt->teid_data = get_teid_from_teidctl(gtpel); - } + } + + if (ietype == GTPV1_IE_TEID_DATA) { + parsedpkt->teid_data = get_teid_from_teidctl(gtpel); } if (ietype == GTPV1_IE_TEID_CTRL) { diff --git a/src/collector/collector_publish.c b/src/collector/collector_publish.c index 1a4e6ab..41d211d 100644 --- a/src/collector/collector_publish.c +++ b/src/collector/collector_publish.c @@ -128,7 +128,8 @@ void free_published_message(openli_export_recv_t *msg) { if (msg->data.ipiri.assignedips) { free(msg->data.ipiri.assignedips); } - } else if (msg->type == OPENLI_EXPORT_UMTSIRI) { + } else if (msg->type == OPENLI_EXPORT_UMTSIRI || + msg->type == OPENLI_EXPORT_EPSIRI) { if (msg->data.mobiri.liid) { free(msg->data.mobiri.liid); } diff --git a/src/collector/encoder_worker.c b/src/collector/encoder_worker.c index 62e6ced..ff9b002 100644 --- a/src/collector/encoder_worker.c +++ b/src/collector/encoder_worker.c @@ -605,7 +605,6 @@ static int encode_templated_epsiri(openli_encoder_t *enc, wandder_release_encoded_result(enc->encoder, body); free_mobileiri_parameters(irijob->customparams); - free(irijob->liid); /* Success */ return 1; } @@ -657,7 +656,6 @@ static int encode_templated_umtsiri(openli_encoder_t *enc, wandder_release_encoded_result(enc->encoder, body); free_mobileiri_parameters(irijob->customparams); - free(irijob->liid); /* Success */ return 1; } From c2957d9777e0abec0f61c52a187928386a211379 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Fri, 20 Sep 2024 12:19:18 +1200 Subject: [PATCH 39/44] Fix RTP intercept failures for reverse INVITES (again) Fixes bug introduced in f3fe7624c1d310cb60e6e39ea63aca3975a63755 where a proxied SIP session would set the "inviter" incorrectly. This meant that a reverse INVITE would not be correctly handled, and therefore RTP traffic could be missed. --- src/collector/collector_sync_voip.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/collector/collector_sync_voip.c b/src/collector/collector_sync_voip.c index b007311..8e0a97d 100644 --- a/src/collector/collector_sync_voip.c +++ b/src/collector/collector_sync_voip.c @@ -787,6 +787,7 @@ static int process_sip_183sessprog(collector_sync_voip_t *sync, } } + announce_rtp_streams_if_required(sync, thisrtp); } free(cseqstr); @@ -1168,6 +1169,7 @@ static int process_sip_invite(collector_sync_voip_t *sync, char *callid, openli_sip_identity_set_t all_identities; uint8_t trust_sip_from; openli_location_t *locptr; + char *invitecseq = NULL; locptr = NULL; loc_cnt = 0; @@ -1192,6 +1194,7 @@ static int process_sip_invite(collector_sync_voip_t *sync, char *callid, trust_sip_from = sync->info->trust_sip_from; pthread_rwlock_unlock(sync->info_mutex); + invitecseq = get_sip_cseq(sync->sipparser); HASH_ITER(hh_liid, sync->voipintercepts, vint, tmp) { vshared = NULL; @@ -1271,7 +1274,9 @@ static int process_sip_invite(collector_sync_voip_t *sync, char *callid, portstr = get_sip_media_port(sync->sipparser, 0); mediatype = get_sip_media_type(sync->sipparser, 0); - if (iritype == ETSILI_IRI_BEGIN || thisrtp->active == 0) { + if (iritype == ETSILI_IRI_BEGIN || ( + thisrtp->invitecseq && invitecseq && + strcmp(thisrtp->invitecseq, invitecseq) == 0)) { memcpy(thisrtp->inviter, irimsg->data.ipmmiri.ipsrc, 16); dir = 0; } else if (memcmp(thisrtp->inviter, irimsg->data.ipmmiri.ipsrc, @@ -1312,13 +1317,17 @@ static int process_sip_invite(collector_sync_voip_t *sync, char *callid, continue; } - thisrtp->invitecseq = get_sip_cseq(sync->sipparser); + thisrtp->invitecseq = invitecseq; + invitecseq = NULL; create_sip_ipiri(sync, vint, irimsg, iritype, vshared->cin, locptr, loc_cnt, pkts, pkt_cnt); exportcount += 1; } + if (invitecseq) { + free(invitecseq); + } if (locptr) { free(locptr); } From 203bbdf3f8c13afbddef282a757bfbbfe1ac5302 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Fri, 20 Sep 2024 18:40:59 +1200 Subject: [PATCH 40/44] Another attempt to resolve reverse INVITEs + proxying This solution seems to work for the conflicting cases that I had discovered so far -- we use a stack to track the details of the RTP session for the initial INVITE sender and try to ignore any other proxying (at least from an RTP interception perspective). Reverse INVITEs are ignored until we see one destined for the initial INVITE sender. We could also now consider discarding the proxied SIP, but that's something that will require a bit more thought. There is still one edge case where this will fail (when the proxied SIP is also sent back to the IP of the initial INVITE sender AND there is a reverse INVITE) but that seems almost impossible to resolve and hopefully won't happen any time soon. --- src/collector/collector_sync_voip.c | 129 +++++++++++++++++----------- src/intercept.c | 2 + src/intercept.h | 1 + 3 files changed, 80 insertions(+), 52 deletions(-) diff --git a/src/collector/collector_sync_voip.c b/src/collector/collector_sync_voip.c index 8e0a97d..8b29a4a 100644 --- a/src/collector/collector_sync_voip.c +++ b/src/collector/collector_sync_voip.c @@ -759,6 +759,12 @@ static int process_sip_183sessprog(collector_sync_voip_t *sync, portstr = get_sip_media_port(sync->sipparser, 0); mediatype = get_sip_media_type(sync->sipparser, 0); + if (!ipstr || !portstr || !mediatype) { + free(cseqstr); + return 0; + } + + if (memcmp(thisrtp->inviter, irimsg->data.ipmmiri.ipsrc, 16) == 0) { dir = 0; @@ -767,7 +773,7 @@ static int process_sip_183sessprog(collector_sync_voip_t *sync, dir = 1; } - while (dir != 0xff && ipstr && portstr && mediatype) { + if (dir != 0xff && thisrtp->invitecseq_stack == 1) { if ((changed = update_rtp_stream(sync, thisrtp, ipstr, portstr, mediatype, dir)) == -1) { @@ -787,8 +793,10 @@ static int process_sip_183sessprog(collector_sync_voip_t *sync, } } - - announce_rtp_streams_if_required(sync, thisrtp); + if (thisrtp->invitecseq_stack >= 1) { + thisrtp->invitecseq_stack --; + announce_rtp_streams_if_required(sync, thisrtp); + } } free(cseqstr); return 0; @@ -811,6 +819,10 @@ static int process_sip_200ok(collector_sync_voip_t *sync, portstr = get_sip_media_port(sync->sipparser, 0); mediatype = get_sip_media_type(sync->sipparser, 0); + if (!ipstr || !portstr || !mediatype) { + free(cseqstr); + return 0; + } if (memcmp(thisrtp->inviter, irimsg->data.ipmmiri.ipsrc, 16) == 0) { @@ -820,7 +832,7 @@ static int process_sip_200ok(collector_sync_voip_t *sync, dir = 1; } - while (dir != 0xff && ipstr && portstr && mediatype) { + if (dir != 0xff && thisrtp->invitecseq_stack == 1) { if ((changed = update_rtp_stream(sync, thisrtp, ipstr, portstr, mediatype, dir)) == -1) { if (sync->log_bad_sip) { @@ -838,8 +850,11 @@ static int process_sip_200ok(collector_sync_voip_t *sync, thisrtp->changed = 1; } } + if (thisrtp->invitecseq_stack >= 1) { + thisrtp->invitecseq_stack --; + announce_rtp_streams_if_required(sync, thisrtp); + } - announce_rtp_streams_if_required(sync, thisrtp); } else if (thisrtp->byecseq && strcmp(thisrtp->byecseq, cseqstr) == 0 && thisrtp->byematched == 0) { sync_epoll_t *timeout = (sync_epoll_t *)calloc(1, @@ -1004,42 +1019,6 @@ static int process_sip_other(collector_sync_voip_t *sync, char *callid, continue; } - /* One thing to note here -- we only track the RTP streams for the - * SIP exchange that BEGAN most recently. - * If we're capturing both sides of a SIP proxy / SBC, we may see (for - * example) the INVITE enter the proxy, then the same INVITE being - * forwarded on to the next hop. We'll also see something - * similar for the response coming back. - * - * Imagine a scenario where we have two clients: A and B, with a proxy - * P between them. Our collector capture sees everything sent to and - * from the proxy. - * - * So we might see (in approximate order): - * INVITE from A to P (RTP port 10001) - * 100 Trying from P to A - * INVITE from P to B (RTP port 40000) - * 100 Trying from B to P - * 180 Ringing from B to P - * 183 Session Progress from B to P (port 40001) - * 180 Ringing from P to A - * 183 Session Progress from P to A (port 12344) - * - * - * In this case, we will look for RTP on ports 40000 and 40001, - * because that is the most recent INVITE for this call. 10001 - * and 12344 are ignored, i.e. we capture RTP from the P to B link. - * - * If the call direction is reversed, we would instead try to capture - * RTP from the P to A side, as P to A would be the most recent INVITE. - * - * This could become a gotcha when an existing callee in a case like - * this decides to change RTP ports and issue a new INVITE in the - * middle of the call -- that will change which side of the proxy we - * are looking for RTP on, so hopefully the collector is able to - * see the RTP on both sides... - */ - /* Check for a new RTP stream announcement in a 200 OK */ if (sip_is_200ok(sync->sipparser)) { if (process_sip_200ok(sync, thisrtp, vint, &iritype, irimsg) < 0) { @@ -1274,9 +1253,10 @@ static int process_sip_invite(collector_sync_voip_t *sync, char *callid, portstr = get_sip_media_port(sync->sipparser, 0); mediatype = get_sip_media_type(sync->sipparser, 0); - if (iritype == ETSILI_IRI_BEGIN || ( - thisrtp->invitecseq && invitecseq && - strcmp(thisrtp->invitecseq, invitecseq) == 0)) { + if (thisrtp->invitecseq && invitecseq && + strcmp(thisrtp->invitecseq, invitecseq) == 0) { + dir = 0xff; + } else if (iritype == ETSILI_IRI_BEGIN) { memcpy(thisrtp->inviter, irimsg->data.ipmmiri.ipsrc, 16); dir = 0; } else if (memcmp(thisrtp->inviter, irimsg->data.ipmmiri.ipsrc, @@ -1287,7 +1267,7 @@ static int process_sip_invite(collector_sync_voip_t *sync, char *callid, dir = 1; } - while (dir != 0xff && ipstr && portstr && !badsip && mediatype) { + if (dir != 0xff && ipstr && portstr && !badsip && mediatype) { int changed; if ((changed = update_rtp_stream(sync, thisrtp, ipstr, portstr, mediatype, dir)) == -1) { @@ -1308,17 +1288,62 @@ static int process_sip_invite(collector_sync_voip_t *sync, char *callid, } //announce_rtp_streams_if_required(sync, thisrtp); - - if (thisrtp->invitecseq != NULL) { - free(thisrtp->invitecseq); - thisrtp->invitecseq = NULL; - } if (badsip) { continue; } - thisrtp->invitecseq = invitecseq; - invitecseq = NULL; + /* A bit of an explanation of invitecseq_stack... + * + * This is mainly dedicated to resolving issues that arise + * when we see both sides of a proxied SIP session (i.e. + * A->B followed by B->C and the reverse for the opposite + * direction). + * + * In these cases, we have to be careful to only track the + * RTP session for ONE of the sides of the proxying, otherwise + * we get confused and try to intercept RTP streams that don't + * exist (such as the outgoing port from A->B and the incoming + * port for C->B). + * + * To further complicate matters, we can see reversed direction + * INVITEs (e.g. on call connection to confirm the media port) + * so we cannot assume that an INVITE is coming from the caller. + * + * So what I'm trying to do here is two things: + * 1. always track the RTP stream for A->B session only. + * 2. don't screw up if we see a reversed INVITE. + * + * I'm doing this by counting the number of times I see a + * specific INVITE cseq, and reducing that count whenever I + * see a 183 or 200 with the response SDP info. When the count + * gets down to zero, that response must belong to the initial + * A->B INVITE. + * + * For subsequent INVITEs, the counting only starts when the initial + * inviting IP address was involved (either as a sender or receiver) + * so if a reverse INVITE from C->B won't be looked at for RTP stream + * tracking purposes until it is proxied to the B->A link. + * + * There is one edge case where this will still break and I have + * no idea how to resolve it: if the proxy is not A->B and B->C, + * but instead is A->B and B->A. + */ + if (invitecseq) { + if (dir != 0xff && thisrtp->invitecseq == NULL) { + thisrtp->invitecseq = invitecseq; + thisrtp->invitecseq_stack = 1; + invitecseq = NULL; + } else if (thisrtp->invitecseq != NULL && + strcmp(invitecseq, thisrtp->invitecseq) == 0) { + thisrtp->invitecseq_stack ++; + } else if (dir != 0xff && thisrtp->invitecseq != NULL) { + free(thisrtp->invitecseq); + thisrtp->invitecseq = NULL; + thisrtp->invitecseq = invitecseq; + thisrtp->invitecseq_stack = 1; + invitecseq = NULL; + } + } create_sip_ipiri(sync, vint, irimsg, iritype, vshared->cin, locptr, loc_cnt, pkts, pkt_cnt); diff --git a/src/intercept.c b/src/intercept.c index db9c52f..2e0f5a2 100644 --- a/src/intercept.c +++ b/src/intercept.c @@ -234,6 +234,7 @@ rtpstreaminf_t *create_rtpstream(voipintercept_t *vint, uint32_t cin) { newcin->ai_family = 0; newcin->seqno = 0; newcin->invitecseq = NULL; + newcin->invitecseq_stack = 0; newcin->byecseq = NULL; newcin->timeout_ev = NULL; newcin->byematched = 0; @@ -299,6 +300,7 @@ rtpstreaminf_t *deep_copy_rtpstream(rtpstreaminf_t *orig) { copy->seqno = 0; copy->active = 1; copy->invitecseq = NULL; + copy->invitecseq_stack = 0; copy->byecseq = NULL; copy->timeout_ev = NULL; copy_intercept_common(&(orig->common), &(copy->common)); diff --git a/src/intercept.h b/src/intercept.h index 9e64a65..8aacfe4 100644 --- a/src/intercept.h +++ b/src/intercept.h @@ -372,6 +372,7 @@ struct rtpstreaminf { uint8_t byematched; char *invitecseq; char *byecseq; + uint16_t invitecseq_stack; uint8_t inviter[16]; From a54204145cfcd261180b2b8df76c0a1ccac829ab Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Mon, 23 Sep 2024 11:38:18 +1200 Subject: [PATCH 41/44] Revert change that broke multi-stream SIP handling --- src/collector/collector_sync_voip.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/collector/collector_sync_voip.c b/src/collector/collector_sync_voip.c index 8b29a4a..5bb22df 100644 --- a/src/collector/collector_sync_voip.c +++ b/src/collector/collector_sync_voip.c @@ -773,7 +773,8 @@ static int process_sip_183sessprog(collector_sync_voip_t *sync, dir = 1; } - if (dir != 0xff && thisrtp->invitecseq_stack == 1) { + while (dir != 0xff && thisrtp->invitecseq_stack == 1 && portstr && + mediatype && ipstr) { if ((changed = update_rtp_stream(sync, thisrtp, ipstr, portstr, mediatype, dir)) == -1) { @@ -832,7 +833,11 @@ static int process_sip_200ok(collector_sync_voip_t *sync, dir = 1; } - if (dir != 0xff && thisrtp->invitecseq_stack == 1) { + /* while loop here because there may be multiple media streams + * in the SDP body (e.g. video and audio). + */ + while (dir != 0xff && thisrtp->invitecseq_stack == 1 && portstr && + ipstr && mediatype) { if ((changed = update_rtp_stream(sync, thisrtp, ipstr, portstr, mediatype, dir)) == -1) { if (sync->log_bad_sip) { @@ -1267,7 +1272,7 @@ static int process_sip_invite(collector_sync_voip_t *sync, char *callid, dir = 1; } - if (dir != 0xff && ipstr && portstr && !badsip && mediatype) { + while (dir != 0xff && ipstr && portstr && !badsip && mediatype) { int changed; if ((changed = update_rtp_stream(sync, thisrtp, ipstr, portstr, mediatype, dir)) == -1) { From e232b3d7df70e60d5ac9d4356ead25d708da0614 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Thu, 26 Sep 2024 15:02:11 +1200 Subject: [PATCH 42/44] Update copyright in all source files Copyright for OpenLI has passed from the University of Waikato to SearchLight. --- README.md | 6 +++--- src/agency.c | 2 +- src/agency.h | 2 +- src/collector/accessplugins/gtp.c | 2 +- src/collector/accessplugins/radius.c | 2 +- src/collector/alushim_parser.c | 2 +- src/collector/alushim_parser.h | 2 +- src/collector/cisco_parser.c | 2 +- src/collector/cisco_parser.h | 2 +- src/collector/collector.c | 2 +- src/collector/collector.h | 2 +- src/collector/collector_base.h | 2 +- src/collector/collector_export.c | 2 +- src/collector/collector_export.h | 2 +- src/collector/collector_forwarder.c | 2 +- src/collector/collector_publish.c | 2 +- src/collector/collector_publish.h | 2 +- src/collector/collector_push_messaging.c | 2 +- src/collector/collector_push_messaging.h | 2 +- src/collector/collector_seqtracker.c | 2 +- src/collector/collector_sync.c | 2 +- src/collector/collector_sync.h | 2 +- src/collector/collector_sync_voip.c | 2 +- src/collector/collector_sync_voip.h | 2 +- src/collector/collector_util.c | 2 +- src/collector/collector_util.h | 2 +- src/collector/email_ingest_service.c | 2 +- src/collector/email_ingest_service.h | 2 +- src/collector/email_worker.c | 2 +- src/collector/email_worker.h | 2 +- src/collector/emailcc.c | 2 +- src/collector/emailiri.c | 2 +- src/collector/emailiri.h | 2 +- src/collector/emailprotocols/imap.c | 2 +- src/collector/emailprotocols/pop3.c | 2 +- src/collector/emailprotocols/smtp.c | 2 +- src/collector/encoder_worker.c | 2 +- src/collector/encoder_worker.h | 2 +- src/collector/epscc.h | 2 +- src/collector/epsiri.h | 2 +- src/collector/etsiencoding/encryptcontainer.c | 2 +- src/collector/etsiencoding/epscc.c | 2 +- src/collector/etsiencoding/epsiri.c | 2 +- src/collector/etsiencoding/etsiencoding.c | 2 +- src/collector/etsiencoding/etsiencoding.h | 2 +- src/collector/etsiencoding/ipmmiri.c | 2 +- src/collector/export_shared.h | 2 +- src/collector/gtp.h | 2 +- src/collector/gtp_worker.c | 2 +- src/collector/gtp_worker.h | 2 +- src/collector/internetaccess.c | 2 +- src/collector/internetaccess.h | 2 +- src/collector/ipcc.c | 2 +- src/collector/ipcc.h | 2 +- src/collector/ipiri.c | 2 +- src/collector/ipiri.h | 2 +- src/collector/ipmmcc.c | 2 +- src/collector/ipmmcc.h | 2 +- src/collector/ipmmiri.h | 2 +- src/collector/jmirror_parser.c | 2 +- src/collector/jmirror_parser.h | 2 +- src/collector/location.c | 2 +- src/collector/location.h | 2 +- src/collector/radius_hasher.c | 2 +- src/collector/radius_hasher.h | 2 +- src/collector/reassembler.c | 2 +- src/collector/reassembler.h | 2 +- src/collector/sipparsing.c | 2 +- src/collector/sipparsing.h | 2 +- src/collector/sms_worker.c | 2 +- src/collector/sms_worker.h | 2 +- src/collector/timed_intercept.c | 2 +- src/collector/timed_intercept.h | 2 +- src/collector/umtsiri.c | 2 +- src/collector/umtsiri.h | 2 +- src/configparser.c | 2 +- src/configparser.h | 2 +- src/coreserver.c | 2 +- src/coreserver.h | 2 +- src/etsili_core.c | 2 +- src/etsili_core.h | 2 +- src/export_buffer.c | 2 +- src/export_buffer.h | 2 +- src/intercept.c | 2 +- src/intercept.h | 2 +- src/mediator/coll_recv_thread.c | 2 +- src/mediator/coll_recv_thread.h | 2 +- src/mediator/handover.c | 2 +- src/mediator/handover.h | 2 +- src/mediator/lea_send_thread.c | 2 +- src/mediator/lea_send_thread.h | 2 +- src/mediator/liidmapping.c | 2 +- src/mediator/liidmapping.h | 2 +- src/mediator/med_epoll.c | 2 +- src/mediator/med_epoll.h | 2 +- src/mediator/mediator.c | 2 +- src/mediator/mediator.h | 2 +- src/mediator/mediator_prov.c | 2 +- src/mediator/mediator_prov.h | 2 +- src/mediator/mediator_rmq.c | 2 +- src/mediator/mediator_rmq.h | 2 +- src/mediator/pcapthread.c | 2 +- src/mediator/pcapthread.h | 2 +- src/netcomms.c | 2 +- src/netcomms.h | 2 +- src/openli_tls.c | 2 +- src/openli_tls.h | 2 +- src/provisioner/clientupdates.c | 2 +- src/provisioner/configwriter.c | 2 +- src/provisioner/hup_reload.c | 2 +- src/provisioner/intercept_timers.c | 2 +- src/provisioner/intercept_timers.h | 2 +- src/provisioner/provisioner.c | 2 +- src/provisioner/provisioner.h | 2 +- src/provisioner/provisioner_client.c | 2 +- src/provisioner/provisioner_client.h | 2 +- src/provisioner/updateserver.c | 2 +- src/provisioner/updateserver.h | 2 +- src/provisioner/updateserver_jsoncreation.c | 2 +- src/provisioner/updateserver_jsonparsing.c | 2 +- src/util.c | 2 +- src/util.h | 2 +- 122 files changed, 124 insertions(+), 124 deletions(-) diff --git a/README.md b/README.md index 8c141f6..8c63e9a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Version: 1.1.9 --------------------------------------------------------------------------- -Copyright (c) 2018 - 2024 The University of Waikato, Hamilton, New Zealand. +Copyright (c) 2024 SearchLight Ltd, New Zealand. All rights reserved. OpenLI was originally developed by the University of Waikato WAND research @@ -78,11 +78,11 @@ will be more than happy to accept your contribution. ## Dependencies for building from source -* [libtrace 4.0.18 or later](https://github.com/LibtraceTeam/libtrace/) +* [libtrace 4.0.24 or later](https://github.com/LibtraceTeam/libtrace/) (packages for Debian / Ubuntu are available [from WAND](https://cloudsmith.io/~wand/repos/libtrace/packages/) as well). -* [libwandder 2.0.4 or later](https://github.com/LibtraceTeam/libwandder/) +* [libwandder 2.0.13 or later](https://github.com/LibtraceTeam/libwandder/) (packages for Debian / Ubuntu are available [from WAND](https://cloudsmith.io/~wand/repos/libwandder/packages/) as well). diff --git a/src/agency.c b/src/agency.c index fd6ff0e..2115d3c 100644 --- a/src/agency.c +++ b/src/agency.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/agency.h b/src/agency.h index afd1551..d3e4b75 100644 --- a/src/agency.h +++ b/src/agency.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/accessplugins/gtp.c b/src/collector/accessplugins/gtp.c index 7eebb2e..10523c6 100644 --- a/src/collector/accessplugins/gtp.c +++ b/src/collector/accessplugins/gtp.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/accessplugins/radius.c b/src/collector/accessplugins/radius.c index 1735ab8..7274065 100644 --- a/src/collector/accessplugins/radius.c +++ b/src/collector/accessplugins/radius.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/alushim_parser.c b/src/collector/alushim_parser.c index a07ac7d..e587c75 100644 --- a/src/collector/alushim_parser.c +++ b/src/collector/alushim_parser.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/alushim_parser.h b/src/collector/alushim_parser.h index 9104cb5..2dc493c 100644 --- a/src/collector/alushim_parser.h +++ b/src/collector/alushim_parser.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/cisco_parser.c b/src/collector/cisco_parser.c index f498b32..6d0bcd1 100644 --- a/src/collector/cisco_parser.c +++ b/src/collector/cisco_parser.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/cisco_parser.h b/src/collector/cisco_parser.h index 9b3c2f3..15273f3 100644 --- a/src/collector/cisco_parser.h +++ b/src/collector/cisco_parser.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/collector.c b/src/collector/collector.c index d28f247..00e2ae0 100644 --- a/src/collector/collector.c +++ b/src/collector/collector.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/collector.h b/src/collector/collector.h index 6106d36..f22b051 100644 --- a/src/collector/collector.h +++ b/src/collector/collector.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/collector_base.h b/src/collector/collector_base.h index 9f66031..9e244b0 100644 --- a/src/collector/collector_base.h +++ b/src/collector/collector_base.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/collector_export.c b/src/collector/collector_export.c index 80a99de..edf0aed 100644 --- a/src/collector/collector_export.c +++ b/src/collector/collector_export.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/collector_export.h b/src/collector/collector_export.h index 5164394..71bd948 100644 --- a/src/collector/collector_export.h +++ b/src/collector/collector_export.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/collector_forwarder.c b/src/collector/collector_forwarder.c index 6ee39f5..363369f 100644 --- a/src/collector/collector_forwarder.c +++ b/src/collector/collector_forwarder.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/collector_publish.c b/src/collector/collector_publish.c index 41d211d..0ec94ff 100644 --- a/src/collector/collector_publish.c +++ b/src/collector/collector_publish.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/collector_publish.h b/src/collector/collector_publish.h index 5c62f5a..d15ad6d 100644 --- a/src/collector/collector_publish.h +++ b/src/collector/collector_publish.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/collector_push_messaging.c b/src/collector/collector_push_messaging.c index faeff45..71633bc 100644 --- a/src/collector/collector_push_messaging.c +++ b/src/collector/collector_push_messaging.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/collector_push_messaging.h b/src/collector/collector_push_messaging.h index 3c8fab6..6a396c9 100644 --- a/src/collector/collector_push_messaging.h +++ b/src/collector/collector_push_messaging.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/collector_seqtracker.c b/src/collector/collector_seqtracker.c index 88bae4b..4595aaa 100644 --- a/src/collector/collector_seqtracker.c +++ b/src/collector/collector_seqtracker.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/collector_sync.c b/src/collector/collector_sync.c index fd49a9c..d2d650e 100644 --- a/src/collector/collector_sync.c +++ b/src/collector/collector_sync.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/collector_sync.h b/src/collector/collector_sync.h index 841f79c..5b6b03b 100644 --- a/src/collector/collector_sync.h +++ b/src/collector/collector_sync.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/collector_sync_voip.c b/src/collector/collector_sync_voip.c index 5bb22df..2b6da41 100644 --- a/src/collector/collector_sync_voip.c +++ b/src/collector/collector_sync_voip.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/collector_sync_voip.h b/src/collector/collector_sync_voip.h index 35decfc..0414534 100644 --- a/src/collector/collector_sync_voip.h +++ b/src/collector/collector_sync_voip.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/collector_util.c b/src/collector/collector_util.c index ffefc65..2ce665d 100644 --- a/src/collector/collector_util.c +++ b/src/collector/collector_util.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2023 Searchlight New Zealand Ltd. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/collector_util.h b/src/collector/collector_util.h index 3c5a372..f376fba 100644 --- a/src/collector/collector_util.h +++ b/src/collector/collector_util.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2023 Searchlight New Zealand Ltd. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/email_ingest_service.c b/src/collector/email_ingest_service.c index 346744e..48d3de4 100644 --- a/src/collector/email_ingest_service.c +++ b/src/collector/email_ingest_service.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/email_ingest_service.h b/src/collector/email_ingest_service.h index 7ea6f8a..3316fd7 100644 --- a/src/collector/email_ingest_service.h +++ b/src/collector/email_ingest_service.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/email_worker.c b/src/collector/email_worker.c index 453c723..7796b7e 100644 --- a/src/collector/email_worker.c +++ b/src/collector/email_worker.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/email_worker.h b/src/collector/email_worker.h index c2a2e28..833129a 100644 --- a/src/collector/email_worker.h +++ b/src/collector/email_worker.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/emailcc.c b/src/collector/emailcc.c index 2858e62..f76b41a 100644 --- a/src/collector/emailcc.c +++ b/src/collector/emailcc.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/emailiri.c b/src/collector/emailiri.c index ef13b33..299f50d 100644 --- a/src/collector/emailiri.c +++ b/src/collector/emailiri.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/emailiri.h b/src/collector/emailiri.h index e67f650..52bc014 100644 --- a/src/collector/emailiri.h +++ b/src/collector/emailiri.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/emailprotocols/imap.c b/src/collector/emailprotocols/imap.c index 9004b54..7648186 100644 --- a/src/collector/emailprotocols/imap.c +++ b/src/collector/emailprotocols/imap.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/emailprotocols/pop3.c b/src/collector/emailprotocols/pop3.c index 6cccbd3..b7265aa 100644 --- a/src/collector/emailprotocols/pop3.c +++ b/src/collector/emailprotocols/pop3.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2023 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/emailprotocols/smtp.c b/src/collector/emailprotocols/smtp.c index b6e01b7..3c357a8 100644 --- a/src/collector/emailprotocols/smtp.c +++ b/src/collector/emailprotocols/smtp.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/encoder_worker.c b/src/collector/encoder_worker.c index ff9b002..fc69439 100644 --- a/src/collector/encoder_worker.c +++ b/src/collector/encoder_worker.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/encoder_worker.h b/src/collector/encoder_worker.h index d25c703..c2bf0c6 100644 --- a/src/collector/encoder_worker.h +++ b/src/collector/encoder_worker.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/epscc.h b/src/collector/epscc.h index 720a3b7..434ae23 100644 --- a/src/collector/epscc.h +++ b/src/collector/epscc.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2024 SearchLight New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/epsiri.h b/src/collector/epsiri.h index 06d80cd..6c1f9b6 100644 --- a/src/collector/epsiri.h +++ b/src/collector/epsiri.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2024 SearchLight New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/etsiencoding/encryptcontainer.c b/src/collector/etsiencoding/encryptcontainer.c index 099fcf8..4101dd1 100644 --- a/src/collector/etsiencoding/encryptcontainer.c +++ b/src/collector/etsiencoding/encryptcontainer.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 Searchlight NZ + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/etsiencoding/epscc.c b/src/collector/etsiencoding/epscc.c index 9a98063..e1e4997 100644 --- a/src/collector/etsiencoding/epscc.c +++ b/src/collector/etsiencoding/epscc.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2024 SearchLight NZ + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/etsiencoding/epsiri.c b/src/collector/etsiencoding/epsiri.c index d31f4ba..c37c2d0 100644 --- a/src/collector/etsiencoding/epsiri.c +++ b/src/collector/etsiencoding/epsiri.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2024 SearchLight NZ + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/etsiencoding/etsiencoding.c b/src/collector/etsiencoding/etsiencoding.c index 7097567..495d76b 100644 --- a/src/collector/etsiencoding/etsiencoding.c +++ b/src/collector/etsiencoding/etsiencoding.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 Searchlight NZ + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/etsiencoding/etsiencoding.h b/src/collector/etsiencoding/etsiencoding.h index 0c32f76..1db06b6 100644 --- a/src/collector/etsiencoding/etsiencoding.h +++ b/src/collector/etsiencoding/etsiencoding.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 Searchlight NZ + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/etsiencoding/ipmmiri.c b/src/collector/etsiencoding/ipmmiri.c index 4882a84..55c2449 100644 --- a/src/collector/etsiencoding/ipmmiri.c +++ b/src/collector/etsiencoding/ipmmiri.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2024 Searchlight NZ + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/export_shared.h b/src/collector/export_shared.h index 0a67229..cf04155 100644 --- a/src/collector/export_shared.h +++ b/src/collector/export_shared.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/gtp.h b/src/collector/gtp.h index 1647c6d..09673bf 100644 --- a/src/collector/gtp.h +++ b/src/collector/gtp.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2024 Searchlight New Zealand Ltd. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/gtp_worker.c b/src/collector/gtp_worker.c index 9ba7f5b..c48c3ad 100644 --- a/src/collector/gtp_worker.c +++ b/src/collector/gtp_worker.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2024 Searchlight New Zealand Ltd. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/gtp_worker.h b/src/collector/gtp_worker.h index 10881df..abf09f7 100644 --- a/src/collector/gtp_worker.h +++ b/src/collector/gtp_worker.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2024 Searchlight New Zealand Ltd. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/internetaccess.c b/src/collector/internetaccess.c index 1cb7754..d175a62 100644 --- a/src/collector/internetaccess.c +++ b/src/collector/internetaccess.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/internetaccess.h b/src/collector/internetaccess.h index ac82bdf..14dca13 100644 --- a/src/collector/internetaccess.h +++ b/src/collector/internetaccess.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/ipcc.c b/src/collector/ipcc.c index a5ecac7..312de37 100644 --- a/src/collector/ipcc.c +++ b/src/collector/ipcc.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/ipcc.h b/src/collector/ipcc.h index 6f55674..d822770 100644 --- a/src/collector/ipcc.h +++ b/src/collector/ipcc.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/ipiri.c b/src/collector/ipiri.c index a564f6d..19ee986 100644 --- a/src/collector/ipiri.c +++ b/src/collector/ipiri.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/ipiri.h b/src/collector/ipiri.h index b713e0d..b5f730e 100644 --- a/src/collector/ipiri.h +++ b/src/collector/ipiri.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/ipmmcc.c b/src/collector/ipmmcc.c index d497456..64df1f4 100644 --- a/src/collector/ipmmcc.c +++ b/src/collector/ipmmcc.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/ipmmcc.h b/src/collector/ipmmcc.h index 317dce0..3371e53 100644 --- a/src/collector/ipmmcc.h +++ b/src/collector/ipmmcc.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/ipmmiri.h b/src/collector/ipmmiri.h index 73d0b72..09a3c28 100644 --- a/src/collector/ipmmiri.h +++ b/src/collector/ipmmiri.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/jmirror_parser.c b/src/collector/jmirror_parser.c index 7346bcd..b5b1591 100644 --- a/src/collector/jmirror_parser.c +++ b/src/collector/jmirror_parser.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/jmirror_parser.h b/src/collector/jmirror_parser.h index 9c5f673..b5cfd44 100644 --- a/src/collector/jmirror_parser.h +++ b/src/collector/jmirror_parser.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/location.c b/src/collector/location.c index d3311a6..d92485f 100644 --- a/src/collector/location.c +++ b/src/collector/location.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/location.h b/src/collector/location.h index ff2bc53..d67e820 100644 --- a/src/collector/location.h +++ b/src/collector/location.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/radius_hasher.c b/src/collector/radius_hasher.c index 561a37f..a30c110 100644 --- a/src/collector/radius_hasher.c +++ b/src/collector/radius_hasher.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2020 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/radius_hasher.h b/src/collector/radius_hasher.h index 79ad421..50546d8 100644 --- a/src/collector/radius_hasher.h +++ b/src/collector/radius_hasher.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2020 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/reassembler.c b/src/collector/reassembler.c index ec37531..1800b7e 100644 --- a/src/collector/reassembler.c +++ b/src/collector/reassembler.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/reassembler.h b/src/collector/reassembler.h index 6a5a8dc..412a914 100644 --- a/src/collector/reassembler.h +++ b/src/collector/reassembler.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/sipparsing.c b/src/collector/sipparsing.c index a380a3a..9bae486 100644 --- a/src/collector/sipparsing.c +++ b/src/collector/sipparsing.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/sipparsing.h b/src/collector/sipparsing.h index de25ae3..010ca12 100644 --- a/src/collector/sipparsing.h +++ b/src/collector/sipparsing.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/sms_worker.c b/src/collector/sms_worker.c index 152cb8e..bb2975b 100644 --- a/src/collector/sms_worker.c +++ b/src/collector/sms_worker.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2023 Searchlight New Zealand Ltd. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/sms_worker.h b/src/collector/sms_worker.h index 5144a03..a07ead8 100644 --- a/src/collector/sms_worker.h +++ b/src/collector/sms_worker.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2023 Searchlight New Zealand Ltd. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/timed_intercept.c b/src/collector/timed_intercept.c index 08e8120..1b34068 100644 --- a/src/collector/timed_intercept.c +++ b/src/collector/timed_intercept.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2021 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/timed_intercept.h b/src/collector/timed_intercept.h index d895b8d..b1e009b 100644 --- a/src/collector/timed_intercept.h +++ b/src/collector/timed_intercept.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2021 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/umtsiri.c b/src/collector/umtsiri.c index fcb6fdb..57f8602 100644 --- a/src/collector/umtsiri.c +++ b/src/collector/umtsiri.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/collector/umtsiri.h b/src/collector/umtsiri.h index ce3d452..6d4808a 100644 --- a/src/collector/umtsiri.h +++ b/src/collector/umtsiri.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/configparser.c b/src/configparser.c index 9ea6199..c104083 100644 --- a/src/configparser.c +++ b/src/configparser.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/configparser.h b/src/configparser.h index dbbf8c8..4a46f39 100644 --- a/src/configparser.h +++ b/src/configparser.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/coreserver.c b/src/coreserver.c index 5ca8ff5..e9edcb3 100644 --- a/src/coreserver.c +++ b/src/coreserver.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/coreserver.h b/src/coreserver.h index 302e28a..bfc0c65 100644 --- a/src/coreserver.h +++ b/src/coreserver.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/etsili_core.c b/src/etsili_core.c index a6ac3ab..0163d31 100644 --- a/src/etsili_core.c +++ b/src/etsili_core.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/etsili_core.h b/src/etsili_core.h index 6c0fb11..7abaaef 100644 --- a/src/etsili_core.h +++ b/src/etsili_core.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/export_buffer.c b/src/export_buffer.c index 37d8c2d..4a18200 100644 --- a/src/export_buffer.c +++ b/src/export_buffer.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/export_buffer.h b/src/export_buffer.h index 9969a44..bbb5b65 100644 --- a/src/export_buffer.h +++ b/src/export_buffer.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/intercept.c b/src/intercept.c index 2e0f5a2..958642b 100644 --- a/src/intercept.c +++ b/src/intercept.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/intercept.h b/src/intercept.h index 8aacfe4..070d67c 100644 --- a/src/intercept.h +++ b/src/intercept.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/mediator/coll_recv_thread.c b/src/mediator/coll_recv_thread.c index 5734245..04d7838 100644 --- a/src/mediator/coll_recv_thread.c +++ b/src/mediator/coll_recv_thread.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/mediator/coll_recv_thread.h b/src/mediator/coll_recv_thread.h index fd6a304..6036450 100644 --- a/src/mediator/coll_recv_thread.h +++ b/src/mediator/coll_recv_thread.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/mediator/handover.c b/src/mediator/handover.c index 2532cc7..3318eb6 100644 --- a/src/mediator/handover.c +++ b/src/mediator/handover.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/mediator/handover.h b/src/mediator/handover.h index 7c96c6e..fa458c9 100644 --- a/src/mediator/handover.h +++ b/src/mediator/handover.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/mediator/lea_send_thread.c b/src/mediator/lea_send_thread.c index aa462ab..8bf88b0 100644 --- a/src/mediator/lea_send_thread.c +++ b/src/mediator/lea_send_thread.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/mediator/lea_send_thread.h b/src/mediator/lea_send_thread.h index fb65b3e..af790c4 100644 --- a/src/mediator/lea_send_thread.h +++ b/src/mediator/lea_send_thread.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/mediator/liidmapping.c b/src/mediator/liidmapping.c index a073fd7..c580f5f 100644 --- a/src/mediator/liidmapping.c +++ b/src/mediator/liidmapping.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/mediator/liidmapping.h b/src/mediator/liidmapping.h index fe123df..161ab76 100644 --- a/src/mediator/liidmapping.h +++ b/src/mediator/liidmapping.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/mediator/med_epoll.c b/src/mediator/med_epoll.c index 2943f25..eae95eb 100644 --- a/src/mediator/med_epoll.c +++ b/src/mediator/med_epoll.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/mediator/med_epoll.h b/src/mediator/med_epoll.h index b30798d..27b9baf 100644 --- a/src/mediator/med_epoll.h +++ b/src/mediator/med_epoll.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/mediator/mediator.c b/src/mediator/mediator.c index f5c26bd..20be5d9 100644 --- a/src/mediator/mediator.c +++ b/src/mediator/mediator.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/mediator/mediator.h b/src/mediator/mediator.h index 0459265..2d2abcc 100644 --- a/src/mediator/mediator.h +++ b/src/mediator/mediator.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/mediator/mediator_prov.c b/src/mediator/mediator_prov.c index 32e0fbf..4c3996c 100644 --- a/src/mediator/mediator_prov.c +++ b/src/mediator/mediator_prov.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/mediator/mediator_prov.h b/src/mediator/mediator_prov.h index ac8df9e..74635f5 100644 --- a/src/mediator/mediator_prov.h +++ b/src/mediator/mediator_prov.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/mediator/mediator_rmq.c b/src/mediator/mediator_rmq.c index 30ab35b..b7e9121 100644 --- a/src/mediator/mediator_rmq.c +++ b/src/mediator/mediator_rmq.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/mediator/mediator_rmq.h b/src/mediator/mediator_rmq.h index cc77789..46a3acb 100644 --- a/src/mediator/mediator_rmq.h +++ b/src/mediator/mediator_rmq.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/mediator/pcapthread.c b/src/mediator/pcapthread.c index 73a7f18..21b9e22 100644 --- a/src/mediator/pcapthread.c +++ b/src/mediator/pcapthread.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/mediator/pcapthread.h b/src/mediator/pcapthread.h index 01b211c..ea04c76 100644 --- a/src/mediator/pcapthread.h +++ b/src/mediator/pcapthread.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/netcomms.c b/src/netcomms.c index 45ec692..cd37f50 100644 --- a/src/netcomms.c +++ b/src/netcomms.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/netcomms.h b/src/netcomms.h index 5dd3f62..05147b2 100644 --- a/src/netcomms.h +++ b/src/netcomms.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/openli_tls.c b/src/openli_tls.c index e7d8681..8516b22 100644 --- a/src/openli_tls.c +++ b/src/openli_tls.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/openli_tls.h b/src/openli_tls.h index f39ed22..c87817a 100644 --- a/src/openli_tls.h +++ b/src/openli_tls.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/provisioner/clientupdates.c b/src/provisioner/clientupdates.c index 6edbb4c..e73fc71 100644 --- a/src/provisioner/clientupdates.c +++ b/src/provisioner/clientupdates.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/provisioner/configwriter.c b/src/provisioner/configwriter.c index 4585eaf..4c0d458 100644 --- a/src/provisioner/configwriter.c +++ b/src/provisioner/configwriter.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/provisioner/hup_reload.c b/src/provisioner/hup_reload.c index 9629974..70327bd 100644 --- a/src/provisioner/hup_reload.c +++ b/src/provisioner/hup_reload.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 - 2022 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/provisioner/intercept_timers.c b/src/provisioner/intercept_timers.c index ae6dea4..bcb552f 100644 --- a/src/provisioner/intercept_timers.c +++ b/src/provisioner/intercept_timers.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018-2023 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/provisioner/intercept_timers.h b/src/provisioner/intercept_timers.h index c4ebafa..362771e 100644 --- a/src/provisioner/intercept_timers.h +++ b/src/provisioner/intercept_timers.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2023 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/provisioner/provisioner.c b/src/provisioner/provisioner.c index aec1cf2..0aa2830 100644 --- a/src/provisioner/provisioner.c +++ b/src/provisioner/provisioner.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/provisioner/provisioner.h b/src/provisioner/provisioner.h index 5e35427..bc064d8 100644 --- a/src/provisioner/provisioner.h +++ b/src/provisioner/provisioner.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/provisioner/provisioner_client.c b/src/provisioner/provisioner_client.c index 39648a1..dfda4cb 100644 --- a/src/provisioner/provisioner_client.c +++ b/src/provisioner/provisioner_client.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/provisioner/provisioner_client.h b/src/provisioner/provisioner_client.h index 79708f2..3b6a532 100644 --- a/src/provisioner/provisioner_client.h +++ b/src/provisioner/provisioner_client.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/provisioner/updateserver.c b/src/provisioner/updateserver.c index 103b878..9197704 100644 --- a/src/provisioner/updateserver.c +++ b/src/provisioner/updateserver.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/provisioner/updateserver.h b/src/provisioner/updateserver.h index e39d644..f2957eb 100644 --- a/src/provisioner/updateserver.h +++ b/src/provisioner/updateserver.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/provisioner/updateserver_jsoncreation.c b/src/provisioner/updateserver_jsoncreation.c index 930fc62..7114302 100644 --- a/src/provisioner/updateserver_jsoncreation.c +++ b/src/provisioner/updateserver_jsoncreation.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/provisioner/updateserver_jsonparsing.c b/src/provisioner/updateserver_jsonparsing.c index 62a9dd5..387ad43 100644 --- a/src/provisioner/updateserver_jsonparsing.c +++ b/src/provisioner/updateserver_jsonparsing.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/util.c b/src/util.c index 955454b..4a9bed3 100644 --- a/src/util.c +++ b/src/util.c @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. diff --git a/src/util.h b/src/util.h index 7744a3b..0503418 100644 --- a/src/util.h +++ b/src/util.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2018 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2024 SearchLight Ltd, New Zealand. * All rights reserved. * * This file is part of OpenLI. From a3065284aa2212605a4ca37d818a94b71e25be14 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Fri, 27 Sep 2024 10:47:13 +1200 Subject: [PATCH 43/44] Update debian changelog --- debian/changelog | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 18c71ba..5fa8040 100644 --- a/debian/changelog +++ b/debian/changelog @@ -25,8 +25,10 @@ openli (1.1.9-1) unstable; urgency=medium happens to have trailing bytes (such as an extra '\r\n' sequence). * SIP: fix double frees that could occur when reassembling TCP SIP traffic. + * Removed some internally defined OID consts and replaced them with + ones defined by libwandder. - -- Shane Alcock Wed, 18 Sep 2024 09:10:41 +1200 + -- Shane Alcock Fri, 27 Sep 2024 10:47:19 +1200 openli (1.1.8-1) unstable; urgency=medium From ef83c949903c0e9bf7da4ef1e71fbceca7fd96c2 Mon Sep 17 00:00:00 2001 From: Shane Alcock Date: Fri, 27 Sep 2024 14:21:55 +1200 Subject: [PATCH 44/44] Stop building packages for debian buster --- .github/workflows/deb-build.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/deb-build.yaml b/.github/workflows/deb-build.yaml index 30a20ef..405bbf2 100644 --- a/.github/workflows/deb-build.yaml +++ b/.github/workflows/deb-build.yaml @@ -17,7 +17,6 @@ jobs: - amd64 target: - "debian:bookworm" - - "debian:buster" - "debian:bullseye" - "ubuntu:focal" - "ubuntu:jammy" @@ -54,7 +53,6 @@ jobs: arch: - amd64 target: - - "debian:buster" - "debian:bullseye" - "ubuntu:focal" - "ubuntu:jammy" @@ -100,7 +98,6 @@ jobs: arch: - amd64 target: - - "debian:buster" - "debian:bullseye" - "debian:bookworm" - "ubuntu:focal"