diff --git a/src/Makefile.am b/src/Makefile.am
index 9e58ca33..780d9e4e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -15,7 +15,8 @@ openliprovisioner_SOURCES=provisioner/provisioner.c provisioner/provisioner.h \
provisioner/updateserver.h \
provisioner/updateserver_jsonparsing.c \
provisioner/updateserver_jsoncreation.c \
- provisioner/hup_reload.c
+ provisioner/hup_reload.c \
+ provisioner/intercept_timers.c provisioner/intercept_timers.h
openliprovisioner_LDFLAGS = -lpthread @PROVISIONER_LIBS@
openliprovisioner_LDADD = @ADD_LIBS@
diff --git a/src/configparser.c b/src/configparser.c
index e64cbc24..780a90af 100644
--- a/src/configparser.c
+++ b/src/configparser.c
@@ -730,6 +730,31 @@ static void parse_intercept_common_fields(intercept_common_t *common,
}
}
+static inline void init_intercept_common(intercept_common_t *common,
+ void *parent, openli_intercept_types_t intercept_type) {
+ prov_intercept_data_t *local;
+
+ common->liid = NULL;
+ common->liid_len = 0;
+ common->authcc = NULL;
+ common->authcc_len = 0;
+ common->delivcc = NULL;
+ common->delivcc_len = 0;
+ common->destid = 0;
+ common->targetagency = NULL;
+ common->encryptkey = NULL;
+ common->tostart_time = 0;
+ common->toend_time = 0;
+ common->tomediate = OPENLI_INTERCEPT_OUTPUTS_ALL;
+ common->encrypt = OPENLI_PAYLOAD_ENCRYPTION_NONE;
+ common->hi1_seqno = 0;
+ common->local = calloc(1, sizeof(prov_intercept_data_t));
+
+ local = (prov_intercept_data_t *)(common->local);
+ local->intercept_type = intercept_type;
+ local->intercept_ref = (void *)parent;
+}
+
static int parse_emailintercept_list(emailintercept_t **mailints,
yaml_document_t *doc, yaml_node_t *inputs) {
@@ -743,17 +768,8 @@ static int parse_emailintercept_list(emailintercept_t **mailints,
unsigned int tgtcount = 0;
newcept = (emailintercept_t *)calloc(1, sizeof(emailintercept_t));
- newcept->common.liid = NULL;
- newcept->common.authcc = NULL;
- newcept->common.delivcc = NULL;
- newcept->common.destid = 0;
- newcept->common.targetagency = NULL;
- newcept->common.encryptkey = NULL;
- newcept->common.tostart_time = 0;
- newcept->common.toend_time = 0;
- newcept->common.tomediate = OPENLI_INTERCEPT_OUTPUTS_ALL;
- newcept->common.encrypt = OPENLI_PAYLOAD_ENCRYPTION_NONE;
- newcept->common.hi1_seqno = 0;
+ init_intercept_common(&(newcept->common), newcept,
+ OPENLI_INTERCEPT_TYPE_EMAIL);
newcept->awaitingconfirm = 1;
newcept->targets = NULL;
newcept->delivercompressed = OPENLI_EMAILINT_DELIVER_COMPRESSED_DEFAULT;
@@ -837,25 +853,16 @@ static int parse_voipintercept_list(voipintercept_t **voipints,
newcept->internalid = nextid;
nextid ++;
- newcept->common.liid = NULL;
- newcept->common.authcc = NULL;
- newcept->common.delivcc = NULL;
+ init_intercept_common(&(newcept->common), newcept,
+ OPENLI_INTERCEPT_TYPE_VOIP);
newcept->active_cins = NULL;
newcept->active_registrations = NULL;
newcept->cin_callid_map = NULL;
newcept->cin_sdp_map = NULL;
newcept->targets = libtrace_list_init(sizeof(openli_sip_identity_t *));
newcept->active = 1;
- newcept->common.destid = 0;
- newcept->common.targetagency = NULL;
- newcept->common.encryptkey = NULL;
- newcept->common.hi1_seqno = 0;
newcept->awaitingconfirm = 1;
newcept->options = 0;
- newcept->common.tostart_time = 0;
- newcept->common.toend_time = 0;
- newcept->common.tomediate = OPENLI_INTERCEPT_OUTPUTS_ALL;
- newcept->common.encrypt = OPENLI_PAYLOAD_ENCRYPTION_NONE;
/* Mappings describe the parameters for each intercept */
for (pair = node->data.mapping.pairs.start;
@@ -917,28 +924,16 @@ static int parse_ipintercept_list(ipintercept_t **ipints, yaml_document_t *doc,
/* Each sequence item is a new intercept */
newcept = (ipintercept_t *)malloc(sizeof(ipintercept_t));
+ init_intercept_common(&(newcept->common), newcept,
+ OPENLI_INTERCEPT_TYPE_IP);
- newcept->common.liid = NULL;
- newcept->common.authcc = NULL;
- newcept->common.delivcc = NULL;
newcept->username = NULL;
- newcept->common.destid = 0;
- newcept->common.targetagency = NULL;
- newcept->common.encryptkey = NULL;
- newcept->common.hi1_seqno = 0;
newcept->awaitingconfirm = 1;
- newcept->common.liid_len = 0;
newcept->username_len = 0;
- newcept->common.authcc_len = 0;
- newcept->common.delivcc_len = 0;
newcept->vendmirrorid = OPENLI_VENDOR_MIRROR_NONE;
newcept->accesstype = INTERNET_ACCESS_TYPE_UNDEFINED;
newcept->statics = NULL;
newcept->options = 0;
- newcept->common.tostart_time = 0;
- newcept->common.toend_time = 0;
- newcept->common.tomediate = OPENLI_INTERCEPT_OUTPUTS_ALL;
- newcept->common.encrypt = OPENLI_PAYLOAD_ENCRYPTION_NONE;
/* Mappings describe the parameters for each intercept */
for (pair = node->data.mapping.pairs.start;
diff --git a/src/intercept.h b/src/intercept.h
index 0a090073..589a2a73 100644
--- a/src/intercept.h
+++ b/src/intercept.h
@@ -36,6 +36,13 @@
#define OPENLI_VENDOR_MIRROR_NONE (0xffffffff)
+typedef enum {
+ OPENLI_INTERCEPT_TYPE_UNKNOWN = 0,
+ OPENLI_INTERCEPT_TYPE_IP = 1,
+ OPENLI_INTERCEPT_TYPE_VOIP = 2,
+ OPENLI_INTERCEPT_TYPE_EMAIL = 3,
+} openli_intercept_types_t;
+
typedef enum {
INTERNET_ACCESS_TYPE_UNDEFINED = 0,
INTERNET_ACCESS_TYPE_DIALUP = 1,
@@ -114,6 +121,13 @@ typedef struct intercept_common {
intercept_outputs_t tomediate;
payload_encryption_method_t encrypt;
char *encryptkey;
+
+ /** A pointer to use for storing "local" data against an instance of
+ * an intercept, i.e. the provisioner might want to associate
+ * certain data against each intercept that is not required by the
+ * collector or mediator.
+ */
+ void *local;
} intercept_common_t;
typedef struct hi1_notify_data {
diff --git a/src/provisioner/clientupdates.c b/src/provisioner/clientupdates.c
index 57ece694..092b8015 100644
--- a/src/provisioner/clientupdates.c
+++ b/src/provisioner/clientupdates.c
@@ -393,6 +393,7 @@ int announce_hi1_notification_to_mediators(provision_state_t *state,
hi1_notify_data_t ndata;
struct timeval tv;
+ prov_intercept_data_t *ceptdata = (prov_intercept_data_t *)(intcomm->local);
if (intcomm == NULL) {
return -1;
@@ -400,6 +401,41 @@ int announce_hi1_notification_to_mediators(provision_state_t *state,
gettimeofday(&tv, NULL);
+ if (ceptdata && not_type == HI1_LI_ACTIVATED) {
+ if (ceptdata->start_hi1_sent) {
+ return 0;
+ }
+ if (intcomm->tostart_time > tv.tv_sec) {
+ return 0;
+ }
+ ceptdata->start_hi1_sent = 1;
+ ceptdata->end_hi1_sent = 0;
+ } else if (ceptdata && not_type == HI1_LI_DEACTIVATED) {
+ if (ceptdata->end_hi1_sent) {
+ return 0;
+ }
+ if (!ceptdata->start_hi1_sent) {
+ return 0;
+ }
+ ceptdata->end_hi1_sent = 1;
+ ceptdata->start_hi1_sent = 0;
+ } else if (ceptdata && not_type == HI1_LI_MODIFIED) {
+ if (ceptdata->end_hi1_sent) {
+ return 0;
+ }
+ if (!ceptdata->start_hi1_sent) {
+ if (intcomm->tostart_time > tv.tv_sec) {
+ return 0;
+ } else {
+ /* shouldn't get here ideally, but just in case we do then
+ * let's send an activated message instead.
+ */
+ not_type = HI1_LI_ACTIVATED;
+ ceptdata->start_hi1_sent = 1;
+ }
+ }
+ }
+
ndata.notify_type = not_type;
ndata.liid = intcomm->liid;
ndata.authcc = intcomm->authcc;
@@ -423,7 +459,7 @@ int announce_hi1_notification_to_mediators(provision_state_t *state,
}
SEND_ALL_MEDIATORS_END
intcomm->hi1_seqno ++;
- return 0;
+ return 1;
}
int remove_liid_mapping(provision_state_t *state,
diff --git a/src/provisioner/hup_reload.c b/src/provisioner/hup_reload.c
index 53552c61..df23bd33 100644
--- a/src/provisioner/hup_reload.c
+++ b/src/provisioner/hup_reload.c
@@ -30,6 +30,7 @@
#include "util.h"
#include "configparser.h"
#include "updateserver.h"
+#include "intercept_timers.h"
static inline int reload_staticips(provision_state_t *currstate,
ipintercept_t *ipint, ipintercept_t *newequiv) {
@@ -242,13 +243,156 @@ static int reload_coreservers(provision_state_t *state, coreserver_t *currserv,
return 0;
}
+static void remove_withdrawn_intercept(provision_state_t *currstate,
+ intercept_common_t *common, char *target_info, int droppedmeds) {
+
+ remove_liid_mapping(currstate, common->liid, common->liid_len, droppedmeds);
+ if (!droppedmeds) {
+ announce_hi1_notification_to_mediators(currstate,
+ common, target_info, HI1_LI_DEACTIVATED);
+ if (target_info) {
+ free(target_info);
+ }
+ }
+
+ logger(LOG_INFO, "OpenLI provisioner: LIID %s has been withdrawn following a config reload.",
+ common->liid);
+}
+
+static int enable_new_intercept(provision_state_t *currstate,
+ intercept_common_t *common, prov_intercept_conf_t *intconf,
+ char *target_info, int droppedmeds) {
+
+ liid_hash_t *h = NULL;
+ struct timeval tv;
+ prov_agency_t *lea = NULL;
+ prov_intercept_data_t *local;
+
+
+ if (strcmp(common->targetagency, "pcapdisk") != 0) {
+ HASH_FIND_STR(intconf->leas, common->targetagency, lea);
+ if (lea == NULL) {
+ return 0;
+ }
+ }
+
+ gettimeofday(&tv, NULL);
+ local = (prov_intercept_data_t *)(common->local);
+ if (local && (common->tostart_time > 0 || common->toend_time > 0)) {
+
+ if (add_intercept_timer(currstate->epoll_fd,
+ common->tostart_time, tv.tv_sec,
+ local, PROV_EPOLL_INTERCEPT_START) < 0) {
+ logger(LOG_INFO,
+ "OpenLI provisioner: unable to schedule HI1 notification for starting email intercept %s", common->liid);
+
+ return -1;
+ }
+
+ if (add_intercept_timer(currstate->epoll_fd,
+ common->toend_time, tv.tv_sec,
+ local, PROV_EPOLL_INTERCEPT_HALT) < 0) {
+ logger(LOG_INFO,
+ "OpenLI provisioner: unable to schedule HI1 notification for halting email intercept %s", common->liid);
+
+ return -1;
+ }
+ }
+
+ /* Add the LIID mapping */
+ h = add_liid_mapping(intconf, common->liid, common->targetagency);
+
+ if (!droppedmeds && announce_hi1_notification_to_mediators(currstate,
+ common, target_info, HI1_LI_ACTIVATED) == -1) {
+ logger(LOG_INFO,
+ "OpenLI provisioner: unable to send HI1 notification for new Email intercept to mediators.");
+ return -1;
+ }
+
+ if (!droppedmeds && announce_liidmapping_to_mediators(currstate, h) == -1) {
+ logger(LOG_INFO,
+ "OpenLI provisioner: unable to announce new Email intercept to mediators.");
+ return -1;
+ }
+ return 1;
+}
+
+static int update_reconfigured_intercept(provision_state_t *currstate,
+ intercept_common_t *old_common, intercept_common_t *new_common,
+ prov_intercept_conf_t *intconf, int cept_changed, int agencychanged,
+ int droppedmeds, char *old_targets, char *new_targets) {
+
+ char errorstring[1024];
+ liid_hash_t *h = NULL;
+
+ prov_intercept_data_t *local, *oldlocal;
+ /* save the "hi1 sent" status from the original intercept
+ * instance.
+ */
+ oldlocal = (prov_intercept_data_t *)(old_common->local);
+ local = (prov_intercept_data_t *)(new_common->local);
+
+ local->start_hi1_sent = oldlocal->start_hi1_sent;
+ local->end_hi1_sent = oldlocal->end_hi1_sent;
+ new_common->hi1_seqno = old_common->hi1_seqno;
+
+ if (agencychanged || cept_changed) {
+ logger(LOG_INFO,
+ "OpenLI provisioner: Details for intercept %s have changed -- updating collectors",
+ new_common->liid);
+ }
+
+ if (!droppedmeds && agencychanged) {
+ announce_hi1_notification_to_mediators(currstate,
+ old_common, old_targets, HI1_LI_DEACTIVATED);
+ new_common->hi1_seqno = 0;
+ announce_hi1_notification_to_mediators(currstate,
+ new_common, new_targets, HI1_LI_ACTIVATED);
+ } else if (!droppedmeds && cept_changed) {
+ announce_hi1_notification_to_mediators(currstate,
+ new_common, new_targets, HI1_LI_MODIFIED);
+ }
+
+
+ /* clear the old HI1 timers, since they will be pointing
+ * at an intercept instance that is going to be removed
+ * when we complete the config reload.
+ */
+ free_prov_intercept_data(old_common, currstate->epoll_fd);
+
+ /* add new intercept timers, and also send any required
+ * HI1 messages
+ */
+ if (reset_intercept_timers(currstate, new_common,
+ new_targets, errorstring, 1024) < 0) {
+ logger(LOG_INFO, "OpenLI provisioner: unable to reset intercept timers: %s", errorstring);
+ }
+
+ if (agencychanged) {
+ remove_liid_mapping(currstate, old_common->liid,
+ old_common->liid_len, droppedmeds);
+
+ h = add_liid_mapping(intconf, new_common->liid,
+ new_common->targetagency);
+ if (!droppedmeds && announce_liidmapping_to_mediators(
+ currstate, h) == -1) {
+ logger(LOG_INFO,
+ "OpenLI provisioner: unable to announce new agency for intercept %s to mediators.", new_common->liid);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
static int reload_emailintercepts(provision_state_t *currstate,
emailintercept_t *curremail, emailintercept_t *newemail,
prov_intercept_conf_t *intconf, int droppedcols, int droppedmeds) {
emailintercept_t *mailint, *tmp, *newequiv;
- liid_hash_t *h = NULL;
char *target_info;
+ prov_intercept_data_t *local, *oldlocal;
+ struct timeval tv;
/* TODO error handling in the "inform other components about changes"
* functions?
@@ -257,23 +401,21 @@ static int reload_emailintercepts(provision_state_t *currstate,
HASH_FIND(hh_liid, newemail, mailint->common.liid,
mailint->common.liid_len, newequiv);
+ local = (prov_intercept_data_t *)(mailint->common.local);
+
if (!newequiv) {
/* Intercept has been withdrawn entirely */
if (!droppedcols) {
halt_existing_intercept(currstate, (void *)mailint,
OPENLI_PROTO_HALT_EMAILINTERCEPT);
}
- remove_liid_mapping(currstate, mailint->common.liid,
- mailint->common.liid_len, droppedmeds);
- if (!droppedmeds) {
- target_info = list_email_targets(mailint, 256);
- announce_hi1_notification_to_mediators(currstate,
- &(mailint->common), target_info,
- HI1_LI_DEACTIVATED);
- if (target_info) {
- free(target_info);
- }
+ target_info = list_email_targets(mailint, 256);
+ remove_withdrawn_intercept(currstate, &(mailint->common),
+ target_info, droppedmeds);
+ if (target_info) {
+ free(target_info);
}
+
continue;
} else {
int intsame = email_intercept_equal(mailint, newequiv);
@@ -282,42 +424,15 @@ static int reload_emailintercepts(provision_state_t *currstate,
int changedtargets = compare_email_targets(currstate, mailint,
newequiv);
- newequiv->common.hi1_seqno = mailint->common.hi1_seqno;
- newequiv->awaitingconfirm = 0;
+ char *old_target_info = list_email_targets(mailint, 256);
+ char *new_target_info = list_email_targets(newequiv, 256);
- if (intsame && !agencychanged && changedtargets == 0) {
- continue;
- }
-
- logger(LOG_INFO, "OpenLI provisioner: Details for Email intercept %s have changed -- updating collectors",
- mailint->common.liid);
-
- if (!droppedmeds) {
- if (agencychanged) {
- target_info = list_email_targets(mailint, 256);
- announce_hi1_notification_to_mediators(currstate,
- &(mailint->common), target_info,
- HI1_LI_DEACTIVATED);
- if (target_info) {
- free(target_info);
- }
- newequiv->common.hi1_seqno = 0;
- target_info = list_email_targets(newequiv, 256);
- announce_hi1_notification_to_mediators(currstate,
- &(newequiv->common), target_info,
- HI1_LI_ACTIVATED);
- if (target_info) {
- free(target_info);
- }
- } else {
- target_info = list_email_targets(newequiv, 256);
- announce_hi1_notification_to_mediators(currstate,
- &(newequiv->common), target_info,
- HI1_LI_MODIFIED);
- if (target_info) {
- free(target_info);
- }
- }
+ newequiv->awaitingconfirm = 0;
+ if (update_reconfigured_intercept(currstate, &(mailint->common),
+ &(newequiv->common), intconf, (!intsame || changedtargets),
+ agencychanged, droppedmeds, old_target_info,
+ new_target_info) < 0) {
+ return -1;
}
if (!intsame && !droppedcols) {
@@ -325,65 +440,34 @@ static int reload_emailintercepts(provision_state_t *currstate,
OPENLI_PROTO_MODIFY_EMAILINTERCEPT);
}
- if (agencychanged) {
- remove_liid_mapping(currstate, mailint->common.liid,
- mailint->common.liid_len, droppedmeds);
-
- h = add_liid_mapping(intconf, newequiv->common.liid,
- newequiv->common.targetagency);
- if (!droppedmeds && announce_liidmapping_to_mediators(
- currstate, h) == -1) {
- logger(LOG_INFO,
- "OpenLI provisioner: unable to announce new agency for Email intercept to mediators.");
- return -1;
- }
+ if (old_target_info) {
+ free(old_target_info);
+ }
+ if (new_target_info) {
+ free(new_target_info);
}
}
}
+ gettimeofday(&tv, NULL);
+
HASH_ITER(hh_liid, newemail, mailint, tmp) {
- int skip = 0;
- prov_agency_t *lea = NULL;
+ int r = 0;
if (!mailint->awaitingconfirm) {
continue;
}
-
- if (strcmp(mailint->common.targetagency, "pcapdisk") != 0) {
- HASH_FIND_STR(intconf->leas, mailint->common.targetagency, lea);
- if (lea == NULL) {
- skip = 1;
- }
- }
-
- if (skip) {
- continue;
- }
-
- /* Add the LIID mapping */
- h = add_liid_mapping(intconf, mailint->common.liid,
- mailint->common.targetagency);
-
target_info = list_email_targets(mailint, 256);
- if (!droppedmeds && announce_hi1_notification_to_mediators(currstate,
- &(mailint->common), target_info,
- HI1_LI_ACTIVATED) == -1) {
- if (target_info) {
- free(target_info);
- }
- logger(LOG_INFO,
- "OpenLI provisioner: unable to send HI1 notification for new Email intercept to mediators.");
- return -1;
- }
+ r = enable_new_intercept(currstate, &(mailint->common), intconf,
+ target_info, droppedmeds);
if (target_info) {
free(target_info);
}
-
- if (!droppedmeds && announce_liidmapping_to_mediators(currstate,
- h) == -1) {
- logger(LOG_INFO,
- "OpenLI provisioner: unable to announce new Email intercept to mediators.");
- return -1;
+ if (r < 0) {
+ return r;
+ }
+ if (r == 0) {
+ continue;
}
if (!droppedcols && announce_single_intercept(currstate,
@@ -408,8 +492,9 @@ static int reload_voipintercepts(provision_state_t *currstate,
prov_intercept_conf_t *intconf, int droppedcols, int droppedmeds) {
voipintercept_t *voipint, *tmp, *newequiv;
- liid_hash_t *h = NULL;
char *target_info;
+ prov_intercept_data_t *local, *oldlocal;
+ struct timeval tv;
/* TODO error handling in the "inform other components about changes"
* functions?
@@ -418,6 +503,8 @@ static int reload_voipintercepts(provision_state_t *currstate,
HASH_FIND(hh_liid, newvoip, voipint->common.liid,
voipint->common.liid_len, newequiv);
+ local = (prov_intercept_data_t *)(voipint->common.local);
+
if (newequiv && currstate->ignorertpcomfort) {
newequiv->options |= (1 << OPENLI_VOIPINT_OPTION_IGNORE_COMFORT);
}
@@ -428,16 +515,11 @@ static int reload_voipintercepts(provision_state_t *currstate,
halt_existing_intercept(currstate, (void *)voipint,
OPENLI_PROTO_HALT_VOIPINTERCEPT);
}
- remove_liid_mapping(currstate, voipint->common.liid,
- voipint->common.liid_len, droppedmeds);
- if (!droppedmeds) {
- target_info = list_sip_targets(voipint, 256);
- announce_hi1_notification_to_mediators(currstate,
- &(voipint->common), target_info,
- HI1_LI_DEACTIVATED);
- if (target_info) {
- free(target_info);
- }
+ target_info = list_sip_targets(voipint, 256);
+ remove_withdrawn_intercept(currstate, &(voipint->common),
+ target_info, droppedmeds);
+ if (target_info) {
+ free(target_info);
}
continue;
} else {
@@ -446,43 +528,15 @@ static int reload_voipintercepts(provision_state_t *currstate,
newequiv->common.targetagency);
int changedtargets = compare_sip_targets(currstate, voipint,
newequiv);
+ char *old_target_info = list_sip_targets(voipint, 256);
+ char *new_target_info = list_sip_targets(newequiv, 256);
- newequiv->common.hi1_seqno = voipint->common.hi1_seqno;
newequiv->awaitingconfirm = 0;
-
- if (intsame && !agencychanged && changedtargets == 0) {
- continue;
- }
-
- logger(LOG_INFO, "OpenLI provisioner: Details for VOIP intercept %s have changed -- updating collectors",
- voipint->common.liid);
-
- if (!droppedmeds) {
- if (agencychanged) {
- target_info = list_sip_targets(voipint, 256);
- announce_hi1_notification_to_mediators(currstate,
- &(voipint->common), target_info,
- HI1_LI_DEACTIVATED);
- if (target_info) {
- free(target_info);
- }
- newequiv->common.hi1_seqno = 0;
- target_info = list_sip_targets(newequiv, 256);
- announce_hi1_notification_to_mediators(currstate,
- &(newequiv->common), target_info,
- HI1_LI_ACTIVATED);
- if (target_info) {
- free(target_info);
- }
- } else {
- target_info = list_sip_targets(newequiv, 256);
- announce_hi1_notification_to_mediators(currstate,
- &(newequiv->common), target_info,
- HI1_LI_MODIFIED);
- if (target_info) {
- free(target_info);
- }
- }
+ if (update_reconfigured_intercept(currstate, &(voipint->common),
+ &(newequiv->common), intconf, (!intsame || changedtargets),
+ agencychanged, droppedmeds, old_target_info,
+ new_target_info) < 0) {
+ return -1;
}
if (!intsame && !droppedcols) {
@@ -490,69 +544,37 @@ static int reload_voipintercepts(provision_state_t *currstate,
OPENLI_PROTO_MODIFY_VOIPINTERCEPT);
}
- if (agencychanged) {
- remove_liid_mapping(currstate, voipint->common.liid,
- voipint->common.liid_len, droppedmeds);
-
- h = add_liid_mapping(intconf, newequiv->common.liid,
- newequiv->common.targetagency);
- if (!droppedmeds && announce_liidmapping_to_mediators(
- currstate, h) == -1) {
- logger(LOG_INFO,
- "OpenLI provisioner: unable to announce new agency for VOIP intercept to mediators.");
- return -1;
- }
+ if (old_target_info) {
+ free(old_target_info);
+ }
+ if (new_target_info) {
+ free(new_target_info);
}
+
}
}
+ gettimeofday(&tv, NULL);
HASH_ITER(hh_liid, newvoip, voipint, tmp) {
- int skip = 0;
- prov_agency_t *lea = NULL;
+ int r = 0;
if (!voipint->awaitingconfirm) {
continue;
}
-
- if (strcmp(voipint->common.targetagency, "pcapdisk") != 0) {
- HASH_FIND_STR(intconf->leas, voipint->common.targetagency, lea);
- if (lea == NULL) {
- skip = 1;
- }
- }
-
- if (skip) {
- continue;
- }
-
+ target_info = list_sip_targets(voipint, 256);
if (currstate->ignorertpcomfort) {
voipint->options |= (1 << OPENLI_VOIPINT_OPTION_IGNORE_COMFORT);
}
-
- /* Add the LIID mapping */
- h = add_liid_mapping(intconf, voipint->common.liid,
- voipint->common.targetagency);
-
- target_info = list_sip_targets(voipint, 256);
- if (!droppedmeds && announce_hi1_notification_to_mediators(currstate,
- &(voipint->common), target_info,
- HI1_LI_ACTIVATED) == -1) {
- if (target_info) {
- free(target_info);
- }
- logger(LOG_INFO,
- "OpenLI provisioner: unable to send HI1 notification for new VOIP intercept to mediators.");
- return -1;
- }
+ r = enable_new_intercept(currstate, &(voipint->common), intconf,
+ target_info, droppedmeds);
if (target_info) {
free(target_info);
}
-
- if (!droppedmeds && announce_liidmapping_to_mediators(currstate,
- h) == -1) {
- logger(LOG_INFO,
- "OpenLI provisioner: unable to announce new VOIP intercept to mediators.");
- return -1;
+ if (r < 0) {
+ return r;
+ }
+ if (r == 0) {
+ continue;
}
if (!droppedcols && announce_single_intercept(currstate,
@@ -577,28 +599,24 @@ static int reload_ipintercepts(provision_state_t *currstate,
prov_intercept_conf_t *intconf, int droppedcols, int droppedmeds) {
ipintercept_t *ipint, *tmp, *newequiv;
- liid_hash_t *h = NULL;
+ prov_intercept_data_t *local, *oldlocal;
+ struct timeval tv;
- /* TODO error handling in the "inform other components about changes"
- * functions?
- */
HASH_ITER(hh_liid, currints, ipint, tmp) {
HASH_FIND(hh_liid, newints, ipint->common.liid,
ipint->common.liid_len, newequiv);
+
+ local = (prov_intercept_data_t *)(ipint->common.local);
+
if (!newequiv) {
/* Intercept has been withdrawn entirely */
if (!droppedcols) {
halt_existing_intercept(currstate, (void *)ipint,
OPENLI_PROTO_HALT_IPINTERCEPT);
}
- remove_liid_mapping(currstate, ipint->common.liid,
- ipint->common.liid_len, droppedmeds);
- if (!droppedmeds) {
- announce_hi1_notification_to_mediators(currstate,
- &(ipint->common), ipint->username, HI1_LI_DEACTIVATED);
- }
- logger(LOG_INFO, "OpenLI provisioner: LIID %s has been withdrawn",
- ipint->common.liid);
+ remove_withdrawn_intercept(currstate, &(ipint->common),
+ ipint->username, droppedmeds);
+
continue;
} else {
int staticchanged = reload_staticips(currstate, ipint, newequiv);
@@ -606,90 +624,38 @@ static int reload_ipintercepts(provision_state_t *currstate,
int agencychanged = strcmp(ipint->common.targetagency,
newequiv->common.targetagency);
- newequiv->common.hi1_seqno = ipint->common.hi1_seqno;
newequiv->awaitingconfirm = 0;
- if (staticchanged == 0 && intsame && agencychanged == 0) {
- continue;
- }
-
- logger(LOG_INFO, "OpenLI provisioner: Details for IP intercept %s have changed -- updating collectors",
- ipint->common.liid);
-
- if (!droppedmeds) {
- if (agencychanged) {
- announce_hi1_notification_to_mediators(currstate,
- &(ipint->common), ipint->username,
- HI1_LI_DEACTIVATED);
- newequiv->common.hi1_seqno = 0;
- announce_hi1_notification_to_mediators(currstate,
- &(newequiv->common), newequiv->username,
- HI1_LI_ACTIVATED);
- } else {
- announce_hi1_notification_to_mediators(currstate,
- &(newequiv->common), newequiv->username,
- HI1_LI_MODIFIED);
- }
+ if (update_reconfigured_intercept(currstate, &(ipint->common),
+ &(newequiv->common), intconf, (!intsame || staticchanged),
+ agencychanged, droppedmeds, ipint->username,
+ newequiv->username) < 0) {
+ return -1;
}
if (!intsame && !droppedcols) {
modify_existing_intercept_options(currstate, (void *)newequiv,
OPENLI_PROTO_MODIFY_IPINTERCEPT);
}
-
- if (agencychanged) {
- remove_liid_mapping(currstate, ipint->common.liid,
- ipint->common.liid_len, droppedmeds);
-
- h = add_liid_mapping(intconf, newequiv->common.liid,
- newequiv->common.targetagency);
- if (!droppedmeds && announce_liidmapping_to_mediators(
- currstate, h) == -1) {
- logger(LOG_INFO,
- "OpenLI provisioner: unable to announce new agency for IP intercept to mediators.");
- return -1;
- }
- }
}
}
HASH_ITER(hh_liid, newints, ipint, tmp) {
- int skip = 0;
- prov_agency_t *lea = NULL;
+ int r = 0;
if (!ipint->awaitingconfirm) {
continue;
}
- if (strcmp(ipint->common.targetagency, "pcapdisk") != 0) {
- HASH_FIND_STR(intconf->leas, ipint->common.targetagency, lea);
- if (lea == NULL) {
- skip = 1;
- }
+ r = enable_new_intercept(currstate, &(ipint->common), intconf,
+ ipint->username, droppedmeds);
+ if (r < 0) {
+ return r;
}
-
- if (skip) {
+ if (r == 0) {
continue;
}
- /* Add the LIID mapping */
- h = add_liid_mapping(intconf, ipint->common.liid,
- ipint->common.targetagency);
-
- if (!droppedmeds && announce_hi1_notification_to_mediators(currstate,
- &(ipint->common), ipint->username, HI1_LI_ACTIVATED) == -1) {
- logger(LOG_INFO,
- "OpenLI provisioner: unable to send HI1 notification for new IP intercept to mediators.");
- return -1;
- }
-
- if (!droppedmeds && announce_liidmapping_to_mediators(currstate,
- h) == -1) {
- logger(LOG_INFO,
- "OpenLI provisioner: unable to announce new IP intercept to mediators.");
- return -1;
- }
-
if (!droppedcols && announce_single_intercept(currstate,
(void *)ipint, push_ipintercept_onto_net_buffer) == -1) {
logger(LOG_INFO,
diff --git a/src/provisioner/intercept_timers.c b/src/provisioner/intercept_timers.c
new file mode 100644
index 00000000..50dd945a
--- /dev/null
+++ b/src/provisioner/intercept_timers.c
@@ -0,0 +1,317 @@
+/*
+ *
+ * Copyright (c) 2018-2023 The University of Waikato, Hamilton, 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 "util.h"
+#include "provisioner.h"
+#include "logger.h"
+
+#include "intercept_timers.h"
+
+int add_intercept_timer(int epoll_fd, uint64_t tssec, uint64_t now,
+ prov_intercept_data_t *ceptdata, int timertype) {
+
+ int fd;
+ prov_epoll_ev_t **timerptr;
+ struct epoll_event ev;
+
+ if (tssec == 0 || tssec < now) {
+ return 0;
+ }
+
+ if (timertype == PROV_EPOLL_INTERCEPT_START) {
+ timerptr = &(ceptdata->start_timer);
+ } else if (timertype == PROV_EPOLL_INTERCEPT_HALT) {
+ timerptr = &(ceptdata->end_timer);
+ } else {
+ return -1;
+ }
+
+ if (*timerptr == NULL) {
+ *timerptr = calloc(1, sizeof(prov_epoll_ev_t));
+ (*timerptr)->fd = -1;
+ }
+ if ((*timerptr)->fd != -1) {
+ epoll_ctl(epoll_fd, EPOLL_CTL_DEL, (*timerptr)->fd, &ev);
+ }
+ fd = epoll_add_timer(epoll_fd, tssec - now, *timerptr);
+ if (fd == -1) {
+ return -1;
+ }
+ (*timerptr)->fd = fd;
+ (*timerptr)->fdtype = timertype;
+ (*timerptr)->client = NULL;
+ (*timerptr)->cept = ceptdata;
+
+ return 1;
+}
+
+int halt_intercept_timer(prov_epoll_ev_t *timer, int epoll_fd) {
+ struct epoll_event ev;
+
+ if (timer == NULL) {
+ return 0;
+ }
+
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, timer->fd, &ev) < 0) {
+ /* what error handling makes sense here? */
+ return -1;
+ }
+
+ close(timer->fd);
+ timer->fd = -1;
+ return 0;
+}
+
+void free_prov_intercept_data(intercept_common_t *common, int epoll_fd) {
+ prov_intercept_data_t *timers = NULL;
+
+ timers = (prov_intercept_data_t *)(common->local);
+ if (timers == NULL) {
+ return;
+ }
+ if (timers->start_timer) {
+ halt_intercept_timer(timers->start_timer, epoll_fd);
+ free(timers->start_timer);
+ }
+ if (timers->end_timer) {
+ halt_intercept_timer(timers->end_timer, epoll_fd);
+ free(timers->end_timer);
+ }
+
+ free(timers);
+ common->local = NULL;
+}
+
+int add_all_intercept_timers(int epoll_fd, prov_intercept_conf_t *conf) {
+ ipintercept_t *ipint;
+ voipintercept_t *vint;
+ emailintercept_t *mailint;
+
+ prov_intercept_data_t *local;
+ struct timeval tv;
+ int failed = 0;
+
+ gettimeofday(&tv, NULL);
+
+ /* Do IP Intercepts */
+ for (ipint = conf->ipintercepts; ipint != NULL; ipint = ipint->hh_liid.next)
+ {
+ local = (prov_intercept_data_t *)(ipint->common.local);
+ /* If the start time is before now, set the started flag to true
+ * so we don't end up sending an erroneous "started" message later
+ * on (i.e. after a config reload)
+ */
+ if (tv.tv_sec > ipint->common.tostart_time) {
+ local->start_hi1_sent = 1;
+ }
+ if (add_intercept_timer(epoll_fd, ipint->common.tostart_time,
+ tv.tv_sec, local, PROV_EPOLL_INTERCEPT_START) < 0) {
+ failed = 1;
+ }
+ /* Same as above, but for the "deactivated" message. */
+ if (tv.tv_sec > ipint->common.toend_time &&
+ ipint->common.toend_time != 0) {
+ local->end_hi1_sent = 1;
+ local->start_hi1_sent = 0;
+ }
+ if (add_intercept_timer(epoll_fd, ipint->common.toend_time,
+ tv.tv_sec, local, PROV_EPOLL_INTERCEPT_HALT) < 0) {
+ failed = 1;
+ }
+
+ }
+
+ /* Now do the VOIP intercepts */
+ for (vint = conf->voipintercepts; vint != NULL; vint = vint->hh_liid.next)
+ {
+ local = (prov_intercept_data_t *)(vint->common.local);
+ if (tv.tv_sec > vint->common.tostart_time) {
+ local->start_hi1_sent = 1;
+ }
+ if (add_intercept_timer(epoll_fd, vint->common.tostart_time,
+ tv.tv_sec, local, PROV_EPOLL_INTERCEPT_START) < 0) {
+ failed = 1;
+ }
+ if (tv.tv_sec > vint->common.toend_time &&
+ vint->common.toend_time != 0) {
+ local->end_hi1_sent = 1;
+ local->start_hi1_sent = 0;
+ }
+ if (add_intercept_timer(epoll_fd, vint->common.toend_time,
+ tv.tv_sec, local, PROV_EPOLL_INTERCEPT_HALT) < 0) {
+ failed = 1;
+ }
+ }
+
+ for (mailint = conf->emailintercepts; mailint != NULL;
+ mailint = mailint->hh_liid.next) {
+ local = (prov_intercept_data_t *)(mailint->common.local);
+ if (tv.tv_sec > mailint->common.tostart_time) {
+ local->start_hi1_sent = 1;
+ }
+ if (add_intercept_timer(epoll_fd, mailint->common.tostart_time,
+ tv.tv_sec, local, PROV_EPOLL_INTERCEPT_START) < 0) {
+ failed = 1;
+ }
+ if (tv.tv_sec > mailint->common.toend_time &&
+ mailint->common.toend_time != 0) {
+ local->end_hi1_sent = 1;
+ local->start_hi1_sent = 0;
+ }
+ if (add_intercept_timer(epoll_fd, mailint->common.toend_time,
+ tv.tv_sec, local, PROV_EPOLL_INTERCEPT_HALT) < 0) {
+ failed = 1;
+ }
+ }
+ return failed;
+}
+
+int remove_all_intercept_timers(int epoll_fd, prov_intercept_conf_t *conf) {
+ ipintercept_t *ipint;
+ voipintercept_t *vint;
+ emailintercept_t *mailint;
+
+ /* Do IP Intercepts */
+ for (ipint = conf->ipintercepts; ipint != NULL; ipint = ipint->hh_liid.next)
+ {
+ free_prov_intercept_data(&(ipint->common), epoll_fd);
+ }
+
+ /* Now do the VOIP intercepts */
+ for (vint = conf->voipintercepts; vint != NULL; vint = vint->hh_liid.next)
+ {
+ free_prov_intercept_data(&(vint->common), epoll_fd);
+ }
+
+ for (mailint = conf->emailintercepts; mailint != NULL;
+ mailint = mailint->hh_liid.next) {
+ free_prov_intercept_data(&(mailint->common), epoll_fd);
+ }
+
+ return 0;
+}
+
+int reset_intercept_timers(provision_state_t *state,
+ intercept_common_t *existing, char *target_info,
+ char *errorstring, int errorstrlen) {
+
+ prov_intercept_data_t *timers = (prov_intercept_data_t *)(existing->local);
+ struct timeval tv;
+
+ if (timers == NULL) {
+ return 0;
+ }
+
+ halt_intercept_timer(timers->start_timer, state->epoll_fd);
+ halt_intercept_timer(timers->end_timer, state->epoll_fd);
+
+ gettimeofday(&tv, NULL);
+
+ if (existing->tostart_time > 0 && existing->toend_time > 0 &&
+ existing->tostart_time >= existing->toend_time) {
+ snprintf(errorstring, errorstrlen, "'starttime' parameter must be a timestamp BEFORE the 'endtime' timestamp");
+ return -1;
+ }
+
+ if (existing->tostart_time > 0 && existing->tostart_time >
+ tv.tv_sec) {
+ if (timers->start_hi1_sent && !timers->end_hi1_sent) {
+ /* start time has been shifted to a later time, but we had
+ * already started intercepting so we need to announce the
+ * deactivation.
+ */
+ announce_hi1_notification_to_mediators(state,
+ existing, target_info, HI1_LI_DEACTIVATED);
+ }
+
+ if (add_intercept_timer(state->epoll_fd, existing->tostart_time,
+ tv.tv_sec, timers, PROV_EPOLL_INTERCEPT_START) < 0) {
+ snprintf(errorstring, errorstrlen,
+ "unable to create 'intercept start' timer for intercept %s",
+ existing->liid);
+ return -1;
+ }
+
+ } else if (existing->tostart_time >= 0 && !timers->start_hi1_sent) {
+ /* our start time has changed to a time BEFORE now, so we
+ * are going to start intercepting...
+ */
+ if (existing->toend_time == 0 || existing->toend_time > tv.tv_sec) {
+ /* but only if the end time is still in the future (or
+ * indefinite...
+ */
+ announce_hi1_notification_to_mediators(state,
+ existing, target_info, HI1_LI_ACTIVATED);
+ }
+ }
+
+ if (existing->toend_time > 0 && existing->toend_time > tv.tv_sec) {
+ if (add_intercept_timer(state->epoll_fd, existing->toend_time,
+ tv.tv_sec, timers, PROV_EPOLL_INTERCEPT_HALT) < 0) {
+ snprintf(errorstring, errorstrlen,
+ "unable to create 'intercept end' timer for intercept %s",
+ existing->liid);
+ return -1;
+ }
+ if (timers->end_hi1_sent) {
+ if (existing->tostart_time < tv.tv_sec) {
+ /* the old end time had been reached, so we have already
+ * sent a deactivated message. But now the end time has
+ * been changed to further in the future so we need to
+ * announce that the intercept is restarting as of now.
+ */
+ announce_hi1_notification_to_mediators(state, existing,
+ target_info, HI1_LI_ACTIVATED);
+ }
+ }
+
+ timers->end_hi1_sent = 0;
+ } else if (existing->toend_time > 0 && !timers->end_hi1_sent
+ && timers->start_hi1_sent) {
+ /* end time has moved to a time BEFORE now, and we've had
+ * previously been intercepting so we need to announce that
+ * we've stopped.
+ */
+ announce_hi1_notification_to_mediators(state,
+ existing, target_info, HI1_LI_DEACTIVATED);
+
+ } else if (existing->toend_time == 0) {
+ if (timers->end_hi1_sent && existing->tostart_time < tv.tv_sec) {
+ announce_hi1_notification_to_mediators(state, existing,
+ target_info, HI1_LI_ACTIVATED);
+ }
+ /* Reset this, so we can correctly send a DEACTIVATED if the
+ * intercept is removed later on.
+ */
+ timers->end_hi1_sent = 0;
+
+ }
+ return 1;
+
+}
+
+
+// vim: set sw=4 tabstop=4 softtabstop=4 expandtab :
diff --git a/src/provisioner/intercept_timers.h b/src/provisioner/intercept_timers.h
new file mode 100644
index 00000000..c4ebafa1
--- /dev/null
+++ b/src/provisioner/intercept_timers.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2018-2023 The University of Waikato, Hamilton, 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_PROVISIONER_INTERCEPT_TIMERS_H_
+#define OPENLI_PROVISIONER_INTERCEPT_TIMERS_H_
+
+#include "intercept.h"
+#include "util.h"
+#include "provisioner.h"
+
+int add_intercept_timer(int epoll_fd, uint64_t tssec, uint64_t now,
+ prov_intercept_data_t *ceptdata, int timertype);
+
+int halt_intercept_timer(prov_epoll_ev_t *timer, int epoll_fd);
+
+void free_prov_intercept_data(intercept_common_t *common, int epoll_fd);
+
+int add_all_intercept_timers(int epoll_fd, prov_intercept_conf_t *conf);
+
+int remove_all_intercept_timers(int epoll_fd, prov_intercept_conf_t *conf);
+
+int reset_intercept_timers(provision_state_t *state,
+ intercept_common_t *existing, char *target_info,
+ char *errorstring, int errorstrlen);
+
+#endif
diff --git a/src/provisioner/provisioner.c b/src/provisioner/provisioner.c
index 230711c4..1a513973 100644
--- a/src/provisioner/provisioner.c
+++ b/src/provisioner/provisioner.c
@@ -51,6 +51,7 @@
#include "openli_tls.h"
#include "provisioner_client.h"
#include "updateserver.h"
+#include "intercept_timers.h"
volatile int provisioner_halt = 0;
volatile int reload_config = 0;
@@ -71,6 +72,9 @@ static inline char *get_event_description(prov_epoll_ev_t *pev) {
if (pev->fdtype == PROV_EPOLL_UPDATE) return "updater";
if (pev->fdtype == PROV_EPOLL_MAIN_TIMER) return "main timer";
if (pev->fdtype == PROV_EPOLL_FD_IDLETIMER) return "client idle timer";
+ if (pev->fdtype == PROV_EPOLL_INTERCEPT_START)
+ return "intercept start timer";
+ if (pev->fdtype == PROV_EPOLL_INTERCEPT_HALT) return "intercept halt timer";
return "unknown";
}
@@ -1520,6 +1524,58 @@ static int process_signal(provision_state_t *state, int sigfd) {
return 0;
}
+static int send_intercept_hi1(provision_state_t *state, prov_epoll_ev_t *pev,
+ hi1_notify_t hi1type) {
+ ipintercept_t *ipint = NULL;
+ emailintercept_t *mailint = NULL;
+ voipintercept_t *vint = NULL;
+ intercept_common_t *common;
+ struct epoll_event ev;
+
+ char *target_info = NULL;
+
+ if (pev == NULL) {
+ return -1;
+ }
+
+ epoll_ctl(state->epoll_fd, EPOLL_CTL_DEL, pev->fd, &ev);
+ close(pev->fd);
+ pev->fd = -1;
+ if (pev->cept == NULL) {
+ return 0;
+ }
+
+ if (pev->cept->intercept_type == OPENLI_INTERCEPT_TYPE_EMAIL) {
+ mailint = (emailintercept_t *)(pev->cept->intercept_ref);
+ target_info = list_email_targets(mailint, 256);
+ common = &(mailint->common);
+ } else if (pev->cept->intercept_type == OPENLI_INTERCEPT_TYPE_VOIP) {
+ vint = (voipintercept_t *)(pev->cept->intercept_ref);
+ target_info = list_sip_targets(vint, 256);
+ common = &(vint->common);
+ } else if (pev->cept->intercept_type == OPENLI_INTERCEPT_TYPE_IP) {
+ ipint = (ipintercept_t *)(pev->cept->intercept_ref);
+ if (ipint->username) {
+ target_info = strdup(ipint->username);
+ }
+ common = &(ipint->common);
+ } else {
+ return -1;
+ }
+
+ if (announce_hi1_notification_to_mediators(state, common, target_info,
+ hi1type) < 0) {
+ logger(LOG_INFO, "OpenLI provisioner: unable to send HI1 notification for intercept %s (which has just %s).",
+ common->liid,
+ hi1type == HI1_LI_ACTIVATED ? "started" : "ended");
+ free(target_info);
+ return -1;
+ }
+
+ free(target_info);
+ return 1;
+}
+
static void remove_idle_client(provision_state_t *state, prov_epoll_ev_t *pev) {
prov_sock_state_t *cs = (prov_sock_state_t *)(pev->client->state);
@@ -1612,6 +1668,12 @@ static int check_epoll_fd(provision_state_t *state, struct epoll_event *ev) {
case PROV_EPOLL_MEDIATE_CONN:
ret = accept_mediator(state);
break;
+ case PROV_EPOLL_INTERCEPT_START:
+ ret = send_intercept_hi1(state, pev, HI1_LI_ACTIVATED);
+ break;
+ case PROV_EPOLL_INTERCEPT_HALT:
+ ret = send_intercept_hi1(state, pev, HI1_LI_DEACTIVATED);
+ break;
case PROV_EPOLL_MAIN_TIMER:
if (ev->events & EPOLLIN) {
return 1;
@@ -1906,6 +1968,12 @@ int main(int argc, char *argv[]) {
}
}
+ if ((ret = add_all_intercept_timers(provstate.epoll_fd,
+ &(provstate.interceptconf))) != 0) {
+ logger(LOG_INFO, "OpenLI: failed to create all start and end timers for configured intercepts. Exiting.");
+ return -1;
+ }
+
/*
* XXX could also sanity check intercept->mediator mappings too...
*/
@@ -1944,6 +2012,7 @@ int main(int argc, char *argv[]) {
run(&provstate);
+ remove_all_intercept_timers(provstate.epoll_fd, &(provstate.interceptconf));
clear_prov_state(&provstate);
if (daemonmode && pidfile) {
diff --git a/src/provisioner/provisioner.h b/src/provisioner/provisioner.h
index f1f56827..5e35427f 100644
--- a/src/provisioner/provisioner.h
+++ b/src/provisioner/provisioner.h
@@ -49,6 +49,7 @@ typedef int MHD_socket;
#endif
typedef struct prov_client prov_client_t;
+typedef struct prov_intercept_data prov_intercept_data_t;
/** Represents an event that has been added to the epoll event set */
typedef struct prov_epoll_ev {
@@ -62,6 +63,11 @@ typedef struct prov_epoll_ev {
* for some event types).
*/
prov_client_t *client;
+
+ /** A reference to the intercept that this fd belongs to (only used for
+ * some event types)
+ */
+ prov_intercept_data_t *cept;
} prov_epoll_ev_t;
@@ -98,6 +104,12 @@ enum {
/** Idle timeout for a client has expired */
PROV_EPOLL_FD_IDLETIMER,
+
+ /** Timer to fire when a delayed intercept begins */
+ PROV_EPOLL_INTERCEPT_START,
+
+ /** Timer to fire when an intercept is scheduled to cease */
+ PROV_EPOLL_INTERCEPT_HALT,
};
/** A LIID->agency mapping, used to ensure mediators route the intercept
@@ -229,6 +241,17 @@ typedef struct mediator_address {
UT_hash_handle hh;
} mediator_address_t;
+struct prov_intercept_data {
+ prov_epoll_ev_t *start_timer;
+ prov_epoll_ev_t *end_timer;
+
+ openli_intercept_types_t intercept_type;
+ void *intercept_ref;
+
+ uint8_t start_hi1_sent;
+ uint8_t end_hi1_sent;
+};
+
/** Global state for the provisioner instance */
typedef struct prov_state {
diff --git a/src/provisioner/updateserver_jsonparsing.c b/src/provisioner/updateserver_jsonparsing.c
index 8dc49da6..b62c4aa4 100644
--- a/src/provisioner/updateserver_jsonparsing.c
+++ b/src/provisioner/updateserver_jsonparsing.c
@@ -28,11 +28,13 @@
#include
#include
+#include
#include "provisioner.h"
#include "updateserver.h"
#include "logger.h"
#include "util.h"
+#include "intercept_timers.h"
struct json_agency {
struct json_object *hi3addr;
@@ -272,19 +274,28 @@ static inline void new_intercept_liidmapping(provision_state_t *state,
static int parse_intercept_common_json(struct json_intercept *jsonp,
intercept_common_t *common, const char *cepttype,
- update_con_info_t *cinfo, bool is_new) {
+ update_con_info_t *cinfo, bool is_new, int epoll_fd) {
int parseerr = 0;
char *encryptmethodstring = NULL;
+ struct timeval tv;
+ prov_intercept_data_t *timers = NULL;
if (is_new) {
common->tostart_time = 0;
common->toend_time = 0;
common->encrypt = OPENLI_PAYLOAD_ENCRYPTION_NONE;
+ timers = calloc(1, sizeof(prov_intercept_data_t));
+ timers->start_timer = NULL;
+ timers->end_timer = NULL;
+ timers->start_hi1_sent = 0;
+ timers->end_hi1_sent = 0;
+ common->local = timers;
} else {
common->tostart_time = (uint64_t)-1;
common->toend_time = (uint64_t)-1;
common->encrypt = OPENLI_PAYLOAD_ENCRYPTION_NOT_SPECIFIED;
+ common->local = NULL;
}
if (common->liid == NULL) {
@@ -334,6 +345,35 @@ static int parse_intercept_common_json(struct json_intercept *jsonp,
return -1;
}
}
+
+ /* If we are new, we can just go ahead and add any timers that
+ * we need for this intercept.
+ */
+ if (timers && (common->tostart_time > 0 || common->toend_time > 0)) {
+ gettimeofday(&tv, NULL);
+
+ if (common->tostart_time > 0 && common->toend_time > 0 &&
+ common->tostart_time >= common->toend_time) {
+ snprintf(cinfo->answerstring, 4096, "'starttime' parameter must be a timestamp BEFORE the 'endtime' timestamp");
+ return -1;
+ }
+
+ if (common->tostart_time > 0 && common->tostart_time > tv.tv_sec) {
+ if (add_intercept_timer(epoll_fd, common->tostart_time,
+ tv.tv_sec, timers, PROV_EPOLL_INTERCEPT_START) < 0) {
+ snprintf(cinfo->answerstring, 4096, "unable to create a 'intercept start' timer for intercept %s", common->liid);
+ return -1;
+ }
+
+ }
+ if (common->toend_time > 0 && common->toend_time > tv.tv_sec) {
+ if (add_intercept_timer(epoll_fd, common->toend_time,
+ tv.tv_sec, timers, PROV_EPOLL_INTERCEPT_HALT) < 0) {
+ snprintf(cinfo->answerstring, 4096, "unable to create a 'intercept end' timer for intercept %s", common->liid);
+ return -1;
+ }
+ }
+ }
}
@@ -345,9 +385,10 @@ static int parse_intercept_common_json(struct json_intercept *jsonp,
static int update_intercept_common(intercept_common_t *parsed,
intercept_common_t *existing, int *changed, int *agencychanged,
- provision_state_t *state, update_con_info_t *cinfo) {
+ int *timeschanged, provision_state_t *state, update_con_info_t *cinfo) {
payload_encryption_method_t enc;
+ prov_intercept_data_t *timers = (prov_intercept_data_t *)(existing->local);
/* Check if encryption options are valid -- if not, roll back without
* changing anything.
@@ -382,9 +423,9 @@ static int update_intercept_common(intercept_common_t *parsed,
if (*agencychanged) {
new_intercept_liidmapping(state, existing->targetagency,
existing->liid);
+ timers->start_hi1_sent = 0;
}
-
if (parsed->encrypt != existing->encrypt &&
parsed->encrypt != OPENLI_PAYLOAD_ENCRYPTION_NOT_SPECIFIED) {
*changed = 1;
@@ -393,7 +434,7 @@ static int update_intercept_common(intercept_common_t *parsed,
MODIFY_STRING_MEMBER(parsed->encryptkey, existing->encryptkey, changed);
if (compare_intercept_times(parsed, existing) == 1) {
- *changed = 1;
+ *timeschanged = 1;
}
return 0;
@@ -417,6 +458,7 @@ int remove_voip_intercept(update_con_info_t *cinfo, provision_state_t *state,
target_info = list_sip_targets(found, 256);
announce_hi1_notification_to_mediators(state, &(found->common),
target_info, HI1_LI_DEACTIVATED);
+ free_prov_intercept_data(&(found->common), state->epoll_fd);
free_single_voipintercept(found);
if (target_info) {
free(target_info);
@@ -447,6 +489,7 @@ int remove_email_intercept(update_con_info_t *cinfo, provision_state_t *state,
target_info = list_email_targets(found, 256);
announce_hi1_notification_to_mediators(state, &(found->common),
target_info, HI1_LI_DEACTIVATED);
+ free_prov_intercept_data(&(found->common), state->epoll_fd);
free_single_emailintercept(found);
if (target_info) {
free(target_info);
@@ -475,6 +518,7 @@ int remove_ip_intercept(update_con_info_t *cinfo, provision_state_t *state,
0);
announce_hi1_notification_to_mediators(state, &(found->common),
found->username, HI1_LI_DEACTIVATED);
+ free_prov_intercept_data(&(found->common), state->epoll_fd);
free_single_ipintercept(found);
logger(LOG_INFO,
"OpenLI: removed IP intercept '%s' via update socket.",
@@ -995,6 +1039,7 @@ int add_new_emailintercept(update_con_info_t *cinfo, provision_state_t *state) {
int parseerr = 0;
char *target_info;
char *delivcompressstring = NULL;
+ prov_intercept_data_t *timers = NULL;
INIT_JSON_INTERCEPT_PARSING
extract_intercept_json_objects(&emailjson, parsed);
@@ -1005,10 +1050,14 @@ int add_new_emailintercept(update_con_info_t *cinfo, provision_state_t *state) {
mailint->targets = NULL;
if (parse_intercept_common_json(&emailjson, &(mailint->common),
- "Email intercept", cinfo, true) < 0) {
+ "Email intercept", cinfo, true, state->epoll_fd) < 0) {
goto cepterr;
}
+ timers = (prov_intercept_data_t *)(mailint->common.local);
+ timers->intercept_type = OPENLI_INTERCEPT_TYPE_EMAIL;
+ timers->intercept_ref = (void *)mailint;
+
EXTRACT_JSON_STRING_PARAM("delivercompressed", "email intercept",
emailjson.delivercompressed, delivcompressstring, &parseerr, false);
@@ -1108,6 +1157,7 @@ int add_new_voipintercept(update_con_info_t *cinfo, provision_state_t *state) {
voipintercept_t *vint = NULL;
int r;
char *target_info;
+ prov_intercept_data_t *timers = NULL;
INIT_JSON_INTERCEPT_PARSING
extract_intercept_json_objects(&voipjson, parsed);
@@ -1125,9 +1175,12 @@ int add_new_voipintercept(update_con_info_t *cinfo, provision_state_t *state) {
}
if (parse_intercept_common_json(&voipjson, &(vint->common),
- "VOIP intercept", cinfo, true) < 0) {
+ "VOIP intercept", cinfo, true, state->epoll_fd) < 0) {
goto cepterr;
}
+ timers = (prov_intercept_data_t *)(vint->common.local);
+ timers->intercept_type = OPENLI_INTERCEPT_TYPE_VOIP;
+ timers->intercept_ref = (void *)vint;
r = 0;
if (voipjson.siptargets != NULL) {
@@ -1218,6 +1271,7 @@ int add_new_ipintercept(update_con_info_t *cinfo, provision_state_t *state) {
char *accessstring = NULL;
char *radiusidentstring = NULL;
ipintercept_t *ipint = NULL;
+ prov_intercept_data_t *timers = NULL;
INIT_JSON_INTERCEPT_PARSING
extract_intercept_json_objects(&ipjson, parsed);
@@ -1229,9 +1283,13 @@ int add_new_ipintercept(update_con_info_t *cinfo, provision_state_t *state) {
ipint->options = 0;
if (parse_intercept_common_json(&ipjson, &(ipint->common),
- "IP intercept", cinfo, true) < 0) {
+ "IP intercept", cinfo, true, state->epoll_fd) < 0) {
goto cepterr;
}
+ timers = (prov_intercept_data_t *)(ipint->common.local);
+ timers->intercept_type = OPENLI_INTERCEPT_TYPE_IP;
+ timers->intercept_ref = (void *)ipint;
+
EXTRACT_JSON_INT_PARAM("vendmirrorid", "IP intercept", ipjson.vendmirrorid,
ipint->vendmirrorid, &parseerr, false);
EXTRACT_JSON_STRING_PARAM("user", "IP intercept", ipjson.user,
@@ -1405,7 +1463,7 @@ int modify_emailintercept(update_con_info_t *cinfo, provision_state_t *state) {
char *delivcompressstring = NULL;
char *liidstr = NULL;
- int parseerr = 0, changed = 0, agencychanged = 0;
+ int parseerr = 0, changed = 0, agencychanged = 0, timeschanged = 0;
INIT_JSON_INTERCEPT_PARSING
extract_intercept_json_objects(&emailjson, parsed);
@@ -1435,12 +1493,12 @@ int modify_emailintercept(update_con_info_t *cinfo, provision_state_t *state) {
mailint->targets = NULL;
if (parse_intercept_common_json(&emailjson, &(mailint->common),
- "Email intercept", cinfo, false) < 0) {
+ "Email intercept", cinfo, false, state->epoll_fd) < 0) {
goto cepterr;
}
if (update_intercept_common(&(mailint->common), &(found->common),
- &changed, &agencychanged, state, cinfo) < 0) {
+ &changed, &agencychanged, ×changed, state, cinfo) < 0) {
goto cepterr;
}
@@ -1486,15 +1544,25 @@ int modify_emailintercept(update_con_info_t *cinfo, provision_state_t *state) {
changed = 1;
}
- if (changed) {
+ if ((changed || timeschanged) && !agencychanged) {
modify_existing_intercept_options(state, (void *)found,
OPENLI_PROTO_MODIFY_EMAILINTERCEPT);
}
- if (changedtargets) {
+ if (changedtargets || timeschanged || agencychanged) {
target_info = list_email_targets(found, 256);
- announce_hi1_notification_to_mediators(state, &(found->common),
- target_info, HI1_LI_MODIFIED);
+ if (agencychanged) {
+ announce_hi1_notification_to_mediators(state, &(found->common),
+ target_info, HI1_LI_ACTIVATED);
+ } else {
+ announce_hi1_notification_to_mediators(state, &(found->common),
+ target_info, HI1_LI_MODIFIED);
+ }
+ if (timeschanged) {
+ reset_intercept_timers(state, &(found->common),
+ target_info, cinfo->answerstring, 4096);
+ }
+
if (target_info) {
free(target_info);
}
@@ -1536,6 +1604,7 @@ int modify_voipintercept(update_con_info_t *cinfo, provision_state_t *state) {
char *liidstr = NULL, *target_info;
int changed = 0, agencychanged = 0, parseerr = 0;
+ int timeschanged = 0;
INIT_JSON_INTERCEPT_PARSING
extract_intercept_json_objects(&voipjson, parsed);
@@ -1565,12 +1634,12 @@ int modify_voipintercept(update_con_info_t *cinfo, provision_state_t *state) {
vint->targets = libtrace_list_init(sizeof(openli_sip_identity_t *));
if (parse_intercept_common_json(&voipjson, &(vint->common),
- "VOIP intercept", cinfo, false) < 0) {
+ "VOIP intercept", cinfo, false, state->epoll_fd) < 0) {
goto cepterr;
}
if (update_intercept_common(&(vint->common), &(found->common),
- &changed, &agencychanged, state, cinfo) < 0) {
+ &changed, &agencychanged, ×changed, state, cinfo) < 0) {
goto cepterr;
}
@@ -1597,15 +1666,26 @@ int modify_voipintercept(update_con_info_t *cinfo, provision_state_t *state) {
*
*/
- if (changed) {
+ if ((changed || timeschanged) && !agencychanged) {
modify_existing_intercept_options(state, (void *)found,
OPENLI_PROTO_MODIFY_VOIPINTERCEPT);
}
- if (changedtargets) {
+ if (changedtargets || timeschanged || agencychanged) {
target_info = list_sip_targets(found, 256);
- announce_hi1_notification_to_mediators(state, &(found->common),
- target_info, HI1_LI_MODIFIED);
+ if (agencychanged) {
+ announce_hi1_notification_to_mediators(state, &(found->common),
+ target_info, HI1_LI_ACTIVATED);
+ } else {
+ announce_hi1_notification_to_mediators(state, &(found->common),
+ target_info, HI1_LI_MODIFIED);
+ }
+
+ if (timeschanged) {
+ reset_intercept_timers(state, &(found->common), target_info,
+ cinfo->answerstring, 4096);
+ }
+
if (target_info) {
free(target_info);
}
@@ -1647,6 +1727,7 @@ int modify_ipintercept(update_con_info_t *cinfo, provision_state_t *state) {
char *accessstring = NULL;
char *radiusidentstring = NULL;
int parseerr = 0, changed = 0, agencychanged = 0;
+ int timeschanged = 0;
INIT_JSON_INTERCEPT_PARSING
extract_intercept_json_objects(&ipjson, parsed);
@@ -1677,12 +1758,12 @@ int modify_ipintercept(update_con_info_t *cinfo, provision_state_t *state) {
ipint->common.liid = liidstr;
if (parse_intercept_common_json(&ipjson, &(ipint->common),
- "IP intercept", cinfo, false) < 0) {
+ "IP intercept", cinfo, false, state->epoll_fd) < 0) {
goto cepterr;
}
if (update_intercept_common(&(ipint->common), &(found->common),
- &changed, &agencychanged, state, cinfo) < 0) {
+ &changed, &agencychanged, ×changed, state, cinfo) < 0) {
goto cepterr;
}
@@ -1780,13 +1861,17 @@ int modify_ipintercept(update_con_info_t *cinfo, provision_state_t *state) {
found->username, HI1_LI_ACTIVATED);
}
- if (changed) {
+ if (changed || timeschanged) {
modify_existing_intercept_options(state, (void *)found,
OPENLI_PROTO_MODIFY_IPINTERCEPT);
if (!agencychanged) {
announce_hi1_notification_to_mediators(state, &(found->common),
found->username, HI1_LI_MODIFIED);
}
+ if (timeschanged) {
+ reset_intercept_timers(state, &(found->common), found->username,
+ cinfo->answerstring, 4096);
+ }
}
logger(LOG_INFO,