Filter outbound TRP updates (compiles but not tested)
authorJennifer Richards <jennifer@painless-security.com>
Mon, 12 Jun 2017 22:03:26 +0000 (18:03 -0400)
committerJennifer Richards <jennifer@painless-security.com>
Mon, 12 Jun 2017 22:03:26 +0000 (18:03 -0400)
 * Add methods to count and remove inforecs from an update
 * Filter updates after collecting but before sending

include/trust_router/trp.h
trp/trp_upd.c
trp/trps.c

index 7e524af..1c8e193 100644 (file)
@@ -79,6 +79,8 @@ void trp_upd_free(TRP_UPD *update);
 TR_EXPORT TRP_INFOREC *trp_upd_get_inforec(TRP_UPD *upd);
 void trp_upd_set_inforec(TRP_UPD *upd, TRP_INFOREC *rec);
 void trp_upd_add_inforec(TRP_UPD *upd, TRP_INFOREC *rec);
+void trp_upd_remove_inforec(TRP_UPD *upd, TRP_INFOREC *rec);
+size_t trp_upd_num_inforecs(TRP_UPD *upd);
 TR_EXPORT TR_NAME *trp_upd_get_realm(TRP_UPD *upd);
 TR_NAME *trp_upd_dup_realm(TRP_UPD *upd);
 void trp_upd_set_realm(TRP_UPD *upd, TR_NAME *realm);
index 9e34dd0..9b39f2c 100644 (file)
@@ -678,6 +678,45 @@ void trp_upd_add_inforec(TRP_UPD *upd, TRP_INFOREC *rec)
   talloc_steal(upd, rec);
 }
 
+/**
+ * Removes and frees the selected inforec.
+ *
+ * @param upd Update to remove from
+ * @param rec Inforec to remove
+ */
+void trp_upd_remove_inforec(TRP_UPD *upd, TRP_INFOREC *rec)
+{
+  TRP_INFOREC *this=upd->records;
+
+  /* special case for the first element */
+  if (this==rec) {
+    upd->records=upd->records->next;
+    trp_inforec_free(this);
+    return;
+  }
+
+  while (this->next!=NULL) {
+    if (this->next==rec) {
+      this->next=this->next->next; /* this->next is not null */
+      trp_inforec_free(rec);
+    }
+    this=this->next;
+  }
+}
+
+size_t trp_upd_num_inforecs(TRP_UPD *upd)
+{
+  size_t count=0;
+  TRP_INFOREC *this=upd->records;
+
+  while (this != NULL) {
+    count++;
+    this=this->next;
+  }
+  return count;
+}
+
+
 TR_NAME *trp_upd_get_realm(TRP_UPD *upd)
 {
   return upd->realm;
index 6e7e56d..aef4b36 100644 (file)
@@ -1652,6 +1652,47 @@ cleanup:
   return rc;
 }
 
+/**
+ * Filter the inforecs in a single update
+ *
+ * @param filt The filter to apply
+ * @param upd The update to filter
+ */
+static void trps_filter_one_outbound_update(TR_FILTER *filt, TRP_UPD *upd)
+{
+  TRP_INFOREC *this=NULL, *next=NULL;
+  TR_FILTER_ACTION action=TR_FILTER_ACTION_REJECT;
+
+  for(this=trp_upd_get_inforec(upd); this!=NULL; this=next) {
+    next=this->next;
+    if ((TR_FILTER_NO_MATCH==tr_filter_apply(this, filt, NULL, &action))
+        || (action!=TR_FILTER_ACTION_ACCEPT)) {
+      /* Either no filter matched or one matched and rejected this record */
+      trp_upd_remove_inforec(upd, this); /* "this" is now invalid */
+    }
+  }
+}
+
+/**
+ * May shuffle the update list.
+ *
+ * @param filters The filter set for the relevant TRP peer
+ * @param updates GPtrArray of updates to filter
+ */
+static void trps_filter_outbound_updates(TR_FILTER_SET *filters, GPtrArray *updates)
+{
+  TRP_UPD *upd=NULL;
+  int ii=0;
+
+  /* walk backward through the array so we can remove elements */
+  for (ii=updates->len-1; ii>=0; ii--) {
+    upd=g_ptr_array_index(updates, ii);
+    trps_filter_one_outbound_update(tr_filter_set_get(filters, TR_FILTER_TYPE_TRP_OUTBOUND), upd);
+    /* see if we removed all the records from this update */
+    if (trp_upd_num_inforecs(upd)==0)
+      g_ptr_array_remove_index_fast(updates, ii); /* does not preserve order at index ii or higher */
+  }
+}
 
 /* helper for trps_update_one_peer. Frees the TRP_UPD pointed to by a GPtrArray element */
 static void trps_trp_upd_destroy(gpointer data)
@@ -1745,26 +1786,33 @@ static TRP_RC trps_update_one_peer(TRPS_INSTANCE *trps,
   if (updates->len<=0)
     tr_debug("trps_update_one_peer: no updates for %.*s", peer_label->len, peer_label->buf);
   else {
-    tr_debug("trps_update_one_peer: sending %d update messages.", updates->len);
-    for (ii=0; ii<updates->len; ii++) {
-      upd=(TRP_UPD *)g_ptr_array_index(updates, ii);
-      /* now encode the update message */
-      tr_msg_set_trp_upd(&msg, upd);
-      encoded=tr_msg_encode(&msg);
-      if (encoded==NULL) {
-        tr_err("trps_update_one_peer: error encoding update.");
-        rc=TRP_ERROR;
-        goto cleanup;
-      }
+    /* Apply outbound TRP filters for this peer */
+    trps_filter_outbound_updates(peer->filters, updates);
 
-      tr_debug("trps_update_one_peer: adding message to queue.");
-      if (trps_send_msg(trps, peer, encoded) != TRP_SUCCESS)
-        tr_err("trps_update_one_peer: error queueing update.");
-      else
-        tr_debug("trps_update_one_peer: update queued successfully.");
+    if (updates->len<=0)
+      tr_debug("trps_update_one_peer: no updates for %.*s after filtering.", peer_label->len, peer_label->buf);
+    else {
+      tr_debug("trps_update_one_peer: sending %d update messages.", updates->len);
+      for (ii=0; ii<updates->len; ii++) {
+        upd = (TRP_UPD *) g_ptr_array_index(updates, ii);
+        /* now encode the update message */
+        tr_msg_set_trp_upd(&msg, upd);
+        encoded = tr_msg_encode(&msg);
+        if (encoded == NULL) {
+          tr_err("trps_update_one_peer: error encoding update.");
+          rc = TRP_ERROR;
+          goto cleanup;
+        }
+
+        tr_debug("trps_update_one_peer: adding message to queue.");
+        if (trps_send_msg(trps, peer, encoded) != TRP_SUCCESS)
+          tr_err("trps_update_one_peer: error queueing update.");
+        else
+          tr_debug("trps_update_one_peer: update queued successfully.");
 
-      tr_msg_free_encoded(encoded);
-      encoded=NULL;
+        tr_msg_free_encoded(encoded);
+        encoded = NULL;
+      }
     }
   }