[tor-commits] [tor/master] Add "+HSPOST" and related "HS_DESC" event flags to the controller.

nickm at torproject.org nickm at torproject.org
Mon May 4 15:52:30 UTC 2015


commit 841c4aa71505e9fea877f45223a0b01fade8a754
Author: Donncha O'Cearbhaill <donncha at donncha.is>
Date:   Sun Mar 22 13:31:53 2015 +0000

    Add "+HSPOST" and related "HS_DESC" event flags to the controller.
    
    "+HSPOST" and the related event changes allow the uploading of HS
    descriptors via the control port, and more comprehensive event
    monitoring of HS descriptor upload status.
---
 changes/feature3523  |    3 +
 src/or/control.c     |  198 ++++++++++++++++++++++++++++++++++++++++++++++++--
 src/or/control.h     |    9 +++
 src/or/directory.c   |    6 ++
 src/or/rendservice.c |   48 +++++++-----
 src/or/rendservice.h |    4 +
 6 files changed, 246 insertions(+), 22 deletions(-)

diff --git a/changes/feature3523 b/changes/feature3523
new file mode 100644
index 0000000..f11d1d3
--- /dev/null
+++ b/changes/feature3523
@@ -0,0 +1,3 @@
+  o Major features (controller):
+    - New HSPOST command to upload a hidden service descriptor. 
+      Closes ticket 3523. Patch by "DonnchaC".
diff --git a/src/or/control.c b/src/or/control.c
index 950e989..ead255f 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -36,17 +36,14 @@
 #include "networkstatus.h"
 #include "nodelist.h"
 #include "policies.h"
-#include "rendcommon.h"
-#include "rendservice.h"
 #include "reasons.h"
 #include "rendclient.h"
 #include "rendcommon.h"
+#include "rendservice.h"
 #include "rephist.h"
 #include "router.h"
 #include "routerlist.h"
 #include "routerparse.h"
-#include "rendclient.h"
-#include "rendcommon.h"
 
 #ifndef _WIN32
 #include <pwd.h>
@@ -170,6 +167,8 @@ static int handle_control_usefeature(control_connection_t *conn,
                                      const char *body);
 static int handle_control_hsfetch(control_connection_t *conn, uint32_t len,
                                   const char *body);
