Browse Source

Implement hidserv_XX functions; there is still an XXX in directory_handle_command

svn:r1404
Nick Mathewson 21 years ago
parent
commit
b32440a028
7 changed files with 142 additions and 18 deletions
  1. 4 4
      doc/TODO
  2. 1 1
      doc/rend-spec.txt
  3. 1 1
      src/common/util.c
  4. 9 11
      src/or/directory.c
  5. 3 0
      src/or/main.c
  6. 6 0
      src/or/or.h
  7. 118 1
      src/or/rendcommon.c

+ 4 - 4
doc/TODO

@@ -103,19 +103,19 @@ Rendezvous service:
                 o Joined to another circuit at the rendezvous point.
               (We should also enumerate all the states that these operations
               can be in.) [NM]
-            o Add circuit metadata [NM] 3 hours
+            o Add circuit metadata [NM]
         - Code to configure hidden services [NM] 4 hours
         . Service descriptors
             - OPs need to maintain identity keys for hidden services [NM] 1 hour
-            o Code to generate and parse service descriptors [NM] 4 hours
+            o Code to generate and parse service descriptors [NM]
         - Advertisement
-            . Generate y.onion hostnames [NM] 1 hour
+            o Generate y.onion hostnames [NM]
             - Code to do an HTTP connection over Tor from within Tor [RD]
             - Publish service descriptors to directory [RD]
             - Directory accepts and remembers service descriptors, and
               delivers them as requested
                 - Frontend [RD]
-                - Backend [NM] 1 hour
+                o Backend [NM]
             - Code for OPs to retrieve (and cache?) service descriptors [RD]
         - Rendezvous
             - Code as needed to generate and parse all rendezvous-related

+ 1 - 1
doc/rend-spec.txt

@@ -186,7 +186,7 @@ Tor Rendezvous Spec
 1.6. Alice's OP retrieves a service descriptor
 
    Alice opens a stream to a directory server via Tor, and makes an HTTP GET
-   request for the document '/rendevous/<y>', where '<y> is replaced with the
+   request for the document '/hidserv/<y>', where '<y> is replaced with the
    encoding of Bob's public key as described above.  The directory replies
    with a 404 HTTP response if it does not recognize <y>, and otherwise
    returns Bob's most recently uploaded service descriptor.

+ 1 - 1
src/common/util.c

