Commit d9829255 authored by Roger Dingledine's avatar Roger Dingledine
Browse files

Integrated onion proxy into or/

The 'or' process can now be told (by the global_role variable) what
roles this server should play -- connect to all ORs, listen for ORs,
listen for OPs, listen for APs, or any combination.

* everything in /src/op/ is now obsolete.
* connection_ap.c now handles all interactions with application proxies
* "port" is now or_port, op_port, ap_port. But routers are still always
  referenced (say, in conn_get_by_addr_port()) by addr / or_port. We
  should make routers.c actually read these new ports (currently I've
  kludged it so op_port = or_port+10, ap_port=or_port+20)
* circuits currently know if they're at the beginning of the path because
  circ->cpath is set. They use this instead for crypts (both ways),
  if it's set.
* I still obey the "send a 0 back to the AP when you're ready" protocol,
  but I think we should phase it out. I can simply not read from the AP
  socket until I'm ready.

I need to do a lot of cleanup work here, but the code appears to work, so
now's a good time for a checkin.


svn:r22
parent b34fad4d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@ bin_PROGRAMS = or
or_LDADD = -L../common -lor

or_SOURCES = args.c buffers.c cell.c circuit.c command.c connection.c \
             connection_exit.c connection_op.c connection_or.c config.c \
             connection_exit.c connection_ap.c connection_op.c connection_or.c config.c \
             main.c onion.c routers.c

