Send triggered updates (not really tested).
authorJennifer Richards <jennifer@painless-security.com>
Wed, 27 Jul 2016 16:18:14 +0000 (12:18 -0400)
committerJennifer Richards <jennifer@painless-security.com>
Wed, 27 Jul 2016 16:18:14 +0000 (12:18 -0400)
include/trp_internal.h
include/trp_rtable.h
tr/tr_main.c
tr/tr_trp.c
trp/trp_rtable.c
trp/trps.c

index 489aee5..6bb827e 100644 (file)
@@ -104,6 +104,10 @@ struct trps_instance {
   struct timeval sweep_interval; /* interval between route table sweeps */
 };
 
+typedef enum trp_update_type {
+  TRP_UPDATE_SCHEDULED=0,
+  TRP_UPDATE_TRIGGERED
+} TRP_UPDATE_TYPE;
 
 TRP_CONNECTION *trp_connection_new(TALLOC_CTX *mem_ctx);
 void trp_connection_free(TRP_CONNECTION *conn);
@@ -187,6 +191,6 @@ TRP_RC trps_sweep_routes(TRPS_INSTANCE *trps);
 TRP_RC trps_add_route(TRPS_INSTANCE *trps, TRP_RENTRY *route);
 TRP_RC trps_add_peer(TRPS_INSTANCE *trps, TRP_PEER *peer);
 TRP_PEER *trps_get_peer(TRPS_INSTANCE *trps, TR_NAME *gssname);
-TRP_RC trps_scheduled_update(TRPS_INSTANCE *trps);
+TRP_RC trps_update(TRPS_INSTANCE *trps, TRP_UPDATE_TYPE type);
 int trps_peer_connected(TRPS_INSTANCE *trps, TRP_PEER *peer);
 #endif /* TRP_INTERNAL_H */
index 36d6eb9..1dde034 100644 (file)
@@ -17,6 +17,7 @@ typedef struct trp_rentry {
   int selected;
   unsigned int interval; /* interval from route update */
   struct timespec *expiry;
+  int triggered;
 } TRP_RENTRY;
 
 typedef GHashTable TRP_RTABLE;
@@ -37,6 +38,7 @@ TRP_RENTRY **trp_rtable_get_realm_entries(TRP_RTABLE *rtbl, TR_NAME *apc, TR_NAM
 TR_NAME **trp_rtable_get_apc_realm_peers(TRP_RTABLE *rtbl, TR_NAME *apc, TR_NAME *realm, size_t *n_out);
 TRP_RENTRY *trp_rtable_get_entry(TRP_RTABLE *rtbl, TR_NAME *apc, TR_NAME *realm, TR_NAME *peer);
 TRP_RENTRY *trp_rtable_get_selected_entry(TRP_RTABLE *rtbl, TR_NAME *apc, TR_NAME *realm);
+void trp_rtable_clear_triggered(TRP_RTABLE *rtbl);
 char *trp_rtable_to_str(TALLOC_CTX *mem_ctx, TRP_RTABLE *rtbl, const char *sep, const char *lineterm);
 
 TRP_RENTRY *trp_rentry_new(TALLOC_CTX *mem_ctx);
@@ -64,6 +66,8 @@ void trp_rentry_set_interval(TRP_RENTRY *entry, int interval);
 int trp_rentry_get_interval(TRP_RENTRY *entry);
 void trp_rentry_set_expiry(TRP_RENTRY *entry, struct timespec *exp);
 struct timespec *trp_rentry_get_expiry(TRP_RENTRY *entry);
+void trp_rentry_set_triggered(TRP_RENTRY *entry, int trig);
+int trp_rentry_get_triggered(TRP_RENTRY *entry);
 char *trp_rentry_to_str(TALLOC_CTX *mem_ctx, TRP_RENTRY *entry, const char *sep);
 
 #endif /* _TRP_RTABLE_H_ */
index c2ccb40..f022fa7 100644 (file)
@@ -288,7 +288,7 @@ int main(int argc, char *argv[])
       return 1;
     }
     trp_peer_set_server(hc_peer, "epsilon.vmnet");
-    trp_peer_set_gssname(hc_peer, tr_new_name("trustrouter@apc.painless-security.com"));
+    trp_peer_set_gssname(hc_peer, tr_new_name("tr-epsilon-vmnet@apc.painless-security.com"));
     switch (tr->trps->port) {
     case 10000:
       trp_peer_set_port(hc_peer, 10001);
index 502c50d..91b9dd7 100644 (file)
@@ -233,7 +233,7 @@ static void tr_trps_update(int listener, short event, void *arg)
   struct event *ev=cookie->ev;
 
   tr_debug("tr_trps_update: sending scheduled route updates.");
-  trps_scheduled_update(trps);
+  trps_update(trps, TRP_UPDATE_SCHEDULED);
   event_add(ev, &(trps->update_interval));
 }
 
