[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] Write necessary backends for online directory generation. ...



Update of /home/or/cvsroot/src/or
In directory moria.mit.edu:/tmp/cvs-serv10680/or

Modified Files:
	Makefile.am connection.c connection_or.c directory.c main.c 
	or.h routers.c 
Added Files:
	dirserv.c 
Log Message:
Write necessary backends for online directory generation.  I think.

--- NEW FILE: dirserv.c ---
/* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
/* See LICENSE for licensing information */
/* $Id: dirserv.c,v 1.1 2003/09/27 21:30:10 nickm Exp $ */

#include "or.h"

static int the_directory_is_dirty = 1;
static char *the_directory = NULL;
static int the_directory_len = -1;

/*
 *    Fingerprint handling code.
 */
typedef struct fingerprint_entry_t {
  char *nickname;
  char *fingerprint;
} fingerprint_entry_t;

static fingerprint_entry_t fingerprint_list[MAX_ROUTERS_IN_DIR];
static int n_fingerprints = 0;

/* return 0 on success, -1 on failure */
int 
dirserv_parse_fingerprint_file(const char *fname)
{
  FILE *file;
#define BUF_LEN (FINGERPRINT_LEN+MAX_NICKNAME_LEN+20)
  char buf[BUF_LEN+1];
  char *cp, *nickname, *fingerprint;
  fingerprint_entry_t fingerprint_list_tmp[MAX_ROUTERS_IN_DIR];
  int n_fingerprints_tmp = 0;
  int lineno=0;
  int i;
  if (!(file = fopen(fname, "r"))) {
    log(LOG_WARNING, "Cannot open fingerprint file %s", fname);
    goto err;
  }
  while (1) {
    cp = fgets(buf, BUF_LEN, file);
    ++lineno;
    if (!cp) {
      if (feof(file))
        break;
      else {
        log(LOG_WARNING, "Error reading from fingerprint file");
        goto err;
      }
    }
    buf[BUF_LEN]='\0';
    cp = buf;
    while (isspace(*cp))
      ++cp;
    if (*cp == '#' || *cp == '\0') 
      continue;
    nickname = cp;
    cp = strchr(cp, ' ');
    if (!cp) {
      log(LOG_WARNING, "Bad line %d of fingerprint file", lineno);
      goto err;
    }
    *cp++ = '\0';
    while (isspace(*cp))
      ++cp;
    if (strlen(cp) < FINGERPRINT_LEN) {
      log(LOG_WARNING, "Bad line %d of fingerprint file", lineno);
      goto err;
    }
    fingerprint = cp;
    cp[FINGERPRINT_LEN] = '\0';
    if (strlen(nickname) > MAX_NICKNAME_LEN) {
      log(LOG_WARNING, "Nickname too long on line %d of fingerprint file",
          lineno);
      goto err;
    }
    if (!crypto_pk_check_fingerprint_syntax(fingerprint)) {
      log(LOG_WARNING, "Invalid fingerprint on line %d of fingerprint file",
          lineno);
      goto err;
    }
    for (i = 0; i < n_fingerprints_tmp; ++i) {
      if (0==strcasecmp(fingerprint_list_tmp[i].nickname, nickname)) {
        log(LOG_WARNING, "Duplicate nickname on line %d of fingerprint file", lineno);
        goto err;
      }
    }
    fingerprint_list_tmp[n_fingerprints_tmp].nickname = strdup(nickname);
    fingerprint_list_tmp[n_fingerprints_tmp].fingerprint = strdup(fingerprint);
    ++n_fingerprints_tmp;
  }
  /* replace the global fingerprints list. */
  dirserv_free_fingerprint_list();
  memcpy(fingerprint_list, fingerprint_list_tmp, 
         sizeof(fingerprint_entry_t)*n_fingerprints_tmp);
  n_fingerprints = n_fingerprints_tmp;
  return 0; 

 err:
  for (i = 0; i < n_fingerprints_tmp; ++i) {
    free(fingerprint_list_tmp[i].nickname);
    free(fingerprint_list_tmp[i].fingerprint);
  }
  return -1;
#undef BUF_LEN
}    

/* return 1 if router's identity and nickname match. */
int
dirserv_router_fingerprint_is_known(const routerinfo_t *router)
{
  int i;
  fingerprint_entry_t *ent =NULL;
  char fp[FINGERPRINT_LEN+1];

  for (i=0;i<n_fingerprints;++i) {
    if (!strcasecmp(router->nickname,fingerprint_list[i].nickname)) {
      ent = &fingerprint_list[i];
      break;
    }
  }
  
  if (!ent) {
    /* No such server known */
    return 0;
  }
  if (crypto_pk_get_fingerprint(router->identity_pkey, fp)) {
    /* XXX Error computing fingerprint: log */
    return 0;
  }
  if (0==strcasecmp(ent->fingerprint, fp)) {
    /* Right fingerprint. */
    return 1;
  } else {
    /* Wrong fingerprint. */
    return 0;
  }
}