+static int handle_control_hspost(control_connection_t *conn, uint32_t len,
+                                 const char *body);
 static int handle_control_add_onion(control_connection_t *conn, uint32_t len,
                                     const char *body);
 static int handle_control_del_onion(control_connection_t *conn, uint32_t len,
@@ -3424,6 +3423,101 @@ handle_control_hsfetch(control_connection_t *conn, uint32_t len,
   return 0;
 }
 
+/** Implementation for the HSPOST command. */
+static int
+handle_control_hspost(control_connection_t *conn,
+                      uint32_t len,
+                      const char *body)
+{
+  static const char *opt_server = "SERVER=";
+  smartlist_t *args = smartlist_new();
+  smartlist_t *hs_dirs = NULL;
+  const char *encoded_desc = body;
+  size_t encoded_desc_len = len;
+
+  char *cp = memchr(body, '\n', len);
+  char *argline = tor_strndup(body, cp-body);
+
+  /* If any SERVER= options were specified, try parse the options line */
+  if (!strcasecmpstart(argline, opt_server)) {
+    /* encoded_desc begins after a newline character */
+    cp = cp + 1;
+    encoded_desc = cp;
+    encoded_desc_len = len-(cp-body);
+
+    smartlist_split_string(args, argline, " ",
+                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+    SMARTLIST_FOREACH_BEGIN(args, const char *, arg) {
+      if (!strcasecmpstart(arg, opt_server)) {
+        const char *server = arg + strlen(opt_server);
+        const node_t *node = node_get_by_hex_id(server);
+
+        if (!node) {
+          connection_printf_to_buf(conn, "552 Server \"%s\" not found\r\n",
+                                   server);
+          goto done;
+        }
+        if (!node->rs->is_hs_dir) {
+          connection_printf_to_buf(conn, "552 Server \"%s\" is not a HSDir"
+                                         "\r\n", server);
+          goto done;
+        }
+        /* Valid server, add it to our local list. */
+        if (!hs_dirs)
+          hs_dirs = smartlist_new();
+        smartlist_add(hs_dirs, node->rs);
+      } else {
+        connection_printf_to_buf(conn, "512 Unexpected argument \"%s\"\r\n",
+                                 arg);
+        goto done;
+      }
+    } SMARTLIST_FOREACH_END(arg);
+  }
+
+  /* Read the dot encoded descriptor, and parse it. */
+  rend_encoded_v2_service_descriptor_t *desc =
+      tor_malloc_zero(sizeof(rend_encoded_v2_service_descriptor_t));
+  read_escaped_data(encoded_desc, encoded_desc_len, &desc->desc_str);
+
+  rend_service_descriptor_t *parsed = NULL;
+  char *intro_content = NULL;
+  size_t intro_size;
+  size_t encoded_size;
+  const char *next_desc;
+  if (!rend_parse_v2_service_descriptor(&parsed, desc->desc_id, &intro_content,
+                                        &intro_size, &encoded_size,
+                                        &next_desc, desc->desc_str, 1)) {
+    /* Post the descriptor. */
+    char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
+    if (!rend_get_service_id(parsed->pk, serviceid)) {
+      smartlist_t *descs = smartlist_new();
+      smartlist_add(descs, desc);
+
+      /* We are about to trigger HS descriptor upload so send the OK now
+       * because after that 650 event(s) are possible so better to have the
+       * 250 OK before them to avoid out of order replies. */
+      send_control_done(conn);
+
+      /* Trigger the descriptor upload */
+      directory_post_to_hs_dir(parsed, descs, hs_dirs, serviceid, 0);
+      smartlist_free(descs);
+    }
+
+    rend_service_descriptor_free(parsed);
+  } else {
+    connection_printf_to_buf(conn, "554 Invalid descriptor\r\n");
+  }
+
+  tor_free(intro_content);
+  rend_encoded_v2_service_descriptor_free(desc);
+ done:
+  tor_free(argline);
+  smartlist_free(hs_dirs); /* Contents belong to the rend service code. */
+  SMARTLIST_FOREACH(args, char *, arg, tor_free(arg));
+  smartlist_free(args);
+  return 0;
+}
+
 /** Called when we get a ADD_ONION command; parse the body, and set up
  * the new ephemeral Onion Service. */
 static int
@@ -4075,6 +4169,9 @@ connection_control_process_inbuf(control_connection_t *conn)
   } else if (!strcasecmp(conn->incoming_cmd, "HSFETCH")) {
     if (handle_control_hsfetch(conn, cmd_data_len, args))
       return -1;
+  } else if (!strcasecmp(conn->incoming_cmd, "+HSPOST")) {
+    if (handle_control_hspost(conn, cmd_data_len, args))
+      return -1;
   } else if (!strcasecmp(conn->incoming_cmd, "ADD_ONION")) {
     int ret = handle_control_add_onion(conn, cmd_data_len, args);
     memwipe(args, 0, cmd_data_len); /* Scrub the private key. */
@@ -5802,6 +5899,31 @@ control_event_hs_descriptor_requested(const rend_data_t *rend_query,
                      desc_id_base32);
 }
 
+/** send HS_DESC upload event.
+ *
+ * <b>service_id</b> is the descriptor onion address.
+ * <b>hs_dir</b> is the description of contacting hs directory.
+ * <b>desc_id_base32</b> is the ID of requested hs descriptor.
+ */
+void
+control_event_hs_descriptor_upload(const char *service_id,
+                                   const char *id_digest,
+                                   const char *desc_id_base32)
+{
+  if (!service_id || !id_digest || !desc_id_base32) {
+    log_warn(LD_BUG, "Called with service_digest==%p, "
+             "desc_id_base32==%p, id_digest==%p", service_id,
+             desc_id_base32, id_digest);
+    return;
+  }
+
+  send_control_event(EVENT_HS_DESC, ALL_FORMATS,
+                     "650 HS_DESC UPLOAD %s UNKNOWN %s %s\r\n",
+                     service_id,
+                     node_describe_longname_by_id(id_digest),
+                     desc_id_base32);
+}
+
 /** send HS_DESC event after got response from hs directory.
  *
  * NOTE: this is an internal function used by following functions:
@@ -5840,9 +5962,43 @@ control_event_hs_descriptor_receive_end(const char *action,
   tor_free(reason_field);
 }
 
+/** send HS_DESC event after got response from hs directory.
+ *
+ * NOTE: this is an internal function used by following functions:
+ * control_event_hs_descriptor_uploaded
+ * control_event_hs_descriptor_upload_failed
+ *
+ * So do not call this function directly.
+ */
+void
+control_event_hs_descriptor_upload_end(const char *action,
+                                       const char *id_digest,
+                                       const char *reason)
+{
+  char *reason_field = NULL;
+
+  if (!action || !id_digest) {
+    log_warn(LD_BUG, "Called with action==%p, id_digest==%p", action,
+             id_digest);
+    return;
+  }
+
+  if (reason) {
+    tor_asprintf(&reason_field, " REASON=%s", reason);
+  }
+
+  send_control_event(EVENT_HS_DESC, ALL_FORMATS,
+                     "650 HS_DESC %s UNKNOWN UNKNOWN %s%s\r\n",
+                     action,
+                     node_describe_longname_by_id(id_digest),
+                     reason_field ? reason_field : "");
+
+  tor_free(reason_field);
+}
+
 /** send HS_DESC RECEIVED event
  *
- * called when a we successfully received a hidden service descriptor.
+ * called when we successfully received a hidden service descriptor.
  */
 void
 control_event_hs_descriptor_received(const char *onion_address,
@@ -5857,6 +6013,21 @@ control_event_hs_descriptor_received(const char *onion_address,
                                           auth_type, id_digest, NULL);
 }
 
+/** send HS_DESC UPLOADED event
+ *
+ * called when we successfully uploaded a hidden service descriptor.
+ */
+void
+control_event_hs_descriptor_uploaded(const char *id_digest)
+{
+  if (!id_digest) {
+    log_warn(LD_BUG, "Called with id_digest==%p",
+             id_digest);
+    return;
+  }
+  control_event_hs_descriptor_upload_end("UPLOADED", id_digest, NULL);
+}
+
 /** Send HS_DESC event to inform controller that query <b>rend_query</b>
  * failed to retrieve hidden service descriptor identified by
  * <b>id_digest</b>. If <b>reason</b> is not NULL, add it to REASON=
@@ -5909,6 +6080,23 @@ control_event_hs_descriptor_content(const char *onion_address,
   tor_free(esc_content);
 }
 
+/** Send HS_DESC event to inform controller upload of hidden service
+ * descriptor identified by <b>id_digest</b> failed. If <b>reason</b>
+ * is not NULL, add it to REASON= field.
+ */
+void
+control_event_hs_descriptor_upload_failed(const char *id_digest,
+                                          const char *reason)
+{
+  if (!id_digest) {
+    log_warn(LD_BUG, "Called with id_digest==%p",
+             id_digest);
+    return;
+  }
+  control_event_hs_descriptor_upload_end("UPLOAD_FAILED",
+                                         id_digest, reason);
+}
+
 /** Free any leftover allocated memory of the control.c subsystem. */
 void
 control_free_all(void)
diff --git a/src/or/control.h b/src/or/control.h
index cb0468f..644caf8 100644
--- a/src/or/control.h
+++ b/src/or/control.h
@@ -106,18 +106,27 @@ MOCK_DECL(const char *, node_describe_longname_by_id,(const char *id_digest));
 void control_event_hs_descriptor_requested(const rend_data_t *rend_query,
                                            const char *desc_id_base32,
                                            const char *hs_dir);
+void control_event_hs_descriptor_upload(const char *service_id,
+                                        const char *desc_id_base32,
+                                        const char *hs_dir);
 void control_event_hs_descriptor_receive_end(const char *action,
                                              const char *onion_address,
                                              rend_auth_type_t auth_type,
                                              const char *id_digest,
                                              const char *reason);
+void control_event_hs_descriptor_upload_end(const char *action,
+                                            const char *hs_dir,
+                                            const char *reason);
 void control_event_hs_descriptor_received(const char *onion_address,
                                           rend_auth_type_t auth_type,
                                           const char *id_digest);
+void control_event_hs_descriptor_uploaded(const char *hs_dir);
 void control_event_hs_descriptor_failed(const char *onion_address,
                                         rend_auth_type_t auth_type,
                                         const char *id_digest,
                                         const char *reason);
+void control_event_hs_descriptor_upload_failed(const char *hs_dir,
+                                               const char *reason);
 void control_event_hs_descriptor_content(const char *onion_address,
                                          const char *desc_id,
                                          const char *hsdir_fp,
diff --git a/src/or/directory.c b/src/or/directory.c
index bad1f62..85da97f 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -2185,6 +2185,9 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
   }
 
   if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2) {
+    #define SEND_HS_DESC_UPLOAD_FAILED_EVENT(reason) ( \
+      control_event_hs_descriptor_upload_failed(conn->identity_digest, \
+                                                reason) )
     log_info(LD_REND,"Uploaded rendezvous descriptor (status %d "
              "(%s))",
              status_code, escaped(reason));