@@ -726,7 +726,8 @@ void tr_config_changed(TR_CFG *new_cfg, void *cookie)
   trps_set_sweep_interval(trps, new_cfg->internal->trp_sweep_interval);
   trps_clear_rtable(trps); /* should we do this every time??? */
   tr_add_local_routes(trps, new_cfg); /* should we do this every time??? */
-  trps_update_active_routes(trps);
+  trps_update_active_routes(trps); /* find new routes */
+  trps_update(trps, TRP_UPDATE_TRIGGERED); /* send any triggered routes */
   tr_trps_print_route_table(trps, stderr);
 }
 
index e69f2a2..7a519bb 100644 (file)
@@ -171,6 +171,16 @@ struct timespec *trp_rentry_get_expiry(TRP_RENTRY *entry)
   return entry->expiry;
 }
 
+void trp_rentry_set_triggered(TRP_RENTRY *entry, int trig)
+{
+  entry->triggered=trig;
+}
+
+int trp_rentry_get_triggered(TRP_RENTRY *entry)
+{
+  return entry->triggered;
+}
+
 
 /* result must be freed with g_free */
 static gchar *tr_name_to_g_str(const TR_NAME *n)
@@ -620,6 +630,19 @@ char *trp_rentry_to_str(TALLOC_CTX *mem_ctx, TRP_RENTRY *entry, const char *sep)
   return result;
 }
 
