Commit 9bf9ca4d authored by Roger Dingledine's avatar Roger Dingledine
Browse files

bugfix: add a circ->resolving_streams field, and make dns resolving ...

bugfix: add a circ->resolving_streams field, and make dns resolving                            streams not actually in the connection_array until they're done resolving.

bugfix: actually complain if we duplicate mark-for-close a circuit

add more logging for relay ends that claim dns resolve failed, so we can
find out why they're not being retried.


svn:r1798
parent e6477a8e
Loading
Loading
Loading
Loading
+45 −6
Changes for src/or/circuit.c: 45 added lines, 6 removed lines.
Original line number Diff line number Diff line
@@ -227,6 +227,10 @@ circuit_t *circuit_get_by_circ_id_conn(uint16_t circ_id, connection_t *conn) {
        if(tmpconn == conn)
          return circ;
      }
      for(tmpconn = circ->resolving_streams; tmpconn; tmpconn = tmpconn->next_stream) {
        if(tmpconn == conn)
          return circ;
      }
    }
  }
  return NULL;
@@ -250,6 +254,9 @@ circuit_t *circuit_get_by_conn(connection_t *conn) {
    for(tmpconn = circ->n_streams; tmpconn; tmpconn=tmpconn->next_stream)
      if(tmpconn == conn)
        return circ;
    for(tmpconn = circ->resolving_streams; tmpconn; tmpconn=tmpconn->next_stream)
      if(tmpconn == conn)
        return circ;
  }
  return NULL;
}
@@ -905,6 +912,12 @@ relay_lookup_conn(circuit_t *circ, cell_t *cell, int cell_direction)
      return tmpconn;
    }
  }
  for(tmpconn = circ->resolving_streams; tmpconn; tmpconn=tmpconn->next_stream) {
    if(rh.stream_id == tmpconn->stream_id) {
      log_fn(LOG_DEBUG,"found conn for stream %d.", rh.stream_id);
      return tmpconn;
    }
  }
  return NULL; /* probably a begin relay cell */
}