@@ -2193,17 +2196,20 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
         log_info(LD_REND,
                  "Uploading rendezvous descriptor: finished with status "
                  "200 (%s)", escaped(reason));
+        control_event_hs_descriptor_uploaded(conn->identity_digest);
         break;
       case 400:
         log_warn(LD_REND,"http status 400 (%s) response from dirserver "
                  "'%s:%d'. Malformed rendezvous descriptor?",
                  escaped(reason), conn->base_.address, conn->base_.port);
+        SEND_HS_DESC_UPLOAD_FAILED_EVENT("UPLOAD_REJECTED");
         break;
       default:
         log_warn(LD_REND,"http status %d (%s) response unexpected (server "
                  "'%s:%d').",
                  status_code, escaped(reason), conn->base_.address,
                  conn->base_.port);
+        SEND_HS_DESC_UPLOAD_FAILED_EVENT("UNEXPECTED");
         break;
     }
   }
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index eb94202..7cfbcf1 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -15,6 +15,7 @@
 #include "circuitlist.h"
 #include "circuituse.h"
 #include "config.h"
+#include "control.h"
 #include "directory.h"
 #include "main.h"
 #include "networkstatus.h"
@@ -3098,14 +3099,16 @@ find_intro_point(origin_circuit_t *circ)
   return NULL;
 }
 