void 
dirserv_free_fingerprint_list()
{
  int i;
  for (i = 0; i < n_fingerprints; ++i) {
    free(fingerprint_list[i].nickname);
    free(fingerprint_list[i].fingerprint);
  }
  n_fingerprints = 0;
}

/*
 *    Descriptor list
 */
typedef struct descriptor_entry_t {
  char *nickname;
  time_t published;
  size_t desc_len;
  char *descriptor;
} descriptor_entry_t;

static descriptor_entry_t *descriptor_list[MAX_ROUTERS_IN_DIR];
static int n_descriptors = 0;

static void free_descriptor_entry(descriptor_entry_t *desc)
{
  if (desc->descriptor)
    free(desc->descriptor);
  if (desc->nickname)
    free(desc->nickname);
  free(desc);
}

void 
dirserv_free_descriptors()
{
  int i;
  for (i = 0; i < n_descriptors; ++i) {
    free_descriptor_entry(descriptor_list[i]);
  }
  n_descriptors = 0;
}

/* Return 0 if descriptor added; -1 if descriptor rejected.  Updates *desc
 * to point after the descriptor if the descriptor is OK.
 */
int
dirserv_add_descriptor(const char **desc)
{
  descriptor_entry_t **desc_ent_ptr;
  routerinfo_t *ri = NULL;
  int i;
  char *start, *end;
  char *desc_tmp = NULL;
  size_t desc_len;

  start = strstr(*desc, "router ");
  if (!start) {
    log(LOG_WARNING, "no descriptor found.");
    goto err;
  }
  end = strstr(start+6, "\nrouter ");
  if (end) {
    ++end; /* Include NL. */
  } else {
    end = start+strlen(start);
  }
  desc_len = end-start;
  desc_tmp = tor_malloc(desc_len+1);
  strncpy(desc_tmp, start, desc_len);
  desc_tmp[desc_len]='\0';

  /* Check: is the descriptor syntactically valid? */
  ri = router_get_entry_from_string(&desc_tmp);
  if (!ri) {
    log(LOG_WARNING, "Couldn't parse descriptor");
    goto err;
  }
  free(desc_tmp); desc_tmp = NULL;
  /* Okay.  Now check whether the fingerprint is recognized. */
  if (!dirserv_router_fingerprint_is_known(ri)) {
    log(LOG_WARNING, "Identity is unrecognized for descriptor");
    goto err;
  }
  /* Do we already have an entry for this router? */
  desc_ent_ptr = NULL;
  for (i = 0; i < n_descriptors; ++i) {
    if (!strcasecmp(ri->nickname, descriptor_list[i]->nickname)) {
      desc_ent_ptr = &descriptor_list[i];
      break;
    }
  }
  if (desc_ent_ptr) {
    /* if so, decide whether to update it. */
    if ((*desc_ent_ptr)->published > ri->published_on) {
      /* We already have a newer descriptor */
      goto err;
    }
    /* We don't have a newer one; we'll update this one. */
    free_descriptor_entry(*desc_ent_ptr);
  } else {
    /* Add this at the end. */
    desc_ent_ptr = &descriptor_list[n_descriptors++];
  }
  
  (*desc_ent_ptr) = tor_malloc(sizeof(descriptor_entry_t));
  (*desc_ent_ptr)->nickname = ri->nickname;
  (*desc_ent_ptr)->published = ri->published_on;
  (*desc_ent_ptr)->desc_len = desc_len;
  (*desc_ent_ptr)->descriptor = tor_malloc(desc_len+1);
  strncpy((*desc_ent_ptr)->descriptor, start, desc_len);
  (*desc_ent_ptr)->descriptor[desc_len] = '\0';
  *desc = end;
  the_directory_is_dirty = 1;
  
  routerinfo_free(ri);
  return 0;
 err:
  if (desc_tmp)
    free(desc_tmp);
  if (ri)
    routerinfo_free(ri);
  
  return -1;
}

void 
directory_set_dirty()
{
  the_directory_is_dirty = 1;
}

int 
dirserv_init_from_directory_string(const char *dir)
{
  const char *cp = dir;
  while(1) {
    cp = strstr(cp, "\nrouter ");
    if (!cp) break;
    ++cp;
    if (dirserv_add_descriptor(&cp)) {
      return -1;
    }
    --cp; /*Back up to newline.*/
  }
  return 0;
}