@@ -380,7 +380,7 @@ void strmap_foreach(strmap_t *map,
  *
  * // uppercase values in "map", removing empty values.
  *
- * strmap_iterator_t *iter;
+ * strmap_iter_t *iter;
  * const char *key;
  * void *val;
  * char *cp;

+ 9 - 11
src/or/directory.c

@@ -288,11 +288,6 @@ int connection_dir_process_inbuf(connection_t *conn) {
   return 0;
 }
 
-/* XXX stubs, probably shouldn't be located here */
-#define MAX_HIDSERV_DESC_SIZE 2048
-int hidserv_lookup(char *query, char *desc, int max_desc_size) { return 0; }
-int hidserv_store(char *desc) { return 0; }
-
 static char answer200[] = "HTTP/1.0 200 OK\r\n\r\n";
 static char answer400[] = "HTTP/1.0 400 Bad request\r\n\r\n";
 static char answer403[] = "HTTP/1.0 403 Unapproved server\r\n\r\n";
@@ -331,12 +326,13 @@ static int directory_handle_command_get(connection_t *conn,
   }
 
   if(!strncmp(url,"/hidserv/",9)) { /* hidserv descriptor fetch */
-    char desc[MAX_HIDSERV_DESC_SIZE];
+    const char *descp;
+    int desc_len;
 
-    switch(hidserv_lookup(url+9, desc, MAX_HIDSERV_DESC_SIZE)) {
+    switch(hidserv_lookup(url+9, &descp, &desc_len)) {
       case 1: /* valid */
         connection_write_to_buf(answer200, strlen(answer200), conn);
-        connection_write_to_buf(desc, strlen(desc)+1, conn);
+        connection_write_to_buf(descp, desc_len, conn); /* XXXX Contains NULs*/
         break;
       case 0: /* well-formed but not present */
         connection_write_to_buf(answer404, strlen(answer404), conn);
@@ -355,7 +351,8 @@ static int directory_handle_command_get(connection_t *conn,
 
 /* always returns 0 */
 static int directory_handle_command_post(connection_t *conn,
-                                         char *headers, char *body) {
+                                         char *headers, char *body,
+                                         int body_len) {
   const char *cp;
   char *url;
 
@@ -387,7 +384,7 @@ static int directory_handle_command_post(connection_t *conn,
   }
 
   if(!strncmp(url,"/hidserv/",9)) { /* hidserv descriptor post */
-    if(hidserv_store(body) < 0)
+    if(hidserv_store(body, body_len) < 0)
       connection_write_to_buf(answer400, strlen(answer400), conn);
     else
       connection_write_to_buf(answer200, strlen(answer200), conn);
@@ -420,7 +417,8 @@ static int directory_handle_command(connection_t *conn) {
   if(!strncasecmp(headers,"GET",3))
     r = directory_handle_command_get(conn, headers, body);
   else if (!strncasecmp(headers,"POST",4))
-    r = directory_handle_command_post(conn, headers, body);
+    /* XXXX this takes a length now, and will fail if the body has NULs. */
+    r = directory_handle_command_post(conn, headers, body, strlen(body));
   else {
     log_fn(LOG_WARN,"Got headers '%s' with unknown command. Closing.", headers);
     r = -1;

+ 3 - 0
src/or/main.c

@@ -334,6 +334,7 @@ static void run_scheduled_events(time_t now) {
       /* We're a directory; dump any old descriptors. */
       dirserv_remove_old_servers();
     }
+    hidserv_cache_clean(); /* should this go elsewhere? */
     time_to_fetch_directory = now + options.DirFetchPostPeriod;
   }
 
@@ -547,6 +548,8 @@ static int do_main_loop(void) {
 
   /* Initialize the history structures. */
   rep_hist_init();
+  /* Intialize the service cache. */
+  hidserv_cache_init();
 
   /* load the private keys, if we're supposed to have them, and set up the
    * TLS context. */

+ 6 - 0
src/or/or.h

@@ -985,6 +985,12 @@ int rend_encode_service_descriptor(rend_service_descriptor_t *desc,
                                    char **str_out,
                                    int *len_out);
 rend_service_descriptor_t *rend_parse_service_descriptor(const char *str, int len);
+int rend_get_service_id(crypto_pk_env_t *pk, char *out);
+
+void hidserv_cache_init(void);
+void hidserv_cache_clean(void);
+int hidserv_lookup(char *query, const char **desc, int *desc_len);
+int hidserv_store(char *desc, int desc_len);
 
 #endif
 

+ 118 - 1
src/or/rendcommon.c

@@ -67,7 +67,6 @@ rend_encode_service_descriptor(rend_service_descriptor_t *desc,
   return 0;
 }
 
-
 rend_service_descriptor_t *rend_parse_service_descriptor(
 				       const char *str, int len)
 {
@@ -128,3 +127,121 @@ rend_service_descriptor_t *rend_parse_service_descriptor(
   return NULL;
 }
 
+int rend_get_service_id(crypto_pk_env_t *pk, char *out)
+{
+  char buf[CRYPTO_SHA1_DIGEST_LEN];
+  assert(pk);
+  if (crypto_pk_get_digest(pk, buf) < 0)
+    return -1;
+  if (base32_encode(out, REND_SERVICE_ID_LEN+1, buf, 10) < 0)
+    return -1;
+  return 0;
+}
+
+/* ==== Hidden service descriptor cache. */
+#define HIDSERV_MAX_AGE 24*60*60
+#define HIDSERV_MAX_SKEW 60*60
+
+typedef struct hidserv_cache_entry_t {
+  int len;
+  char *desc;
+  rend_service_descriptor_t *parsed;
+} hidserv_cache_entry_t;
+
+static strmap_t *hidserv_cache = NULL;
+
+void hidserv_cache_init(void)
+{
+  hidserv_cache = strmap_new();
+}
+
+void hidserv_cache_clean(void)
+{
+  strmap_iter_t *iter;
+  const char *key;
+  void *val;
+  hidserv_cache_entry_t *ent;
+  time_t cutoff;
+  cutoff = time(NULL) - HIDSERV_MAX_AGE;
+  for (iter = strmap_iter_init(hidserv_cache); !strmap_iter_done(iter); ) {
+    strmap_iter_get(iter, &key, &val);
+    ent = (hidserv_cache_entry_t*)val;
+    if (ent->parsed->timestamp < cutoff) {
+      iter = strmap_iter_next_rmv(hidserv_cache, iter);
+      rend_service_descriptor_free(ent->parsed);
+      tor_free(ent->desc);
+      tor_free(ent);
+    } else {
+      iter = strmap_iter_next(hidserv_cache, iter);
+    }
+  }
+}
+
+int hidserv_lookup(char *query, const char **desc, int *desc_len)
+{
+  hidserv_cache_entry_t *e;
+  assert(hidserv_cache);
+  if (strlen(query) != REND_SERVICE_ID_LEN)
+    return -1; /* XXXX also check for bad chars. */
+  e = (hidserv_cache_entry_t*) strmap_get_lc(hidserv_cache, query);
+  if (!e)
+    return 0;
+  *desc = e->desc;
+  *desc_len = e->len;
+  return 1;
+}
+
+int hidserv_store(char *desc, int desc_len)
+{
+  hidserv_cache_entry_t *e;
+  rend_service_descriptor_t *parsed;
+  char query[REND_SERVICE_ID_LEN+1];
+  time_t now;
+  assert(hidserv_cache);
+  parsed = rend_parse_service_descriptor(desc,desc_len);
+  if (!parsed) {
+    log_fn(LOG_WARN,"Couldn't parse service descriptor");
+    return -1;
+  }
+  if (rend_get_service_id(parsed->pk, query)<0) {
+    log_fn(LOG_WARN,"Couldn't compute service ID");
+    rend_service_descriptor_free(parsed);
+    return -1;
+  }
+  now = time(NULL);
+  if (parsed->timestamp < now-HIDSERV_MAX_AGE) {
+    log_fn(LOG_WARN,"Service descriptor is too old");
+    rend_service_descriptor_free(parsed);
+    return -1;
+  }
+  if (parsed->timestamp > now+HIDSERV_MAX_SKEW) {
+    log_fn(LOG_WARN,"Service descriptor is too far in the future");
+    rend_service_descriptor_free(parsed);
+    return -1;
+  }
+  e = (hidserv_cache_entry_t*) strmap_get_lc(hidserv_cache, query);
+  if (e && e->parsed->timestamp > parsed->timestamp) {
+    log_fn(LOG_WARN,"We already have a newer service descriptor with the same ID");
+    rend_service_descriptor_free(parsed);
+    return -1;
+  }
+  if (e && e->len == desc_len && !memcmp(desc,e->desc,desc_len)) {
+    log_fn(LOG_WARN,"We already have this service descriptor");
+    rend_service_descriptor_free(parsed);
+    return -1;
+  }
+  if (!e) {
+    e = tor_malloc_zero(sizeof(hidserv_cache_entry_t));
+    strmap_set_lc(hidserv_cache, query, e);
+  } else {
+    rend_service_descriptor_free(e->parsed);
+    tor_free(e->desc);
+  }
+  e->parsed = parsed;
+  e->len = desc_len;
+  e->desc = tor_strdup(desc);
+
+  return 0;
+}
+
+