Browse Source

r9290@31-35-219: nickm | 2006-10-20 10:32:33 -0400
Add a GETINFO target so controllers can ask Tor for the current state of a router. (Results given in networkstatus format.)


svn:r8772

Nick Mathewson 19 years ago
parent
commit
e5f064c983
7 changed files with 126 additions and 4 deletions
  1. 2 0
      ChangeLog
  2. 7 2
      doc/TODO
  3. 12 0
      doc/control-spec.txt
  4. 3 0
      src/or/control.c
  5. 2 2
      src/or/dirserv.c
  6. 2 0
      src/or/or.h
  7. 98 0
      src/or/routerlist.c

+ 2 - 0
ChangeLog

@@ -20,6 +20,8 @@ Changes in version 0.1.2.3-alpha - 2006-10-??
       Perry)
     - Add a REMOTE_REASON field to CIRC events to tell the controller about
       why a remote OR told us to close a circuit.
+    - There's now a GETINFO ns/... field so that controllers can ask Tor
+      about the current state of a router.
 
   o Security bugfixes:
     - When the user sends a NEWNYM signal, clear the client-side DNS

+ 7 - 2
doc/TODO

@@ -30,7 +30,7 @@ N - Test guard unreachable logic; make sure that we actually attempt to
     connect to guards that we think are unreachable from time to time.
     Make sure that we don't freak out when the network is down.
 N - Stop recommending exits as guards?
-N - Clients stop dumping old descriptors if the network-statuses
+  o Clients stop dumping old descriptors if the network-statuses
     claim they're still valid.
 P - Figure out why dll's compiled in mingw don't work right in WinXP.
 P - Figure out why openssl 0.9.8d "make test" fails at sha256t test.
@@ -76,7 +76,12 @@ N - Simplify authority operation
     being a client.
     . Reduce resource load
 d     - Tolerate clock skew on bridge relays.
-N     - A way to examine router flags from controller.
+      o A way to examine router flags from controller.
+        o Specify: GETINFO ns/id/x, ns/name/x, ns/all.
+        o Implement
+N     - A way to alert controller when router flags change.
+        - Specify: SETEVENTS NS
+        - Implement
 d     - A way to adjust router flags from the controller
 d     - a way to pick entries based wholly on extend_info equivalent;
         a way to export extend_info equivalent.

+ 12 - 0
doc/control-spec.txt

@@ -349,6 +349,18 @@ $Id$
     "desc/id/<OR identity>" or "desc/name/<OR nickname>" -- the latest
       server descriptor for a given OR, NUL-terminated.
 
+    "ns/id/<OR identity>" or "desc/name/<OR nickname>" -- the latest network
+      status info for a given OR.  Network status info is as given in
+      dir-spec.txt, and reflects the current beliefs of this Tor about the
+      router in question. [First implemented in 0.1.2.3-alpha]  Like
+      directory clients, controllers MUST tolerate unrecognized flags and
+      lines.  The published date and descriptor digest are those believed to
+      be best by this Tor, not necessarily those for a descriptor that Tor
+      currently has.
+
+    "ns/all" -- Network status info for all ORs we have an opinion about,
+      joined by newlines. [First implemented in 0.1.2.3-alpha.]
+
     "desc/all-recent" -- the latest server descriptor for every router that
       Tor knows about.
 

+ 3 - 0
src/or/control.c

@@ -1437,6 +1437,7 @@ list_getinfo_options(void)
     "orconn-status Status of each current OR connection.\n"
     "stream-status Status of each current application stream.\n"
     "version The current version of Tor.\n");
+  // XXXX Uptodate!
 }
 
 /** Lookup the 'getinfo' entry <b>question</b>, and return
@@ -1493,6 +1494,8 @@ handle_getinfo_helper(control_connection_t *control_conn,
     *answer = smartlist_join_strings(sl, "", 0, NULL);
     SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
     smartlist_free(sl);
+  } else if (!strcmpstart(question, "ns/")) {
+    return networkstatus_getinfo_helper(question, answer);
   } else if (!strcmpstart(question, "unregistered-servers-")) {
     *answer = dirserver_getinfo_unregistered(question +
                                              strlen("unregistered-servers-"));

+ 2 - 2
src/or/dirserv.c

@@ -1334,8 +1334,8 @@ dirserv_compute_performance_thresholds(routerlist_t *rl)
 static cached_dir_t *
 generate_v2_networkstatus(void)
 {
-#define LONGEST_STATUS_FLAG_NAME_LEN 7
-#define N_STATUS_FLAGS 6
+#define LONGEST_STATUS_FLAG_NAME_LEN 9
+#define N_STATUS_FLAGS 9
 #define RS_ENTRY_LEN                                                    \
   ( /* first line */                                                    \
    MAX_NICKNAME_LEN+BASE64_DIGEST_LEN*2+ISO_TIME_LEN+INET_NTOA_BUF_LEN+ \