int
dirserv_dump_directory_to_string(char *s, int maxlen,
                                 crypto_pk_env_t *private_key)
{
  char *cp, *eos;
  char digest[20];
  char signature[128];
  char published[33];
  time_t published_on;
  int i;
  eos = s+maxlen;

  if (list_running_servers(&cp))
    return -1;
  published_on = time(NULL);
  strftime(published, 32, "%Y-%m-%d %H:%M:%S", gmtime(&published_on));
  snprintf(s, maxlen,
           "signed-directory\n"
           "published %s\n"
           "recommended-software "RECOMMENDED_SOFTWARE_VERSIONS"\n"
           "running-routers %s\n", published, cp);
  free(cp);
  i = strlen(s);
  cp = s+i;
  
  for (i = 0; i < n_descriptors; ++i) {
    strncat(cp, descriptor_list[i]->descriptor, descriptor_list[i]->desc_len);
    cp += descriptor_list[i]->desc_len;
    assert(!cp);
  }
  /* These multiple strlen calls are inefficient, but dwarfed by the RSA
     signature.
  */
  i = strlen(s);
  strncat(s, "directory-signature\n", maxlen-i);
  i = strlen(s);
  cp = s + i;
  
  if (crypto_SHA_digest(s, i, digest)) {
    log_fn(LOG_WARNING,"couldn't compute digest");
    return -1;
  }
  if (crypto_pk_private_sign(private_key, digest, 20, signature) < 0) {
    log_fn(LOG_WARNING,"couldn't sign digest");
    return -1;
  }
  
  strncpy(cp, 
          "-----BEGIN SIGNATURE-----\n", maxlen-i);
          
  i = strlen(s);
  cp = s+i;
  if (base64_encode(cp, maxlen-i, signature, 128) < 0) {
    log_fn(LOG_WARNING," couldn't base64-encode signature");
    return -1;
  }

  i = strlen(s);
  cp = s+i;
  strncat(cp, "-----END SIGNATURE-----\n", maxlen-i);
  i = strlen(s);
  if (i == maxlen) {
    log_fn(LOG_WARNING,"tried to exceed string length.");
    return -1;
  }

  return 0;
}

size_t dirserv_get_directory(const char **directory)
{
  char *new_directory;
  if (the_directory_is_dirty) {
    new_directory = tor_malloc(MAX_DIR_SIZE);
    if (dirserv_dump_directory_to_string(new_directory, MAX_DIR_SIZE,
                                         get_identity_key())) {
      log(LOG_WARNING, "Error creating directory.");
      free(new_directory);
      return 0;
    }
    if (the_directory)
      free(the_directory);
    the_directory = new_directory;
    the_directory_len = strlen(the_directory);
    log_fn(LOG_INFO,"New directory (size %d):\n%s",the_directory_len,
           the_directory);
    the_directory_is_dirty = 0;
    /* Now read the directory we just made in order to update our own
     * router lists.  This does more signature checking than is strictly
     * necessary, but safe is better than sorry. */
    new_directory = strdup(*directory);
    if (router_get_dir_from_string(new_directory, get_identity_key())) {
      log_fn(LOG_ERR, "We just generated a directory we can't parse. Dying.");
      exit(0);
    }
    free(new_directory);
  } else {
    log(LOG_INFO,"Directory still clean, reusing.");
  }
  *directory = the_directory;
  return the_directory_len;
}

Index: Makefile.am
===================================================================
RCS file: /home/or/cvsroot/src/or/Makefile.am,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -d -r1.21 -r1.22
--- Makefile.am	22 Sep 2003 06:22:08 -0000	1.21
+++ Makefile.am	27 Sep 2003 21:30:10 -0000	1.22
@@ -5,14 +5,14 @@
 bin_PROGRAMS = tor
 
 tor_SOURCES = buffers.c circuit.c command.c connection.c \
-             connection_or.c config.c \
+             connection_or.c config.c dirserv.c \
              onion.c routers.c directory.c dns.c connection_edge.c \
              cpuworker.c main.c tor_main.c
 
 tor_LDADD = ../common/libor.a
 
 test_SOURCES = buffers.c circuit.c command.c connection.c \
-             connection_or.c config.c \
+             connection_or.c config.c dirserv.c \
              onion.c routers.c directory.c dns.c connection_edge.c \
              cpuworker.c main.c test.c
 

Index: connection.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection.c,v
retrieving revision 1.106
retrieving revision 1.107
diff -u -d -r1.106 -r1.107
--- connection.c	27 Sep 2003 21:09:55 -0000	1.106
+++ connection.c	27 Sep 2003 21:30:10 -0000	1.107
@@ -110,6 +110,8 @@
     crypto_free_pk_env(conn->link_pkey);
   if (conn->identity_pkey)
     crypto_free_pk_env(conn->identity_pkey);
+  if (conn->nickname) 
+    free(conn->nickname);
 
   if(conn->s > 0) {
     log_fn(LOG_INFO,"closing fd %d.",conn->s);

Index: connection_or.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection_or.c,v
retrieving revision 1.57
retrieving revision 1.58
diff -u -d -r1.57 -r1.58
--- connection_or.c	27 Sep 2003 21:09:56 -0000	1.57
+++ connection_or.c	27 Sep 2003 21:30:10 -0000	1.58
@@ -81,6 +81,7 @@
   conn->onion_pkey = crypto_pk_dup_key(router->onion_pkey);
   conn->link_pkey = crypto_pk_dup_key(router->link_pkey);
   conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey);
+  conn->nickname = strdup(router->nickname);
   if(conn->address)
     free(conn->address);
   conn->address = strdup(router->address);

Index: directory.c
===================================================================
RCS file: /home/or/cvsroot/src/or/directory.c,v
retrieving revision 1.35
retrieving revision 1.36
diff -u -d -r1.35 -r1.36
--- directory.c	27 Sep 2003 21:09:56 -0000	1.35
+++ directory.c	27 Sep 2003 21:30:10 -0000	1.36
@@ -4,22 +4,17 @@
 
 #include "or.h"
 