-/** Determine the responsible hidden service directories for the
- * rend_encoded_v2_service_descriptor_t's in <b>descs</b> and upload them;
- * <b>service_id</b> and <b>seconds_valid</b> are only passed for logging
- * purposes. */
-static void
+/** Upload the rend_encoded_v2_service_descriptor_t's in <b>descs</b>
+ * associated with the rend_service_descriptor_t <b>renddesc</b> to
+ * the responsible hidden service directories OR the hidden service
+ * directories specified by <b>hs_dirs</b>; <b>service_id</b> and
+ * <b>seconds_valid</b> are only passed for logging purposes.
+ */
+void
 directory_post_to_hs_dir(rend_service_descriptor_t *renddesc,
-                         smartlist_t *descs, const char *service_id,
-                         int seconds_valid)
+                         smartlist_t *descs, smartlist_t *hs_dirs,
+                         const char *service_id, int seconds_valid)
 {
   int i, j, failed_upload = 0;
   smartlist_t *responsible_dirs = smartlist_new();
@@ -3113,14 +3116,21 @@ directory_post_to_hs_dir(rend_service_descriptor_t *renddesc,
   routerstatus_t *hs_dir;
   for (i = 0; i < smartlist_len(descs); i++) {
     rend_encoded_v2_service_descriptor_t *desc = smartlist_get(descs, i);
-    /* Determine responsible dirs. */
-    if (hid_serv_get_responsible_directories(responsible_dirs,
-                                             desc->desc_id) < 0) {
-      log_warn(LD_REND, "Could not determine the responsible hidden service "
-                        "directories to post descriptors to.");
-      smartlist_free(responsible_dirs);
-      smartlist_free(successful_uploads);
-      return;
+    /** If any HSDirs are specified, they should be used instead of
+     *  the responsible directories */
+    if (hs_dirs && smartlist_len(hs_dirs) > 0) {
+      smartlist_add_all(responsible_dirs, hs_dirs);
+    } else {
+      /* Determine responsible dirs. */
+      if (hid_serv_get_responsible_directories(responsible_dirs,
+                                               desc->desc_id) < 0) {
+        log_warn(LD_REND, "Could not determine the responsible hidden service "
+                          "directories to post descriptors to.");
+        control_event_hs_descriptor_upload(service_id,
+                                           "UNKNOWN",
+                                           "UNKNOWN");
+        goto done;
+      }
     }
     for (j = 0; j < smartlist_len(responsible_dirs); j++) {
       char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
@@ -3160,6 +3170,9 @@ directory_post_to_hs_dir(rend_service_descriptor_t *renddesc,
                hs_dir->nickname,
                hs_dir_ip,
                hs_dir->or_port);
+      control_event_hs_descriptor_upload(service_id,
+                                         hs_dir->identity_digest,
+                                         desc_id_base32);
       tor_free(hs_dir_ip);
       /* Remember successful upload to this router for next time. */
       if (!smartlist_contains_digest(successful_uploads,
@@ -3187,6 +3200,7 @@ directory_post_to_hs_dir(rend_service_descriptor_t *renddesc,
       }
     });
   }
+ done:
   smartlist_free(responsible_dirs);
   smartlist_free(successful_uploads);
 }
@@ -3251,7 +3265,7 @@ upload_service_descriptor(rend_service_t *service)
         rend_get_service_id(service->desc->pk, serviceid);
         log_info(LD_REND, "Launching upload for hidden service %s",
                      serviceid);
-        directory_post_to_hs_dir(service->desc, descs, serviceid,
+        directory_post_to_hs_dir(service->desc, descs, NULL, serviceid,
                                  seconds_valid);
         /* Free memory for descriptors. */
         for (i = 0; i < smartlist_len(descs); i++)
@@ -3280,7 +3294,7 @@ upload_service_descriptor(rend_service_t *service)
             smartlist_free(client_cookies);
             return;
           }
-          directory_post_to_hs_dir(service->desc, descs, serviceid,
+          directory_post_to_hs_dir(service->desc, descs, NULL, serviceid,
                                    seconds_valid);
           /* Free memory for descriptors. */
           for (i = 0; i < smartlist_len(descs); i++)
diff --git a/src/or/rendservice.h b/src/or/rendservice.h
index 6d0973b..ec783d5 100644
--- a/src/or/rendservice.h
+++ b/src/or/rendservice.h
@@ -120,5 +120,9 @@ rend_service_add_ephemeral_status_t rend_service_add_ephemeral(crypto_pk_t *pk,
                                char **service_id_out);
 int rend_service_del_ephemeral(const char *service_id);
 
+void directory_post_to_hs_dir(rend_service_descriptor_t *renddesc,
+                              smartlist_t *descs, smartlist_t *hs_dirs,
+                              const char *service_id, int seconds_valid);
+
 #endif
 





More information about the tor-commits mailing list