@@ -985,7 +998,7 @@ int _circuit_mark_for_close(circuit_t *circ) {
  connection_t *conn;

  assert_circuit_ok(circ);
  if (circ->marked_for_close < 0)
  if (circ->marked_for_close)
    return -1;

  if(circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) {
@@ -1010,14 +1023,18 @@ int _circuit_mark_for_close(circuit_t *circ) {

  if(circ->n_conn)
    connection_send_destroy(circ->n_circ_id, circ->n_conn);
  for(conn=circ->n_streams; conn; conn=conn->next_stream) {
  for(conn=circ->n_streams; conn; conn=conn->next_stream)
    connection_edge_destroy(circ->n_circ_id, conn);
  while(circ->resolving_streams) {
    conn = circ->resolving_streams;
    circ->resolving_streams = conn->next_stream;
    log_fn(LOG_INFO,"Freeing resolving-conn.");
    connection_free(conn);
  }
  if(circ->p_conn)
    connection_send_destroy(circ->p_circ_id, circ->p_conn);
  for(conn=circ->p_streams; conn; conn=conn->next_stream) {
  for(conn=circ->p_streams; conn; conn=conn->next_stream)
    connection_edge_destroy(circ->p_circ_id, conn);
  }

  circ->marked_for_close = 1;

@@ -1042,16 +1059,38 @@ void circuit_detach_stream(circuit_t *circ, connection_t *conn) {
    circ->n_streams = conn->next_stream;
    return;
  }
  for(prevconn = circ->p_streams; prevconn && prevconn->next_stream && prevconn->next_stream != conn; prevconn = prevconn->next_stream) ;
  if(conn == circ->resolving_streams) {
    circ->resolving_streams = conn->next_stream;
    return;
  }

  for(prevconn = circ->p_streams;
      prevconn && prevconn->next_stream && prevconn->next_stream != conn;
      prevconn = prevconn->next_stream)
    ;
  if(prevconn && prevconn->next_stream) {
    prevconn->next_stream = conn->next_stream;
    return;
  }

  for(prevconn = circ->n_streams;
      prevconn && prevconn->next_stream && prevconn->next_stream != conn;
      prevconn = prevconn->next_stream)
    ;
  if(prevconn && prevconn->next_stream) {
    prevconn->next_stream = conn->next_stream;
    return;
  }
  for(prevconn = circ->n_streams; prevconn && prevconn->next_stream && prevconn->next_stream != conn; prevconn = prevconn->next_stream) ;

  for(prevconn = circ->resolving_streams;
      prevconn && prevconn->next_stream && prevconn->next_stream != conn;
      prevconn = prevconn->next_stream)
    ;
  if(prevconn && prevconn->next_stream) {
    prevconn->next_stream = conn->next_stream;
    return;
  }

  log_fn(LOG_ERR,"edge conn not in circuit's list?");
  tor_assert(0); /* should never get here */
}
+4 −3
Changes for src/or/connection.c: 4 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -79,6 +79,7 @@ connection_t *connection_new(int type) {
  conn = tor_malloc_zero(sizeof(connection_t));
  conn->magic = CONNECTION_MAGIC;
  conn->s = -1; /* give it a default of 'not used' */
  conn->poll_index = -1; /* also default to 'not used' */

  conn->type = type;
  if(!connection_is_listener(conn)) { /* listeners never use their buf */
@@ -631,8 +632,8 @@ int connection_read_to_buf(connection_t *conn) {
    switch(result) {
      case TOR_TLS_ERROR:
      case TOR_TLS_CLOSE:
        log_fn(LOG_INFO,"tls error. breaking (nickname %s).",
               conn->nickname ? conn->nickname : "not set");
        log_fn(LOG_INFO,"tls error. breaking (nickname %s, address %s).",
               conn->nickname ? conn->nickname : "not set", conn->address);
        return -1; /* XXX deal with close better */
      case TOR_TLS_WANTWRITE:
        connection_start_writing(conn);
@@ -864,7 +865,7 @@ connection_t *connection_get_by_type_state_lastwritten(int type, int state) {
  return best;
}

connection_t *connection_get_by_type_rendquery(int type, char *rendquery) {
connection_t *connection_get_by_type_rendquery(int type, const char *rendquery) {
  int i, n;
  connection_t *conn;
  connection_t **carray;
+38 −18
Changes for src/or/connection_edge.c: 38 added lines, 18 removed lines.
Original line number Diff line number Diff line
/* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
/* Copyright 2001 Matej Pfajfar, 2001-2004 Roger Dingledine. */
/* See LICENSE for licensing information */
/* $Id$ */

@@ -165,10 +165,10 @@ int connection_edge_end(connection_t *conn, char reason, crypt_path_t *cpath_lay
}

/* Make a relay cell out of 'relay_command' and 'payload', and
 * send it onto the open circuit 'circ'. If it's a control cell,
 * set fromconn to NULL, else it's the stream that's sending the
 * relay cell. Use cpath_layer NULL if you're responding to the OP;
 * If it's an outgoing cell it must specify the destination hop.
 * send it onto the open circuit 'circ'. 'fromconn' is the stream
 * that's sending the relay cell, or NULL if it's a control cell,
 * 'cpath_layer' is NULL for OR->OP cells, or the destination hop
 * for OP->OR cells.
 *
 * If you can't send the cell, mark the circuit for close and
 * return -1. Else return 0.
@@ -229,12 +229,15 @@ int connection_edge_process_relay_cell_not_open(
    reason = *(cell->payload+RELAY_HEADER_SIZE);
    /* We have to check this here, since we aren't connected yet. */
    if (rh->length >= 5 && reason == END_STREAM_REASON_EXITPOLICY) {
      log_fn(LOG_INFO,"Address %s refused due to exit policy. Retrying.",
             conn->socks_request->address);
      addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+1));
      client_dns_set_entry(conn->socks_request->address, addr);
      conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
      circuit_detach_stream(circ,conn);
      if(connection_ap_handshake_attach_circuit(conn) >= 0)
        return 0;
      log_fn(LOG_INFO,"Giving up on retrying (from exitpolicy); conn can't be handled.");
      /* else, conn will get closed below */
    } else if (rh->length && reason == END_STREAM_REASON_RESOLVEFAILED) {
      if (client_dns_incr_failures(conn->socks_request->address)
@@ -245,6 +248,10 @@ int connection_edge_process_relay_cell_not_open(
        if(connection_ap_handshake_attach_circuit(conn) >= 0)
          return 0;
        /* else, conn will get closed below */
        log_fn(LOG_INFO,"Giving up on retrying (from resolvefailed); conn can't be handled.");
      } else {
        log_fn(LOG_WARN,"Have tried resolving address %s at %d different places. Giving up.",
               conn->socks_request->address, MAX_RESOLVE_FAILURES);
      }
    }
    log_fn(LOG_INFO,"Edge got end (%s) before we're connected. Marking for close.",
@@ -253,8 +260,6 @@ int connection_edge_process_relay_cell_not_open(
      circuit_log_path(LOG_INFO,circ);
    conn->has_sent_end = 1; /* we just got an 'end', don't need to send one */
    connection_mark_for_close(conn, 0);
    /* XXX here we should send a socks reject back if necessary, and hold
     * open til flushed */
    return 0;
  }

@@ -280,13 +285,13 @@ int connection_edge_process_relay_cell_not_open(
      return 0;
    }
    return 0;
  } else {
  }

  log_fn(LOG_WARN,"Got an unexpected relay command %d, in state %d (%s). Closing.",
         rh->command, conn->state, conn_state_to_string[conn->type][conn->state]);
  connection_mark_for_close(conn, END_STREAM_REASON_MISC);
  return -1;
}
}

/* an incoming relay cell has arrived. return -1 if you want to tear down the
 * circuit, else 0. */
@@ -893,7 +898,7 @@ int connection_ap_handshake_attach_circuit(connection_t *conn) {
  if(conn_age > 60) {
    /* XXX make this cleaner than '60' */
    log_fn(LOG_WARN,"Giving up on unattached conn (%d sec old).", conn_age);
    connection_mark_for_close(conn, 0);
    return -1;
  }

  if(!connection_edge_is_rendezvous_stream(conn)) { /* we're a general conn */
@@ -1180,13 +1185,6 @@ static int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) {
  n_stream->package_window = STREAMWINDOW_START;
  n_stream->deliver_window = STREAMWINDOW_START;

  log_fn(LOG_DEBUG,"finished adding conn");

  /* add it into the linked list of streams on this circuit */
  n_stream->next_stream = circ->n_streams;
  circ->n_streams = n_stream;
  assert_circuit_ok(circ);

  if(circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) {
    log_fn(LOG_DEBUG,"begin is for rendezvous. configuring stream.");
    n_stream->address = tor_strdup("(rendezvous)");
@@ -1204,6 +1202,12 @@ static int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) {
    assert_circuit_ok(circ);
    log_fn(LOG_DEBUG,"Finished assigning addr/port");
    n_stream->cpath_layer = circ->cpath->prev; /* link it */

    /* add it into the linked list of n_streams on this circuit */
    n_stream->next_stream = circ->n_streams;
    circ->n_streams = n_stream;
    assert_circuit_ok(circ);

    connection_exit_connect(n_stream);
    return 0;
  }
@@ -1214,6 +1218,12 @@ static int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) {
  /* send it off to the gethostbyname farm */
  switch(dns_resolve(n_stream)) {
    case 1: /* resolve worked */

      /* add it into the linked list of n_streams on this circuit */
      n_stream->next_stream = circ->n_streams;
      circ->n_streams = n_stream;
      assert_circuit_ok(circ);

      connection_exit_connect(n_stream);
      return 0;
    case -1: /* resolve failed */
@@ -1222,6 +1232,10 @@ static int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) {
      connection_free(n_stream);
      break;
    case 0: /* resolve added to pending list */
      /* add it into the linked list of resolving_streams on this circuit */
      n_stream->next_stream = circ->resolving_streams;
      circ->resolving_streams = n_stream;
      assert_circuit_ok(circ);
      ;
  }
  return 0;
@@ -1234,6 +1248,8 @@ void connection_exit_connect(connection_t *conn) {
      router_compare_to_my_exit_policy(conn) == ADDR_POLICY_REJECTED) {
    log_fn(LOG_INFO,"%s:%d failed exit policy. Closing.", conn->address, conn->port);
    connection_mark_for_close(conn, END_STREAM_REASON_EXITPOLICY);
    circuit_detach_stream(circuit_get_by_conn(conn), conn);
    connection_free(conn);
    return;
  }

@@ -1241,6 +1257,7 @@ void connection_exit_connect(connection_t *conn) {
  switch(connection_connect(conn, conn->address, conn->addr, conn->port)) {
    case -1:
      connection_mark_for_close(conn, END_STREAM_REASON_CONNECTFAILED);
      circuit_detach_stream(circuit_get_by_conn(conn), conn);
      connection_free(conn);
      return;
    case 0:
@@ -1368,7 +1385,10 @@ static int client_dns_incr_failures(const char *address)
{
  struct client_dns_entry *ent;
  ent = _get_or_create_ent(address);
  return ++ent->n_failures;
  ++ent->n_failures;
  log_fn(LOG_DEBUG,"Address %s now has %d resolve failures.",
         address, ent->n_failures);
  return ent->n_failures;
}

static void client_dns_set_entry(const char *address, uint32_t val)
+1 −1
Changes for src/or/cpuworker.c: 1 added line, 1 removed line.
Original line number Diff line number Diff line
@@ -167,7 +167,7 @@ done_processing:
 * Read and writes from fdarray[1].  Reads requests, writes answers.
 *
 *   Request format:
 *          Task type           [1 byte, always ONIONSKIN_CHALLENGE_LEN]
 *          Task type           [1 byte, always CPUWORKER_TASK_ONION]
 *          Opaque tag          TAG_LEN
 *          Onionskin challenge ONIONSKIN_CHALLENGE_LEN
 *   Response format:
+11 −11
Changes for src/or/directory.c: 11 added lines, 11 removed lines.
Original line number Diff line number Diff line
@@ -221,8 +221,8 @@ int connection_dir_process_inbuf(connection_t *conn) {

  /* Directory clients write, then read data until they receive EOF;
   * directory servers read data until they get an HTTP command, then
   * write their response, mark the conn for close (?) and hold the
   * conn open till it's flushed. (??)XXXXNMNM
   * write their response (when it's finished flushing, they mark for
   * close).
   */
  if(conn->inbuf_reached_eof) {
    if(conn->state != DIR_CONN_STATE_CLIENT_READING) {
@@ -360,10 +360,10 @@ static char answer404[] = "HTTP/1.0 404 Not found\r\n\r\n";
static char answer503[] = "HTTP/1.0 503 Directory unavailable\r\n\r\n";

/* Helper function: called when a dirserver gets a complete HTTP GET
 * request.  Looks for a request for a directory or for a rendezvous
 * service descriptor.  On finding one, writes a response into
 * request.  Look for a request for a directory or for a rendezvous
 * service descriptor.  On finding one, write a response into
 * conn->outbuf.  If the request is unrecognized, send a 404.
 * Always returns 0. */
 * Always return 0. */
static int directory_handle_command_get(connection_t *conn,
                                        char *headers, char *body,
                                        int body_len) {
@@ -425,11 +425,11 @@ static int directory_handle_command_get(connection_t *conn,
  return 0;
}

/* Helper function: called when a dirserver gets a complete HTTP GET
 * request.  Looks for an uploaded server descriptor or rendezvous
 * service descriptor.  On finding one, processes it and writes a
 * response into conn->outbuf.  If the request is unrecognized, sends a
 * 404.  Always returns 0. */
/* Helper function: called when a dirserver gets a complete HTTP POST
 * request.  Look for an uploaded server descriptor or rendezvous
 * service descriptor.  On finding one, process it and write a
 * response into conn->outbuf.  If the request is unrecognized, send a
 * 404.  Always return 0. */
static int directory_handle_command_post(connection_t *conn,
                                         char *headers, char *body,
                                         int body_len) {
@@ -519,7 +519,7 @@ static int directory_handle_command(connection_t *conn) {
}

/* Write handler for directory connections; called when all data has
 * been flushed.  Handle a completed connection; close the connection,
 * been flushed.  Handle a completed connection: close the connection
 * or wait for a response as appropriate.
 */
int connection_dir_finished_flushing(connection_t *conn) {
Loading