-#define MAX_DIR_SIZE 50000 /* XXX, big enough? */
-
 static int directory_send_command(connection_t *conn, int command);
-static void directory_rebuild(void);
 static int directory_handle_command(connection_t *conn);
 
 /********* START VARIABLES **********/
 
 extern or_options_t options; /* command-line and config-file options */
 
-static char the_directory[MAX_DIR_SIZE+1];
-static int directorylen=0;
-static int directory_dirty=1;
-
 static char fetchstring[] = "GET / HTTP/1.0\r\n\r\n";
 static char answerstring[] = "HTTP/1.0 200 OK\r\n\r\n";
+static char the_directory[MAX_DIR_SIZE+1];
+static int directorylen=0;
 
 /********* END VARIABLES ************/
 
@@ -115,25 +110,6 @@
   return 0;
 }
 
-void directory_set_dirty(void) {
-  directory_dirty = 1;
-}
-
-static void directory_rebuild(void) {
-  if(directory_dirty) {
-    if (dump_signed_directory_to_string(the_directory, MAX_DIR_SIZE,
-                                        get_identity_key())) {
-      log(LOG_WARNING, "Error creating directory");
-      return;
-    }
-    directorylen = strlen(the_directory);
-    log(LOG_INFO,"New directory (size %d):\n%s",directorylen,the_directory);
-    directory_dirty = 0;
-  } else {
-    log(LOG_INFO,"Directory still clean, reusing.");
-  }
-}
-
 int connection_dir_process_inbuf(connection_t *conn) {
 
   assert(conn && conn->type == CONN_TYPE_DIR);
@@ -191,6 +167,8 @@
 static int directory_handle_command(connection_t *conn) {
   char headers[1024];
   char body[50000]; /* XXX */
+  size_t dl;
+  const char *cp;
 
   assert(conn && conn->type == CONN_TYPE_DIR);
 
@@ -209,16 +187,16 @@
   if(!strncasecmp(headers,"GET",3)) {
     /* XXX should check url and http version */
 
-    directory_rebuild(); /* rebuild it now, iff it's dirty */
+    dl = dirserv_get_directory(&cp);
 
-    if(directorylen == 0) {
+    if(dl == 0) {
       log_fn(LOG_WARNING,"My directory is empty. Closing.");
       return -1;
     }
 
     log_fn(LOG_DEBUG,"Dumping directory to client."); 
     if((connection_write_to_buf(answerstring, strlen(answerstring), conn) < 0) ||
-       (connection_write_to_buf(the_directory, directorylen, conn) < 0)) {
+       (connection_write_to_buf(cp, dl, conn) < 0)) {
       log_fn(LOG_WARNING,"Failed to write answerstring+directory to outbuf.");
       return -1;
     }

Index: main.c
===================================================================
RCS file: /home/or/cvsroot/src/or/main.c,v
retrieving revision 1.107
retrieving revision 1.108
diff -u -d -r1.107 -r1.108
--- main.c	27 Sep 2003 21:09:56 -0000	1.107
+++ main.c	27 Sep 2003 21:30:10 -0000	1.108
@@ -741,11 +741,12 @@
   strftime(published, 32, "%Y-%m-%d %H:%M:%S", gmtime(&router->published_on));
   
   result = snprintf(s, maxlen, 
-                    "router %s %d %d %d %d\n"
+                    "router %s %s %d %d %d %d\n"
                     "published %s\n"
                     "onion-key\n%s"
                     "link-key\n%s"
                     "signing-key\n%s",
+    router->nickname,                   
     router->address,
     router->or_port,
     router->ap_port,
@@ -805,126 +806,36 @@
   return written+1;
 }
 
-static int 
-build_directory(directory_t *dir) {
-  routerinfo_t **routers = NULL;
+int 
+list_running_servers(char **nicknames_out)
+{
+  char *nickname_lst[MAX_ROUTERS_IN_DIR];
   connection_t *conn;
-  routerinfo_t *router;
-  int i, n = 0;
-
-  routers = (routerinfo_t **)tor_malloc(sizeof(routerinfo_t*) * (nfds+1));
-  if (my_routerinfo) {
-    log(LOG_INFO, "build_directory(): adding self (%s:%d)", 
-        my_routerinfo->address, my_routerinfo->or_port);
-    routers[n++] = my_routerinfo;
-  }
-  for(i = 0; i<nfds; ++i) {
+  char *cp;
+  int n = 0, i;
+  int length;
+  *nicknames_out = NULL;
+  if (my_routerinfo)
+    nickname_lst[n++] = my_routerinfo->nickname;
+  for (i = 0; i<nfds; ++i) {
     conn = connection_array[i];
-
-    if(conn->type != CONN_TYPE_OR)
-      continue; /* we only want to list ORs */
-    if(conn->state != OR_CONN_STATE_OPEN)
-      continue; /* we only want to list ones that successfully handshaked */
-    router = router_get_by_addr_port(conn->addr,conn->port);
-    if(!router) {
-      /* XXX this legitimately happens when conn is an OP. How to detect this? */
-      log(LOG_INFO,"build_directory(): couldn't find router %d:%d!",
-          conn->addr,conn->port);
-      continue;
-    }
-    log(LOG_INFO, "build_directory(): adding router (%s:%d)",
-        router->address, router->or_port);
-    routers[n++] = router;
-  }
-  dir->routers = routers;
-  dir->n_routers = n;
-  return 0;
-}
-
-int
-dump_signed_directory_to_string(char *s, int maxlen,
-                                crypto_pk_env_t *private_key)
-{
-  directory_t dir;
-  if (build_directory(&dir)) {
-    log(LOG_WARNING,"dump_signed_directory_to_string(): build_directory failed.");
-    return -1;
-  }
-  return dump_signed_directory_to_string_impl(s, maxlen, &dir, private_key);
-}
-
-int
-dump_signed_directory_to_string_impl(char *s, int maxlen, directory_t *dir,
-                                     crypto_pk_env_t *private_key)
-{
-  char *cp, *eos;
-  char digest[20];
-  char signature[128];
-  int i, written;
-  routerinfo_t *router;
-  eos = s+maxlen;
-  strncpy(s, 
-          "signed-directory\n"
-          "recommended-software "
-          RECOMMENDED_SOFTWARE_VERSIONS
-          "\n"
-          , maxlen);
-  
-  i = strlen(s);
-  cp = s+i;
-  for (i = 0; i < dir->n_routers; ++i) {
-    router = dir->routers[i];
-    /* XXX This is wrong; we shouldn't sign routers, but rather propagate
-     * XXX the original router blocks, unaltered.
-     */
-    written = dump_router_to_string(cp, eos-cp, router, private_key);
-
-    if(written < 0) { 
-      log(LOG_WARNING,"dump_signed_directory_to_string(): tried to exceed string length.");
-      cp[maxlen-1] = 0; /* make sure it's null terminated */
-      free(dir->routers);
-      return -1;
-    }
-    cp += written;
-  }
-  free(dir->routers); /* not needed anymore */
-
-  /* These multiple strlen calls are inefficient, but dwarfed by the RSA
-     signature.
-  */
-  i = strlen(s);
-  strncat(s, "directory-signature\n", maxlen-i);
-  i = strlen(s);
-  cp = s + i;
-  
-  if (crypto_SHA_digest(s, i, digest)) {
-    log(LOG_WARNING,"dump_signed_directory_to_string(): couldn't compute digest");
-    return -1;
-  }
-  if (crypto_pk_private_sign(private_key, digest, 20, signature) < 0) {
-    log(LOG_WARNING,"dump_signed_directory_to_string(): couldn't sign digest");
-    return -1;
+    if (conn->type != CONN_TYPE_OR || conn->state != OR_CONN_STATE_OPEN)
+      continue; /* only list successfully handshaked OR's. */
+    nickname_lst[n++] = conn->nickname;
   }
-  
-  strncpy(cp, 
-          "-----BEGIN SIGNATURE-----\n", maxlen-i);
-          
-  i = strlen(s);
-  cp = s+i;
-  if (base64_encode(cp, maxlen-i, signature, 128) < 0) {
-    log_fn(LOG_WARNING," couldn't base64-encode signature");
-    return -1;
+  length = n + 1; /* spaces + EOS + 1. */
+  for (i = 0; i<n; ++i) {
+    length += strlen(nickname_lst[i]);
   }
-
-  i = strlen(s);
-  cp = s+i;
-  strncat(cp, "-----END SIGNATURE-----\n", maxlen-i);
-  i = strlen(s);
-  if (i == maxlen) {
-    log(LOG_WARNING,"dump_signed_directory_to_string(): tried to exceed string length.");
-    return -1;
+  *nicknames_out = tor_malloc(length);
+  cp = *nicknames_out;
+  for (i = 0; i<n; ++i) {
+    if (i)
+      strcat(cp, " ");
+    strcat(cp, nickname_lst[i]);
+    while (*cp) 
+      ++cp;
   }
-
   return 0;
 }
 

Index: or.h
===================================================================
RCS file: /home/or/cvsroot/src/or/or.h,v
retrieving revision 1.143
retrieving revision 1.144
diff -u -d -r1.143 -r1.144
--- or.h	27 Sep 2003 21:09:56 -0000	1.143
+++ or.h	27 Sep 2003 21:30:10 -0000	1.144
@@ -102,6 +102,7 @@
 #define MAX_BUF_SIZE (640*1024)
 #define DEFAULT_BANDWIDTH_OP (1024 * 1000)
 #define MAX_NICKNAME_LEN 32
+#define MAX_DIR_SIZE 50000 /* XXX, big enough? */
 
 #define ACI_TYPE_LOWER 0
 #define ACI_TYPE_HIGHER 1
@@ -214,6 +215,8 @@
 
 /* legal characters in a filename */
 #define CONFIG_LEGAL_FILENAME_CHARACTERS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_/"
+/* legal characters in a nickname */
+#define LEGAL_NICKNAME_CHARACTERS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
 
 /* structure of a socks client operation */
 typedef struct {
@@ -282,6 +285,7 @@
   crypto_pk_env_t *onion_pkey; /* public RSA key for the other side's onions */
   crypto_pk_env_t *link_pkey; /* public RSA key for the other side's TLS */
   crypto_pk_env_t *identity_pkey; /* public RSA key for the other side's signing */
+  char *nickname;
 
 /* Used only by OR connections: */
   tor_tls *tls;
@@ -335,6 +339,8 @@
   crypto_pk_env_t *link_pkey;  /* public RSA key for TLS */
   crypto_pk_env_t *identity_pkey;  /* public RSA key for signing */
  
+  int is_running;
+
   /* link info */
   uint32_t bandwidth;
   struct exit_policy_t *exit_policy;
@@ -345,6 +351,7 @@
   routerinfo_t **routers;
   int n_routers;
   char *software_versions;
+  time_t published_on;
 } directory_t;
 
 struct crypt_path_t { 
@@ -582,7 +589,6 @@
 /********************************* directory.c ***************************/
 
 void directory_initiate_command(routerinfo_t *router, int command);
-void directory_set_dirty(void);
 int connection_dir_process_inbuf(connection_t *conn);
 int connection_dir_finished_flushing(connection_t *conn);
 
@@ -618,12 +624,8 @@
 void connection_stop_writing(connection_t *conn);
 void connection_start_writing(connection_t *conn);
 
-int dump_signed_directory_to_string(char *s, int maxlen, 
-                                    crypto_pk_env_t *private_key);
-/* Exported for debugging */
-int dump_signed_directory_to_string_impl(char *s, int maxlen, 
-                                         directory_t *dir, 
-                                         crypto_pk_env_t *private_key); 
+int list_running_servers(char **nicknames_out);
+
 const char *router_get_my_descriptor(void);
 
 int main(int argc, char *argv[]);
@@ -676,7 +678,7 @@
 /* Reads a list of known routers, unsigned. */
 int router_get_list_from_string(char *s);
 /* Exported for debugging */
-int router_get_list_from_string_impl(char **s, directory_t **dest);
+int router_get_list_from_string_impl(char **s, directory_t **dest, int n_good_nicknames, const char *good_nickname_lst[]);
 /* Reads a signed directory. */
 int router_get_dir_from_string(char *s, crypto_pk_env_t *pkey);
 /* Exported or debugging */
@@ -685,6 +687,19 @@
 routerinfo_t *router_get_entry_from_string(char **s);
 int router_compare_to_exit_policy(connection_t *conn);
 void routerinfo_free(routerinfo_t *router);
+
+/********************************* dirserv.c ***************************/
+int dirserv_parse_fingerprint_file(const char *fname);
+int dirserv_router_fingerprint_is_known(const routerinfo_t *router);
+void dirserv_free_fingerprint_list();
+int dirserv_add_descriptor(const char **desc);
+int dirserv_init_from_directory_string(const char *dir);
+void dirserv_free_descriptors();
+int dirserv_dump_directory_to_string(char *s, int maxlen,
+                                     crypto_pk_env_t *private_key);
+void directory_set_dirty();
+size_t dirserv_get_directory(const char **cp);
+
 
 #endif
 

Index: routers.c
===================================================================
RCS file: /home/or/cvsroot/src/or/routers.c,v
retrieving revision 1.54
retrieving revision 1.55
diff -u -d -r1.54 -r1.55
--- routers.c	26 Sep 2003 20:41:23 -0000	1.54
+++ routers.c	27 Sep 2003 21:30:10 -0000	1.55
@@ -319,6 +319,7 @@
   K_LINK_KEY,
   K_ROUTER_SIGNATURE,
   K_PUBLISHED,
+  K_RUNNING_ROUTERS,
   _SIGNATURE, 
   _PUBLIC_KEY, 
   _ERR, 
@@ -339,10 +340,11 @@
   { "link-key", K_LINK_KEY },
   { "router-signature", K_ROUTER_SIGNATURE },
   { "published", K_PUBLISHED },
+  { "running-routers", K_RUNNING_ROUTERS },
   { NULL, -1 }
 };
 
-#define MAX_ARGS 8
+#define MAX_ARGS 1024
 struct directory_token {
   directory_keyword tp;
   union {
@@ -495,6 +497,7 @@
     case K_LINK_KEY: printf("Link-key"); break;
     case K_ROUTER_SIGNATURE: printf("Router-signature"); break;
     case K_PUBLISHED: printf("Published"); break;
+    case K_RUNNING_ROUTERS: printf("Running-routers"); break;
     default:
       printf("?????? %d\n", tok->tp); return;
     }
@@ -551,7 +554,7 @@
 
 int router_get_list_from_string(char *s) 
 {
-  if (router_get_list_from_string_impl(&s, &directory)) {
+  if (router_get_list_from_string_impl(&s, &directory, -1, NULL)) {
     log(LOG_WARNING, "Error parsing router file");
     return -1;
   }
@@ -653,6 +656,10 @@
   char signed_digest[128];
   directory_t *new_dir = NULL;
   char *versions;
+  struct tm published;
+  time_t published_on;
+  const char *good_nickname_lst[1024];
+  int n_good_nicknames;
   
 #define NEXT_TOK()                                                      \
   do {                                                                  \
@@ -676,6 +683,18 @@
   TOK_IS(K_SIGNED_DIRECTORY, "signed-directory");
 
   NEXT_TOK();
+  TOK_IS(K_PUBLISHED, "published");
+  if (tok.val.cmd.n_args != 2) {
+    log_fn(LOG_WARNING, "Invalid published line");
+    goto err;
+  }
+  tok.val.cmd.args[1][-1] = ' ';
+  if (!strptime(tok.val.cmd.args[0], "%Y-%m-%d %H:%M:%S", &published)) {
+    log_fn(LOG_WARNING, "Published time was unparseable"); goto err;
+  }
+  published_on = timegm(&published);  
+
+  NEXT_TOK();
   TOK_IS(K_RECOMMENDED_SOFTWARE, "recommended-software");
   if (tok.val.cmd.n_args != 1) {
     log_fn(LOG_WARNING, "Invalid recommded-software line");
@@ -683,11 +702,18 @@
   }
   versions = strdup(tok.val.cmd.args[0]);
   
-  if (router_get_list_from_string_impl(&s, &new_dir)) {
+  NEXT_TOK();
+  TOK_IS(K_RUNNING_ROUTERS, "running-routers");
+  n_good_nicknames = tok.val.cmd.n_args;
+  memcpy(good_nickname_lst, tok.val.cmd.args, n_good_nicknames);
+
+  if (router_get_list_from_string_impl(&s, &new_dir,
+                                       n_good_nicknames, good_nickname_lst)) {
     log_fn(LOG_WARNING, "Error reading routers from directory");
     goto err;
   }
   new_dir->software_versions = versions;
+  new_dir->published_on = published_on;
 
   NEXT_TOK();
   TOK_IS(K_DIRECTORY_SIGNATURE, "directory-signature");
@@ -725,11 +751,14 @@
 #undef TOK_IS
 }
 
-int router_get_list_from_string_impl(char **s, directory_t **dest)
+int router_get_list_from_string_impl(char **s, directory_t **dest, 
+                                     int n_good_nicknames, 
+                                     const char **good_nickname_lst)
 {
   routerinfo_t *router;
   routerinfo_t **rarray;
   int rarray_len = 0;
+  int i, router_is_running;
 
   assert(s);
 
@@ -749,6 +778,15 @@
       routerinfo_free(router);
       continue;
     } 
+    if (n_good_nicknames>=0) {
+      router->is_running = 0;
+      for (i = 0; i < n_good_nicknames; ++i) {
+        if (0==strcasecmp(good_nickname_lst[i], router->nickname)) {
+          router->is_running = 1;
+          break;
+        }
+      }
+    }
     rarray[rarray_len++] = router;
   }
  
@@ -846,31 +884,38 @@
      thank me for this someday. */
   router->onion_pkey = router->identity_pkey = router->link_pkey = NULL; 
 
-  if (tok->val.cmd.n_args != 5) {
+  if (tok->val.cmd.n_args != 6) {
     log_fn(LOG_WARNING,"Wrong # of arguments to \"router\"");
     goto err;
   }
-
+  if (!(router->nickname = strdup(ARGS[0])))
+    goto err;
+  if (strlen(router->nickname) > MAX_NICKNAME_LEN)
+    goto err;
+  if (strspn(router->nickname, LEGAL_NICKNAME_CHARACTERS) != 
+      strlen(router->nickname))
+    goto err;
+  
   /* read router.address */
-  if (!(router->address = strdup(ARGS[0])))
+  if (!(router->address = strdup(ARGS[1])))
     goto err;
   router->addr = 0;
 
   /* Read router->or_port */
-  router->or_port = atoi(ARGS[1]);
+  router->or_port = atoi(ARGS[2]);
   if(!router->or_port) {
     log_fn(LOG_WARNING,"or_port unreadable or 0. Failing.");
     goto err;
   }
   
   /* Router->ap_port */
-  router->ap_port = atoi(ARGS[2]);
+  router->ap_port = atoi(ARGS[3]);
   
   /* Router->dir_port */
-  router->dir_port = atoi(ARGS[3]);
+  router->dir_port = atoi(ARGS[4]);
 
   /* Router->bandwidth */
-  router->bandwidth = atoi(ARGS[4]);
+  router->bandwidth = atoi(ARGS[5]);
   if (!router->bandwidth) {
     log_fn(LOG_WARNING,"bandwidth unreadable or 0. Failing.");
   }
@@ -885,8 +930,8 @@
   if (tok->val.cmd.n_args != 2) {
     log_fn(LOG_WARNING, "Wrong number of arguments to published"); goto err;
   }
-  tok->val.cmd.args[1][-1] = ' '; /* Re-insert space. */
-  if (!strptime(tok->val.cmd.args[0], "%Y-%m-%d %H:%M:%S", &published)) {
+  ARGS[1][-1] = ' '; /* Re-insert space. */
+  if (!strptime(ARGS[0], "%Y-%m-%d %H:%M:%S", &published)) {
     log_fn(LOG_WARNING, "Published time was unparseable"); goto err;
   }
   router->published_on = timegm(&published);
@@ -1072,127 +1117,6 @@
 
   return 0; /* accept all by default. */
 }
-
-/*** Fingerprint handling code. ***/
-typedef struct fingerprint_entry_t {
-  char *nickname;
-  char *fingerprint;
-} fingerprint_entry_t;
-
-static fingerprint_entry_t fingerprint_list[MAX_ROUTERS_IN_DIR];
-static int n_fingerprints = 0;
-/* return 0 on success, -1 on failure */
-int directory_parse_fingerprint_file(const char *fname)
-{
-  FILE *file;
-#define BUF_LEN (FINGERPRINT_LEN+MAX_NICKNAME_LEN+20)
-  char buf[BUF_LEN+1];
-  char *cp, *nickname, *fingerprint;
-  fingerprint_entry_t fingerprint_list_tmp[MAX_ROUTERS_IN_DIR];
-  int n_fingerprints_tmp = 0;
-  int lineno=0;
-  int i;
-  if (!(file = fopen(fname, "r"))) {
-    log(LOG_WARNING, "Cannot open fingerprint file %s", fname);
-    goto err;
-  }
-  while (1) {
-    cp = fgets(buf, BUF_LEN, file);
-    ++lineno;
-    if (!cp) {
-      if (feof(file))
-        break;
-      else {
-        log(LOG_WARNING, "Error reading from fingerprint file");
-        goto err;
-      }
-    }
-    buf[BUF_LEN]='\0';
-    cp = buf;
-    while (isspace(*cp))
-      ++cp;
-    if (*cp == '#' || *cp == '\0') 
-      continue;
-    nickname = cp;
-    cp = strchr(cp, ' ');
-    if (!cp) {
-      log(LOG_WARNING, "Bad line %d of fingerprint file", lineno);
-      goto err;
-    }
-    *cp++ = '\0';
-    while (isspace(*cp))
-      ++cp;
-    if (strlen(cp) < FINGERPRINT_LEN) {
-      log(LOG_WARNING, "Bad line %d of fingerprint file", lineno);
-      goto err;
-    }
-    fingerprint = cp;
-    cp[FINGERPRINT_LEN] = '\0';
-    if (strlen(nickname) > MAX_NICKNAME_LEN) {
-      log(LOG_WARNING, "Nickname too long on line %d of fingerprint file",
-          lineno);
-      goto err;
-    }
-    if (!crypto_pk_check_fingerprint_syntax(fingerprint)) {
-      log(LOG_WARNING, "Invalid fingerprint on line %d of fingerprint file",
-          lineno);
-      goto err;
-    }
-    for (i = 0; i < n_fingerprints_tmp; ++i) {
-      if (0==strcasecmp(fingerprint_list_tmp[i].nickname, nickname)) {
-        log(LOG_WARNING, "Duplicate nickname on line %d of fingerprint file", lineno);
-        goto err;
-      }
-    }
-    fingerprint_list_tmp[n_fingerprints_tmp].nickname = strdup(nickname);
-    fingerprint_list_tmp[n_fingerprints_tmp].fingerprint = strdup(fingerprint);
-    ++n_fingerprints_tmp;
-  }
-  /* replace the global fingerprints list. */
-  for (i = 0; i < n_fingerprints; ++i) {
-    free(fingerprint_list[i].nickname);
-    free(fingerprint_list[i].fingerprint);
-  }
-  memcpy(fingerprint_list, fingerprint_list_tmp, 
-         sizeof(fingerprint_entry_t)*n_fingerprints_tmp);
-  n_fingerprints = n_fingerprints_tmp;
-  return 0; 
-
- err:
-  for (i = 0; i < n_fingerprints_tmp; ++i) {
-    free(fingerprint_list_tmp[i].nickname);
-    free(fingerprint_list_tmp[i].fingerprint);
-  }
-  return -1;
-#undef BUF_LEN
-}    
-
-/* return 1 if router's identity and nickname match. */
-int
-directory_check_router_identity(const routerinfo_t *router)
-{
-  int i;
-  char fp[FINGERPRINT_LEN+1];
-  if (crypto_pk_get_fingerprint(router->identity_pkey, fp)) {
-    /* XXX Error computing fingerprint: log */
-    return 0;
-  }
-  for (i=0;i<n_fingerprints;++i) {
-    if (0==strcasecmp(fingerprint_list[i].nickname,router->nickname)) {
-      /* Right nickname... */
-      if (0==strcasecmp(fingerprint_list[i].fingerprint, fp)) {
-        /* Right fingerprint. */
-        return 1;
-      } else {
-        /* Wrong fingerprint. */
-        return 0;
-      }
-    }
-  }
-  /* No match found. XXX log. */
-  return 0;
-}
-
 
 
 /*