noinst_HEADERS = or.h
+91 −32
Original line number Diff line number Diff line
@@ -52,9 +52,6 @@ circuit_t *circuit_new(aci_t p_aci, connection_t *p_conn) {
  circ->p_conn = p_conn;

  circ->state = CIRCUIT_STATE_OPEN_WAIT;
  circ->onion = NULL;
  circ->onionlen=0;
  circ->recvlen=0;

  /* ACIs */
  circ->p_aci = p_aci;
@@ -72,9 +69,19 @@ void circuit_free(circuit_t *circ) {

  if(circ->onion)
    free(circ->onion);
  if(circ->cpath)
    circuit_free_cpath(circ->cpath, circ->cpathlen);

  free(circ);
}

void circuit_free_cpath(crypt_path_t **cpath, size_t cpathlen) {
  int i;

  for(i=0;i<cpathlen;i++)
    free(cpath[i]);

  free(cpath);
}

aci_t get_unique_aci_by_addr_port(uint32_t addr, uint16_t port, int aci_type) {
@@ -89,6 +96,7 @@ aci_t get_unique_aci_by_addr_port(uint32_t addr, uint16_t port, int aci_type) {
    test_aci &= htons(0x00FF);
  if(aci_type == ACI_TYPE_HIGHER)
    test_aci &= htons(0xFF00);
  /* if aci_type == ACI_BOTH, don't filter any of it */

  if(test_aci == 0)
    return get_unique_aci_by_addr_port(addr, port, aci_type); /* try again */ 
@@ -110,12 +118,10 @@ int circuit_init(circuit_t *circ, int aci_type) {
  unsigned char digest1[20];
  unsigned char digest2[20];

  if (!circ)
    return -1;
  assert(circ);

  ol = (onion_layer_t *)circ->onion;
  if (!ol)
    return -1;
  assert(ol);

  log(LOG_DEBUG,"circuit_init(): starting");
  circ->n_addr = ol->addr;
@@ -204,6 +210,16 @@ int circuit_init(circuit_t *circ, int aci_type) {
  return 0;
}

circuit_t *circuit_get_by_naddr_nport(uint32_t naddr, uint16_t nport) {
  circuit_t *circ;

  for(circ=global_circuitlist;circ;circ = circ->next) {
    if(circ->n_addr == naddr && circ->n_port == nport)
       return circ;
  }
  return NULL;
}

circuit_t *circuit_get_by_aci_conn(aci_t aci, connection_t *conn) {
  circuit_t *circ;

@@ -244,24 +260,24 @@ int circuit_deliver_data_cell(cell_t *cell, circuit_t *circ, connection_t *conn,

  if(conn->type == CONN_TYPE_EXIT) { /* send payload directly */
    log(LOG_DEBUG,"circuit_deliver_data_cell(): Sending to exit.");
    if(connection_exit_process_data_cell(cell, conn) < 0) {
      return -1;
    }
  } else { /* send it as a cell */
    log(LOG_DEBUG,"circuit_deliver_data_cell(): Sending to connection.");
    if(connection_write_cell_to_buf(cell, conn) < 0) {
      return -1;
    return connection_exit_process_data_cell(cell, conn);
  }
  if(conn->type == CONN_TYPE_AP) { /* send payload directly */
    log(LOG_DEBUG,"circuit_deliver_data_cell(): Sending to AP.");
    return connection_ap_process_data_cell(cell, conn);
  }
  return 0; /* success */
  /* else send it as a cell */
  log(LOG_DEBUG,"circuit_deliver_data_cell(): Sending to connection.");
  return connection_write_cell_to_buf(cell, conn);
}

int circuit_crypt(circuit_t *circ, char *in, size_t inlen, char crypt_type) {
  char *out;
  int outlen;
  int i;
  crypt_path_t *thishop;

  if(!circ || !in)
    return -1;
  assert(circ && in);

  out = malloc(inlen);
  if(!out)
@@ -269,24 +285,65 @@ int circuit_crypt(circuit_t *circ, char *in, size_t inlen, char crypt_type) {

  if(crypt_type == 'e') {
    log(LOG_DEBUG,"circuit_crypt(): Encrypting %d bytes.",inlen);
    if(circ->cpath) { /* we're at the beginning of the circuit. We'll want to do layered crypts. */
      /* 'e' means we're preparing to send it out. */
      for (i=0; i < circ->cpathlen; i++) /* moving from last to first hop 
                                          * Remember : cpath is in reverse order, i.e. last hop first
                                          */
      { 
        log(LOG_DEBUG,"circuit_crypt() : Encrypting via cpath: Processing hop %u",circ->cpathlen-i);
        thishop = circ->cpath[i];
    
        /* encrypt */
        if(!EVP_EncryptUpdate(&thishop->f_ctx,out,&outlen,in,inlen)) {
          log(LOG_ERR,"Error performing encryption:%s",ERR_reason_error_string(ERR_get_error()));
          free(out);
          return -1;
        }

        /* copy ciphertext back to buf */
        memcpy(in,out,inlen);
      }
    } else { /* we're in the middle. Just one crypt. */
      if(!EVP_EncryptUpdate(&circ->p_ctx,out,&outlen,in,inlen)) {
      log(LOG_ERR,"circuit_encrypt(): Encryption failed for ACI : %u (%s).",circ->p_aci, ERR_reason_error_string(ERR_get_error()));
        log(LOG_ERR,"circuit_encrypt(): Encryption failed for ACI : %u (%s).",
            circ->p_aci, ERR_reason_error_string(ERR_get_error()));
        free(out);
        return -1;
      }
      memcpy(in,out,inlen);
    }
  } else if(crypt_type == 'd') {
    log(LOG_DEBUG,"circuit_crypt(): Decrypting %d bytes.",inlen);
    if(!EVP_DecryptUpdate(&circ->n_ctx,out,&outlen,in,inlen)) {
      log(LOG_ERR,"circuit_crypt(): Decryption failed for ACI : %u (%s).",circ->n_aci, ERR_reason_error_string(ERR_get_error()));
    if(circ->cpath) { /* we're at the beginning of the circuit. We'll want to do layered crypts. */
      for (i=circ->cpathlen-1; i >= 0; i--) /* moving from first to last hop 
                                       * Remember : cpath is in reverse order, i.e. last hop first
                                       */
      { 
        log(LOG_DEBUG,"circuit_crypt() : Decrypting via cpath: Processing hop %u",circ->cpathlen-i);
        thishop = circ->cpath[i];

        /* encrypt */
        if(!EVP_DecryptUpdate(&thishop->b_ctx,out,&outlen,in,inlen)) {
          log(LOG_ERR,"Error performing decryption:%s",ERR_reason_error_string(ERR_get_error()));
          free(out);
          return -1;
        }
  }

  if(outlen != inlen) {
    log(LOG_DEBUG,"circuit_crypt(): %d bytes crypted to %d bytes. Weird.",inlen,outlen);
        /* copy ciphertext back to buf */
        memcpy(in,out,inlen);
      }
    } else { /* we're in the middle. Just one crypt. */
      if(!EVP_DecryptUpdate(&circ->n_ctx,out,&outlen,in,inlen)) {
        log(LOG_ERR,"circuit_crypt(): Decryption failed for ACI : %u (%s).",
            circ->n_aci, ERR_reason_error_string(ERR_get_error()));
        free(out);
        return -1;
      }
  
      memcpy(in,out,inlen);
    }
  }

  free(out);

  return 0;
@@ -294,7 +351,9 @@ int circuit_crypt(circuit_t *circ, char *in, size_t inlen, char crypt_type) {

void circuit_close(circuit_t *circ) {
  circuit_remove(circ);
  if(circ->n_conn)
    connection_send_destroy(circ->n_aci, circ->n_conn); 
  if(circ->p_conn)
    connection_send_destroy(circ->p_aci, circ->p_conn); 
  circuit_free(circ);
}
+17 −5
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ void command_process_create_cell(cell_t *cell, connection_t *conn) {
    memcpy((void *)&circ->onionlen,(void *)cell->payload, 4);
    circ->onionlen = ntohl(circ->onionlen);
    log(LOG_DEBUG,"command_process_create_cell():  Onion length is %u.",circ->onionlen);
    if(circ->onionlen > 50000) { /* too big */
    if(circ->onionlen > 50000 || circ->onionlen < 1) { /* too big or too small */
      log(LOG_DEBUG,"That's ludicrous. Closing.");
      circuit_close(circ);
      return;
@@ -172,6 +172,10 @@ void command_process_data_cell(cell_t *cell, connection_t *conn) {
    log(LOG_DEBUG,"command_process_data_cell(): circuit in open_wait. Dropping data cell.");
    return;
  }
  if(circ->state == CIRCUIT_STATE_OR_WAIT) {
    log(LOG_DEBUG,"command_process_data_cell(): circuit in or_wait. Dropping data cell.");
    return;
  }

  /* at this point both circ->n_conn and circ->p_conn are guaranteed to be set */

@@ -184,6 +188,13 @@ void command_process_data_cell(cell_t *cell, connection_t *conn) {
    }
  } else { /* it's an ingoing cell */
    cell->aci = circ->p_aci; /* switch it */
    if(circ->p_conn->type == CONN_TYPE_AP) { /* we want to decrypt, not encrypt */
      if(circuit_deliver_data_cell(cell, circ, circ->p_conn, 'd') < 0) {
        log(LOG_DEBUG,"command_process_data_cell(): circuit_deliver_data_cell (backward to AP) failed. Closing.");
        circuit_close(circ);
        return;
      }
    } else {
      if(circuit_deliver_data_cell(cell, circ, circ->p_conn, 'e') < 0) {
        log(LOG_DEBUG,"command_process_data_cell(): circuit_deliver_data_cell (backward) failed. Closing.");
        circuit_close(circ);
@@ -191,6 +202,7 @@ void command_process_data_cell(cell_t *cell, connection_t *conn) {
      }
    }
  }
}

void command_process_destroy_cell(cell_t *cell, connection_t *conn) {
  circuit_t *circ;
+116 −24
Original line number Diff line number Diff line
@@ -61,6 +61,10 @@ void connection_free(connection_t *conn) {
  buf_free(conn->outbuf);
  if(conn->address)
    free(conn->address);
  if(conn->dest_addr)
    free(conn->dest_addr);
  if(conn->dest_port)
    free(conn->dest_port);

 /* FIXME should we do these for all connections, or just ORs, or what */
  if(conn->type == CONN_TYPE_OR ||
@@ -161,18 +165,11 @@ int connection_handle_listener_read(connection_t *conn, int new_type, int new_st
  return 0;
}

int retry_all_connections(routerinfo_t **router_array, int rarray_len,
  RSA *prkey, uint16_t or_port, uint16_t op_port, uint16_t ap_port) {

  /* start all connections that should be up but aren't */

  routerinfo_t *router;
  int i;

/* private function, to create the 'local' variable used below */
static int learn_local(struct sockaddr_in *local) {
  /* local host information */
  char localhostname[512];
  struct hostent *localhost;
  struct sockaddr_in local; /* local address */

  /* obtain local host information */
  if(gethostname(localhostname,512) < 0) {
@@ -184,31 +181,69 @@ int retry_all_connections(routerinfo_t **router_array, int rarray_len,
    log(LOG_ERR,"Error obtaining local host info.");
    return -1;
  }
  memset((void *)&local,0,sizeof(local));
  local.sin_family = AF_INET;
  local.sin_addr.s_addr = INADDR_ANY;
  local.sin_port = htons(or_port);
  memcpy((void *)&local.sin_addr,(void *)localhost->h_addr,sizeof(struct in_addr));
  memset((void *)local,0,sizeof(struct sockaddr_in));
  local->sin_family = AF_INET;
  local->sin_addr.s_addr = INADDR_ANY;
  memcpy((void *)&local->sin_addr,(void *)localhost->h_addr,sizeof(struct in_addr));

  return 0;
}

int retry_all_connections(int role, routerinfo_t **router_array, int rarray_len,
  RSA *prkey, uint16_t or_listenport, uint16_t op_listenport, uint16_t ap_listenport) {

  /* start all connections that should be up but aren't */

  routerinfo_t *router;
  int i;
  struct sockaddr_in local; /* local address */

  if(learn_local(&local) < 0)
    return -1;

  local.sin_port = htons(or_listenport);
  if(role & ROLE_OR_CONNECT_ALL) {
    for (i=0;i<rarray_len;i++) {
      router = router_array[i];
    if(!connection_get_by_addr_port(router->addr,router->port)) { /* not in the list */
      connect_to_router(router, prkey, &local);
      if(!connection_get_by_addr_port(router->addr,router->or_port)) { /* not in the list */
        log(LOG_DEBUG,"retry_all_connections(): connecting to OR %s:%u.",router->address,ntohs(router->or_port));
        connection_or_connect_as_or(router, prkey, &local);
      }
    }
  }

  if(role & ROLE_OR_LISTEN) {
    if(!connection_get_by_type(CONN_TYPE_OR_LISTENER)) {
      connection_or_create_listener(prkey, &local);
    }
  }
      
  local.sin_port = htons(op_port);
  if(role & ROLE_OP_LISTEN) {
    local.sin_port = htons(op_listenport);
    if(!connection_get_by_type(CONN_TYPE_OP_LISTENER)) {
      connection_op_create_listener(prkey, &local);
    }
  }

  if(role & ROLE_AP_LISTEN) {
    local.sin_port = htons(ap_listenport);
    if(!connection_get_by_type(CONN_TYPE_AP_LISTENER)) {
      connection_ap_create_listener(NULL, &local); /* no need to tell it the private key. */
    }
  }
 
  return 0;
}

connection_t *connection_connect_to_router_as_op(routerinfo_t *router, RSA *prkey, uint16_t local_or_port) {
  struct sockaddr_in local; /* local address */

  if(learn_local(&local) < 0)
    return NULL;
  local.sin_port = htons(local_or_port);
  return connection_or_connect_as_or(router, prkey, &local);
}

int connection_read_to_buf(connection_t *conn) {
  return read_to_buf(conn->s, &conn->inbuf, &conn->inbuflen, &conn->inbuf_datalen, &conn->inbuf_reached_eof);
}
@@ -234,6 +269,7 @@ int connection_send_destroy(aci_t aci, connection_t *conn) {
  assert(conn);

  if(conn->type == CONN_TYPE_OP ||
     conn->type == CONN_TYPE_AP ||
     conn->type == CONN_TYPE_EXIT) {
     log(LOG_DEBUG,"connection_send_destroy(): At an edge. Marking connection for close.");
     conn->marked_for_close = 1;
@@ -296,12 +332,66 @@ int connection_process_inbuf(connection_t *conn) {
      return connection_or_process_inbuf(conn);
    case CONN_TYPE_EXIT:
      return connection_exit_process_inbuf(conn);
    case CONN_TYPE_AP:
      return connection_ap_process_inbuf(conn);
    default:
      log(LOG_DEBUG,"connection_process_inbuf() got unexpected conn->type.");
      return -1;
  }
}

int connection_package_raw_inbuf(connection_t *conn) {
  int amount_to_process;
  cell_t cell;
  circuit_t *circ;

  assert(conn);
  assert(conn->type == CONN_TYPE_EXIT || conn->type == CONN_TYPE_AP);

  amount_to_process = conn->inbuf_datalen;

  if(!amount_to_process)
    return 0;

  if(amount_to_process > CELL_PAYLOAD_SIZE) {
    cell.length = CELL_PAYLOAD_SIZE;
  } else {
    cell.length = amount_to_process;
  }

  if(connection_fetch_from_buf(cell.payload, cell.length, conn) < 0)
    return -1;

  circ = circuit_get_by_conn(conn);
  if(!circ) {
    log(LOG_DEBUG,"connection_raw_package_inbuf(): conn has no circuits!");
    return -1;
  }

  log(LOG_DEBUG,"connection_raw_package_inbuf(): Packaging %d bytes.",cell.length);
  if(circ->n_conn == conn) { /* send it backward. we're an exit. */
    cell.aci = circ->p_aci;
    cell.command = CELL_DATA;
    if(circuit_deliver_data_cell(&cell, circ, circ->p_conn, 'e') < 0) {
      log(LOG_DEBUG,"connection_raw_package_inbuf(): circuit_deliver_data_cell (backward) failed. Closing.");
      circuit_close(circ);
      return 0;
    }
  } else { /* send it forward. we're an AP */
    cell.aci = circ->n_aci;
    cell.command = CELL_DATA;
    if(circuit_deliver_data_cell(&cell, circ, circ->n_conn, 'e') < 0) {
      /* yes, we use 'e' here, because the AP connection must *encrypt* its input. */
      log(LOG_DEBUG,"connection_raw_package_inbuf(): circuit_deliver_data_cell (forward) failed. Closing.");
      circuit_close(circ);
      return 0;
    }
  }
  if(amount_to_process > CELL_PAYLOAD_SIZE)
    return connection_package_raw_inbuf(conn);
  return 0;
}

int connection_finished_flushing(connection_t *conn) {

  assert(conn);
@@ -309,6 +399,8 @@ int connection_finished_flushing(connection_t *conn) {
  log(LOG_DEBUG,"connection_finished_flushing() entered. Socket %u.", conn->s);

  switch(conn->type) {
    case CONN_TYPE_AP:
      return connection_ap_finished_flushing(conn);
    case CONN_TYPE_OP:
      return connection_op_finished_flushing(conn);
    case CONN_TYPE_OR:

src/or/connection_ap.c

0 → 100644
+381 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading