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

[or-cvs] incremental path building in; uses ephemeral DH; onions are...



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

Modified Files:
	circuit.c command.c connection.c connection_edge.c main.c 
	onion.c or.h routers.c 
Log Message:
incremental path building in; uses ephemeral DH; onions are gone
still need to change circuit-level sendmes



Index: circuit.c
===================================================================
RCS file: /home/or/cvsroot/src/or/circuit.c,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -d -r1.41 -r1.42
--- circuit.c	2 May 2003 21:29:25 -0000	1.41
+++ circuit.c	5 May 2003 23:24:45 -0000	1.42
@@ -65,7 +65,7 @@
   circ->p_aci = p_aci;
   circ->p_conn = p_conn;
 
-  circ->state = CIRCUIT_STATE_ONION_WAIT;
+  circ->state = CIRCUIT_STATE_ONIONSKIN_PENDING;
 
   /* ACIs */
   circ->p_aci = p_aci;
@@ -87,8 +87,6 @@
   if (circ->p_crypto)
     crypto_free_cipher_env(circ->p_crypto);
 
-  if(circ->onion)
-    free(circ->onion);
   circuit_free_cpath(circ->cpath);
   while(circ->relay_queue) {
     tmpd = circ->relay_queue;
@@ -122,6 +120,8 @@
     crypto_free_cipher_env(victim->f_crypto);
   if(victim->b_crypto)
     crypto_free_cipher_env(victim->b_crypto);
+  if(victim->handshake_state)
+    crypto_dh_free(victim->handshake_state);
   free(victim);
 }
 
@@ -155,66 +155,6 @@
   return test_aci;
 }
 
-int circuit_init(circuit_t *circ, int aci_type, onion_layer_t *layer) {
-  unsigned char iv[16];
-  unsigned char digest1[20];
-  unsigned char digest2[20];
-  struct timeval start, end;
-  long time_passed;
-
-  assert(circ && circ->onion);
-
-  log(LOG_DEBUG,"circuit_init(): starting");
-  circ->n_port = layer->port;
-  log(LOG_DEBUG,"circuit_init(): Set port to %u.",circ->n_port);
-  circ->n_addr = layer->addr;
-  circ->state = CIRCUIT_STATE_OPEN;
-
-  log(LOG_DEBUG,"circuit_init(): aci_type = %u.",aci_type);
-
-  my_gettimeofday(&start);
-
-  circ->n_aci = get_unique_aci_by_addr_port(circ->n_addr, circ->n_port, aci_type);
-  if(!circ->n_aci) {
-    log(LOG_ERR,"circuit_init(): failed to get unique aci.");
-    return -1;
-  }
-
-  my_gettimeofday(&end);
-
-  time_passed = tv_udiff(&start, &end);
-  if (time_passed > 1000) {/* more than 1ms */
-    log(LOG_NOTICE,"circuit_init(): get_unique_aci just took %d us!",time_passed);
-  }
-
-  log(LOG_DEBUG,"circuit_init(): Chosen ACI %u.",circ->n_aci);
-
-  /* keys */
-  memset(iv, 0, 16);
-  crypto_SHA_digest(layer->keyseed,16,digest1);
-  crypto_SHA_digest(digest1,20,digest2);
-  crypto_SHA_digest(digest2,20,digest1);
-  log(LOG_DEBUG,"circuit_init(): Computed keys.");
-
-  if (!(circ->p_crypto = 
-        crypto_create_init_cipher(DEFAULT_CIPHER,digest2,iv,1))) {
-    log(LOG_ERR,"Cipher initialization failed (ACI %u).",circ->n_aci);
-    return -1;
-  }
-  
-  if (!(circ->n_crypto = 
-        crypto_create_init_cipher(DEFAULT_CIPHER,digest1,iv,0))) {
-    log(LOG_ERR,"Cipher initialization failed (ACI %u).",circ->n_aci);
-    return -1;
-  }
-
-  log(LOG_DEBUG,"circuit_init(): Cipher initialization complete.");
-
-  circ->expire = layer->expire;
-
-  return 0;
-}
-
 circuit_t *circuit_enumerate_by_naddr_nport(circuit_t *circ, uint32_t naddr, uint16_t nport) {
 
   if(!circ) /* use circ if it's defined, else start from the beginning */
@@ -269,13 +209,11 @@
   circuit_t *circ, *bestcirc=NULL;
 
   for(circ=global_circuitlist;circ;circ = circ->next) {
-    if(!circ->p_conn || circ->p_conn->type == CONN_TYPE_AP) {
-      if(circ->state == CIRCUIT_STATE_OPEN && (!bestcirc ||
-        bestcirc->timestamp_created < circ->timestamp_created)) {
-        log(LOG_DEBUG,"circuit_get_newest_ap(): Choosing n_aci %d.", circ->n_aci);
-        assert(circ->n_aci);
-        bestcirc = circ;
-      }
+    if(circ->cpath && circ->state == CIRCUIT_STATE_OPEN && (!bestcirc ||
+      bestcirc->timestamp_created < circ->timestamp_created)) {
+      log(LOG_DEBUG,"circuit_get_newest_ap(): Choosing n_aci %d.", circ->n_aci);
+      assert(circ->n_aci);
+      bestcirc = circ;
     }
   }
   return bestcirc;
@@ -331,7 +269,7 @@
   buf[0] = cell->length;
   memcpy(buf+1, cell->payload, CELL_PAYLOAD_SIZE);
 
-  log(LOG_DEBUG,"circuit_deliver_relay_cell(): streamid %d before crypt.", *(int*)(cell->payload+1));
+  log(LOG_DEBUG,"circuit_deliver_relay_cell(): direction %d, streamid %d before crypt.", cell_direction, *(int*)(cell->payload+1));
 
   if(relay_crypt(circ, buf, 1+CELL_PAYLOAD_SIZE, cell_direction, layer_hint, &recognized, &conn) < 0) {
     log(LOG_DEBUG,"circuit_deliver_relay_cell(): relay crypt failed. Dropping connection.");
@@ -363,6 +301,7 @@
     return 0;
   }
 
+  log(LOG_DEBUG,"circuit_deliver_relay_cell(): Passing on unrecognized cell.");
   return connection_write_cell_to_buf(cell, conn);
 }
 
@@ -378,32 +317,42 @@
   if(cell_direction == CELL_DIRECTION_IN) { 
     if(circ->cpath) { /* we're at the beginning of the circuit. We'll want to do layered crypts. */
       thishop = circ->cpath;
+      if(thishop->state != CPATH_STATE_OPEN) {
+        log(LOG_INFO,"relay_crypt(): Relay cell before first created cell?");
+        return -1;
+      }
       do { /* Remember: cpath is in forward order, that is, first hop first. */
         assert(thishop);
 
+        log(LOG_DEBUG,"relay_crypt(): before decrypt: %d",*(int*)(in+2));
         /* decrypt */
         if(crypto_cipher_decrypt(thishop->b_crypto, in, inlen, out)) {
           log(LOG_ERR,"Error performing decryption:%s",crypto_perror());
           return -1;
         }
         memcpy(in,out,inlen);
+        log(LOG_DEBUG,"relay_crypt(): after decrypt: %d",*(int*)(in+2));
 
         if( (*recognized = relay_check_recognized(circ, cell_direction, in+2, conn)))
           return 0;
 
         thishop = thishop->next;
-      } while(thishop != circ->cpath);
+      } while(thishop != circ->cpath && thishop->state == CPATH_STATE_OPEN);
       log(LOG_INFO,"relay_crypt(): in-cell at OP not recognized. Killing circuit.");
-      return -1;
+      return 0;
+//      return -1;
     } else { /* we're in the middle. Just one crypt. */
 
+      log(LOG_DEBUG,"relay_crypt(): before encrypt: %d",*(int*)(in+2));
       if(crypto_cipher_encrypt(circ->p_crypto, in, inlen, out)) {
         log(LOG_ERR,"circuit_encrypt(): Encryption failed for ACI : %u (%s).",
             circ->p_aci, crypto_perror());
         return -1;
       }
       memcpy(in,out,inlen);
+      log(LOG_DEBUG,"relay_crypt(): after encrypt: %d",*(int*)(in+2));
 
+      log(LOG_DEBUG,"circuit_encrypt(): Skipping recognized check, because we're not the OP.");
       /* don't check for recognized. only the OP can recognize a stream on the way back. */
 
     }
@@ -415,12 +364,13 @@
       do {
         assert(thishop);
 
-        /* encrypt */
+        log(LOG_DEBUG,"relay_crypt(): before encrypt: %d",*(int*)(in+2));
         if(crypto_cipher_encrypt(thishop->f_crypto, in, inlen, out)) {
           log(LOG_ERR,"Error performing encryption:%s",crypto_perror());
           return -1;
         }
         memcpy(in,out,inlen);
+        log(LOG_DEBUG,"relay_crypt(): after encrypt: %d",*(int*)(in+2));
 
         thishop = thishop->prev;
       } while(thishop != circ->cpath->prev);
@@ -450,8 +400,10 @@
   connection_t *tmpconn;
 
   log(LOG_DEBUG,"relay_check_recognized(): entering");
-  if(!memcmp(stream,ZERO_STREAM,STREAM_ID_SIZE))
+  if(!memcmp(stream,ZERO_STREAM,STREAM_ID_SIZE)) {
+    log(LOG_DEBUG,"relay_check_recognized(): It's the zero stream. Recognized.");
     return 1; /* the zero stream is always recognized */
+  }
 
   if(cell_direction == CELL_DIRECTION_OUT)
     tmpconn = circ->n_conn;
@@ -459,8 +411,10 @@
     tmpconn = circ->p_conn;
 
   log(LOG_DEBUG,"relay_check_recognized(): not the zero stream.");
-  if(!tmpconn)
+  if(!tmpconn) {
+    log(LOG_DEBUG,"relay_check_recognized(): No conns. Not recognized.");
     return 0; /* no conns? don't recognize it */
+  }
 
   while(tmpconn && tmpconn->type == CONN_TYPE_OR) {
     log(LOG_DEBUG,"relay_check_recognized(): skipping over an OR conn");
@@ -723,7 +677,7 @@
     return;
   }
 
-  if(circuit_create_onion() < 0) {
+  if(circuit_establish_circuit() < 0) {
     failures++;
     goto retry_circuit;
   }
@@ -732,50 +686,21 @@
   return;
 }
 
-int circuit_create_onion(void) {
-  int routelen; /* length of the route */
-  unsigned int *route; /* hops in the route as an array of indexes into rarray */
-  unsigned char *onion; /* holds the onion */
-  int onionlen; /* onion length in host order */
-  crypt_path_t *cpath; /* defines the crypt operations that need to be performed on incoming/outgoing data */
-
-  /* choose a route */
-  route = (unsigned int *)router_new_route(&routelen);
-  if (!route) { 
-    log(LOG_ERR,"circuit_create_onion(): Error choosing a route through the OR network.");
-    return -1;
-  }
-  log(LOG_DEBUG,"circuit_create_onion(): Chosen a route of length %u : ",routelen);
-
-  /* create an onion and calculate crypto keys */
-  onion = router_create_onion(route,routelen,&onionlen, &cpath);
-  if (!onion) {
-    log(LOG_ERR,"circuit_create_onion(): Error creating an onion.");
-    free(route);
-    return -1;
-  }
-  log(LOG_DEBUG,"circuit_create_onion(): Created an onion of size %u bytes.",onionlen);
-//  log(LOG_DEBUG,"circuit_create_onion(): Crypt path :");
-
-  return circuit_establish_circuit(route, routelen, onion, onionlen, cpath);
-}
-
-int circuit_establish_circuit(unsigned int *route, int routelen, char *onion,
-                                   int onionlen, crypt_path_t *cpath) {
+int circuit_establish_circuit(void) {
   routerinfo_t *firsthop;
   connection_t *n_conn;
   circuit_t *circ;
 
-  /* now see if we're already connected to the first OR in 'route' */
-  firsthop = router_get_first_in_route(route, routelen);
-  assert(firsthop); /* should always be defined */
-  free(route); /* we don't need it anymore */
-
   circ = circuit_new(0, NULL); /* sets circ->p_aci and circ->p_conn */
   circ->state = CIRCUIT_STATE_OR_WAIT;
-  circ->onion = onion;
-  circ->onionlen = onionlen;
-  circ->cpath = cpath;
+  circ->cpath = onion_generate_cpath(&firsthop);
+  if(!circ->cpath) {
+    log(LOG_DEBUG,"circuit_establish_circuit(): Generating cpath failed.");
+    circuit_close(circ);
+    return -1;
+  }
+
+  /* now see if we're already connected to the first OR in 'route' */
 
   log(LOG_DEBUG,"circuit_establish_circuit(): Looking for firsthop '%s:%u'",
       firsthop->address,firsthop->or_port);
@@ -798,14 +723,22 @@
       }
     }
 
+    log(LOG_DEBUG,"circuit_establish_circuit(): connecting in progress (or finished). Good.");
     return 0; /* return success. The onion/circuit/etc will be taken care of automatically
                * (may already have been) whenever n_conn reaches OR_CONN_STATE_OPEN.
                */ 
   } else { /* it (or a twin) is already open. use it. */
     circ->n_addr = n_conn->addr;
     circ->n_port = n_conn->port;
-    return circuit_send_onion(n_conn, circ);
+    circ->n_conn = n_conn;
+    log(LOG_DEBUG,"circuit_establish_circuit(): Conn open. Delivering first onion skin.");
+    if(circuit_send_next_onion_skin(circ) < 0) {
+      log(LOG_DEBUG,"circuit_establish_circuit(): circuit_send_next_onion_skin failed.");
+      circuit_close(circ);
+      return -1;
+    }
   }
+  return 0;
 }
 
 /* find circuits that are waiting on me, if any, and get them to send the onion */
@@ -818,8 +751,9 @@
     if(!circ)
       return;
 
-    log(LOG_DEBUG,"circuit_n_conn_open(): Found circ, sending onion.");
-    if(circuit_send_onion(or_conn, circ) < 0) {
+    log(LOG_DEBUG,"circuit_n_conn_open(): Found circ, sending onion skin.");
+    circ->n_conn = or_conn;
+    if(circuit_send_next_onion_skin(circ) < 0) {
       log(LOG_DEBUG,"circuit_n_conn_open(): circuit marked for closing.");
       circuit_close(circ);
       return; /* FIXME will want to try the other circuits too? */
@@ -828,50 +762,182 @@
   }
 }
 
-int circuit_send_onion(connection_t *n_conn, circuit_t *circ) {
+int circuit_send_next_onion_skin(circuit_t *circ) {
   cell_t cell;
-  int tmpbuflen, dataleft;
-  char *tmpbuf;
+  crypt_path_t *hop;
+  routerinfo_t *router;
 
-  circ->n_aci = get_unique_aci_by_addr_port(circ->n_addr, circ->n_port, ACI_TYPE_BOTH);
-  circ->n_conn = n_conn;
-  log(LOG_DEBUG,"circuit_send_onion(): n_conn is %s:%u",n_conn->address,n_conn->port);
+  assert(circ && circ->cpath);
 
-  /* deliver the onion as one or more create cells */
-  cell.command = CELL_CREATE;
-  cell.aci = circ->n_aci;
+  if(circ->cpath->state == CPATH_STATE_CLOSED) {
 
-  tmpbuflen = circ->onionlen+4;
-  tmpbuf = malloc(tmpbuflen);
-  if(!tmpbuf)
-    return -1;
-  *(uint32_t*)tmpbuf = htonl(circ->onionlen);
-  memcpy(tmpbuf+4, circ->onion, circ->onionlen);
+    log(LOG_DEBUG,"circuit_send_next_onion_skin(): First skin; sending create cell.");
+    circ->n_aci = get_unique_aci_by_addr_port(circ->n_addr, circ->n_port, ACI_TYPE_BOTH);
 
-  dataleft = tmpbuflen;
-  while(dataleft) {
+    memset(&cell, 0, sizeof(cell_t));
     cell.command = CELL_CREATE;
     cell.aci = circ->n_aci;
-    log(LOG_DEBUG,"circuit_send_onion(): Sending a create cell for the onion...");
-    if(dataleft >= CELL_PAYLOAD_SIZE) {
-      cell.length = CELL_PAYLOAD_SIZE;
-      memcpy(cell.payload, tmpbuf + tmpbuflen - dataleft, CELL_PAYLOAD_SIZE);
-      connection_write_cell_to_buf(&cell, n_conn);
-      dataleft -= CELL_PAYLOAD_SIZE;
-    } else { /* last cell */
-      cell.length = dataleft;
-      memcpy(cell.payload, tmpbuf + tmpbuflen - dataleft, dataleft);
-      /* fill extra space with 0 bytes */
-      memset(cell.payload + dataleft, 0, CELL_PAYLOAD_SIZE - dataleft);
-      connection_write_cell_to_buf(&cell, n_conn);
-      dataleft = 0;
+    cell.length = 208;
+
+    if(onion_skin_create(circ->n_conn->pkey, &(circ->cpath->handshake_state), cell.payload) < 0) {
+      log(LOG_INFO,"circuit_send_next_onion_skin(): onion_skin_create (first hop) failed.");
+      return -1;
+    }
+
+    if(connection_write_cell_to_buf(&cell, circ->n_conn) < 0) {
+      return -1;
+    }
+
+    circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
+    circ->state = CIRCUIT_STATE_BUILDING;
+    log(LOG_DEBUG,"circuit_send_next_onion_skin(): first skin; finished sending create cell.");
+  } else {
+    assert(circ->cpath->state == CPATH_STATE_OPEN);
+    assert(circ->state == CIRCUIT_STATE_BUILDING);
+    log(LOG_DEBUG,"circuit_send_next_onion_skin(): starting to send subsequent skin.");
+    for(hop=circ->cpath->next;
+        hop != circ->cpath && hop->state == CPATH_STATE_OPEN;
+        hop=hop->next) ;
+    if(hop == circ->cpath) { /* done building the circuit. whew. */
+      circ->state = CIRCUIT_STATE_OPEN;
+      log(LOG_DEBUG,"circuit_send_next_onion_skin(): circuit built!");
+      return 0;
+    }
+
+    router = router_get_by_addr_port(hop->addr,hop->port);
+    if(!router) {
+      log(LOG_INFO,"circuit_send_next_onion_skin(): couldn't lookup router %d:%d",hop->addr,hop->port);
+      return -1;
+    }
+
+    memset(&cell, 0, sizeof(cell_t));
+    cell.command = CELL_RELAY; 
+    cell.aci = circ->n_aci;
+    SET_CELL_RELAY_COMMAND(cell, RELAY_COMMAND_EXTEND);
+    SET_CELL_STREAM_ID(cell, ZERO_STREAM);
+
+    cell.length = RELAY_HEADER_SIZE + 6 + 208;
+    *(uint32_t*)(cell.payload+RELAY_HEADER_SIZE) = htonl(hop->addr);
+    *(uint32_t*)(cell.payload+RELAY_HEADER_SIZE+4) = htons(hop->port);
+    if(onion_skin_create(router->pkey, &(hop->handshake_state), cell.payload+RELAY_HEADER_SIZE+6) < 0) {
+      log(LOG_INFO,"circuit_send_next_onion_skin(): onion_skin_create failed.");
+      return -1;
     }
+
+    log(LOG_DEBUG,"circuit_send_next_onion_skin(): Sending extend relay cell.");
+    /* send it to hop->prev, because it will transfer it to a create cell and then send to hop */
+    if(circuit_deliver_relay_cell_from_edge(&cell, circ, EDGE_AP, hop->prev) < 0) {
+      log(LOG_DEBUG,"circuit_send_next_onion_skin(): failed to deliver extend cell. Closing.");
+      return -1;
+    }
+    hop->state = CPATH_STATE_AWAITING_KEYS;
   }
-  free(tmpbuf);
+  return 0;
+}
 
-  circ->state = CIRCUIT_STATE_OPEN;
-  /* FIXME should set circ->expire to something here */
+/* take the 'extend' cell, pull out addr/port plus the onion skin. Connect
+ * to the next hop, and pass it the onion skin in a create cell.
+ */
+int circuit_extend(cell_t *cell, circuit_t *circ) {
+  connection_t *n_conn;
+  aci_t aci_type;
+  struct sockaddr_in me; /* my router identity */
+  cell_t newcell;
+
+  circ->n_addr = ntohl(*(uint32_t*)(cell->payload+RELAY_HEADER_SIZE));
+  circ->n_port = ntohs(*(uint16_t*)(cell->payload+RELAY_HEADER_SIZE+4));
+
+  if(learn_my_address(&me) < 0)
+    return -1;
+
+  n_conn = connection_twin_get_by_addr_port(circ->n_addr,circ->n_port);
+  if(!n_conn || n_conn->type != CONN_TYPE_OR) {
+    /* i've disabled making connections through OPs, but it's definitely
+     * possible here. I'm not sure if it would be a bug or a feature. -RD
+     */
+    /* note also that this will close circuits where the onion has the same
+     * router twice in a row in the path. i think that's ok. -RD
+     */
+    log(LOG_DEBUG,"circuit_extend(): Next router not connected. Closing.");
+    /* XXX later we should fail more gracefully here, like with a 'truncated' */
+    return -1;
+  }
+
+  circ->n_addr = n_conn->addr; /* these are different if we found a twin instead */
+  circ->n_port = n_conn->port;
+
+  circ->n_conn = n_conn;
+  log(LOG_DEBUG,"circuit_extend(): n_conn is %s:%u",n_conn->address,n_conn->port);
+
+  aci_type = decide_aci_type(ntohl(me.sin_addr.s_addr), ntohs(me.sin_port),
+                             circ->n_addr, circ->n_port);
+
+  log(LOG_DEBUG,"circuit_extend(): aci_type = %u.",aci_type);
+  circ->n_aci = get_unique_aci_by_addr_port(circ->n_addr, circ->n_port, aci_type);
+  if(!circ->n_aci) {
+    log(LOG_ERR,"circuit_extend(): failed to get unique aci.");
+    return -1;
+  }
+  log(LOG_DEBUG,"circuit_extend(): Chosen ACI %u.",circ->n_aci);
+
+  memset(&newcell, 0, sizeof(cell_t));
+  newcell.command = CELL_CREATE;
+  newcell.aci = circ->n_aci;
+  newcell.length = 208;
+
+  memcpy(newcell.payload, cell->payload+RELAY_HEADER_SIZE+6, 208);
+
+  if(connection_write_cell_to_buf(&newcell, circ->n_conn) < 0) {
+    return -1;
+  }
+
+  return 0;
+}
+
+int circuit_finish_handshake(circuit_t *circ, char *reply) {
+  unsigned char iv[16];
+  unsigned char keys[32];
+  crypt_path_t *hop;
+
+  memset(iv, 0, 16);
+
+  assert(circ->cpath);
+  if(circ->cpath->state == CPATH_STATE_AWAITING_KEYS)
+    hop = circ->cpath;
+  else {
+    for(hop=circ->cpath->next;
+        hop != circ->cpath && hop->state == CPATH_STATE_OPEN;
+        hop=hop->next) ;
+    if(hop == circ->cpath) { /* got an extended when we're all done? */
+      log(LOG_INFO,"circuit_finish_handshake(): got extended when circ already built? Weird.");
+      return 0;
+    }
+  }
+  assert(hop->state == CPATH_STATE_AWAITING_KEYS);
 
+  if(onion_skin_client_handshake(hop->handshake_state, reply, keys, 32) < 0) {
+    log(LOG_ERR,"circuit_finish_handshake(): onion_skin_client_handshake failed.");
+    return -1;
+  }
+
+  crypto_dh_free(hop->handshake_state); /* don't need it anymore */
+  hop->handshake_state = NULL;
+
+  log(LOG_DEBUG,"circuit_finish_handshake(): hop %d init cipher forward %d, backward %d.", hop, *(int*)keys, *(int*)(keys+16));
+  if (!(hop->f_crypto =
+        crypto_create_init_cipher(DEFAULT_CIPHER,keys,iv,1))) {
+    log(LOG_ERR,"Cipher initialization failed.");
+    return -1;
+  }
+
+  if (!(hop->b_crypto =
+        crypto_create_init_cipher(DEFAULT_CIPHER,keys+16,iv,0))) {
+    log(LOG_ERR,"Cipher initialization failed.");
+    return -1;
+  }
+
+  hop->state = CPATH_STATE_OPEN;
+  log(LOG_DEBUG,"circuit_finish_handshake(): Completed.");
   return 0;
 }
 

Index: command.c
===================================================================
RCS file: /home/or/cvsroot/src/or/command.c,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -d -r1.26 -r1.27
--- command.c	2 May 2003 21:29:25 -0000	1.26
+++ command.c	5 May 2003 23:24:45 -0000	1.27
@@ -28,8 +28,8 @@
 }
 
 void command_process_cell(cell_t *cell, connection_t *conn) {
-  static int num_create=0, num_relay=0, num_destroy=0, num_sendme=0;
-  static int create_time=0, relay_time=0, destroy_time=0, sendme_time=0;
+  static int num_create=0, num_created=0, num_relay=0, num_destroy=0, num_sendme=0;
+  static int create_time=0, created_time=0, relay_time=0, destroy_time=0, sendme_time=0;
   static long current_second = 0; /* from previous calls to gettimeofday */
   struct timeval now;
 
@@ -39,18 +39,20 @@
     /* print stats */
     log(LOG_INFO,"At end of second:"); 
     log(LOG_INFO,"Create:    %d (%d ms)", num_create, create_time/1000);
+    log(LOG_INFO,"Created:   %d (%d ms)", num_created, created_time/1000);
     log(LOG_INFO,"Relay:     %d (%d ms)", num_relay, relay_time/1000);
     log(LOG_INFO,"Destroy:   %d (%d ms)", num_destroy, destroy_time/1000);
     log(LOG_INFO,"Sendme:    %d (%d ms)", num_sendme, sendme_time/1000);
 
     /* zero out stats */
-    num_create = num_relay = num_destroy = num_sendme = 0;
-    create_time = relay_time = destroy_time = sendme_time = 0;
+    num_create = num_created = num_relay = num_destroy = num_sendme = 0;
+    create_time = created_time = relay_time = destroy_time = sendme_time = 0;
 
     /* remember which second it is, for next time */
     current_second = now.tv_sec; 
   }
 
+  log(LOG_DEBUG,"command_process_cell(): Examining cell type %d.", cell->command);
   switch(cell->command) {
     case CELL_PADDING:
       /* do nothing */
@@ -59,6 +61,10 @@
       command_time_process_cell(cell, conn, &num_create, &create_time,
                                 command_process_create_cell);
       break;
+    case CELL_CREATED:
+      command_time_process_cell(cell, conn, &num_created, &created_time,
+                                command_process_created_cell);
+      break;
     case CELL_RELAY:
       command_time_process_cell(cell, conn, &num_relay, &relay_time,
                                 command_process_relay_cell);
@@ -82,60 +88,76 @@
 
   circ = circuit_get_by_aci_conn(cell->aci, conn);
 
-  if(circ && circ->state != CIRCUIT_STATE_ONION_WAIT) {
-    log(LOG_DEBUG,"command_process_create_cell(): received CREATE cell, not in onion_wait. Dropping.");
+  if(circ) {
+    log(LOG_DEBUG,"command_process_create_cell(): received CREATE cell for known circ. Dropping.");
     return;
   }
 
-  if(!circ) { /* if it's not there, create it */
-    circ = circuit_new(cell->aci, conn);
-    circ->state = CIRCUIT_STATE_ONION_WAIT;
-    circ->onionlen = ntohl(*(int*)cell->payload);
-    log(LOG_DEBUG,"command_process_create_cell():  Onion length is %u.",circ->onionlen);
-    if(circ->onionlen > 50000 || circ->onionlen < 1) { /* too big or too small */
-      log(LOG_DEBUG,"That's ludicrous. Closing.");
-      circuit_close(circ);
-      return;
-    }
-    circ->onion = malloc(circ->onionlen);
-    if(!circ->onion) { 
-      log(LOG_DEBUG,"command_process_create_cell(): Out of memory. Closing.");
+  circ = circuit_new(cell->aci, conn);
+  circ->state = CIRCUIT_STATE_ONIONSKIN_PENDING;
+  if(cell->length != 208) {
+    log(LOG_DEBUG,"command_process_create_cell(): Bad cell length %d. Dropping.", cell->length);
+    circuit_close(circ);
+    return;
+  }
+
+  memcpy(circ->onionskin,cell->payload,cell->length);
+
+  /* add it to the pending onions queue, and then return */
+  if(onion_pending_add(circ) < 0) {
+    log(LOG_DEBUG,"command_process_create_cell(): Failed to queue onionskin. Closing.");
+    circuit_close(circ);
+  }
+  log(LOG_DEBUG,"command_process_create_cell(): success: queued onionskin.");
+  return;
+}
+
+void command_process_created_cell(cell_t *cell, connection_t *conn) {
+  circuit_t *circ;
+  cell_t newcell;
+
+  circ = circuit_get_by_aci_conn(cell->aci, conn);
+
+  if(!circ) {
+    log(LOG_DEBUG,"command_process_created_cell(): received CREATED cell for unknown circ. Dropping.");
+    return;
+  }
+
+  if(circ->n_aci != cell->aci) {
+    log(LOG_DEBUG,"command_process_created_cell(): got created cell from OPward? Dropping.");
+    return;
+  }
+  assert(cell->length == 192);
+
+  if(circ->cpath) { /* we're the OP. Handshake this. */
+    log(LOG_DEBUG,"command_process_created_cell(): at OP. Finishing handshake.");
+    if(circuit_finish_handshake(circ, cell->payload) < 0) {
+      log(LOG_INFO,"command_process_created_cell(): circuit_finish_handshake failed.");
       circuit_close(circ);
       return;
     }
-    if(circ->onionlen < cell->length-4) { /* protect from buffer overflow */
-      log(LOG_DEBUG,"command_process_create_cell(): Onion too small. Closing.");
+    log(LOG_DEBUG,"command_process_created_cell(): Moving to next skin.");
+    if(circuit_send_next_onion_skin(circ) < 0) {
+      log(LOG_INFO,"command_process_created_cell(): circuit_send_next_onion_skin failed.");
       circuit_close(circ);
       return;
     }
-    memcpy((void *)circ->onion,(void *)(cell->payload+4),cell->length-4);
-    circ->recvlen = cell->length-4;
-    log(LOG_DEBUG,"command_process_create_cell(): Primary create cell handled, have received %d of %d onion bytes.",
-        circ->recvlen,circ->onionlen);
+  } else { /* pack it into an extended relay cell, and send it. */
+    memset(&newcell, 0, sizeof(cell_t));
+    newcell.command = CELL_RELAY;
+    newcell.aci = circ->p_aci;
+    SET_CELL_RELAY_COMMAND(newcell, RELAY_COMMAND_EXTENDED);
+    SET_CELL_STREAM_ID(newcell, ZERO_STREAM);
 
-  } else { /* pull over as much of the onion as we can */
-    if(cell->length + circ->recvlen > circ->onionlen) { /* protect from buffer overflow */
-      log(LOG_DEBUG,"command_process_create_cell(): payload too big for onion. Closing.");
+    newcell.length = RELAY_HEADER_SIZE + cell->length;
+    memcpy(newcell.payload+RELAY_HEADER_SIZE, cell->payload, 192);
+
+    log(LOG_DEBUG,"command_process_created_cell(): Sending extended relay cell.");
+    if(circuit_deliver_relay_cell_from_edge(&newcell, circ, EDGE_EXIT, NULL) < 0) {
+      log(LOG_DEBUG,"command_process_created_cell(): failed to deliver extended cell. Closing.");
       circuit_close(circ);
       return;
     }
-    memcpy((void *)(circ->onion+circ->recvlen),(void *)cell->payload,cell->length);
-    circ->recvlen += cell->length;
-    log(LOG_DEBUG,"command_process_create_cell(): Secondary create cell handled, have received %d of %d onion bytes (aci %d)",
-        circ->recvlen,circ->onionlen,circ->p_aci);
-  }
-
-  if(circ->recvlen != circ->onionlen) {
-    log(LOG_DEBUG,"command_process_create_cell(): Onion not all here yet. Ok.");
-    return;
-  }
-
-  /* add it to the pending onions queue, and then return */
-  circ->state = CIRCUIT_STATE_ONION_PENDING;
-
-  if(onion_pending_add(circ) < 0) {
-    log(LOG_DEBUG,"command_process_create_cell(): Failed to queue onion. Closing.");
-    circuit_close(circ);
   }
   return;
 }
@@ -150,6 +172,7 @@
     return;
   }
 
+#if 0
   if(circ->state == CIRCUIT_STATE_ONION_WAIT) {
     log(LOG_DEBUG,"command_process_sendme_cell(): circuit in onion_wait. Dropping.");
     return;
@@ -158,6 +181,7 @@
     log(LOG_DEBUG,"command_process_sendme_cell(): circuit in or_wait. Dropping.");
     return;
   }
+#endif
 
   /* at this point both circ->n_conn and circ->p_conn are guaranteed to be set */
 
@@ -205,7 +229,7 @@
     return;
   }
 
-  if(circ->state == CIRCUIT_STATE_ONION_PENDING) {
+  if(circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) {
     log(LOG_DEBUG,"command_process_relay_cell(): circuit in create_wait. Queueing relay cell.");
     onion_pending_relay_add(circ, cell);
     return;
@@ -213,22 +237,23 @@
 
   if(cell->aci == circ->p_aci) { /* it's an outgoing cell */
     if(--circ->p_receive_circwindow < 0) { /* is it less than 0 after decrement? */
-      log(LOG_INFO,"connection_process_relay_cell(): Too many relay cells for out circuit (aci %d). Closing.", circ->p_aci);
+      log(LOG_INFO,"command_process_relay_cell(): Too many relay cells for out circuit (aci %d). Closing.", circ->p_aci);
       circuit_close(circ);
       return;
     }
-    log(LOG_DEBUG,"connection_process_relay_cell(): p_receive_circwindow for aci %d is %d.",circ->p_aci,circ->p_receive_circwindow);
+    log(LOG_DEBUG,"command_process_relay_cell(): p_receive_circwindow for aci %d is %d.",circ->p_aci,circ->p_receive_circwindow);
   }
 
   if(cell->aci == circ->n_aci) { /* it's an ingoing cell */
     if(--circ->n_receive_circwindow < 0) { /* is it less than 0 after decrement? */
-      log(LOG_INFO,"connection_process_relay_cell(): Too many relay cells for in circuit (aci %d). Closing.", circ->n_aci);
+      log(LOG_INFO,"command_process_relay_cell(): Too many relay cells for in circuit (aci %d). Closing.", circ->n_aci);
       circuit_close(circ);
       return;
     }
-    log(LOG_DEBUG,"connection_process_relay_cell(): n_receive_circwindow for aci %d is %d.",circ->n_aci,circ->n_receive_circwindow);
+    log(LOG_DEBUG,"command_process_relay_cell(): n_receive_circwindow for aci %d is %d.",circ->n_aci,circ->n_receive_circwindow);
   }
 
+#if 0
   if(circ->state == CIRCUIT_STATE_ONION_WAIT) {
     log(LOG_WARNING,"command_process_relay_cell(): circuit in onion_wait. Dropping relay cell.");
     return;
@@ -237,6 +262,7 @@
     log(LOG_WARNING,"command_process_relay_cell(): circuit in or_wait. Dropping relay cell.");
     return;
   }
+#endif
   /* circ->p_conn and n_conn are only null if we're at an edge point with no connections yet */
 
   if(cell->aci == circ->p_aci) { /* it's an outgoing cell */
@@ -267,7 +293,7 @@
   }
 
   log(LOG_DEBUG,"command_process_destroy_cell(): Received for aci %d.",cell->aci);
-  if(circ->state == CIRCUIT_STATE_ONION_PENDING) {
+  if(circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) {
     onion_pending_remove(circ);
   }
 

Index: connection.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection.c,v
retrieving revision 1.59
retrieving revision 1.60
diff -u -d -r1.59 -r1.60
--- connection.c	2 May 2003 21:29:25 -0000	1.59
+++ connection.c	5 May 2003 23:24:45 -0000	1.60
@@ -607,6 +607,8 @@
   printf("\n");
 #endif
 
+  assert(conn);
+
   if(crypto_cipher_encrypt(conn->f_crypto, cellp, CELL_NETWORK_SIZE, cryptcell)) {
     log(LOG_ERR,"Could not encrypt cell for connection %s:%u.",conn->address,conn->port);
     return -1;

Index: connection_edge.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection_edge.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- connection_edge.c	2 May 2003 21:29:25 -0000	1.7
+++ connection_edge.c	5 May 2003 23:24:45 -0000	1.8
@@ -23,7 +23,7 @@
     circ = circuit_get_by_conn(conn);
     if (!circ)
       return -1;
-    
+
     memset(&cell, 0, sizeof(cell_t));
     cell.command = CELL_RELAY;
     cell.length = RELAY_HEADER_SIZE;
@@ -123,13 +123,12 @@
       if(edge_type == EDGE_AP) {
         log(LOG_INFO,"connection_edge_process_relay_cell(): relay begin request unsupported. Dropping.");
         return 0;
-      } else {
-        if(conn) {
-          log(LOG_INFO,"connection_edge_process_relay_cell(): begin cell for known stream. Dropping.");
-          return 0;
-        }
-        return connection_exit_begin_conn(cell, circ);
       }
+      if(conn) {
+        log(LOG_INFO,"connection_edge_process_relay_cell(): begin cell for known stream. Dropping.");
+        return 0;
+      }
+      return connection_exit_begin_conn(cell, circ);
     case RELAY_COMMAND_DATA:
       if(!conn) {
         log(LOG_DEBUG,"connection_edge_process_relay_cell(): relay cell dropped, unknown stream %d.",*(int*)conn->stream_id);
@@ -166,14 +165,6 @@
       }
       log(LOG_DEBUG,"connection_edge_process_relay_cell(): end cell for stream %d. Removing stream.",*(int*)conn->stream_id);
 
-      /* go through and identify who points to conn. remove conn from the list. */
-#if 0
-      if(conn == circ->p_conn) {
-        circ->p_conn = conn->next_stream;
-      }
-      for(prevconn = circ->p_conn; prevconn->next_stream != conn; prevconn = prevconn->next_stream) ;
-      prevconn->next_stream = conn->next_stream;
-#endif
 #ifdef HALF_OPEN
       conn->done_sending = 1;
       shutdown(conn->s, 1); /* XXX check return; refactor NM */
@@ -182,6 +173,23 @@
 #endif
       conn->marked_for_close = 1;
       break;
+    case RELAY_COMMAND_EXTEND:
+      if(conn) {
+        log(LOG_INFO,"connection_edge_process_relay_cell(): 'extend' for non-zero stream. Dropping.");
+        return 0;
+      }
+      return circuit_extend(cell, circ);
+    case RELAY_COMMAND_EXTENDED:
+      if(edge_type == EDGE_EXIT) {
+        log(LOG_INFO,"connection_edge_process_relay_cell(): 'extended' unsupported at exit. Dropping.");
+        return 0;
+      }
+      log(LOG_DEBUG,"connection_edge_process_relay_cell(): Got an extended cell! Yay.");
+      if(circuit_finish_handshake(circ, cell->payload+RELAY_HEADER_SIZE) < 0) {
+        log(LOG_INFO,"connection_edge_process_relay_cell(): circuit_finish_handshake failed.");
+        return -1;
+      }
+      return circuit_send_next_onion_skin(circ);
     case RELAY_COMMAND_CONNECTED:
       if(edge_type == EDGE_EXIT) {
         log(LOG_INFO,"connection_edge_process_relay_cell(): 'connected' unsupported at exit. Dropping.");

Index: main.c
===================================================================
RCS file: /home/or/cvsroot/src/or/main.c,v
retrieving revision 1.51
retrieving revision 1.52
diff -u -d -r1.51 -r1.52
--- main.c	1 May 2003 22:55:51 -0000	1.51
+++ main.c	5 May 2003 23:24:45 -0000	1.52
@@ -337,7 +337,6 @@
     for(i=0;i<nfds;i++) {
       tmpconn = connection_array[i];
       connection_increment_receiver_bucket(tmpconn);
-      connection_array[i]->onions_handled_this_second = 0;
 
       /* check connections to see whether we should send a keepalive, expire, or wait */
       if(!connection_speaks_cells(tmpconn))
@@ -683,7 +682,6 @@
     }
   }
 
-  init_tracked_tree(); /* initialize the replay detection tree */
   init_cache_tree(); /* initialize the dns resolve tree */
 
   signal (SIGINT,  catch); /* catch kills so we can exit cleanly */

Index: onion.c
===================================================================
RCS file: /home/or/cvsroot/src/or/onion.c,v
retrieving revision 1.43
retrieving revision 1.44
diff -u -d -r1.43 -r1.44
--- onion.c	5 May 2003 04:26:57 -0000	1.43
+++ onion.c	5 May 2003 23:24:45 -0000	1.44
@@ -6,11 +6,8 @@
 
 extern or_options_t options; /* command-line and config-file options */
 
-static int onion_process(circuit_t *circ);
-static int onion_deliver_to_conn(aci_t aci, unsigned char *onion, uint32_t onionlen, connection_t *conn);
 static int count_acceptable_routers(routerinfo_t **rarray, int rarray_len);
-static int find_tracked_onion(unsigned char *onion, uint32_t onionlen,
-                              int expire);
+static int onionskin_process(circuit_t *circ);
 
 int decide_aci_type(uint32_t local_addr, uint16_t local_port,
                     uint32_t remote_addr, uint16_t remote_port) {
@@ -76,17 +73,19 @@
   if(!ol_list)
     return; /* no onions pending, we're done */
 
-  assert(ol_list->circ && ol_list->circ->p_conn);
+  assert(ol_list->circ);
+  assert(ol_list->circ->p_conn);
   assert(ol_length > 0);
   circ = ol_list->circ;
 
-  if(onion_process(circ) < 0) {
+  if(onionskin_process(circ) < 0) {
     log(LOG_DEBUG,"onion_pending_process_one(): Failed. Closing.");
     onion_pending_remove(circ);
     circuit_close(circ);
   } else {
     log(LOG_DEBUG,"onion_pending_process_one(): Succeeded. Delivering queued relay cells.");
     for(tmpd = ol_list->relay_cells; tmpd; tmpd=tmpd->next) {
+      log(LOG_DEBUG,"onion_pending_process_one(): Delivering relay cell...");
       command_process_relay_cell(tmpd->cell, circ->p_conn); 
     }
     onion_pending_remove(circ);
@@ -174,136 +173,48 @@
   }
 }
 
-/* helper function for onion_process */
-static int onion_deliver_to_conn(aci_t aci, unsigned char *onion, uint32_t onionlen, connection_t *conn) {
-  char *buf;
-  int buflen, dataleft;
+/* learn keys, initialize, then send a created cell back */
+static int onionskin_process(circuit_t *circ) {
+  unsigned char iv[16];
+  unsigned char keys[32];
   cell_t cell;
- 
-  assert(aci && onion && onionlen);
- 
-  buflen = onionlen+4;
-  buf = malloc(buflen);
-  if(!buf)
-    return -1;
- 
-  log(LOG_DEBUG,"onion_deliver_to_conn(): Setting onion length to %u.",onionlen);
-  *(uint32_t*)buf = htonl(onionlen);
-  memcpy((buf+4),onion,onionlen);
- 
-  dataleft = buflen;
-  while(dataleft > 0) {
-    memset(&cell,0,sizeof(cell_t));
-    cell.command = CELL_CREATE;
-    cell.aci = aci;
-    if(dataleft >= CELL_PAYLOAD_SIZE)
-      cell.length = CELL_PAYLOAD_SIZE;
-    else
-      cell.length = dataleft;
-    memcpy(cell.payload, buf+buflen-dataleft, cell.length);
-    dataleft -= cell.length;
- 
-    log(LOG_DEBUG,"onion_deliver_to_conn(): Delivering create cell, payload %d bytes.",cell.length);
-    if(connection_write_cell_to_buf(&cell, conn) < 0) {
-      log(LOG_DEBUG,"onion_deliver_to_conn(): Could not buffer new create cells. Closing.");
-      free(buf);
-      return -1;
-    }
-  }
-  free(buf);
-  return 0;
-}
 
-static int onion_process(circuit_t *circ) {
-  connection_t *n_conn;
-  int retval;
-  aci_t aci_type;
-  struct sockaddr_in me; /* my router identity */
-  onion_layer_t layer;
+  memset(iv, 0, 16);
 
-  if(learn_my_address(&me) < 0)
-    return -1;
+  memset(&cell, 0, sizeof(cell_t));
+  cell.command = CELL_CREATED;
+  cell.aci = circ->p_aci;
+  cell.length = 192;
 
-  /* decrypt it in-place */
-  if(decrypt_onion(circ->onion,circ->onionlen,getprivatekey(),&layer) < 0) {
-    log(LOG_DEBUG,"command_process_create_cell(): decrypt_onion() failed, closing circuit.");
+  circ->state = CIRCUIT_STATE_OPEN;
+
+  log(LOG_DEBUG,"onionskin_process(): Entering.");
+
+  if(onion_skin_server_handshake(circ->onionskin, getprivatekey(),
+    cell.payload, keys, 32) < 0) {
+    log(LOG_ERR,"onionskin_process(): onion_skin_server_handshake failed.");
     return -1;
   }
-  log(LOG_DEBUG,"command_process_create_cell(): Onion decrypted.");
 
-  /* check freshness */
-  if (layer.expire < (uint32_t)time(NULL)) /* expired onion */ /*XXXX*/
-  { 
-    log(LOG_NOTICE,"I have just received an expired onion. This could be a replay attack.");
+  log(LOG_DEBUG,"onionskin_process: init cipher forward %d, backward %d.", *(int*)keys, *(int*)(keys+16));
+
+  if (!(circ->n_crypto =
+        crypto_create_init_cipher(DEFAULT_CIPHER,keys,iv,0))) {
+    log(LOG_ERR,"Cipher initialization failed.");
     return -1;
   }
 
-  aci_type = decide_aci_type(ntohl(me.sin_addr.s_addr), ntohs(me.sin_port),
-                             layer.addr, layer.port);
-      
-  if(circuit_init(circ, aci_type, &layer) < 0) { 
-    log(LOG_ERR,"process_onion(): init_circuit() failed.");
+  if (!(circ->p_crypto =
+        crypto_create_init_cipher(DEFAULT_CIPHER,keys+16,iv,1))) {
+    log(LOG_ERR,"Cipher initialization failed.");
     return -1;
   }
 
-  /* check for replay. at the same time, add it to the pile of tracked onions. */
-  if(find_tracked_onion(circ->onion, circ->onionlen, layer.expire)) {
-    log(LOG_NOTICE,"process_onion(): I have just received a replayed onion. This could be a replay attack.");
+  if(connection_write_cell_to_buf(&cell, circ->p_conn) < 0) {
     return -1;
   }
+  log(LOG_DEBUG,"onionskin_process(): Finished sending 'created' cell.");
 
-  /* now we must send create cells to the next router */
-  if(circ->n_addr && circ->n_port) {
-    n_conn = connection_twin_get_by_addr_port(circ->n_addr,circ->n_port);
-    if(!n_conn || n_conn->type != CONN_TYPE_OR) {
-      /* i've disabled making connections through OPs, but it's definitely
-       * possible here. I'm not sure if it would be a bug or a feature. -RD
-       */
-      /* note also that this will close circuits where the onion has the same
-       * router twice in a row in the path. i think that's ok. -RD
-       */
-      log(LOG_DEBUG,"command_process_create_cell(): Next router not connected. Closing.");
-      return -1;
-    }
-
-    circ->n_addr = n_conn->addr; /* these are different if we found a twin instead */
-    circ->n_port = n_conn->port;
-
-    circ->n_conn = n_conn;
-    log(LOG_DEBUG,"command_process_create_cell(): n_conn is %s:%u",n_conn->address,n_conn->port);
-
-    /* send the CREATE cells on to the next hop  */
-    pad_onion(circ->onion, circ->onionlen, ONION_LAYER_SIZE);
-    log(LOG_DEBUG,"command_process_create_cell(): Padded the onion with random data.");
-
-    retval = onion_deliver_to_conn(circ->n_aci, circ->onion, circ->onionlen, n_conn); 
-    free(circ->onion);
-    circ->onion = NULL;
-    if (retval == -1) {
-      log(LOG_DEBUG,"command_process_create_cell(): Could not deliver the onion to next conn. Closing.");
-      return -1;
-    }
-  } else { /* this is destined for an exit */
-    log(LOG_DEBUG,"command_process_create_cell(): create cell reached exit. Circuit established.");
-#if 0
-    log(LOG_DEBUG,"command_process_create_cell(): Creating new exit connection.");
-    n_conn = connection_new(CONN_TYPE_EXIT);
-    if(!n_conn) {
-      log(LOG_DEBUG,"command_process_create_cell(): connection_new failed. Closing.");
-      return -1;
-    }
-    n_conn->state = EXIT_CONN_STATE_CONNECTING_WAIT;
-    n_conn->receiver_bucket = -1; /* edge connections don't do receiver buckets */
-    n_conn->bandwidth = -1;
-    n_conn->s = -1; /* not yet valid */
-    if(connection_add(n_conn) < 0) { /* no space, forget it */
-      log(LOG_DEBUG,"command_process_create_cell(): connection_add failed. Closing.");
-      connection_free(n_conn);
-      return -1;
-    }
-    circ->n_conn = n_conn;
-#endif
-  }
   return 0;
 }
 
@@ -432,402 +343,82 @@
   return num;
 }
 
-/* creates a new onion from route, stores it and its length into buf and len respectively */
-unsigned char *create_onion(routerinfo_t **rarray, int rarray_len, unsigned int *route, int routelen, int *len, crypt_path_t **cpath)
-{
+crypt_path_t *onion_generate_cpath(routerinfo_t **firsthop) {
+  int routelen; /* length of the route */
+  unsigned int *route; /* hops in the route as an array of indexes into rarray */
+  crypt_path_t *cpath=NULL;
+  routerinfo_t **rarray;
+  int rarray_len;
   int i;
-  char *layerp;
   crypt_path_t *hop;
-  unsigned char *buf;
   routerinfo_t *router;
-  unsigned char iv[16];
   struct in_addr netaddr;
-  onion_layer_t layer;
-
-  assert(rarray && route && len && routelen && cpath);
 
-  *cpath = NULL;
-
-  /* calculate the size of the onion */
-  *len = routelen * ONION_LAYER_SIZE + ONION_PADDING_SIZE;
-  /* 28 bytes per layer + 100 bytes padding for the innermost layer */
-  log(LOG_DEBUG,"create_onion() : Size of the onion is %u.",*len);
+  router_get_rarray(&rarray, &rarray_len);
 
-  /* allocate memory for the onion */
-  buf = malloc(*len);
-  if(!buf) {
-    log(LOG_ERR,"Error allocating memory.");
+  /* choose a route */
+  route = new_route(options.CoinWeight, rarray, rarray_len, &routelen);
+  if (!route) {
+    log(LOG_ERR,"onion_generate_cpath(): Error choosing a route through the OR network.");
     return NULL;
   }
-  log(LOG_DEBUG,"create_onion() : Allocated memory for the onion.");
+  log(LOG_DEBUG,"onion_generate_cpath(): Chosen a route of length %u: ",routelen);
+
+  *firsthop = rarray[route[routelen-1]];
+  assert(*firsthop); /* should always be defined */
 
   for(i=0; i<routelen; i++) {
     netaddr.s_addr = htonl((rarray[route[i]])->addr);
 
-    log(LOG_DEBUG,"create_onion(): %u : %s:%u, %u/%u",routelen-i,
+    log(LOG_DEBUG,"onion_generate_cpath(): %u : %s:%u, %u/%u",routelen-i,
         inet_ntoa(netaddr),
         (rarray[route[i]])->or_port,
         (rarray[route[i]])->pkey,
         crypto_pk_keysize((rarray[route[i]])->pkey));
   }
 
-  layerp = buf + *len - ONION_LAYER_SIZE - ONION_PADDING_SIZE; /* pointer to innermost layer */
-  /* create the onion layer by layer, starting with the innermost */
+  /* create the cpath layer by layer, starting at the last hop */
   for (i=0;i<routelen;i++) {
     router = rarray[route[i]];
 
-    layer.version = OR_VERSION;
-    if (i) { /* not last hop */
-      layer.port = rarray[route[i-1]]->or_port;
-      layer.addr = rarray[route[i-1]]->addr;
-    } else {
-      layer.port = 0;
-      layer.addr = 0;
-    }
-
-    /* Expiration Time */
-    layer.expire = (uint32_t)(time(NULL) + 86400); /* NOW + 1 day */
-  
-    /* Key Seed Material */
-    if(crypto_rand(ONION_KEYSEED_LEN, layer.keyseed)) { /* error */
-      log(LOG_ERR,"Error generating random data.");
-      goto error;
-    }
-
-    onion_pack(layerp, &layer);
-
-//      log(LOG_DEBUG,"create_onion() : Onion layer %u built : %u, %u, %u, %s, %u.",i+1,layer->zero,layer->backf,layer->forwf,inet_ntoa(*((struct in_addr *)&layer->addr)),layer->port);
-
     /* build up the crypt_path */
     hop = (crypt_path_t *)malloc(sizeof(crypt_path_t));
     if(!hop) {
-      log(LOG_ERR,"Error allocating memory.");
-      goto error;
+      log(LOG_ERR,"Error allocating crypt path hop memory.");
+      circuit_free_cpath(cpath);
+      free(route);
+      return NULL;
     }
+    memset(hop, 0, sizeof(crypt_path_t));
 
     /* link hop into the cpath, at the front */
-    hop->next = *cpath;
+    hop->next = cpath;
     hop->prev = NULL;
-    hop->state = CPATH_STATE_OPEN; /* change when we move to incremental paths */
-    if(*cpath) {
-      (*cpath)->prev = hop;
-    }
-    *cpath = hop;
-
-    log(LOG_DEBUG,"create_onion() : Building hop %u of crypt path.",i+1);
-
-    /* calculate keys */
-    crypto_SHA_digest(layer.keyseed,16,hop->digest3);
-    log(LOG_DEBUG,"create_onion() : First SHA pass performed.");
-    crypto_SHA_digest(hop->digest3,20,hop->digest2);
-    log(LOG_DEBUG,"create_onion() : Second SHA pass performed.");
-    crypto_SHA_digest(hop->digest2,20,hop->digest3);
-    log(LOG_DEBUG,"create_onion() : Third SHA pass performed.");
-    log(LOG_DEBUG,"create_onion() : Keys generated.");
-    /* set IV to zero */
-    memset((void *)iv,0,16);
-
-    /* initialize cipher engines */
-    if (! (hop->f_crypto = 
-           crypto_create_init_cipher(DEFAULT_CIPHER, hop->digest3, iv, 1))) {
-      /* cipher initialization failed */
-      log(LOG_ERR,"Could not create a crypto environment.");
-      goto error;
-    }
-
-    if (! (hop->b_crypto = 
-           crypto_create_init_cipher(DEFAULT_CIPHER, hop->digest2, iv, 0))) {
-      /* cipher initialization failed */
-      log(LOG_ERR,"Could not create a crypto environment.");
-      goto error;
-    }
-
-    log(LOG_DEBUG,"create_onion() : Built corresponding crypt path hop.");
-
-    /* padding if this is the innermost layer */
-    if (!i) {
-      if (crypto_pseudo_rand(ONION_PADDING_SIZE, layerp + ONION_LAYER_SIZE)) { /* error */
-        log(LOG_ERR,"Error generating pseudo-random data.");
-        goto error;
-      }
-      log(LOG_DEBUG,"create_onion() : This is the innermost layer. Adding 100 bytes of padding.");
+    hop->state = CPATH_STATE_CLOSED;
+    if(cpath) {
+      cpath->prev = hop;
     }
+    cpath = hop;
 
-    /* encrypt */
-
-    if(encrypt_onion(layerp,ONION_PADDING_SIZE+(i+1)*ONION_LAYER_SIZE,router->pkey,layer.keyseed) < 0) {
-      log(LOG_ERR,"Error encrypting onion layer.");
-      goto error;
+#if 0
+    if (i) { /* not last hop. (last hop has 0's for these.) */
+      hop->port = rarray[route[i-1]]->or_port;
+      hop->addr = rarray[route[i-1]]->addr;
     }
-    log(LOG_DEBUG,"create_onion() : Encrypted layer.");
+#endif
+    hop->port = rarray[route[i]]->or_port;
+    hop->addr = rarray[route[i]]->addr;
 
-    /* calculate pointer to next layer */
-    layerp = buf + (routelen-i-2)*ONION_LAYER_SIZE;
+    log(LOG_DEBUG,"onion_generate_cpath() : Building hop %u of crypt path.",i+1);
   }
 
   /* now link cpath->prev to the end of cpath */
-  for(hop=*cpath; hop->next; hop=hop->next) ;
-  hop->next = *cpath;
-  (*cpath)->prev = hop;
-
-  return buf;
-
- error:
-  if(buf)
-    free(buf);
-  circuit_free_cpath(*cpath);
-  return NULL;
-}
-
-/* encrypts 128 bytes of the onion with the specified public key, the rest with 
- * DES OFB with the key as defined in the outter layer */
-int encrypt_onion(unsigned char *onion, uint32_t onionlen, crypto_pk_env_t *pkey, char* keyseed) {
-  unsigned char *tmpbuf = NULL; /* temporary buffer for crypto operations */
-  unsigned char digest[20]; /* stores SHA1 output - 160 bits */
-  unsigned char iv[8];
-  
-  crypto_cipher_env_t *crypt_env = NULL; /* crypto environment */
- 
-  assert(onion && pkey);
-  assert(onionlen >= 128);
-
-  memset(iv,0,8);
-    
-//  log(LOG_DEBUG,"Onion layer : %u, %u, %u, %s, %u.",onion->zero,onion->backf,onion->forwf,inet_ntoa(*((struct in_addr *)&onion->addr)),onion->port);
-  /* allocate space for tmpbuf */
-  tmpbuf = (unsigned char *)malloc(onionlen);
-  if(!tmpbuf) {
-    log(LOG_ERR,"Could not allocate memory.");
-    return -1;
-  }
-  log(LOG_DEBUG,"encrypt_onion() : allocated %u bytes of memory for the encrypted onion (at %u).",onionlen,tmpbuf);
-  
-  /* get key1 = SHA1(KeySeed) */
-  if (crypto_SHA_digest(keyseed,16,digest)) {
-    log(LOG_ERR,"Error computing SHA1 digest.");
-    goto error;
-  }
-  log(LOG_DEBUG,"encrypt_onion() : Computed DES key.");
-    
-  log(LOG_DEBUG,"encrypt_onion() : Trying to RSA encrypt.");
-  /* encrypt 128 bytes with RSA *pkey */
-  if (crypto_pk_public_encrypt(pkey, onion, 128, tmpbuf, RSA_NO_PADDING) == -1) {
-    log(LOG_ERR,"Error RSA-encrypting data :%s",crypto_perror());
-    goto error;
-  }
-
-  log(LOG_DEBUG,"encrypt_onion() : RSA encrypted first 128 bytes of the onion."); 
-    
-  /* now encrypt the rest with 3DES OFB */
-  crypt_env = crypto_create_init_cipher(CRYPTO_CIPHER_3DES, digest, iv, 1);
-  if (!crypt_env) {
-    log(LOG_ERR,"Error creating the crypto environment.");
-    goto error;
-  }
-    
-  if (crypto_cipher_encrypt(crypt_env,onion+128, onionlen-128, (unsigned char *)tmpbuf+128)) { /* error */
-    log(LOG_ERR,"Error performing DES encryption:%s",crypto_perror()); 
-    goto error;
-  }
-  log(LOG_DEBUG,"encrypt_onion() : 3DES OFB encrypted the rest of the onion.");
-    
-  /* now copy tmpbuf to onion */
-  memcpy(onion,tmpbuf,onionlen);
-  log(LOG_DEBUG,"encrypt_onion() : Copied cipher to original onion buffer.");
-  free(tmpbuf);
-  crypto_free_cipher_env(crypt_env);
-  return 0;
-
- error:
-  if (tmpbuf)
-    free(tmpbuf);
-  if (crypt_env)
-    crypto_free_cipher_env(crypt_env);
-  return -1;
-}
-
-/* decrypts the first 128 bytes using RSA and prkey, decrypts the rest with DES OFB with key1 */
-int decrypt_onion(unsigned char *onion, uint32_t onionlen, crypto_pk_env_t *prkey, onion_layer_t *layer) {
-  void *tmpbuf = NULL; /* temporary buffer for crypto operations */
-  unsigned char digest[20]; /* stores SHA1 output - 160 bits */
-  unsigned char iv[8];
-  
-  crypto_cipher_env_t *crypt_env =NULL; /* crypto environment */
-  
-  assert(onion && prkey);
-
-  memset(iv,0,8);
-    
-  /* allocate space for tmpbuf */
-  tmpbuf = malloc(onionlen);
-  if (!tmpbuf) {
-    log(LOG_ERR,"Could not allocate memory.");
-    return -1;
-  }
-  log(LOG_DEBUG,"decrypt_onion() : Allocated memory for the temporary buffer.");
-
-  /* decrypt 128 bytes with RSA *prkey */
-  if (crypto_pk_private_decrypt(prkey, onion, 128, tmpbuf, RSA_NO_PADDING) == -1)
-  {
-    log(LOG_ERR,"Error RSA-decrypting data :%s",crypto_perror());
-    goto error;
-  }
-  log(LOG_DEBUG,"decrypt_onion() : RSA decryption complete.");
-    
-  onion_unpack(layer, tmpbuf);
-
-  /* get key1 = SHA1(KeySeed) */
-  if (crypto_SHA_digest(layer->keyseed,16,digest)) {
-    log(LOG_ERR,"Error computing SHA1 digest.");
-    goto error;
-  }
-  log(LOG_DEBUG,"decrypt_onion() : Computed DES key.");
-    
-  /* now decrypt the rest with 3DES OFB */
-  crypt_env = crypto_create_init_cipher(CRYPTO_CIPHER_3DES, digest, iv, 0);
-  if (!crypt_env) {
-    log(LOG_ERR,"Error creating crypto environment");
-    goto error;
-  }
- 
-  if (crypto_cipher_decrypt(crypt_env,onion+128, onionlen-128,tmpbuf+128)) {
-    log(LOG_ERR,"Error performing DES decryption:%s",crypto_perror());
-    goto error;
-  }
-    
-  log(LOG_DEBUG,"decrypt_onion() : DES decryption complete.");
-    
-  /* now copy tmpbuf to onion */
-  memcpy(onion,tmpbuf,onionlen);
-  free(tmpbuf);
-  crypto_free_cipher_env(crypt_env);
-  return 0;
-
- error:
-  if (tmpbuf)
-    free(tmpbuf);
-  if (crypt_env)
-    crypto_free_cipher_env(crypt_env);
-  return -1;
-}
-
-/* delete first n bytes of the onion and pads the end with n bytes of random data */
-void pad_onion(unsigned char *onion, uint32_t onionlen, int n)
-{
-  assert(onion);
-
-  memmove(onion,onion+n,onionlen-n);
-  crypto_pseudo_rand(n, onion+onionlen-n);
-}
-
-
-
-
-/* red black tree using Niels' tree.h. I used
-http://www.openbsd.org/cgi-bin/cvsweb/src/regress/sys/sys/tree/rb/
-as my guide */
-
-#include "tree.h"
-
-struct tracked_onion { 
-  RB_ENTRY(tracked_onion) node;
-  uint32_t expire;
-  char digest[20]; /* SHA digest of the onion */
-  struct tracked_onion *next;
-};
-
-RB_HEAD(tracked_tree, tracked_onion) tracked_root;
-
-int compare_tracked_onions(struct tracked_onion *a, struct tracked_onion *b) {
-  return memcmp(a->digest, b->digest, 20);
-}
-
-RB_PROTOTYPE(tracked_tree, tracked_onion, node, compare_tracked_onions)
-RB_GENERATE(tracked_tree, tracked_onion, node, compare_tracked_onions)
-
-void init_tracked_tree(void) {
-  RB_INIT(&tracked_root);
-}
-
-/* see if this onion has been seen before. if so, return 1, else
- * return 0 and add the sha1 of this onion to the tree.
- */
-static int find_tracked_onion(unsigned char *onion, uint32_t onionlen,
-                              int expire) {
-  static struct tracked_onion *head_tracked_onions = NULL; /* linked list of tracked onions */
-  static struct tracked_onion *tail_tracked_onions = NULL;
-
-  uint32_t now = time(NULL); 
-  struct tracked_onion *to;
-
-  /* first take this opportunity to see if there are any expired
-   * onions in the tree. we know this is fast because the linked list
-   * 'tracked_onions' is ordered by when they were seen.
-   */
-  while(head_tracked_onions && (head_tracked_onions->expire < now)) {
-    to = head_tracked_onions;
-    log(LOG_DEBUG,"find_tracked_onion(): Forgetting old onion (expires %d)", to->expire);
-    head_tracked_onions = to->next;
-    if(!head_tracked_onions)          /* if there are no more, */
-      tail_tracked_onions = NULL; /* then make sure the list's tail knows that too */
-    RB_REMOVE(tracked_tree, &tracked_root, to);
-    free(to);
-  }
-
-  to = malloc(sizeof(struct tracked_onion));
-  
-  /* compute the SHA digest of the onion */
-  crypto_SHA_digest(onion, onionlen, to->digest);
-
-  /* try adding it to the tree. if it's already there it will return it. */
-  if(RB_INSERT(tracked_tree, &tracked_root, to)) {
-    /* yes, it's already there: this is a replay. */
-    free(to);
-    return 1;
-  }
-  
-  /* this is a new onion. add it to the list. */
-
-  to->expire = expire; /* set the expiration date */
-  to->next = NULL;
-
-  if (!head_tracked_onions) {
-    head_tracked_onions = to;
-  } else {
-    tail_tracked_onions->next = to;
-  }
-  tail_tracked_onions = to;
-
-  log(LOG_DEBUG,"find_tracked_onion(): Remembered new onion (expires %d)", to->expire);
- 
-  return 0;
-}
-
-void
-onion_pack(char *dest, onion_layer_t *src)
-{
-  assert((src->version & 0x80) == 0);
-  
-  *(uint8_t*)(dest) = src->version;
-  *(uint16_t*)(dest+1) = htons(src->port);
-  *(uint32_t*)(dest+3) = htonl(src->addr);
-  *(uint32_t*)(dest+7) = htonl(src->expire);
-  memcpy(dest+11, src->keyseed, ONION_KEYSEED_LEN);
-  log(LOG_DEBUG,"onion_pack(): version %d, port %d, addr %s, expire %u", src->version, src->port,
-    inet_ntoa(*((struct in_addr *)(dest+3))), src->expire);
-}
-
-void
-onion_unpack(onion_layer_t *dest, char *src)
-{
-  dest->version = *(uint8_t*)src;
-  dest->port = ntohs(*(uint16_t*)(src+1));
-  dest->addr = ntohl(*(uint32_t*)(src+3));
-  dest->expire = ntohl(*(uint32_t*)(src+7));
-  memcpy(dest->keyseed, src+11, ONION_KEYSEED_LEN);
+  for(hop=cpath; hop->next; hop=hop->next) ;
+  hop->next = cpath;
+  cpath->prev = hop;
 
-  log(LOG_DEBUG,"onion_unpack(): version %d, port %d, addr %s, expire %u", dest->version, dest->port,
-    inet_ntoa(*((struct in_addr *)(src+3))), dest->expire);
+  free(route);
+  return cpath;
 }
 
 /*----------------------------------------------------------------------*/
@@ -843,7 +434,7 @@
  * and the last 80 are encrypted with the symmetric key.
  */
 int
-onion_skin_create(crypto_pk_env_t *router_key,
+onion_skin_create(crypto_pk_env_t *dest_router_key,
                   crypto_dh_env_t **handshake_state_out,
                   char *onion_skin_out) /* Must be 208 bytes long */
 {
@@ -861,7 +452,7 @@
     goto err;
   
   dhbytes = crypto_dh_get_bytes(dh);
-  pkbytes = crypto_pk_keysize(router_key);
+  pkbytes = crypto_pk_keysize(dest_router_key);
   assert(dhbytes+16 == 208);
   if (!(pubkey = malloc(dhbytes+16)))
     goto err;
@@ -896,7 +487,7 @@
   if (!cipher)
     goto err;
 
-  if (crypto_pk_public_encrypt(router_key, pubkey, pkbytes,
+  if (crypto_pk_public_encrypt(dest_router_key, pubkey, pkbytes,
                                onion_skin_out, RSA_NO_PADDING)==-1)
     goto err;
 

Index: or.h
===================================================================
RCS file: /home/or/cvsroot/src/or/or.h,v
retrieving revision 1.72
retrieving revision 1.73
diff -u -d -r1.72 -r1.73
--- or.h	5 May 2003 04:26:59 -0000	1.72
+++ or.h	5 May 2003 23:24:46 -0000	1.73
@@ -113,9 +113,9 @@
 #define DIR_CONN_STATE_COMMAND_WAIT 3
 #define DIR_CONN_STATE_WRITING 4
 
-#define CIRCUIT_STATE_ONION_WAIT 0 /* receiving the onion */
-#define CIRCUIT_STATE_ONION_PENDING 1 /* waiting to process the onion */
-#define CIRCUIT_STATE_OR_WAIT 2 /* I'm at the beginning of the path, my firsthop is still connecting */
+#define CIRCUIT_STATE_BUILDING 0 /* I'm the OP, still haven't done all my handshakes */
+#define CIRCUIT_STATE_ONIONSKIN_PENDING 1 /* waiting to process the onion */
+#define CIRCUIT_STATE_OR_WAIT 2 /* I'm the OP, my firsthop is still connecting */
 #define CIRCUIT_STATE_OPEN 3 /* onion processed, ready to send data along the connection */
 //#define CIRCUIT_STATE_CLOSE_WAIT1 4 /* sent two "destroy" signals, waiting for acks */
 //#define CIRCUIT_STATE_CLOSE_WAIT2 5 /* received one ack, waiting for one more 
@@ -127,23 +127,14 @@
 #define RELAY_COMMAND_END 3
 #define RELAY_COMMAND_CONNECTED 4
 #define RELAY_COMMAND_SENDME 5
+#define RELAY_COMMAND_EXTEND 6
+#define RELAY_COMMAND_EXTENDED 7
 
 #define RELAY_HEADER_SIZE 8
 
 #define RELAY_STATE_RESOLVING
 
-/* available cipher functions */
-#if 0
-#define ONION_CIPHER_IDENTITY 0
-#define ONION_CIPHER_DES 1
-#define ONION_CIPHER_RC4 2
-#define ONION_CIPHER_3DES 3
-#endif
-
 /* default cipher function */
-#if 0
-#define ONION_DEFAULT_CIPHER ONION_CIPHER_3DES
-#endif
 #define DEFAULT_CIPHER CRYPTO_CIPHER_3DES
 
 #define CELL_DIRECTION_IN 1
@@ -160,9 +151,10 @@
 /* cell commands */
 #define CELL_PADDING 0
 #define CELL_CREATE 1
-#define CELL_RELAY 2
-#define CELL_DESTROY 3
-#define CELL_SENDME 4
+#define CELL_CREATED 2
+#define CELL_RELAY 3
+#define CELL_DESTROY 4
+#define CELL_SENDME 5
 
 #define CELL_PAYLOAD_SIZE 248
 #define CELL_NETWORK_SIZE 256
@@ -246,8 +238,6 @@
 
   long timestamp_created;
 
-  int onions_handled_this_second;
-
 /* used by OR and OP: */
 
   uint32_t bandwidth; /* connection bandwidth */
@@ -339,16 +329,19 @@
 } routerinfo_t;
 
 struct crypt_path_t { 
-  char digest2[20]; /* second SHA output for onion_layer_t.keyseed */
-  char digest3[20]; /* third SHA output for onion_layer_t.keyseed */
 
   /* crypto environments */
   crypto_cipher_env_t *f_crypto;
   crypto_cipher_env_t *b_crypto;
 
+  crypto_dh_env_t *handshake_state;
+
+  uint32_t addr;
+  uint16_t port;
+
   char state;
 #define CPATH_STATE_CLOSED 0
-#define CPATH_STATE_AWAITING_KEY 1
+#define CPATH_STATE_AWAITING_KEYS 1
 #define CPATH_STATE_OPEN 2
   struct crypt_path_t *next;
   struct crypt_path_t *prev; /* doubly linked list */
@@ -382,15 +375,15 @@
 
   crypt_path_t *cpath;
 
-  uint32_t expire; /* expiration time for the corresponding onion */
+  char onionskin[208]; /* for storage while onionskin pending */
   long timestamp_created;
   char dirty; /* whether this circuit has been used yet */
 
   int state;
 
-  unsigned char *onion; /* stores the onion when state is CONN_STATE_OPEN_WAIT */
-  uint32_t onionlen; /* total onion length */
-  uint32_t recvlen; /* length of the onion so far */
+//  unsigned char *onion; /* stores the onion when state is CONN_STATE_OPEN_WAIT */
+//  uint32_t onionlen; /* total onion length */
+//  uint32_t recvlen; /* length of the onion so far */
 
   void *next;
 } circuit_t;
@@ -538,17 +531,18 @@
 
 void circuit_expire_unused_circuits(void);
 void circuit_launch_new(int failure_status);
-int circuit_create_onion(void);
-int circuit_establish_circuit(unsigned int *route, int routelen, char *onion,
-                                   int onionlen, crypt_path_t *cpath);
+int circuit_establish_circuit(void);
 void circuit_n_conn_open(connection_t *or_conn);
-int circuit_send_onion(connection_t *or_conn, circuit_t *circ);
+int circuit_send_next_onion_skin(circuit_t *circ);
+int circuit_extend(cell_t *cell, circuit_t *circ);
+int circuit_finish_handshake(circuit_t *circ, char *reply);
 
 /********************************* command.c ***************************/
 
 void command_process_cell(cell_t *cell, connection_t *conn);
 
 void command_process_create_cell(cell_t *cell, connection_t *conn);
+void command_process_created_cell(cell_t *cell, connection_t *conn);
 void command_process_sendme_cell(cell_t *cell, connection_t *conn);
 void command_process_relay_cell(cell_t *cell, connection_t *conn);
 void command_process_destroy_cell(cell_t *cell, connection_t *conn);
@@ -775,23 +769,7 @@
  */
 unsigned int *new_route(double cw, routerinfo_t **rarray, int rarray_len, int *routelen);
 
-/* creates a new onion from route, stores it and its length into bufp and lenp respectively */
-unsigned char *create_onion(routerinfo_t **rarray, int rarray_len, unsigned int *route, int routelen, int *len, crypt_path_t **cpath);
-
-/* encrypts 128 bytes of the onion with the specified public key, the rest with 
- * DES OFB with the key as defined in the outter layer */
-int encrypt_onion(unsigned char *onion, uint32_t onionlen, crypto_pk_env_t *pkey, char *keyseed);
-
-/* decrypts the first 128 bytes using RSA and prkey, decrypts the rest with DES OFB with key1. Writes the first layer into 'layer' */
-int decrypt_onion(unsigned char *onion, uint32_t onionlen, crypto_pk_env_t *prkey, onion_layer_t *layer);
-
-/* delete first n bytes of the onion and pads the end with n bytes of random data */
-void pad_onion(unsigned char *onion, uint32_t onionlen, int n);
-
-void init_tracked_tree(void);
-
-void onion_pack(char *dest, onion_layer_t *src);
-void onion_unpack(onion_layer_t *dest, char *src);
+crypt_path_t *onion_generate_cpath(routerinfo_t **firsthop);
 
 int onion_skin_create(crypto_pk_env_t *router_key,
                       crypto_dh_env_t **handshake_state_out,
@@ -814,10 +792,8 @@
 void router_retry_connections(void);
 routerinfo_t *router_pick_directory_server(void);
 routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port);
-unsigned int *router_new_route(int *routelen);
-unsigned char *router_create_onion(unsigned int *route, int routelen, int *len, crypt_path_t **cpath);
+void router_get_rarray(routerinfo_t ***prouter_array, int *prarray_len);
 int router_is_me(uint32_t addr, uint16_t port);
-routerinfo_t *router_get_first_in_route(unsigned int *route, int routelen);
 void router_forget_router(uint32_t addr, uint16_t port);
 int router_get_list_from_file(char *routerfile);
 int router_get_list_from_string(char *s);

Index: routers.c
===================================================================
RCS file: /home/or/cvsroot/src/or/routers.c,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -d -r1.21 -r1.22
--- routers.c	8 Apr 2003 06:44:38 -0000	1.21
+++ routers.c	5 May 2003 23:24:46 -0000	1.22
@@ -98,18 +98,9 @@
   return NULL;
 }
 
-routerinfo_t *router_get_first_in_route(unsigned int *route, int routelen) {
-  return router_array[route[routelen-1]];
-}
-
-/* a wrapper around new_route. put all these in routers.c perhaps? */
-unsigned int *router_new_route(int *routelen) {
-  return new_route(options.CoinWeight, router_array, rarray_len, routelen);
-}
-
-/* a wrapper around create_onion */
-unsigned char *router_create_onion(unsigned int *route, int routelen, int *len, crypt_path_t **cpath) {
-  return create_onion(router_array,rarray_len,route,routelen,len,cpath);
+void router_get_rarray(routerinfo_t ***prouter_array, int *prarray_len) {
+  *prouter_array = router_array;
+  *prarray_len = rarray_len;
 }
 
 /* return 1 if addr and port corresponds to my addr and my or_listenport. else 0,
@@ -132,52 +123,6 @@
 
   return 0;
 
-#if 0
-  /* local host information */
-  char localhostname[512];
-  struct hostent *localhost;
-  struct in_addr *a;
-  char *tmp1;
-  
-  char *addr = NULL;
-  int i = 0;
-
-  /* obtain local host information */
-  if (gethostname(localhostname,512) < 0) {
-    log(LOG_ERR,"router_is_me(): Error obtaining local hostname.");
-    return -1;
-  }
-  localhost = gethostbyname(localhostname);
-  if (!localhost) {
-    log(LOG_ERR,"router_is_me(): Error obtaining local host info.");
-    return -1;
-  }
-  
-  /* check host addresses for a match with or_address above */
-  addr = localhost->h_addr_list[i++]; /* set to the first local address */
-  while(addr)
-  {
-    a = (struct in_addr *)addr;
-
-    tmp1 = strdup(inet_ntoa(*a)); /* can't call inet_ntoa twice in the same
-                                     printf, since it overwrites its static
-                                     memory each time */
-    log(LOG_DEBUG,"router_is_me(): Comparing '%s' to '%s'.",tmp1,
-       inet_ntoa( *((struct in_addr *)&or_address) ) );
-    free(tmp1);
-    if (!memcmp((void *)&or_address, (void *)addr, sizeof(uint32_t))) { /* addresses match */
-      log(LOG_DEBUG,"router_is_me(): Addresses match. Comparing ports.");
-      if (or_listenport == my_or_listenport) { /* ports also match */
-        log(LOG_DEBUG,"router_is_me(): Ports match too.");
-        return 1;
-      }
-    }
-    
-    addr = localhost->h_addr_list[i++];
-  }
-
-  return 0;
-#endif
 }
 
 /* delete a list of routers from memory */