]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
Control: groud work for the HSFETCH command
authorDavid Goulet <dgoulet@ev0ke.net>
Thu, 19 Feb 2015 19:53:41 +0000 (14:53 -0500)
committerDavid Goulet <dgoulet@ev0ke.net>
Tue, 21 Apr 2015 18:15:02 +0000 (14:15 -0400)
This adds the command on the controller side that parses and validate
arguments but does nothing for now. The HS desriptor fetch must be
modularized a bit more before we can use the command.

See control-spec.txt section 3.26 for more information on this command.

Signed-off-by: David Goulet <dgoulet@ev0ke.net>
src/or/control.c

index d4216d2688f79ac51347c31e5dd97db5be37519d..1bc833371da57c552ede7ac5014d888ccd739d09 100644 (file)
@@ -157,6 +157,8 @@ static int handle_control_resolve(control_connection_t *conn, uint32_t len,
 static int handle_control_usefeature(control_connection_t *conn,
                                      uint32_t len,
                                      const char *body);
+static int handle_control_hsfetch(control_connection_t *conn, uint32_t len,
+                                  const char *body);
 static int write_stream_target_to_buf(entry_connection_t *conn, char *buf,
                                       size_t len);
 static void orconn_target_get_name(char *buf, size_t len,
@@ -3253,6 +3255,98 @@ handle_control_dropguards(control_connection_t *conn,
   return 0;
 }
 
+/** Implementation for the HSFETCH command. */
+static int
+handle_control_hsfetch(control_connection_t *conn, uint32_t len,
+                       const char *body)
+{
+  char digest[DIGEST_LEN], *hsaddress = NULL, *arg1 = NULL, *desc_id = NULL;
+  smartlist_t *args = NULL, *hsdirs = NULL;
+  (void) len; /* body is nul-terminated; it's safe to ignore the length */
+  static const char *v2_str = "v2-";
+  const size_t v2_str_len = strlen(v2_str);
+
+  /* Make sure we have at least one argument, the HSAddress. */
+  args = getargs_helper("HSFETCH", conn, body, 1, -1);
+  if (!args) {
+    goto done;
+  }
+
+  /* Extract the HS address that should NOT contain the .onion part. */
+  arg1 = smartlist_get(args, 0);
+  /* Remove the HS address from the argument list so we can safely iterate
+   * on all the rest to find optional argument(s). */
+  smartlist_del(args, 0);
+  /* Test if it's an HS address without the .onion part. */
+  if (strlen(arg1) == REND_SERVICE_ID_LEN_BASE32 &&
+      base32_decode(digest, sizeof(digest), arg1,
+                    REND_SERVICE_ID_LEN_BASE32) == 0) {
+    hsaddress = arg1;
+  } else if (strstr(arg1, v2_str) &&
+             strlen(arg1 + v2_str_len) == REND_DESC_ID_V2_LEN_BASE32 &&
+             base32_decode(digest, sizeof(digest), arg1 + v2_str_len,
+                           REND_DESC_ID_V2_LEN_BASE32) == 0) {
+    /* We have a well formed version 2 descriptor ID. */
+    desc_id = arg1 + v2_str_len;
+  } else {
+    connection_printf_to_buf(conn, "552 Unrecognized \"%s\"\r\n",
+                             arg1);
+    goto done;
+  }
+
+  /* Stores routerstatus_t object for each specified server. */
+  hsdirs = smartlist_new();
+
+  /* Skip first argument because it's the HSAddress. */
+  SMARTLIST_FOREACH_BEGIN(args, char *, arg) {
+    const node_t *node;
+    static const char *opt_server = "SERVER=";
+
+    if (!strcasecmpstart(arg, opt_server)) {
+      const char *server;
+
+      memset(digest, 0, sizeof(digest));
+      server = arg + strlen(opt_server);
+      /* Is the server fingerprint valid?. */
+      if (!string_is_hex(server) || strlen(server) != HEX_DIGEST_LEN ||
+          base16_decode(digest, sizeof(digest), server, HEX_DIGEST_LEN)) {
+        connection_printf_to_buf(conn, "552 Invalid fingerprint \"%s\"\r\n",
+                                 server);
+        goto done;
+      }
+      node = node_get_by_id(digest);
+      if (!node) {
+        connection_printf_to_buf(conn, "552 Server \"%s\" not found\r\n",
+                                 server);
+        goto done;
+      }
+      /* Valid server, add it to our local list. */
+      smartlist_add(hsdirs, node->rs);
+    } else {
+      connection_printf_to_buf(conn, "552 Unexpected argument \"%s\"\r\n",
+                               arg);
+      goto done;
+    }
+  } SMARTLIST_FOREACH_END(arg);
+
+  /* XXX: Actually trigger the fetch(es). */
+  (void) hsaddress;
+  (void) desc_id;
+  (void) hsdirs;
+
+  /* All good, thanks and come again! */
+  send_control_done(conn);
+
+done:
+  if (args) {
+    SMARTLIST_FOREACH(args, char *, cp, tor_free(cp));
+    smartlist_free(args);
+  }
+  tor_free(arg1);
+  smartlist_free(hsdirs);
+  return 0;
+}
+
 /** Called when <b>conn</b> has no more bytes left on its outbuf. */
 int
 connection_control_finished_flushing(control_connection_t *conn)
@@ -3550,6 +3644,9 @@ connection_control_process_inbuf(control_connection_t *conn)
   } else if (!strcasecmp(conn->incoming_cmd, "DROPGUARDS")) {
     if (handle_control_dropguards(conn, cmd_data_len, args))
       return -1;
+  } else if (!strcasecmp(conn->incoming_cmd, "HSFETCH")) {
+    if (handle_control_hsfetch(conn, cmd_data_len, args))
+      return -1;
   } else {
     connection_printf_to_buf(conn, "510 Unrecognized command \"%s\"\r\n",
                              conn->incoming_cmd);