Pārlūkot izejas kodu

Implement hidserv_XX functions; there is still an XXX in directory_handle_command

svn:r1404
Nick Mathewson 21 gadi atpakaļ
vecāks
revīzija
b32440a028
7 mainītis faili ar 142 papildinājumiem un 18 dzēšanām
  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.
                 o Joined to another circuit at the rendezvous point.
               (We should also enumerate all the states that these operations
               (We should also enumerate all the states that these operations
               can be in.) [NM]
               can be in.) [NM]
-            o Add circuit metadata [NM] 3 hours
+            o Add circuit metadata [NM]
         - Code to configure hidden services [NM] 4 hours
         - Code to configure hidden services [NM] 4 hours
         . Service descriptors
         . Service descriptors
             - OPs need to maintain identity keys for hidden services [NM] 1 hour
             - 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
         - 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]
             - Code to do an HTTP connection over Tor from within Tor [RD]
             - Publish service descriptors to directory [RD]
             - Publish service descriptors to directory [RD]
             - Directory accepts and remembers service descriptors, and
             - Directory accepts and remembers service descriptors, and
               delivers them as requested
               delivers them as requested
                 - Frontend [RD]
                 - Frontend [RD]
-                - Backend [NM] 1 hour
+                o Backend [NM]
             - Code for OPs to retrieve (and cache?) service descriptors [RD]
             - Code for OPs to retrieve (and cache?) service descriptors [RD]
         - Rendezvous
         - Rendezvous
             - Code as needed to generate and parse all rendezvous-related
             - 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
 1.6. Alice's OP retrieves a service descriptor
 
 
    Alice opens a stream to a directory server via Tor, and makes an HTTP GET
    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
    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
    with a 404 HTTP response if it does not recognize <y>, and otherwise
    returns Bob's most recently uploaded service descriptor.
    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.
  * // uppercase values in "map", removing empty values.
  *
  *
- * strmap_iterator_t *iter;
+ * strmap_iter_t *iter;
  * const char *key;
  * const char *key;
  * void *val;
  * void *val;
  * char *cp;
  * char *cp;

+ 9 - 11
src/or/directory.c

@@ -288,11 +288,6 @@ int connection_dir_process_inbuf(connection_t *conn) {
   return 0;
   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 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 answer400[] = "HTTP/1.0 400 Bad request\r\n\r\n";
 static char answer403[] = "HTTP/1.0 403 Unapproved server\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 */
   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 */
       case 1: /* valid */
         connection_write_to_buf(answer200, strlen(answer200), conn);
         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;
         break;
       case 0: /* well-formed but not present */
       case 0: /* well-formed but not present */
         connection_write_to_buf(answer404, strlen(answer404), conn);
         connection_write_to_buf(answer404, strlen(answer404), conn);
@@ -355,7 +351,8 @@ static int directory_handle_command_get(connection_t *conn,
 
 
 /* always returns 0 */
 /* always returns 0 */
 static int directory_handle_command_post(connection_t *conn,
 static int directory_handle_command_post(connection_t *conn,
-                                         char *headers, char *body) {
+                                         char *headers, char *body,
+                                         int body_len) {
   const char *cp;
   const char *cp;
   char *url;
   char *url;
 
 
@@ -387,7 +384,7 @@ static int directory_handle_command_post(connection_t *conn,
   }
   }
 
 
   if(!strncmp(url,"/hidserv/",9)) { /* hidserv descriptor post */
   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);
       connection_write_to_buf(answer400, strlen(answer400), conn);
     else
     else
       connection_write_to_buf(answer200, strlen(answer200), conn);
       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))
   if(!strncasecmp(headers,"GET",3))
     r = directory_handle_command_get(conn, headers, body);
     r = directory_handle_command_get(conn, headers, body);
   else if (!strncasecmp(headers,"POST",4))
   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 {
   else {
     log_fn(LOG_WARN,"Got headers '%s' with unknown command. Closing.", headers);
     log_fn(LOG_WARN,"Got headers '%s' with unknown command. Closing.", headers);
     r = -1;
     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. */
       /* We're a directory; dump any old descriptors. */
       dirserv_remove_old_servers();
       dirserv_remove_old_servers();
     }
     }
+    hidserv_cache_clean(); /* should this go elsewhere? */
     time_to_fetch_directory = now + options.DirFetchPostPeriod;
     time_to_fetch_directory = now + options.DirFetchPostPeriod;
   }
   }
 
 
@@ -547,6 +548,8 @@ static int do_main_loop(void) {
 
 
   /* Initialize the history structures. */
   /* Initialize the history structures. */
   rep_hist_init();
   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
   /* load the private keys, if we're supposed to have them, and set up the
    * TLS context. */
    * 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,
                                    char **str_out,
                                    int *len_out);
                                    int *len_out);
 rend_service_descriptor_t *rend_parse_service_descriptor(const char *str, int len);
 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
 #endif
 
 

+ 118 - 1
src/or/rendcommon.c

@@ -67,7 +67,6 @@ rend_encode_service_descriptor(rend_service_descriptor_t *desc,
   return 0;
   return 0;
 }
 }
 
 
-
 rend_service_descriptor_t *rend_parse_service_descriptor(
 rend_service_descriptor_t *rend_parse_service_descriptor(
 				       const char *str, int len)
 				       const char *str, int len)
 {
 {
@@ -128,3 +127,121 @@ rend_service_descriptor_t *rend_parse_service_descriptor(
   return NULL;
   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;
+}
+
+