+ 2 - 0
src/or/or.h

@@ -2668,6 +2668,8 @@ void router_reset_status_download_failures(void);
 int router_differences_are_cosmetic(routerinfo_t *r1, routerinfo_t *r2);
 const char *esc_router_info(routerinfo_t *router);
 
+int networkstatus_getinfo_helper(const char *question, char **answer);
+
 /********************************* routerparse.c ************************/
 
 #define MAX_STATUS_TAG_LEN 32

+ 98 - 0
src/or/routerlist.c

@@ -4109,6 +4109,104 @@ router_differences_are_cosmetic(routerinfo_t *r1, routerinfo_t *r2)
   return 1;
 }
 
+/** Generate networkstatus lines for a single routerstatus_t object, and
+ * return the result in a newly allocated string.  Used only by controller
+ * interface (for now.) */
+/* XXXX This should eventually merge into generate_v2_networkstatus() */
+static char *
+networkstatus_getinfo_helper_single(routerstatus_t *rs)
+{
+  char buf[192];
+  int r;
+  struct in_addr in;
+
+  int f_authority;
+  char published[ISO_TIME_LEN+1];
+  char ipaddr[INET_NTOA_BUF_LEN];
+  char identity64[BASE64_DIGEST_LEN+1];
+  char digest64[BASE64_DIGEST_LEN+1];
+
+  format_iso_time(published, rs->published_on);
+  digest_to_base64(identity64, rs->identity_digest);
+  digest_to_base64(digest64, rs->descriptor_digest);
+  in.s_addr = htonl(rs->addr);
+  tor_inet_ntoa(&in, ipaddr, sizeof(ipaddr));
+
+  f_authority = router_digest_is_trusted_dir(rs->identity_digest);
+
+  r = tor_snprintf(buf, sizeof(buf),
+                   "r %s %s %s %s %s %d %d\n"
+                   "s%s%s%s%s%s%s%s%s%s%s\n",
+                   rs->nickname,
+                   identity64,
+                   digest64,
+                   published,
+                   ipaddr,
+                   (int)rs->or_port,
+                   (int)rs->dir_port,
+
+                   f_authority?" Authority":"",
+                   rs->is_bad_exit?" BadExit":"",
+                   rs->is_exit?" Exit":"",
+                   rs->is_fast?" Fast":"",
+                   rs->is_possible_guard?" Guard":"",
+                   rs->is_named?" Named":"",
+                   rs->is_stable?" Stable":"",
+                   rs->is_running?" Running":"",
+                   rs->is_valid?" Valid":"",
+                   rs->is_v2_dir?" V2Dir":"");
+  if (r<0)
+    log_warn(LD_BUG, "Not enough space in buffer.");
+
+  return tor_strdup(buf);
+}
+
+/** If <b>question</b> is a string beginning with "ns/" in a format the
+ * control interface expects for a GETINFO question, set *<b>answer</b> to a
+ * newly-allocated string containing networkstatus lines for the appropriate
+ * ORs.  Return 0 on success, -1 on failure. */
+int
+networkstatus_getinfo_helper(const char *question, char **answer)
+{
+  local_routerstatus_t *status;
+
+  if (!routerstatus_list) {
+    *answer = tor_strdup("");
+    return 0;
+  }
+
+  if (!strcmpstart(question, "ns/all")) {
+    smartlist_t *statuses = smartlist_create();
+    SMARTLIST_FOREACH(routerstatus_list, local_routerstatus_t *, lrs,
+      {
+        routerstatus_t *rs = &(lrs->status);
+        smartlist_add(statuses, networkstatus_getinfo_helper_single(rs));
+      });
+    *answer = smartlist_join_strings(statuses, "", 0, NULL);
+    SMARTLIST_FOREACH(statuses, char *, cp, tor_free(cp));
+    smartlist_free(statuses);
+    return 0;
+  } else if (!strcmpstart(question, "ns/id/")) {
+    char d[DIGEST_LEN];
+
+    if (base16_decode(d, DIGEST_LEN, question+6, strlen(question+6)))
+      return -1;
+    status = router_get_combined_status_by_digest(d);
+  } else if (!strcmpstart(question, "ns/name/")) {
+    status = router_get_combined_status_by_nickname(question+8, 0);
+  } else {
+    return -1;
+  }
+
+  if (status) {
+    *answer = networkstatus_getinfo_helper_single(&status->status);
+  } else {
+    *answer = tor_strdup("");
+  }
+  return 0;
+}
+
+/*DOCDOC*/
 static void
 routerlist_assert_ok(routerlist_t *rl)
 {