[or-cvs] laying the groundwork for dynamic router lists

Roger Dingledine arma at seul.org
Tue Sep 24 10:43:59 UTC 2002


Update of /home/or/cvsroot/src/or
In directory moria.seul.org:/home/arma/work/onion/cvs/src/or

Modified Files:
	circuit.c connection.c connection_ap.c connection_or.c main.c 
	onion.c or.h routers.c 
Log Message:
laying the groundwork for dynamic router lists

revamped the router reading section

reference counting for crypto pk env's (so we can dup them)

we now read and write pem pk keys from string rather than from FILE*,
  in anticipation of fetching directories over a socket
  (so now on startup we slurp in the whole file, then parse it as a string)

fixed a bug in the proxy side, where you could get some circuits
  wedged if they showed up while the connection was being made



Index: circuit.c
===================================================================
RCS file: /home/or/cvsroot/src/or/circuit.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- circuit.c	21 Sep 2002 22:41:48 -0000	1.13
+++ circuit.c	24 Sep 2002 10:43:56 -0000	1.14
@@ -241,10 +241,14 @@
   return 0;
 }
 
-circuit_t *circuit_get_by_naddr_nport(uint32_t naddr, uint16_t nport) {
-  circuit_t *circ;
+circuit_t *circuit_enumerate_by_naddr_nport(circuit_t *circ, uint32_t naddr, uint16_t nport) {
 
-  for(circ=global_circuitlist;circ;circ = circ->next) {
+  if(!circ) /* use circ if it's defined, else start from the beginning */
+    circ = global_circuitlist; 
+  else
+    circ = circ->next;
+
+  for( ;circ;circ = circ->next) {
     if(circ->n_addr == naddr && circ->n_port == nport)
        return circ;
   }

Index: connection.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection.c,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -d -r1.23 -r1.24
--- connection.c	22 Sep 2002 11:09:07 -0000	1.23
+++ connection.c	24 Sep 2002 10:43:56 -0000	1.24
@@ -125,6 +125,11 @@
       crypto_free_cipher_env(conn->b_crypto);
   }
 
+  if (conn->pkey)
+    crypto_free_pk_env(conn->pkey);
+  if (conn->prkey)
+    crypto_free_pk_env(conn->prkey);
+
   if(conn->s > 0) {
     log(LOG_INFO,"connection_free(): closing fd %d.",conn->s);
     close(conn->s);
@@ -175,7 +180,8 @@
 
   /* remember things so you can tell the baby sockets */
   memcpy(&conn->local,local,sizeof(struct sockaddr_in));
-  conn->prkey = prkey;
+  if(prkey)
+    conn->prkey = crypto_pk_dup_key(prkey);
 
   log(LOG_DEBUG,"connection_create_listener(): Listening on local port %u.",ntohs(local->sin_port));
 
@@ -214,7 +220,8 @@
 
   /* learn things from parent, so we can perform auth */
   memcpy(&newconn->local,&conn->local,sizeof(struct sockaddr_in));
-  newconn->prkey = conn->prkey;
+  if(conn->prkey)
+    newconn->prkey = crypto_pk_dup_key(conn->prkey);
   newconn->address = strdup(inet_ntoa(remote.sin_addr)); /* remember the remote address */
 
   if(connection_add(newconn) < 0) { /* no space, forget it */

Index: connection_ap.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection_ap.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- connection_ap.c	23 Sep 2002 01:04:59 -0000	1.14
+++ connection_ap.c	24 Sep 2002 10:43:56 -0000	1.15
@@ -191,7 +191,7 @@
   log(LOG_DEBUG,"ap_handshake_establish_circuit(): Looking for firsthop '%s:%u'",
       firsthop->address,firsthop->or_port);
   n_conn = connection_twin_get_by_addr_port(firsthop->addr,firsthop->or_port);
-  if(!n_conn) { /* not currently connected */
+  if(!n_conn || n_conn->state != OR_CONN_STATE_OPEN) { /* not currently connected */
     circ->n_addr = firsthop->addr;
     circ->n_port = firsthop->or_port;
     if(global_role & ROLE_OR_CONNECT_ALL) { /* we would be connected if he were up. but he's not. */
@@ -199,14 +199,15 @@
       circuit_close(circ); 
       return -1;
     }
-    
-    /* ok, launch the connection */
-    n_conn = connect_to_router_as_op(firsthop);
-    if(!n_conn) { /* connect failed, forget the whole thing */
-      log(LOG_DEBUG,"ap_handshake_establish_circuit(): connect to firsthop failed. Closing.");
-      circuit_close(circ);
-      return -1;
-    }   
+
+    if(!n_conn) { /* launch the connection */
+      n_conn = connect_to_router_as_op(firsthop);
+      if(!n_conn) { /* connect failed, forget the whole thing */
+        log(LOG_DEBUG,"ap_handshake_establish_circuit(): connect to firsthop failed. Closing.");
+        circuit_close(circ);
+        return -1;
+      }   
+    }
     conn->state = AP_CONN_STATE_OR_WAIT;
     connection_stop_reading(conn); /* Stop listening for input from the AP! */
     return 0; /* return success. The onion/circuit/etc will be taken care of automatically
@@ -219,21 +220,31 @@
   }
 }
 
-/* find the circ that's waiting on me, if any, and get it to send its onion */
-int ap_handshake_n_conn_open(connection_t *or_conn) {
+/* find circuits that are waiting on me, if any, and get them to send the onion */
+void ap_handshake_n_conn_open(connection_t *or_conn) {
   circuit_t *circ;
+  connection_t *p_conn;
 
   log(LOG_DEBUG,"ap_handshake_n_conn_open(): Starting.");
-  circ = circuit_get_by_naddr_nport(or_conn->addr, or_conn->port);
-  if(!circ)
-    return 0; /* i'm ok with that. no need to close the connection or anything. */
+  circ = circuit_enumerate_by_naddr_nport(NULL, or_conn->addr, or_conn->port);
+  for(;;) {
+    if(!circ)
+      return;
 
-  if(circ->p_conn->state != AP_CONN_STATE_OR_WAIT) {
-    log(LOG_DEBUG,"Bug: ap_handshake_n_conn_open() got an ap_conn not in OR_WAIT state.");
+    p_conn = circ->p_conn;
+    if(p_conn->state != AP_CONN_STATE_OR_WAIT) {
+      log(LOG_WARNING,"Bug: ap_handshake_n_conn_open() got an ap_conn not in OR_WAIT state.");
+    }
+    connection_start_reading(p_conn); /* resume listening for reads */
+    log(LOG_DEBUG,"ap_handshake_n_conn_open(): Found circ, sending onion.");
+    if(ap_handshake_send_onion(p_conn, or_conn, circ)<0) {
+      log(LOG_DEBUG,"ap_handshake_n_conn_open(): circuit marked for closing.");
+      p_conn->marked_for_close = 1;
+      return; /* XXX will want to try the rest too */
+    } else {
+      circ = circuit_enumerate_by_naddr_nport(circ, or_conn->addr, or_conn->port);
+    }
   }
-  connection_start_reading(circ->p_conn); /* resume listening for reads */
-  log(LOG_DEBUG,"ap_handshake_n_conn_open(): Found circ, sending onion.");
-  return ap_handshake_send_onion(circ->p_conn, or_conn, circ);
 }
 
 int ap_handshake_send_onion(connection_t *ap_conn, connection_t *n_conn, circuit_t *circ) {

Index: connection_or.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection_or.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- connection_or.c	20 Sep 2002 19:33:13 -0000	1.13
+++ connection_or.c	24 Sep 2002 10:43:56 -0000	1.14
@@ -154,9 +154,10 @@
 
   /* set up conn so it's got all the data we need to remember */
   conn->addr = router->addr, conn->port = router->or_port; /* NOTE we store or_port here always */
-  conn->prkey = prkey;
-  conn->bandwidth = router->min; /* kludge, should make a router->bandwidth and use that */
-  conn->pkey = router->pkey;
+  if(prkey)
+    conn->prkey = crypto_pk_dup_key(prkey);
+  conn->bandwidth = router->bandwidth;
+  conn->pkey = crypto_pk_dup_key(router->pkey);
   conn->address = strdup(router->address);
   memcpy(&conn->local,local,sizeof(struct sockaddr_in));
 
@@ -331,8 +332,8 @@
   conn->state = OR_CONN_STATE_OPEN;
   connection_init_timeval(conn);
   connection_watch_events(conn, POLLIN); /* give it a default, tho the ap_handshake call may change it */
-  return ap_handshake_n_conn_open(conn); /* send the pending onion */
-
+  ap_handshake_n_conn_open(conn); /* send the pending onions */
+  return 0;
 }
 
 /*
@@ -601,14 +602,14 @@
   /* update link info */
   bandwidth = ntohl(*(uint32_t *)(buf+28));
 
-  conn->bandwidth = router->min; /* FIXME, should make a router->bandwidth and use that */
+  conn->bandwidth = router->bandwidth;
 
   if (conn->bandwidth > bandwidth)
     conn->bandwidth = bandwidth;
 
   /* copy all relevant info to conn */
   conn->addr = router->addr, conn->port = router->or_port;
-  conn->pkey = router->pkey;
+  conn->pkey = crypto_pk_dup_key(router->pkey);
   conn->address = strdup(router->address);
 
   /* generate a nonce */

Index: main.c
===================================================================
RCS file: /home/or/cvsroot/src/or/main.c,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -d -r1.23 -r1.24
--- main.c	22 Sep 2002 11:09:07 -0000	1.23
+++ main.c	24 Sep 2002 10:43:56 -0000	1.24
@@ -87,12 +87,6 @@
   return 0;  
 }
 
-int pkey_cmp(crypto_pk_env_t *a, crypto_pk_env_t *b) {
-  /* return 0 if a and b are "the same key". Return non-0 otherwise. */
-
-  return crypto_pk_cmp_keys(a, b);
-}
-
 connection_t *connection_twin_get_by_addr_port(uint32_t addr, uint16_t port) {
   /* Find a connection to the router described by addr and port,
    *   or alternately any router which knows its key.
@@ -119,7 +113,7 @@
   for(i=0;i<nfds;i++) {
     conn = connection_array[i];
     assert(conn);
-    if(connection_state_is_open(conn) && !pkey_cmp(conn->pkey, router->pkey)) {
+    if(connection_state_is_open(conn) && !crypto_pk_cmp_keys(conn->pkey, router->pkey)) {
       log(LOG_INFO,"connection_twin_get_by_addr_port(): Found twin (%s).",conn->address);
       return conn;
     }
@@ -412,7 +406,7 @@
   int poll_result;
 
   /* load the routers file */
-  router_array = getrouters(options.RouterFile,&rarray_len, options.ORPort);
+  router_array = router_get_list_from_file(options.RouterFile,&rarray_len, options.ORPort);
   if (!router_array)
   {
     log(LOG_ERR,"Error loading router list.");
@@ -426,7 +420,7 @@
       log(LOG_ERR,"Error creating a crypto environment.");
       return -1;
     }
-    if (crypto_pk_read_private_key_filename(prkey, options.PrivateKeyFile))
+    if (crypto_pk_read_private_key_from_filename(prkey, options.PrivateKeyFile))
     {
       log(LOG_ERR,"Error loading private key.");
       return -1;

Index: onion.c
===================================================================
RCS file: /home/or/cvsroot/src/or/onion.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- onion.c	19 Sep 2002 20:13:27 -0000	1.15
+++ onion.c	24 Sep 2002 10:43:56 -0000	1.16
@@ -118,7 +118,7 @@
       goto next_i_loop;
     }
     for(j=0;j<i;j++) {
-      if(!pkey_cmp(rarray[i]->pkey, rarray[j]->pkey)) {
+      if(!crypto_pk_cmp_keys(rarray[i]->pkey, rarray[j]->pkey)) {
         /* these guys are twins. so we've already counted him. */
         log(LOG_DEBUG,"Nope, %d is a twin of %d.",i,j);
         goto next_i_loop;
@@ -158,7 +158,7 @@
     choice = choice % (rarray_len);
     log(LOG_DEBUG,"new_route(): Contemplating router %u.",choice);
     if(choice == oldchoice ||
-      (oldchoice < rarray_len && !pkey_cmp(rarray[choice]->pkey, rarray[oldchoice]->pkey)) ||
+      (oldchoice < rarray_len && !crypto_pk_cmp_keys(rarray[choice]->pkey, rarray[oldchoice]->pkey)) ||
       ((global_role & ROLE_OR_CONNECT_ALL) && !connection_twin_get_by_addr_port(rarray[choice]->addr, rarray[choice]->or_port))) {
       /* Same router as last choice, or router twin,
        *   or no routers with that key are connected to us.

Index: or.h
===================================================================
RCS file: /home/or/cvsroot/src/or/or.h,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -d -r1.25 -r1.26
--- or.h	23 Sep 2002 01:04:59 -0000	1.25
+++ or.h	24 Sep 2002 10:43:57 -0000	1.26
@@ -30,6 +30,7 @@
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <sys/time.h>
+#include <sys/stat.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <errno.h>
@@ -244,12 +245,13 @@
   uint16_t or_port;
   uint16_t op_port;
   uint16_t ap_port;
+  uint16_t dir_port;
  
   crypto_pk_env_t *pkey; /* public RSA key */
  
   /* link info */
-  uint32_t min;
-  uint32_t max;
+  uint32_t bandwidth;
+
 //  struct timeval  min_interval;
  
   /* time when last data was sent to that router */
@@ -392,7 +394,7 @@
 
 circuit_t *circuit_get_by_aci_conn(aci_t aci, connection_t *conn);
 circuit_t *circuit_get_by_conn(connection_t *conn);
-circuit_t *circuit_get_by_naddr_nport(uint32_t naddr, uint16_t nport);
+circuit_t *circuit_enumerate_by_naddr_nport(circuit_t *start, uint32_t naddr, uint16_t nport);
 
 int circuit_deliver_data_cell(cell_t *cell, circuit_t *circ, connection_t *conn, int crypt_type);
 int circuit_crypt(circuit_t *circ, char *in, int inlen, char crypt_type);
@@ -487,8 +489,7 @@
 int ap_handshake_establish_circuit(connection_t *conn, unsigned int *route, int routelen, char *onion,
 		                                   int onionlen, crypt_path_t **cpath);
 
-/* find the circ that's waiting on me, if any, and get it to send its onion */
-int ap_handshake_n_conn_open(connection_t *or_conn);
+void ap_handshake_n_conn_open(connection_t *or_conn);
 
 int ap_handshake_send_onion(connection_t *ap_conn, connection_t *or_conn, circuit_t *circ);
 
@@ -553,7 +554,6 @@
 int connection_remove(connection_t *conn);
 void connection_set_poll_socket(connection_t *conn);
 
-int pkey_cmp(crypto_pk_env_t *a, crypto_pk_env_t *b);
 connection_t *connection_twin_get_by_addr_port(uint32_t addr, uint16_t port);
 connection_t *connection_exact_get_by_addr_port(uint32_t addr, uint16_t port);
 
@@ -625,10 +625,6 @@
 
 /********************************* routers.c ***************************/
 
-routerinfo_t **getrouters(char *routerfile, int *listlenp, uint16_t or_listenport);
-void delete_routerlist(routerinfo_t *list);
-/* create an NULL-terminated array of pointers pointing to elements of a router list */
-routerinfo_t **make_rarray(routerinfo_t* list, int *len);
-
+routerinfo_t **router_get_list_from_file(char *routerfile, int *len, uint16_t or_listenport);
 
 #endif

Index: routers.c
===================================================================
RCS file: /home/or/cvsroot/src/or/routers.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- routers.c	4 Sep 2002 06:29:28 -0000	1.10
+++ routers.c	24 Sep 2002 10:43:57 -0000	1.11
@@ -9,13 +9,20 @@
  * Matej Pfajfar <mp292 at cam.ac.uk>
  */
 
-#define OR_ROUTERLIST_SEPCHARS " \t\n"
-#define OR_PUBLICKEY_BEGIN_TAG "-----BEGIN RSA PUBLIC KEY-----\n"
+#define OR_PUBLICKEY_END_TAG "-----END RSA PUBLIC KEY-----\n"
 
 #include "or.h"
 
 extern int global_role; /* from main.c */
 
+/* static function prototypes */
+static int router_is_me(uint32_t or_address, uint16_t or_listenport, uint16_t my_or_listenport);
+static void routerlist_free(routerinfo_t *list);
+static routerinfo_t **make_rarray(routerinfo_t* list, int *len);
+static char *eat_whitespace(char *s);
+static char *find_whitespace(char *s);
+static routerinfo_t *router_get_entry_from_string(char **s);
+
 /* private function, to determine whether the current entry in the router list is actually us */
 static int router_is_me(uint32_t or_address, uint16_t or_listenport, uint16_t my_or_listenport)
 {
@@ -35,12 +42,12 @@
   
   /* obtain local host information */
   if (gethostname(localhostname,512) < 0) {
-    log(LOG_ERR,"Error obtaining local hostname.");
+    log(LOG_ERR,"router_is_me(): Error obtaining local hostname.");
     return -1;
   }
   localhost = gethostbyname(localhostname);
   if (!localhost) {
-    log(LOG_ERR,"Error obtaining local host info.");
+    log(LOG_ERR,"router_is_me(): Error obtaining local host info.");
     return -1;
   }
   
@@ -71,7 +78,7 @@
 }
 
 /* delete a list of routers from memory */
-void delete_routerlist(routerinfo_t *list)
+static void routerlist_free(routerinfo_t *list)
 {
   routerinfo_t *tmp = NULL;
   
@@ -91,10 +98,17 @@
   return;
 }
 
+void rarray_free(routerinfo_t **list) {
+  if(!list)
+    return;
+  routerlist_free(*list);
+  free(list);
+}
+
 /* create a NULL-terminated array of pointers pointing to elements of a router list */
 /* this is done in two passes through the list - inefficient but irrelevant as this is
  * only done once when op/or start up */
-routerinfo_t **make_rarray(routerinfo_t* list, int *len)
+static routerinfo_t **make_rarray(routerinfo_t* list, int *len)
 {
   routerinfo_t *tmp=NULL;
   int listlen = 0;
@@ -135,303 +149,220 @@
   return array;
 }
 
+
 /* load the router list */
-routerinfo_t **getrouters(char *routerfile, int *len, uint16_t or_listenport)
+routerinfo_t **router_get_list_from_file(char *routerfile, int *len, uint16_t or_listenport)
 {
-  int retval = 0;
-  char *retp = NULL;
-  routerinfo_t *router=NULL, *routerlist=NULL, *lastrouter=NULL;
-  FILE *rf; /* router file */
-  fpos_t fpos;
-  char line[512];
-  char *token;
-  char *errtest; /* detecting errors in strtoul() calls */
-  struct hostent *rent;
+  routerinfo_t *routerlist=NULL;
+  routerinfo_t *router;
+  int fd; /* router file */
+  struct stat statbuf;
+  char *string;
+  char *tmps;
 
   assert(routerfile && len);
   
   if (strcspn(routerfile,CONFIG_LEGAL_FILENAME_CHARACTERS) != 0) {
-    log(LOG_ERR,"Filename %s contains illegal characters.",routerfile);
+    log(LOG_ERR,"router_get_list_from_file(): Filename %s contains illegal characters.",routerfile);
     return NULL;
   }
   
+  if(stat(routerfile, &statbuf) < 0) {
+    log(LOG_ERR,"router_get_list_from_file(): Could not stat %s.",routerfile);
+    return NULL;
+  }
+
   /* open the router list */
-  rf = fopen(routerfile,"r");
-  if (!rf) {
-    log(LOG_ERR,"Could not open %s.",routerfile);
+  fd = open(routerfile,O_RDONLY,0);
+  if (fd<0) {
+    log(LOG_ERR,"router_get_list_from_file(): Could not open %s.",routerfile);
+    return NULL;
+  }
+
+  string = malloc(statbuf.st_size+1);
+  if(!string) {
+    log(LOG_ERR,"router_get_list_from_file(): Out of memory.");
     return NULL;
   }
+
+  if(read(fd,string,statbuf.st_size) != statbuf.st_size) {
+    log(LOG_ERR,"router_get_list_from_file(): Couldn't read all %d bytes of file '%s'.",statbuf.st_size,routerfile);
+    return NULL;
+  }
+  close(fd);
   
-  retp = fgets(line,512,rf);
-  while (retp) {
-    log(LOG_DEBUG,"getrouters():Line :%s",line);
-    token = (char *)strtok(line,OR_ROUTERLIST_SEPCHARS);
-    if (token)
-    {
-      log(LOG_DEBUG,"getrouters():Token : %s",token);
-      if (token[0] != '#') /* ignore comment lines */
-      {
-	router = malloc(sizeof(routerinfo_t));
-	if (!router)
-	{
-	  log(LOG_ERR,"Could not allocate memory.");
-	  fclose(rf);
-	  delete_routerlist(routerlist);
-	  return NULL;
-	}
-	
-	/* read the address */
-	router->address = malloc(strlen(token)+1);
-	if (!router->address)
-	{
-	  log(LOG_ERR,"Could not allocate memory.");
-	  fclose(rf);
-	  free((void *)router);
-	  delete_routerlist(routerlist);
-	  return NULL;
-	}
-	strcpy(router->address,token);
-	
-	rent = (struct hostent *)gethostbyname(router->address);
-	if (!rent)
-	{
-	  log(LOG_ERR,"Could not get address for router %s.",router->address);
-	  fclose(rf);
-	  free((void *)router->address);
-	  free((void *)router);
-	  delete_routerlist(routerlist);
-	  return NULL;
-	}
+  string[statbuf.st_size] = 0; /* null terminate it */
+  tmps = string;
+  while(*tmps) { /* while not at the end of the string */
+    router = router_get_entry_from_string(&tmps);
+    if(router == NULL) {
+      routerlist_free(routerlist);
+      free(string);
+      return NULL;
+    }
+    if(!router_is_me(router->addr, router->or_port, or_listenport)) {
+      router->next = routerlist;
+      routerlist = router;
+    }
+    tmps = eat_whitespace(tmps);
+  }
+  free(string);
+  return make_rarray(routerlist, len);
+} 
 
-	memcpy(&router->addr, rent->h_addr,rent->h_length);
-	
-	/* read the port */
-	token = (char *)strtok(NULL,OR_ROUTERLIST_SEPCHARS);
-	if (token)
-	{
-	  log(LOG_DEBUG,"getrouters():Token :%s",token);
-	  router->or_port = (uint16_t)strtoul(token,&errtest,0);
-	  if ((*token != '\0') && (*errtest == '\0')) /* conversion was successful */
-	  {
-/* FIXME patch from RD. We should make it actually read these. */
-	    router->op_port = router->or_port + 10;
-	    router->ap_port = router->or_port + 20;
-	    
-	    /* read min bandwidth */
-	    token = (char *)strtok(NULL,OR_ROUTERLIST_SEPCHARS);
-	    if (token) /* min bandwidth */
-	    {
-	      router->min = (uint32_t)strtoul(token,&errtest,0);
-	      if ((*token != '\0') && (*errtest == '\0')) /* conversion was successful */
-	      {
-		if (router->min) /* must not be zero */
-		{
-		  /* read max bandwidth */
-		  token = (char *)strtok(NULL,OR_ROUTERLIST_SEPCHARS);
-		  if (token) /* max bandwidth */
-		  {
-		    router->max = (uint32_t)strtoul(token,&errtest,0);
-		    if ((*token != '\0') && (*errtest == '\0')) /* conversion was successful */
-		    {
-		      if (router->max) /* must not be zero */
-		      {
-			/* check that there is a public key entry for that router */
-			retval = fgetpos(rf, &fpos); /* save the current file position
-						      * we wil return to it later if we find a public key */
-			if (retval == -1)
-			{
-			  log(LOG_ERR,"Could not save position in %s.",routerfile);
-			  free((void *)router->address);
-			  free((void *)router);
-			  fclose(rf);
-			  delete_routerlist(routerlist);
-			  return NULL;
-			}
-			do /* read through to the next non-empty line */
-			{
-			  retp=fgets(line,512,rf);
-			  if (!retp)
-			  {
-			    log(LOG_ERR,"Could not find a public key entry for router %s:%u.",
-				router->address,router->or_port);
-			    free((void *)router->address);
-			    free((void *)router);
-			    fclose(rf);
-			    delete_routerlist(routerlist);
-			    return NULL;
-			  }
-			  log(LOG_DEBUG,"getrouters():Line:%s",line);
-			  if ((*line != '#') && ( strspn(line,OR_ROUTERLIST_SEPCHARS) != strlen(line) ))
-			  {
-			    break;
-			  }
-			} while (1);
-			
-			if (!strcmp(line,OR_PUBLICKEY_BEGIN_TAG)) /* we've got the public key */
-			{
-			  retval = fsetpos(rf,&fpos); /* get us back to where we were otherwise crypto lib won't find the key */
-			  if (retval == -1)
-			  {
-			    log(LOG_ERR,"Could not set position in %s.",routerfile);
-			    free((void *)router->address);
-			    free((void *)router);
-			    fclose(rf);
-			    delete_routerlist(routerlist);
-			    return NULL;
-			  }
-			}
-			else /* we found something else; this isn't right */
-			{
-			  log(LOG_ERR,"Could not find a public key entry for router %s:%u.",
-			      router->address,router->or_port);
-			  free((void *)router->address);
-			  free((void *)router);
-			  fclose(rf);
-			  delete_routerlist(routerlist);
-			  return NULL;
-			}
-			
-			log(LOG_DEBUG,"getrouters():Reading the key ...");
-			/* read the public key into router->pkey */
-			router->pkey = crypto_new_pk_env(CRYPTO_PK_RSA);
-			if (crypto_pk_read_public_key(router->pkey, rf)) /* something went wrong */
-			{
-			  log(LOG_ERR,"Could not read public key for router %s:%u.", 
-			      router->address,router->or_port);
-			  free((void *)router->address);
-			  free((void *)router);
-			  fclose(rf);
-			  delete_routerlist(routerlist);
-			  return NULL;
-			}
-			else /* read the key */
-			{
-			  log(LOG_DEBUG,"getrouters():Public key size = %u.", crypto_pk_keysize(router->pkey));
-			  if (crypto_pk_keysize(router->pkey) != 128) /* keys MUST be 1024 bits in size */
-			  {
-			    log(LOG_ERR,"Key for router %s:%u is not 1024 bits. All keys must be exactly 1024 bits long.",router->address,router->or_port);
-			    free((void *)router->address);
-			    crypto_free_pk_env(router->pkey);
-			    free((void *)router);
-			    fclose(rf);
-			    delete_routerlist(routerlist);
-			    return NULL;
-			  }
-			  
-			  /* check that this router doesn't actually represent us */
-			  retval = router_is_me(router->addr, router->or_port, or_listenport);
-			  if (!retval) { /* this isn't us, continue */
-			    router->next = NULL;
-			    /* save the entry into the routerlist linked list */
-			    if (!routerlist) /* this is the first entry */
-				    routerlist = router;
-			    else
-				    lastrouter->next = (void *)router;
-			    lastrouter = router;
-			  }
-			  else if (retval == 1) /* this is us, ignore */
-			  {
-			    log(LOG_DEBUG,"getrouters(): This entry is actually me. Ignoring.");
-			    free((void *)router->address);
-			    crypto_free_pk_env(router->pkey);
-			    free((void *)router);
-			  }
-			  else /* router_is_me() returned an error */
-			  {
-			    free((void *)router->address);
-			    crypto_free_pk_env(router->pkey);
-			    free((void *)router);
-			    fclose(rf);
-			    delete_routerlist(routerlist);
-			    return NULL;
-			  }
-			}
-		      }
-		      else /* maximum link utilisation is zero */
-		      {
-			log(LOG_ERR,"Entry for router %s doesn't contain a valid maximum bandwidth entry (must be > 0).",router->address);
-			free((void *)router->address);
-			free((void *)router);
-			fclose(rf);
-			delete_routerlist(routerlist);
-			return NULL;
-		      }
-		    }
-		    else
-		    {
-		      log(LOG_ERR,"Entry for router %s doesn't seem to contain a valid maximum bandwidth entry.",router->address);
-		      free((void *)router->address);
-		      free((void *)router);
-		      fclose(rf);
-		      delete_routerlist(routerlist);
-		      return NULL;
-		    }
-		  }
-		  else
-		  {
-		    log(LOG_ERR,"Entry for router %s doesn't seem to contain a maximum bandwidth entry.",router->address);
-		    free((void *)router->address);
-		    free((void *)router);
-		    fclose(rf);
-		    delete_routerlist(routerlist);
-		    return NULL;
-		  }
-		}
-		else
-		{
-		  log(LOG_ERR,"Entry for router %s doesn't contain a valid minimum bandwidth entry (must be > 0).",router->address);
-		  free((void *)router->address);
-		  free((void *)router);
-		  fclose(rf);
-		  delete_routerlist(routerlist);
-		  return NULL;
-		}
-	      }
-	      else
-	      {
-		log(LOG_ERR,"Entry for router %s doesn't seem to contain a valid minimum bandwidth entry.",router->address);
-		free((void *)router->address);
-		free((void *)router);
-		fclose(rf);
-		delete_routerlist(routerlist);
-		return NULL;
-	      }
-	    }
-	    else
-	    {
-	      log(LOG_ERR,"Entry for router %s doesn't seem to contain a minimum bandwidth entry.",router->address);
-	      free((void *)router->address);
-	      free((void *)router);
-	      fclose(rf);
-	      delete_routerlist(routerlist);
-	      return NULL;
-	    }
-	  }
-	  else
-	  {
-	    log(LOG_ERR,"Entry for router %s doesn't seem to contain a valid port number.",router->address);
-	    free((void *)router->address);
-	    free((void *)router);
-	    fclose(rf);
-	    delete_routerlist(routerlist);
-	    return NULL;
-	  }
-	}
-	else
-	{
-	  log(LOG_ERR,"Entry for router %s doesn't seem to contain a port number.",router->address);
-	  free((void *)router->address);
-	  free((void *)router);
-	  fclose(rf);
-	  delete_routerlist(routerlist);
-	  return NULL;
-	}
-      }
+/* return the first char of s that is not whitespace and not a comment */
+static char *eat_whitespace(char *s) {
+  assert(s);
+
+  while(isspace(*s) || *s == '#') {
+    while(isspace(*s))
+      s++;
+    if(*s == '#') { /* read to a \n or \0 */
+      while(*s && *s != '\n')
+        s++;
+      if(!*s)
+        return s;
     }
-    retp=fgets(line,512,rf);
   }
+  return s;
+}
+
+/* return the first char of s that is whitespace or '#' or '\0 */
+static char *find_whitespace(char *s) {
+  assert(s);
+
+  while(*s && !isspace(*s) && *s != '#')
+    s++;
+
+  return s;
+}
+
+/* reads a single router entry from s.
+ * updates s so it points to after the router it just read.
+ * mallocs a new router, returns it if all goes well, else returns NULL.
+ */
+static routerinfo_t *router_get_entry_from_string(char **s) {
+  routerinfo_t *router;
+  char *next;
+  struct hostent *rent;
+
+  router = malloc(sizeof(routerinfo_t));
+  if (!router) {
+    log(LOG_ERR,"router_get_entry_from_string(): Could not allocate memory.");
+    return NULL;
+  }
+  memset(router,0,sizeof(routerinfo_t)); /* zero it out first */
+
+#define NEXT_TOKEN(s, next)    \
+  *s = eat_whitespace(*s);     \
+  next = find_whitespace(*s);  \
+  if(!*next) {                 \
+    goto router_read_failed;   \
+  }                            \
+  *next = 0;
+
+  /* read router->address */
+  NEXT_TOKEN(s, next);
+  router->address = strdup(*s);
+  *s = next+1;
+
+  rent = (struct hostent *)gethostbyname(router->address);
+  if (!rent) {
+    log(LOG_ERR,"router_get_entry_from_string(): Could not get address for router %s.",router->address);
+    goto router_read_failed;
+  }
+  assert(rent->h_length == 4);
+  memcpy(&router->addr, rent->h_addr,rent->h_length);
+
+  /* read router->or_port */
+  NEXT_TOKEN(s, next);
+  router->or_port = atoi(*s);
+  if(!router->or_port) {
+    log(LOG_ERR,"router_get_entry_from_string(): or_port '%s' unreadable or 0. Failing.",*s);
+    goto router_read_failed;
+  }
+  *s = next+1;
   
-  fclose(rf);
-  return make_rarray(routerlist, len);
+  /* read router->op_port */
+  NEXT_TOKEN(s, next);
+  router->op_port = atoi(*s);
+  *s = next+1;
+  
+  /* read router->ap_port */
+  NEXT_TOKEN(s, next);
+  router->ap_port = atoi(*s);
+  *s = next+1;
+  
+  /* read router->dir_port */
+  NEXT_TOKEN(s, next);
+  router->dir_port = atoi(*s);
+  *s = next+1;
+
+  /* read router->bandwidth */
+  NEXT_TOKEN(s, next);
+  router->bandwidth = atoi(*s);
+  if(!router->bandwidth) {
+    log(LOG_ERR,"router_get_entry_from_string(): bandwidth '%s' unreadable or 0. Failing.",*s);
+    goto router_read_failed;
+  }
+  *s = next+1;
+
+  log(LOG_DEBUG,"or_port %d, op_port %d, ap_port %d, dir_port %d, bandwidth %d.",
+    router->or_port, router->op_port, router->ap_port, router->dir_port, router->bandwidth);
+
+  *s = eat_whitespace(*s); 
+  next = strstr(*s,OR_PUBLICKEY_END_TAG);
+  router->pkey = crypto_new_pk_env(CRYPTO_PK_RSA);
+  if(!next || !router->pkey) {
+    log(LOG_ERR,"router_get_entry_from_string(): Couldn't find pk in string");
+    goto router_read_failed;
+  }
+  
+  /* now advance *s so it's at the end of this router entry */
+  next = strchr(next, '\n');
+  assert(next); /* can't fail, we just checked it was here */
+  *next = 0;
+  log(LOG_DEBUG,"Key about to be read is: '%s'",*s);
+  if((crypto_pk_read_public_key_from_string(router->pkey, *s, strlen(*s))<0)) {
+    log(LOG_ERR,"router_get_entry_from_string(): Couldn't read pk from string");
+    goto router_read_failed;
+  }
+  log(LOG_DEBUG,"router_get_entry_from_string(): Public key size = %u.", crypto_pk_keysize(router->pkey));
+
+  if (crypto_pk_keysize(router->pkey) != 128) { /* keys MUST be 1024 bits in size */
+    log(LOG_ERR,"Key for router %s:%u is not 1024 bits. All keys must be exactly 1024 bits long.",
+      router->address,router->or_port);
+    goto router_read_failed;
+  }
+
+//  test_write_pkey(router->pkey);  
+
+  *s = next+1;
+
+  /* success */
+  return(router);
+
+router_read_failed:
+  if(router->address)
+    free(router->address);
+  if(router->pkey)
+    crypto_free_pk_env(router->pkey);
+  free(router);
+  return NULL;
 }
+
+#if 0
+void test_write_pkey(crypto_pk_env_t *pkey) {
+  char *string;
+  int len;
+
+  log(LOG_DEBUG,"Trying test write.");
+  if(crypto_pk_write_public_key_to_string(pkey,&string,&len)<0) {
+    log(LOG_DEBUG,"router_get_entry_from_string(): write pkey to string failed\n");
+    return;
+  }
+  log(LOG_DEBUG,"I did it: len %d, string '%s'.",len,string);
+  free(string);
+}
+#endif
 



More information about the tor-commits mailing list