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

put in initial support for ".nickname.exit" addresses, to let alice

decide what exit node to use; based on a patch by geoff goodell.

needs more work: e.g. it goes bananas building new circuits when the
chosen exit node's exit policy rejects the connection.


svn:r3015
parent 4effabd7
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -706,12 +706,27 @@ circuit_get_open_circ_or_launch(connection_t *conn,
      }
      if (!router_get_by_nickname(exitname)) {
        log_fn(LOG_WARN,"Advertised intro point '%s' is not known. Closing.", exitname);
        tor_free(exitname);
        return -1;
      }
      /* XXX if we failed, then refetch the descriptor */
      log_fn(LOG_INFO,"Chose %s as intro point for %s.", exitname, conn->rend_query);
    }

    /* If we have specified a particular exit node for our
     * connection, then be sure to open a circuit to that exit node.
     */
    if(desired_circuit_purpose == CIRCUIT_PURPOSE_C_GENERAL) {
      if (conn->chosen_exit_name) {
        exitname = tor_strdup(conn->chosen_exit_name);
        if(!router_get_by_nickname(exitname)) {
          log_fn(LOG_WARN,"Requested exit point '%s' is not known. Closing.", exitname);
          tor_free(exitname);
          return -1;
        }
      }
    }

    if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_REND_JOINED)
      new_circ_purpose = CIRCUIT_PURPOSE_C_ESTABLISH_REND;
    else if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT)
+1 −0
Original line number Diff line number Diff line
@@ -148,6 +148,7 @@ void connection_free(connection_t *conn) {
    buf_free(conn->outbuf);
  }
  tor_free(conn->address);
  tor_free(conn->chosen_exit_name);

  if (connection_speaks_cells(conn)) {
    if (conn->state == OR_CONN_STATE_OPEN)
+78 −9
Original line number Diff line number Diff line
@@ -352,6 +352,7 @@ void connection_ap_attach_pending(void)
static int connection_ap_handshake_process_socks(connection_t *conn) {
  socks_request_t *socks;
  int sockshere;
  int addresstype;

  tor_assert(conn);
  tor_assert(conn->type == CONN_TYPE_AP);
@@ -397,9 +398,24 @@ static int connection_ap_handshake_process_socks(connection_t *conn) {
    }
  }

  /* this call _modifies_ socks->address iff it's a hidden-service request */
  if (rend_parse_rendezvous_address(socks->address) < 0) {
    /* normal request */
  /* Parse the address provided by SOCKS.  Modify it in-place if it
   * specifies a hidden-service (.onion) or particular exit node (.exit).
   */
  addresstype = parse_address(socks->address);

  if (addresstype == 1) {
    /* .exit -- modify conn to specify the exit node. */
    char *s = strrchr(socks->address,'.');
    if (!s || s[1] == '\0') {
      log_fn(LOG_WARN,"Malformed address '%s.exit'. Refusing.", socks->address);
      return -1;
    }
    conn->chosen_exit_name = tor_strdup(s+1);
    *s = 0;
  }

  if (addresstype != 2) {
    /* not a hidden-service request (i.e. normal or .exit) */
    if (socks->command == SOCKS_COMMAND_CONNECT && socks->port == 0) {
      log_fn(LOG_WARN,"Application asked to connect to port 0. Refusing.");
      return -1;
@@ -447,7 +463,7 @@ static int connection_ap_handshake_process_socks(connection_t *conn) {
      }
    }
  }
  return 0;
  return 0; /* unreached but keeps the compiler happy */
}

/** Iterate over the two bytes of stream_id until we get one that is not
@@ -991,18 +1007,34 @@ int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit)
  tor_assert(conn);
  tor_assert(conn->type == CONN_TYPE_AP);
  tor_assert(conn->socks_request);
  tor_assert(exit);

  log_fn(LOG_DEBUG,"considering nickname %s, for address %s / port %d:",
         exit->nickname, conn->socks_request->address,
         conn->socks_request->port);

  /* If a particular exit node has been requested for the new connection,
   * make sure the exit node of the existing circuit matches exactly.
   */
  if (conn->chosen_exit_name) {
    if (router_get_by_nickname(conn->chosen_exit_name) != exit) {
      /* doesn't match */
      log_fn(LOG_DEBUG,"Requested node '%s', considering node '%s'. No.",
             conn->chosen_exit_name, exit->nickname);
      return 0;
    }
  }

  if (conn->socks_request->command == SOCKS_COMMAND_RESOLVE) {
    /* 0.0.8 servers have buggy resolve support. */
    return tor_version_as_new_as(exit->platform, "0.0.9pre1");
  }
    if (!tor_version_as_new_as(exit->platform, "0.0.9pre1"))
      return 0;
  } else {
    addr = client_dns_lookup_entry(conn->socks_request->address);
    if (router_compare_addr_to_addr_policy(addr, conn->socks_request->port,
                                           exit->exit_policy) < 0)
      return 0;
  }
  return 1;
}