+void trp_rtable_clear_triggered(TRP_RTABLE *rtbl)
+{
+  size_t n_entries=0;
+  TRP_RENTRY **entries=trp_rtable_get_entries(rtbl, &n_entries);
+  size_t ii=0;
+
+  if (entries!=NULL) {
+    for (ii=0; ii<n_entries; ii++)
+      trp_rentry_set_triggered(entries[ii], 0);
+    talloc_free(entries);
+  }
+}
+
 static int sort_tr_names_cmp(const void *a, const void *b)
 {
   TR_NAME **n1=(TR_NAME **)a;
index 34528c4..03567dd 100644 (file)
@@ -672,8 +672,15 @@ TRP_RC trps_update_active_routes(TRPS_INSTANCE *trps)
       if (cur_route!=NULL) {
         cur_metric=trp_rentry_get_metric(cur_route);
         if ((best_metric < cur_metric) && (trp_metric_is_finite(best_metric))) {
+          /* The new route has a lower metric than the previous, and is finite. Accept. */
           trp_rentry_set_selected(cur_route, 0);
           trp_rentry_set_selected(best_route, 1);
+          /* Check whether we just changed trust routers for this destination. If so,
+           * we must send a triggered update. (We should probably try to avoid changing
+           * trust routers, perhaps accepting a slightly worse metric, but that is todo.) */
+          if (0!=tr_name_cmp(trp_rentry_get_trust_router(cur_route),
+                             trp_rentry_get_trust_router(best_route)))
+            trp_rentry_set_triggered(best_route, 1); /* need to send a triggered update for this route */
         } else if (!trp_metric_is_finite(cur_metric)) /* rejects infinite or invalid metrics */
           trp_rentry_set_selected(cur_route, 0);
       } else if (trp_metric_is_finite(best_metric))
@@ -699,6 +706,7 @@ TRP_RC trps_handle_tr_msg(TRPS_INSTANCE *trps, TR_MSG *tr_msg)
     rc=trps_handle_update(trps, tr_msg_get_trp_upd(tr_msg));
     if (rc==TRP_SUCCESS) {
       rc=trps_update_active_routes(trps);
+      trps_update(trps, TRP_UPDATE_TRIGGERED); /* send any triggered routes */
     }
     return rc;
 
@@ -789,8 +797,12 @@ static TRP_RENTRY *trps_select_realm_update(TRPS_INSTANCE *trps, TR_NAME *comm,
 
 /* returns an array of pointers to updates (*not* an array of updates). Returns number of entries
  * via n_update parameter. (The allocated space will generally be larger than required, see note in
- * the code.) */
-static TRP_RENTRY **trps_select_updates_for_peer(TALLOC_CTX *memctx, TRPS_INSTANCE *trps, TR_NAME *peer_gssname, size_t *n_update)
+ * the code.) If triggered is set, sends only triggered updates. */
+static TRP_RENTRY **trps_select_updates_for_peer(TALLOC_CTX *memctx,
+                                                 TRPS_INSTANCE *trps,
+                                                 TR_NAME *peer_gssname,
+                                                 int triggered,
+                                                 size_t *n_update)
 {
   size_t n_apc=0;
   TR_NAME **apc=trp_rtable_get_apcs(trps->rtable, &n_apc);
@@ -816,7 +828,9 @@ static TRP_RENTRY **trps_select_updates_for_peer(TALLOC_CTX *memctx, TRPS_INSTAN
     realm=trp_rtable_get_apc_realms(trps->rtable, apc[ii], &n_realm);
     for (jj=0; jj<n_realm; jj++) {
       best=trps_select_realm_update(trps, apc[ii], realm[jj], peer_gssname);
-      if (best!=NULL)
+      /* If we found a route, add it to the list. If triggered!=0, then only
+       * add triggered routes. */
+      if ((best!=NULL) && ((!triggered) || trp_rentry_get_triggered(best)))
         result[n_used++]=best;
     }
     if (realm!=NULL)
@@ -856,7 +870,7 @@ static TRP_INFOREC *trps_rentry_to_inforec(TALLOC_CTX *mem_ctx, TRPS_INSTANCE *t
   return rec;
 }
 
-TRP_RC trps_scheduled_update(TRPS_INSTANCE *trps)
+TRP_RC trps_update(TRPS_INSTANCE *trps, TRP_UPDATE_TYPE triggered)
 {
   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
   TRP_PTABLE_ITER *iter=trp_ptable_iter_new(tmp_ctx);
@@ -871,7 +885,7 @@ TRP_RC trps_scheduled_update(TRPS_INSTANCE *trps)
   TR_NAME *peer_gssname=NULL;
 
   if (iter==NULL) {
-    tr_err("trps_scheduled_update: failed to allocate peer table iterator.");
+    tr_err("trps_update: failed to allocate peer table iterator.");
     talloc_free(tmp_ctx);
     return TRP_NOMEM;
   }
@@ -882,22 +896,31 @@ TRP_RC trps_scheduled_update(TRPS_INSTANCE *trps)
   {
     peer_gssname=trp_peer_get_gssname(peer);
     if (!trps_peer_connected(trps, peer)) {
-      tr_debug("trps_scheduled_update: no TRP connection to %.*s, skipping.",
+      tr_debug("trps_update: no TRP connection to %.*s, skipping.",
                peer_gssname->len, peer_gssname->buf);
       continue;
     }
-    tr_debug("trps_scheduled_update: preparing scheduled route update for %.*s",
-             peer_gssname->len, peer_gssname->buf);
+    if (triggered==TRP_UPDATE_TRIGGERED) {
+      tr_debug("trps_update: preparing triggered route update for %.*s",
+               peer_gssname->len, peer_gssname->buf);
+    } else {
+      tr_debug("trps_update: preparing scheduled route update for %.*s",
+               peer_gssname->len, peer_gssname->buf);
+    }
     /* do not fill in peer, recipient does that */
-    update_list=trps_select_updates_for_peer(tmp_ctx, trps, peer_gssname, &n_updates);
+    update_list=trps_select_updates_for_peer(tmp_ctx,
+                                             trps,
+                                             peer_gssname,
+                                             triggered==TRP_UPDATE_TRIGGERED,
+                                            &n_updates);
     if ((n_updates>0) && (update_list!=NULL)) {
-      tr_debug("trps_scheduled_update: sending %u update records.", (unsigned int)n_updates);
+      tr_debug("trps_update: sending %u update records.", (unsigned int)n_updates);
       upd=trp_upd_new(tmp_ctx);
 
       for (ii=0; ii<n_updates; ii++) {
         rec=trps_rentry_to_inforec(tmp_ctx, trps, update_list[ii]);
         if (rec==NULL) {
-          tr_err("trps_scheduled_update: could not create all update records.");
+          tr_err("trps_update: could not create all update records.");
           rc=TRP_ERROR;
           goto cleanup;
         }
@@ -910,16 +933,16 @@ TRP_RC trps_scheduled_update(TRPS_INSTANCE *trps)
       tr_msg_set_trp_upd(&msg, upd);
       encoded=tr_msg_encode(&msg);
       if (encoded==NULL) {
-        tr_err("trps_scheduled_update: error encoding update.");
+        tr_err("trps_update: error encoding update.");
         rc=TRP_ERROR;
         goto cleanup;
       }
 
-      tr_debug("trps_scheduled_update: adding message to queue.");
+      tr_debug("trps_update: adding message to queue.");
       if (trps_send_msg(trps, peer, encoded) != TRP_SUCCESS)
-        tr_err("trps_scheduled_update: error queueing update.");
+        tr_err("trps_update: error queueing update.");
       else
-        tr_debug("trps_scheduled_update: update queued successfully.");
+        tr_debug("trps_update: update queued successfully.");
 
       encoded=NULL;
       tr_msg_free_encoded(encoded);
@@ -930,6 +953,7 @@ TRP_RC trps_scheduled_update(TRPS_INSTANCE *trps)
   
 cleanup:
   trp_ptable_iter_free(iter);
+  trp_rtable_clear_triggered(trps->rtable); /* don't re-send triggered updates */
   talloc_free(tmp_ctx);
   return rc;
 }