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" diff --git a/README.md b/README.md index 7d93660..8c63e9a 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ OpenLI -- open source ETSI-compliant Lawful Intercept software -Version: 1.1.8 +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/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 c5fcc20..5fa8040 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,35 @@ +openli (1.1.9-1) unstable; urgency=medium + + * RADIUS: fix crash that can occur under very rare circumstances due to + a dangling user record pointer in an old unmatched request. + * 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. + * 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). + * 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). + * 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 Fri, 27 Sep 2024 10:47:19 +1200 + openli (1.1.8-1) unstable; urgency=medium * Collector: fix crash in sync_voip thread if an invalid SIP packet 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 diff --git a/src/Makefile.am b/src/Makefile.am index 9e9e2a3..f6e314e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -71,7 +71,11 @@ 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/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 \ collector/location.c collector/location.h \ collector/collector_util.c collector/collector_util.h \ $(PLUGIN_SRCS) 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 c0fe219..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. @@ -33,13 +33,17 @@ #include "logger.h" #include "internetaccess.h" #include "util.h" +#include "gtp.h" +#include "epsiri.h" #define GTP_FLUSH_OLD_PKT_FREQ 180 enum { GTPV1_IE_CAUSE = 1, 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, @@ -51,11 +55,17 @@ 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, + 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, + GTPV2_IE_PDN_TYPE = 99, }; /* TODO add more cause values here */ @@ -65,45 +75,17 @@ 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, }; -/* 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 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 { @@ -136,6 +118,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]; @@ -144,25 +127,30 @@ 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]; + char *tunnel_endpoints[2]; internetaccess_ip_t *pdpaddrs; uint8_t pdpaddrcount; uint16_t pdptype; int64_t cin; + uint8_t gtpversion; uint8_t serverid[16]; uint8_t serveripfamily; 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; + uint8_t defaultbearer; + } gtp_session_t; struct gtp_saved_packet { @@ -172,6 +160,11 @@ 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; + char *endpoint_ip; uint8_t *ipcontent; uint16_t iplen; @@ -189,12 +182,15 @@ typedef struct gtp_parsed { double tvsec; uint32_t teid; uint32_t teid_ctl; + uint32_t teid_data; uint32_t seqno; uint8_t response_cause; + uint8_t bearerid; uint8_t serveripfamily; uint8_t serverid[16]; + char tunnel_endpoint[256]; char imsi[16]; char msisdn[16]; char imei[16]; @@ -214,7 +210,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; @@ -228,10 +224,13 @@ 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; + parsed->bearerid = 255; parsed->serveripfamily = 0; + memset(parsed->tunnel_endpoint, 0, 256); memset(parsed->serverid, 0, 16); memset(parsed->imsi, 0, 16); memset(parsed->imei, 0, 16); @@ -244,6 +243,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; @@ -264,6 +271,17 @@ static inline void destroy_gtp_session(gtp_session_t *sess) { free(sess->sessid); } + if (sess->tunnel_endpoints[0]) { + free(sess->tunnel_endpoints[0]); + } + if (sess->tunnel_endpoints[1]) { + free(sess->tunnel_endpoints[1]); + } + + if (sess->altsessid) { + free(sess->altsessid); + } + if (sess->saved.imei) { free(sess->saved.imei); } @@ -306,8 +324,10 @@ 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) { @@ -318,11 +338,13 @@ static void gtp_destroy_plugin_data(access_plugin_t *p) { 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); } JSLFA(res, glob->session_map); - JSLFA(res, glob->alt_session_map); indexnum = 0; JLF(pval, glob->saved_packets, indexnum); @@ -332,16 +354,21 @@ 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); } JLFA(res, glob->saved_packets); + if (glob->parsedpkt) { free(glob->parsedpkt); } free(glob); + p->plugindata = NULL; } static void gtp_uncouple_parsed_data(access_plugin_t *p) { @@ -362,6 +389,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); } @@ -370,6 +400,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); } @@ -393,6 +426,12 @@ 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: + case GTPV2_IE_AMBR: + case GTPV2_IE_BEARER_ID: + case GTPV2_IE_PDN_TYPE: return true; } } else if (gtpv == 1) { @@ -400,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: @@ -471,6 +511,108 @@ static inline uint8_t get_cause_from_ie(gtp_infoelem_t *gtpel) { return *((uint8_t *)(gtpel->iecontent)); } +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; + 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, uint8_t is_req) { + + 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 + 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; + } + + 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) { @@ -575,9 +717,6 @@ 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); } @@ -589,6 +728,10 @@ static int walk_gtpv1_ies(gtp_parsed_t *parsedpkt, uint8_t *ptr, uint32_t rem, } } + if (ietype == GTPV1_IE_TEID_DATA) { + parsedpkt->teid_data = get_teid_from_teidctl(gtpel); + } + if (ietype == GTPV1_IE_TEID_CTRL) { parsedpkt->teid_ctl = get_teid_from_teidctl(gtpel); } @@ -630,9 +773,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); } @@ -642,12 +782,18 @@ 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_BEARER_CONTEXT) { + 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); + } if (ietype == GTPV2_IE_CAUSE) { parsedpkt->response_cause = get_cause_from_ie(gtpel); } @@ -677,6 +823,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 ++; @@ -721,6 +870,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; } @@ -762,6 +914,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; } @@ -814,17 +970,48 @@ 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 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: + case GTPV2_DELETE_BEARER_REQUEST: + case GTPV2_UPDATE_BEARER_RESPONSE: + case GTPV2_MODIFY_BEARER_COMMAND: + case GTPV2_DELETE_BEARER_COMMAND: 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 GTPV2_DELETE_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: + case GTPV2_UPDATE_BEARER_REQUEST: + case GTPV2_DELETE_BEARER_RESPONSE: + case GTPV2_MODIFY_BEARER_FAILURE_INDICATION: + case GTPV2_DELETE_BEARER_FAILURE_INDICATION: case GTPV1_UPDATE_PDP_CONTEXT_RESPONSE: case GTPV1_DELETE_PDP_CONTEXT_RESPONSE: memcpy(glob->parsedpkt->serverid, &(ip->ip_src.s_addr), 4); @@ -840,16 +1027,51 @@ 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 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: + case GTPV2_UPDATE_BEARER_RESPONSE: + case GTPV2_DELETE_BEARER_REQUEST: + case GTPV2_MODIFY_BEARER_COMMAND: + case GTPV2_DELETE_BEARER_COMMAND: 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 GTPV2_DELETE_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: + case GTPV2_UPDATE_BEARER_REQUEST: + case GTPV2_DELETE_BEARER_RESPONSE: + case GTPV2_MODIFY_BEARER_FAILURE_INDICATION: + case GTPV2_DELETE_BEARER_FAILURE_INDICATION: case GTPV1_UPDATE_PDP_CONTEXT_RESPONSE: case GTPV1_DELETE_PDP_CONTEXT_RESPONSE: memcpy(glob->parsedpkt->serverid, &(ip6->ip_src.s6_addr), @@ -933,25 +1155,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; @@ -967,16 +1179,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); @@ -986,23 +1191,10 @@ 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. - */ - 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); - - if (!pval) { - JSLI(pval, glob->alt_session_map, alt_sessid); - *pval = (Word_t)gparsed->matched_session; + if (gparsed->msgtype == GTPV2_CREATE_SESSION_RESPONSE) { + if (gparsed->bearerid != 255) { + gparsed->matched_session->defaultbearer = gparsed->bearerid; } - } uids = copy_identifiers(gparsed, numberids); @@ -1020,12 +1212,19 @@ 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; + if (gparsed->tunnel_endpoint[0] != '\0') { + saved->endpoint_ip = strdup(gparsed->tunnel_endpoint); + } gparsed->ies = NULL; openli_copy_ipcontent(gparsed->origpkt, &(saved->ipcontent), @@ -1040,6 +1239,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; @@ -1048,16 +1250,19 @@ 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; + sess->gtpversion = gparsed->version; + sess->defaultbearer = 255; memcpy(sess->serverid, gparsed->serverid, 16); + sess->tunnel_endpoints[0] = strdup(gparsed->tunnel_endpoint); 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); @@ -1244,7 +1449,51 @@ 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 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[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; + 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, session_state_t current) { @@ -1254,10 +1503,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; @@ -1271,6 +1534,17 @@ static void apply_gtp_fsm_logic(gtp_parsed_t *gparsed, access_action_t *action, extract_gtp_assigned_ip_address(gpkt, sess, gparsed->matched_session); + /* 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; + 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) { current = SESSION_STATE_OVER; *action = ACCESS_ACTION_REJECT; @@ -1284,6 +1558,19 @@ static void apply_gtp_fsm_logic(gtp_parsed_t *gparsed, access_action_t *action, extract_gtp_assigned_ip_address(gpkt, sess, gparsed->matched_session); + + /* 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; + 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 >= 192) { current = SESSION_STATE_OVER; *action = ACCESS_ACTION_REJECT; @@ -1301,6 +1588,12 @@ 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_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; } @@ -1309,7 +1602,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, + uint8_t incr_refcount) { access_session_t *thissess = NULL; @@ -1322,8 +1616,11 @@ 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 ++; + } HASH_ADD_KEYPTR(hh, *sesslist, thissess->sessionid, strlen(thissess->sessionid), thissess); @@ -1342,14 +1639,25 @@ 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; + } else { + incr_refcount = 0; + } + if (reqid == gparsed->matched_session->last_reqid && gparsed->msgtype == gparsed->matched_session->last_reqtype) { @@ -1358,13 +1666,29 @@ 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); *oldstate = gparsed->matched_session->savedoldstate; *action = gparsed->action; *newstate = gparsed->matched_session->savednewstate; 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; @@ -1377,6 +1701,11 @@ 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; + saved->endpoint_ip = strdup(gparsed->tunnel_endpoint); gparsed->ies = NULL; gparsed->matched_session->last_reqid = reqid; @@ -1393,16 +1722,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); + 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; @@ -1417,19 +1750,28 @@ 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 && check->type == GTPV2_CREATE_SESSION_RESPONSE) { - 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_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; @@ -1443,11 +1785,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; @@ -1472,6 +1816,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; @@ -1483,13 +1830,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); + 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); + gparsed->response->matched_session, 0); *oldstate = gparsed->response->matched_session->current; gparsed->matched_session = gparsed->response->matched_session; gparsed->matched_session->savedoldstate = *oldstate; @@ -1497,12 +1844,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; } @@ -1589,7 +1936,277 @@ static void parse_uli_v2(uint8_t *locinfo, } -static int gtp_create_pdp_generic_iri(gtp_parsed_t *gparsed, +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); + } + } + + 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, + gtp_session_t *gsess, + etsili_generic_t **params, etsili_generic_freelist_t *freelist, + uint32_t evtype) { + + etsili_generic_t *np; + etsili_ipaddress_t ipaddr, netelipaddr; + uint32_t initiator = 1; + struct timeval tv; + gtp_infoelem_t *el; + + /* + * - 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); + 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); + + 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); + + 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, 1); + 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; + 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; + 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; + + + + } + 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; + 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; + } + } + + + 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, uint32_t evtype) { @@ -1712,7 +2329,8 @@ 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 UNUSED) { switch(*gtpcause) { case GTPV2_CAUSE_REQUEST_ACCEPTED: @@ -1722,64 +2340,161 @@ 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; + 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_bearer_deactivation_iri(gtp_parsed_t *gparsed, + etsili_generic_t **params, + etsili_generic_freelist_t *freelist) { + + 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; + } + + 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; +} + 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 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; + 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 != 255 && + gparsed->bearerid == gparsed->matched_session->defaultbearer) { + bearertype = 1; + } else if (gparsed->bearerid != 255) { + bearertype = 2; + } + + 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; +} + +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; } @@ -1791,19 +2506,73 @@ 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; } +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) { + + 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) { 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; +} + +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 linkedbearer = 0; + uint32_t bearertype = 0; + + gtp_create_eps_generic_iri(gparsed, gparsed->matched_session, + params, freelist, evtype); + + if (gparsed->bearerid != 255 && + gparsed->bearerid == gparsed->matched_session->defaultbearer) { + bearertype = 1; + } else { + bearertype = 2; + } + + 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; } @@ -1813,7 +2582,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; @@ -1827,27 +2596,69 @@ static int gtp_generate_iri_data(access_plugin_t *p UNUSED, 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; + } + if (gparsed->version == 2 && + gtpv2_create_session_activation_iri(gparsed, params, + freelist) < 0) { return -1; } return 0; } else if (gparsed->action == ACCESS_ACTION_REJECT) { - /* TODO need to generate a PDP context activation failed IRI */ + *iritype = ETSILI_IRI_REPORT; + if (gparsed->version == 1 && + gtp_create_context_activation_failed_iri(gparsed, params, + freelist) < 0) { + return -1; + } + if (gparsed->version == 2 && + gtpv2_create_session_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; + } else if (gparsed->version == 2 && + gtpv2_create_session_modification_iri(gparsed, params, + freelist) < 0) { return -1; } return 0; } + 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; + } else if (gparsed->version == 2 && + gtpv2_create_session_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; + } + if (gparsed->version == 2 && + gtp_create_bearer_deactivation_iri(gparsed, params, + freelist) < 0) { return -1; } return 0; @@ -1879,8 +2690,13 @@ 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; + } else if (gsess->gtpversion == 2 && + gtp_create_start_with_bearer_active_iri(gsess, params, + freelist) < 0) { return -1; } } @@ -1928,8 +2744,23 @@ static uint8_t *gtp_get_ip_contents(access_plugin_t *p UNUSED, void *parseddata, static void gtp_destroy_session_data(access_plugin_t *p UNUSED, 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; + unsigned char altid[64]; + + 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, (uint8_t *)gtpsess->sessid); + GEN_SESSID((char *)altid, gtpsess->serveripfamily, + gtpsess->serverid, gtpsess->control_teid[1]); + JSLD(rc, glob->session_map, altid); + destroy_gtp_session(gtpsess); + } } } @@ -1963,10 +2794,33 @@ 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)); + gtp_init_plugin_data(gtp); + 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/accessplugins/radius.c b/src/collector/accessplugins/radius.c index a7f1632..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. @@ -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); @@ -1638,6 +1642,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); @@ -1665,7 +1670,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 +1706,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 +1726,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; @@ -2133,10 +2138,6 @@ static void radius_destroy_session_data(access_plugin_t *p UNUSED, Word_t rcw; radius_user_session_t *usess = (radius_user_session_t *)sess->statedata; - if (sess->sessionid) { - free(sess->sessionid); - } - if (usess == NULL) { return; } @@ -2154,8 +2155,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? } } 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 5a034c4..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. @@ -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", @@ -285,6 +287,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); @@ -302,6 +322,8 @@ static void *start_processing_thread(libtrace_t *trace UNUSED, 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]; @@ -314,6 +336,20 @@ static void *start_processing_thread(libtrace_t *trace UNUSED, 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; } @@ -412,6 +448,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); @@ -446,6 +483,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(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)); @@ -457,9 +521,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)); @@ -512,7 +578,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; @@ -599,7 +665,6 @@ static void add_payload_info_from_packet(libtrace_packet_t *pkt, } - static void do_sms_check(colthread_local_t *loc, libtrace_packet_t *pkt, collector_global_t *glob) { @@ -714,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; + + libtrace_packet_t *copy = openli_copy_packet(pkt); - x = add_sip_packet_to_parser(&(loc->sipparser), pkt, 0); + 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, @@ -810,6 +881,92 @@ static inline uint32_t is_core_server_packet( } +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; + + if (loc->gtpservers == NULL) { + return 0; + } + + if ( !is_core_server_packet(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; + 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 */ + if (pinfo->payload_len < sizeof(gtpv1_header_t)) { + return 0; + } + + 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; + } + } + + 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 libtrace_packet_t *process_packet(libtrace_t *trace, libtrace_thread_t *t, void *global, void *tls, libtrace_packet_t *pkt) { @@ -820,7 +977,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; @@ -841,6 +998,14 @@ static libtrace_packet_t *process_packet(libtrace_t *trace, process_incoming_messages(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(loc, &syncpush); + } + } + l3 = trace_get_layer3(pkt, ðertype, &rem); if (l3 == NULL || rem == 0) { @@ -1013,12 +1178,7 @@ static libtrace_packet_t *process_packet(libtrace_t *trace, goto processdone; } - if (loc->gtpservers && is_core_server_packet(&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(&pinfo, @@ -1386,6 +1546,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) { @@ -1616,6 +1783,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; @@ -2240,6 +2408,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)); @@ -2450,6 +2622,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..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. @@ -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 ba41b20..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. @@ -85,6 +85,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_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 f10a7ca..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. @@ -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/collector_publish.c b/src/collector/collector_publish.c index 7123181..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. @@ -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); } @@ -121,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); } @@ -139,7 +147,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) { @@ -247,6 +255,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 f913ec3..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. @@ -61,6 +61,8 @@ enum { OPENLI_EXPORT_EMAILIRI = 22, OPENLI_EXPORT_RAW_CC = 23, OPENLI_EXPORT_RAW_IRI = 24, + OPENLI_EXPORT_EPSCC = 25, + OPENLI_EXPORT_EPSIRI = 26, }; /* This structure is also used for IPMMCCs since they require the same @@ -76,6 +78,16 @@ 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; + uint16_t gtpseqno; +} PACKED openli_mobcc_job_t; + typedef struct openli_emailiri_job { char *liid; uint32_t cin; @@ -117,6 +129,7 @@ typedef struct openli_mobiri_job { etsili_generic_t *customparams; } openli_mobiri_job_t; + typedef struct openli_ipiri_job { char *liid; uint32_t cin; @@ -186,6 +199,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; @@ -201,6 +215,33 @@ 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. + * + * 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_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 ce0077e..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. @@ -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: @@ -82,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; } @@ -98,6 +101,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: @@ -107,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", @@ -394,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 ++; @@ -473,12 +480,14 @@ 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: 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/collector_sync.c b/src/collector/collector_sync.c index e0c2fba..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. @@ -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 *) @@ -83,7 +79,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; @@ -91,10 +86,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; @@ -114,6 +111,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); @@ -174,10 +174,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); } @@ -190,7 +186,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) { @@ -226,6 +221,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); @@ -238,6 +235,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); @@ -517,34 +515,6 @@ static inline void push_static_iprange_remove_to_collectors( } -static inline void push_single_ipintercept( - 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) { @@ -808,24 +778,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); } } @@ -1097,7 +1053,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(sendq->q, cept, sess); + push_session_ips_to_collector_queue(sendq->q, cept, sess); } create_iri_from_session(sync, sess, cept, @@ -1245,7 +1201,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) { @@ -1583,6 +1539,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); @@ -1629,6 +1590,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); @@ -1660,6 +1626,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: @@ -1690,6 +1661,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) { @@ -1865,6 +1841,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"); @@ -1899,7 +1877,7 @@ static void push_all_active_intercepts(internet_user_t *allusers, user = lookup_user_by_intercept(allusers, orig); if (user) { HASH_ITER(hh, user->sessions, sess, tmp2) { - push_single_ipintercept(q, orig, sess); + push_session_ips_to_collector_queue(q, orig, sess); } } } @@ -2148,7 +2126,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(sendq->q, ipint, sess); + push_session_ips_to_collector_queue(sendq->q, ipint, sess); } } pthread_mutex_lock(sync->glob->stats_mutex); @@ -2199,8 +2177,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 088d7ea..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. @@ -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; @@ -81,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/collector_sync_voip.c b/src/collector/collector_sync_voip.c index e49748c..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. @@ -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,8 @@ static int process_sip_183sessprog(collector_sync_voip_t *sync, dir = 1; } - while (dir != 0xff && ipstr && portstr && mediatype) { + while (dir != 0xff && thisrtp->invitecseq_stack == 1 && portstr && + mediatype && ipstr) { if ((changed = update_rtp_stream(sync, thisrtp, ipstr, portstr, mediatype, dir)) == -1) { @@ -787,7 +794,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; @@ -810,6 +820,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) { @@ -819,7 +833,11 @@ static int process_sip_200ok(collector_sync_voip_t *sync, dir = 1; } - while (dir != 0xff && ipstr && portstr && mediatype) { + /* 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) { @@ -837,8 +855,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, @@ -1003,42 +1024,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) { @@ -1168,6 +1153,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 +1178,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 +1258,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) { + 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, @@ -1303,22 +1293,71 @@ 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 = get_sip_cseq(sync->sipparser); + /* 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); exportcount += 1; } + if (invitecseq) { + free(invitecseq); + } if (locptr) { free(locptr); } @@ -2054,6 +2093,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/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 34cc62b..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. @@ -32,7 +32,9 @@ #include "ipcc.h" #include "ipmmiri.h" #include "umtsiri.h" +#include "epsiri.h" #include "emailiri.h" +#include "epscc.h" #include "collector_base.h" #include "logger.h" #include "etsili_core.h" @@ -152,7 +154,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; @@ -225,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); @@ -481,13 +480,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 +502,123 @@ 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_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->liid, + job->cin, epsccjob->gtpseqno, epsccjob->dir, job->origreq->ts, + epsccjob->icetype, epsccjob->ipclen); + + 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) { + + 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 +655,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; } @@ -606,6 +713,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) { @@ -823,12 +931,18 @@ 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; 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..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. @@ -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..434ae23 --- /dev/null +++ b/src/collector/epscc.h @@ -0,0 +1,49 @@ +/* + * + * Copyright (c) 2024 SearchLight Ltd, 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, uint16_t gtpseqno); + +wandder_encoded_result_t *encode_epscc_body(wandder_encoder_t *encoder, + 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/epsiri.h b/src/collector/epsiri.h new file mode 100644 index 0000000..6c1f9b6 --- /dev/null +++ b/src/collector/epsiri.h @@ -0,0 +1,90 @@ +/* + * + * Copyright (c) 2024 SearchLight Ltd, 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, + 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 + */ + EPSIRI_CONTENTS_RAW_ULI = 101, + 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, + 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 */ +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 de83a46..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. @@ -46,6 +46,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/epscc.c b/src/collector/etsiencoding/epscc.c new file mode 100644 index 0000000..e1e4997 --- /dev/null +++ b/src/collector/etsiencoding/epscc.c @@ -0,0 +1,132 @@ +/* + * + * Copyright (c) 2024 SearchLight Ltd, 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 . + * + * + */ + +#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, uint16_t gtpseqno) { + + 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; + msg->data.mobcc.gtpseqno = gtpseqno; + + return msg; +} + +wandder_encoded_result_t *encode_epscc_body(wandder_encoder_t *encoder, + 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); + END_ENCODED_SEQUENCE(encoder, 6); + return wandder_encode_finish(encoder); +} diff --git a/src/collector/etsiencoding/epsiri.c b/src/collector/etsiencoding/epsiri.c new file mode 100644 index 0000000..c37c2d0 --- /dev/null +++ b/src/collector/etsiencoding/epsiri.c @@ -0,0 +1,357 @@ +/* + * + * Copyright (c) 2024 SearchLight Ltd, 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 . + * + * + */ + +#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; + 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)); + + 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 (3) -- use UTCTime */ + jobarray[5] = &(precomputed[OPENLI_PREENCODE_CSEQUENCE_3]); + wandder_encode_next_preencoded(encoder, jobarray, 6); + + 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, + p->itemptr, p->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) */ + + /* 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 (24) -- also appears in networkIdentifier, but why not... */ + lookup = EPSIRI_CONTENTS_GGSN_IPADDRESS; + + HASH_FIND(hh, params, &lookup, sizeof(lookup), p); + if (p) { + 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); + 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_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; + 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) { + wandder_encode_next(encoder, WANDDER_TAG_OCTETSTRING, + WANDDER_CLASS_CONTEXT_PRIMITIVE, 2, p->itemptr, p->itemlen); + } + + /* 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); + } + + 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); + } + + 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); + } + + 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); +} diff --git a/src/collector/etsiencoding/etsiencoding.c b/src/collector/etsiencoding/etsiencoding.c index aa39ed0..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. @@ -166,11 +166,13 @@ 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: 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/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 new file mode 100644 index 0000000..09673bf --- /dev/null +++ b/src/collector/gtp.h @@ -0,0 +1,78 @@ +/* + * + * Copyright (c) 2024 SearchLight Ltd, 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_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_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); + +#endif diff --git a/src/collector/gtp_worker.c b/src/collector/gtp_worker.c new file mode 100644 index 0000000..c48c3ad --- /dev/null +++ b/src/collector/gtp_worker.c @@ -0,0 +1,1019 @@ +/* + * + * Copyright (c) 2024 SearchLight Ltd, 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 . + * + * + */ +#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" +#include "epscc.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. + */ + + 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 UNUSED, + ipintercept_t *ipint 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; + } + + 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); + + 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 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. + */ + 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; + + return 1; +} + +static void update_modified_gtp_intercept(openli_gtp_worker_t *worker, + ipintercept_t *found, ipintercept_t *ipint) { + + int changed = 0; + + if (ipint->accesstype != INTERNET_ACCESS_TYPE_MOBILE) { + /* Intercept has changed to be NOT mobile, so just remove it */ + 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; + } + + update_modified_intercept_common(&(found->common), &(ipint->common), + OPENLI_INTERCEPT_TYPE_IP, &changed); + if (strcmp(ipint->username, found->username) != 0 || + ipint->mobileident != found->mobileident) { + 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 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) { + HASH_ITER(hh, queues, sendq, tmpq) { + push_session_update_to_collector_queue(sendq->q, ipint, sess, + OPENLI_PUSH_HALT_IPINTERCEPT); + } + } +} + +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) { + + /* 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; + 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; + } + + gettimeofday(&now, NULL); + if (!INTERCEPT_IS_ACTIVE(ipint, now)) { + return; + } + + irimsg = (openli_export_recv_t *)calloc(1, sizeof(openli_export_recv_t)); + 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); + 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, + 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, + libtrace_packet_t *packet, uint8_t *payload, + uint32_t plen, uint32_t teid, uint16_t gtpseqno) { + + 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)) { + return; + } + if (ethertype == TRACE_ETHERTYPE_IP) { + libtrace_ip_t *ip = (libtrace_ip_t *)l3; + + 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; + } + snprintf(keystr, 1024, "%lu-%lu-%u", + *(uint64_t *)(&(ip6->ip_dst.s6_addr)), + *(uint64_t *)(&(ip6->ip_dst.s6_addr[8])), + teid); + } else { + return; + } + + 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]; + access_session_t *sess = found->session[i]; + user_intercept_list_t *userint; + + HASH_FIND(hh, worker->userintercepts, owner->userid, + strlen(owner->userid), userint); + + if (!userint) { + continue; + } + + HASH_ITER(hh_user, userint->intlist, ipint, tmp) { + 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 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); + } + } +} + +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; + } + + HASH_FIND(hh, worker->userintercepts, iuser->userid, + strlen(iuser->userid), userint); + + if (oldstate != newstate) { + if (newstate == SESSION_STATE_ACTIVE) { + 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], + sess->gtp_tunnel_endpoints[0]); + remove_teid_to_session_mapping(worker, sess, sess->teids[1], + sess->gtp_tunnel_endpoints[1]); + } + } + + 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); + } + } + +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); + } + +} + +static void process_gtp_packet(openli_gtp_worker_t *worker, + libtrace_packet_t *packet) { + uint8_t *payload; + uint32_t plen; + uint8_t proto; + uint32_t rem; + void *transport; + uint8_t msgtype; + uint32_t teid; + uint16_t seqno = 0; + + 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 = ntohl(v2hdr->teid); + seqno = ntohs(v2hdr->seqno); + 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 = ntohl(v1hdr->teid); + seqno = ntohs(v1hdr->seqno); + payload += sizeof(gtpv1_header_t); + plen -= sizeof(gtpv1_header_t); + } else { + return; + } + + if (msgtype == 0xff) { + /* This is GTP-U */ + process_gtp_u_packet(worker, packet, payload, plen, teid, seqno); + } 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; + + 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; + } + + process_gtp_packet(worker, recvd.data.pkt); + + 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; + 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; + close(topoll[2].fd); + + /* 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; + 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, + "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); + + 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); + 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); + } + + 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->all_data_teids = 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); + 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..abf09f7 --- /dev/null +++ b/src/collector/gtp_worker.h @@ -0,0 +1,105 @@ +/* + * + * Copyright (c) 2024 SearchLight Ltd, 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_GTP_WORKER_H_ +#define OPENLI_GTP_WORKER_H_ + +#include "gtp.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; + + /* 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; + + /* Instance of the GTP session state processing plugin used to + * track sessions observed in GTP-C traffic + */ + 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, + void *globarg); + +#endif diff --git a/src/collector/internetaccess.c b/src/collector/internetaccess.c index 1c4a647..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. @@ -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) { @@ -65,9 +114,18 @@ 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[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); } + if (sess->sessionid) { + free(sess->sessionid); + } free(sess); } @@ -176,6 +234,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 +249,18 @@ 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[0] = NULL; + newsess->gtp_tunnel_endpoints[1] = NULL; 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 +320,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..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. @@ -109,8 +109,27 @@ typedef struct ip_to_session { UT_hash_handle hh; } ip_to_session_t; +typedef struct teid_to_session { + char *idstring; + uint32_t teid; + int sessioncount; + access_session_t **session; + internet_user_t **owner; + uint32_t cin; + uint8_t dir; + 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; @@ -125,6 +144,11 @@ struct access_session { struct timeval started; + char *gtp_tunnel_endpoints[2]; + uint8_t gtp_version; + uint32_t teids[2]; + uint8_t teids_mapped; + UT_hash_handle hh; } ; @@ -192,12 +216,17 @@ 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); 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/collector/ipcc.c b/src/collector/ipcc.c index 08a285a..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. @@ -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 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 53dc379..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. @@ -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 ++; } @@ -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 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 9508227..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. @@ -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; } 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 02c4b27..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. @@ -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 && @@ -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 (strcasecmp(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) { @@ -369,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); @@ -378,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); } @@ -476,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); } } @@ -538,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); @@ -546,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); } } @@ -608,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); @@ -658,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); @@ -668,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); @@ -713,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); @@ -734,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); @@ -744,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) { @@ -774,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; @@ -847,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; @@ -937,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); } @@ -1010,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; @@ -1032,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, @@ -1042,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) { @@ -1054,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) { @@ -1070,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); @@ -1183,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; } @@ -1191,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); @@ -1204,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); @@ -1218,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); @@ -1232,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; } @@ -1259,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; @@ -1268,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; @@ -1277,86 +1300,66 @@ 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; } } - 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 && - 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. @@ -1413,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; @@ -1422,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; @@ -1437,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); } @@ -1481,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) */ @@ -1532,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) */ @@ -1544,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) { @@ -1555,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) { @@ -1566,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) { @@ -1577,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); } @@ -1660,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; } @@ -1668,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; @@ -1677,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; @@ -1686,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; } @@ -1694,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; } @@ -1702,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; @@ -1711,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; @@ -1720,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; @@ -1729,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; @@ -1738,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; @@ -1747,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; @@ -1756,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 = @@ -1789,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); } 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 7d5c21b..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. @@ -34,14 +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}; static inline void encode_tri_body(wandder_encoder_t *encoder) { ENC_CSEQUENCE(encoder, 2); // Payload @@ -114,7 +109,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 +146,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, @@ -456,10 +450,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 @@ -1161,6 +1151,20 @@ 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_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; @@ -1224,45 +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 *)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, 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, 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; 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 *)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 *)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 *)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, 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; @@ -1450,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 @@ -1464,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; diff --git a/src/etsili_core.h b/src/etsili_core.h index 4ae927f..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. @@ -172,6 +172,8 @@ 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_CSEQUENCE_17, /* EPSCC-PDU */ OPENLI_PREENCODE_PSDOMAINID, OPENLI_PREENCODE_LIID, OPENLI_PREENCODE_AUTHCC, @@ -184,6 +186,7 @@ typedef enum { OPENLI_PREENCODE_IPCCOID, OPENLI_PREENCODE_IPIRIOID, OPENLI_PREENCODE_UMTSIRIOID, + OPENLI_PREENCODE_EPSIRIOID, OPENLI_PREENCODE_EMAILIRIOID, OPENLI_PREENCODE_EMAILCCOID, OPENLI_PREENCODE_IPMMCCOID, @@ -192,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; @@ -247,10 +251,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); @@ -259,6 +259,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); 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 5417cd4..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. @@ -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)); @@ -403,19 +405,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 0634f3f..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. @@ -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, @@ -368,6 +372,7 @@ struct rtpstreaminf { uint8_t byematched; char *invitecseq; char *byecseq; + uint16_t invitecseq_stack; uint8_t inviter[16]; @@ -436,6 +441,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); 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 b0ca115..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. @@ -256,9 +256,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.", @@ -612,7 +614,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); 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.