@@ -1211,3 +1243,40 @@ set_exit_redirects(smartlist_t *lst)
  redirect_exit_list = lst;
}

/** If address is of the form "y.onion" with a well-formed handle y:
 *     Put a '\0' after y, lower-case it, and return 2.
 *
 * If address is of the form "y.exit":
 *     Put a '\0' after y and return 1.
 *
 * Otherwise:
 *     Return 0 and change nothing.
 */
int parse_address(char *address) {
    char *s;
    char query[REND_SERVICE_ID_LEN+1];

    s = strrchr(address,'.');
    if (!s) return 0; /* no dot, thus normal */
    if (!strcasecmp(s+1,"exit")) {
      *s = 0; /* null-terminate it */
      return 1; /* .exit */
    }
    if (strcasecmp(s+1,"onion"))
      return 0; /* neither .exit nor .onion, thus normal */

    /* so it is .onion */
    *s = 0; /* null-terminate it */
    if (strlcpy(query, address, REND_SERVICE_ID_LEN+1) >= REND_SERVICE_ID_LEN+1)
      goto failed;
    tor_strlower(query);
    if (rend_valid_service_id(query)) {
      tor_strlower(address);
      return 2; /* success */
    }
failed:
    /* otherwise, return to previous state and return 0 */
    *s = '.';
    return 0;
}
+5 −2
Original line number Diff line number Diff line
@@ -526,6 +526,9 @@ struct connection_t {
  char identity_digest[DIGEST_LEN]; /**< Hash of identity_pkey */
  char *nickname; /**< Nickname of OR on other side (if any). */

  /** Nickname of planned exit node -- to be used with .exit support. */
  char *chosen_exit_name;

/* Used only by OR connections: */
  tor_tls *tls; /**< TLS connection state (OR only.) */
  uint16_t next_circ_id; /**< Which circ_id do we try to use next on
@@ -1223,6 +1226,7 @@ int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit);
void connection_ap_expire_beginning(void);
void connection_ap_attach_pending(void);

void parse_socks_policy(void);
int socks_policy_permits_address(uint32_t addr);

void client_dns_init(void);
@@ -1231,7 +1235,7 @@ int client_dns_incr_failures(const char *address);
void client_dns_set_entry(const char *address, uint32_t val);
void client_dns_clean(void);
void set_exit_redirects(smartlist_t *lst);
void parse_socks_policy(void);
int parse_address(char *address);

/********************************* connection_or.c ***************************/

@@ -1453,7 +1457,6 @@ int rend_client_receive_rendezvous(circuit_t *circ, const char *request, size_t
void rend_client_desc_fetched(char *query, int status);

char *rend_client_get_random_intro(char *query);
int rend_parse_rendezvous_address(char *address);

int rend_client_send_introduction(circuit_t *introcirc, circuit_t *rendcirc);

+0 −27
Original line number Diff line number Diff line
@@ -439,30 +439,3 @@ char *rend_client_get_random_intro(char *query) {
  return nickname;
}
/** If address is of the form "y.onion" with a well-formed handle y,
 * then put a '\0' after y, lower-case it, and return 0.
 * Else return -1 and change nothing.
 */
int rend_parse_rendezvous_address(char *address) {
  char *s;
  char query[REND_SERVICE_ID_LEN+1];

  s = strrchr(address,'.');
  if (!s) return -1; /* no dot */
  if (strcasecmp(s+1,"onion"))
    return -1; /* not .onion */

  *s = 0; /* null terminate it */
  if (strlcpy(query, address, REND_SERVICE_ID_LEN+1) >= REND_SERVICE_ID_LEN+1)
    goto failed;
  tor_strlower(query);
  if (rend_valid_service_id(query)) {
    tor_strlower(address);
    return 0; /* success */
  }
failed:
  /* otherwise, return to previous state and return -1 */
  *s = '.';
  return -1;
}
Loading