Loading src/or/buffers.c +16 −5 Changes for src/or/buffers.c: 16 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -409,6 +409,9 @@ int fetch_from_buf_http(buf_t *buf, return 1; } #define SOCKS_COMMAND_CONNECT 0x01 #define SOCKS_COMMAND_RESOLVE 0xF0 /** There is a (possibly incomplete) socks handshake on <b>buf</b>, of one * of the forms * - socks4: "socksheader username\\0" Loading Loading @@ -467,8 +470,12 @@ int fetch_from_buf_socks(buf_t *buf, socks_request_t *req) { log_fn(LOG_DEBUG,"socks5: checking request"); if(buf->datalen < 8) /* basic info plus >=2 for addr plus 2 for port */ return 0; /* not yet */ if(*(buf->mem+1) != 1) { /* not a connect? we don't support it. */ log_fn(LOG_WARN,"socks5: command %d not '1'. Rejecting.",*(buf->mem+1)); req->command = (unsigned char) *(buf->mem+1); if(req->command != SOCKS_COMMAND_CONNECT && req->command != SOCKS_COMMAND_RESOLVE) { /* not a connect or resolve? we don't support it. */ log_fn(LOG_WARN,"socks5: command %d not recognized. Rejecting.", req->command); return -1; } switch(*(buf->mem+3)) { /* address type */ Loading Loading @@ -516,14 +523,18 @@ int fetch_from_buf_socks(buf_t *buf, socks_request_t *req) { if(buf->datalen < SOCKS4_NETWORK_LEN) /* basic info available? */ return 0; /* not yet */ if(*(buf->mem+1) != 1) { /* not a connect? we don't support it. */ log_fn(LOG_WARN,"socks4: command %d not '1'. Rejecting.",*(buf->mem+1)); req->command = (unsigned char) *(buf->mem+1); if(req->command != SOCKS_COMMAND_CONNECT && req->command != SOCKS_COMMAND_RESOLVE) { /* not a connect or resolve? we don't support it. */ log_fn(LOG_WARN,"socks4: command %d not recognized. Rejecting.", req->command); return -1; } req->port = ntohs(*(uint16_t*)(buf->mem+2)); destip = ntohl(*(uint32_t*)(buf->mem+4)); if(!req->port || !destip) { if((!req->port && req->command!=SOCKS_COMMAND_RESOLVE) || !destip) { log_fn(LOG_WARN,"socks4: Port or DestIP is zero. Rejecting."); return -1; } Loading src/or/circuituse.c +16 −3 Changes for src/or/circuituse.c: 16 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -73,7 +73,14 @@ static int circuit_is_acceptable(circuit_t *circ, return 0; /* this circuit is screwed and doesn't know it yet */ } if(purpose == CIRCUIT_PURPOSE_C_GENERAL) { if (conn->socks_request && conn->socks_request->command == SOCKS_COMMAND_RESOLVE) { /* 0.0.7 servers and earlier don't support DNS resolution. There are no * ORs running code before 0.0.7, so we only worry about 0.0.7. Once all * servers are running 0.0.8, remove this check. */ if (!strncmp(exitrouter->platform, "Tor 0.0.7", 9)) return 0; } else if(purpose == CIRCUIT_PURPOSE_C_GENERAL) { if(connection_ap_can_use_exit(conn, exitrouter) == ADDR_POLICY_REJECTED) { /* can't exit from this router */ return 0; Loading Loading @@ -618,10 +625,12 @@ circuit_get_open_circ_or_launch(connection_t *conn, circuit_t **circp) { circuit_t *circ; uint32_t addr; int is_resolve; tor_assert(conn); tor_assert(circp); tor_assert(conn->state == AP_CONN_STATE_CIRCUIT_WAIT); is_resolve = conn->socks_request->command == SOCKS_COMMAND_RESOLVE; circ = circuit_get_best(conn, 1, desired_circuit_purpose); Loading @@ -630,7 +639,8 @@ circuit_get_open_circ_or_launch(connection_t *conn, return 1; /* we're happy */ } if(!connection_edge_is_rendezvous_stream(conn)) { /* general purpose circ */ /* Do we need to check exit policy? */ if(!is_resolve && !connection_edge_is_rendezvous_stream(conn)) { addr = client_dns_lookup_entry(conn->socks_request->address); if(router_exit_policy_all_routers_reject(addr, conn->socks_request->port)) { log_fn(LOG_WARN,"No Tor server exists that allows exit to %s:%d. Rejecting.", Loading Loading @@ -742,10 +752,13 @@ int connection_ap_handshake_attach_circuit(connection_t *conn) { circ->timestamp_dirty = time(NULL); link_apconn_to_circ(conn, circ); tor_assert(conn->socks_request); if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) connection_ap_handshake_send_begin(conn, circ); else connection_ap_handshake_send_resolve(conn, circ); return 1; } else { /* we're a rendezvous conn */ circuit_t *rendcirc=NULL, *introcirc=NULL; Loading src/or/connection.c +4 −1 Changes for src/or/connection.c: 4 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -1276,7 +1276,10 @@ void assert_connection_ok(connection_t *conn, time_t now) } else { tor_assert(!conn->socks_request); } if(conn->type != CONN_TYPE_DIR) { if (conn->type == CONN_TYPE_EXIT) { tor_assert(conn->purpose == EXIT_PURPOSE_CONNECT || conn->purpose == EXIT_PURPOSE_RESOLVE); } else if(conn->type != CONN_TYPE_DIR) { tor_assert(!conn->purpose); /* only used for dir types currently */ } Loading src/or/connection_edge.c +163 −0 Changes for src/or/connection_edge.c: 163 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -371,6 +371,23 @@ static int connection_ap_handshake_process_socks(connection_t *conn) { return sockshere; } /* else socks handshake is done, continue processing */ if (socks->command == SOCKS_COMMAND_RESOLVE) { /* Reply to resolves immediately if we can. */ if (strlen(socks->address) > RELAY_PAYLOAD_SIZE) { connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,0,NULL); conn->socks_request->has_finished = 1; connection_mark_for_close(conn); } uint32_t answer = htonl(client_dns_lookup_entry(socks->address)); if (answer) { connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_IPV4,4, (char*)&answer); conn->socks_request->has_finished = 1; connection_mark_for_close(conn); return 0; } } /* this call _modifies_ socks->address iff it's a hidden-service request */ if (rend_parse_rendezvous_address(socks->address) < 0) { /* normal request */ Loading Loading @@ -487,6 +504,46 @@ int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ) return 0; } /** Write a relay resolve cell, using destaddr and destport from ap_conn's * socks_request field, and send it down circ. * * If ap_conn is broken, mark it for close and return -1. Else return 0. */ int connection_ap_handshake_send_resolve(connection_t *ap_conn, circuit_t *circ) { int payload_len; const char *string_addr; tor_assert(ap_conn->type == CONN_TYPE_AP); tor_assert(ap_conn->state == AP_CONN_STATE_CIRCUIT_WAIT); tor_assert(ap_conn->socks_request); tor_assert(ap_conn->socks_request->command == SOCKS_COMMAND_RESOLVE); tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_GENERAL); ap_conn->stream_id = get_unique_stream_id_by_circ(circ); if (ap_conn->stream_id==0) { /* Don't send end: there is no 'other side' yet */ ap_conn->has_sent_end = 1; connection_mark_for_close(ap_conn); circuit_mark_for_close(circ); return -1; } string_addr = ap_conn->socks_request->address; payload_len = strlen(string_addr); tor_assert(strlen(string_addr) <= RELAY_PAYLOAD_SIZE); log_fn(LOG_DEBUG,"Sending relay cell to begin stream %d.",ap_conn->stream_id); if(connection_edge_send_command(ap_conn, circ, RELAY_COMMAND_RESOLVE, string_addr, payload_len, ap_conn->cpath_layer) < 0) return -1; /* circuit is closed, don't continue */ ap_conn->state = AP_CONN_STATE_RESOLVE_WAIT; log_fn(LOG_INFO,"Address sent for resolve, ap socket %d, n_circ_id %d",ap_conn->s,circ->n_circ_id); return 0; } /** Make an AP connection_t, do a socketpair and attach one side * to the conn, connection_add it, initialize it to circuit_wait, * and call connection_ap_handshake_attach_circuit(conn) on it. Loading Loading @@ -544,6 +601,59 @@ int connection_ap_make_bridge(char *address, uint16_t port) { return fd[1]; } void connection_ap_handshake_socks_resolved(connection_t *conn, int answer_type, int answer_len, const char *answer) { char buf[256]; int replylen; if (answer_type == RESOLVED_TYPE_IPV4) { uint32_t a = get_uint32(answer); client_dns_set_entry(conn->socks_request->address, ntohl(a)); } if (conn->socks_request->socks_version == 4) { buf[0] = 0x00; /* version */ if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) { buf[1] = 90; /* "Granted" */ set_uint16(buf+2, 0); memcpy(buf+4, answer, 4); /* address */ replylen = SOCKS4_NETWORK_LEN; } else { buf[1] = 91; /* "error" */ memset(buf+2, 0, 6); replylen = SOCKS4_NETWORK_LEN; } } else { /* SOCKS5 */ buf[0] = 0x05; /* version */ if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) { buf[1] = 0; /* succeeded */ buf[2] = 0; /* reserved */ buf[3] = 0x01; /* IPv4 address type */ memcpy(buf+4, answer, 4); /* address */ set_uint16(buf+8, 0); /* port == 0. */ replylen = 10; } else if (answer_type == RESOLVED_TYPE_IPV6 && answer_len == 16) { buf[1] = 0; /* succeeded */ buf[2] = 0; /* reserved */ buf[3] = 0x04; /* IPv6 address type */ memcpy(buf+4, answer, 16); /* address */ set_uint16(buf+20, 0); /* port == 0. */ replylen = 22; } else { buf[1] = 0x04; /* host unreachable */ memset(buf+2, 0, 8); replylen = 10; } } connection_ap_handshake_socks_reply(conn, buf, replylen, answer_type == RESOLVED_TYPE_IPV4 || answer_type == RESOLVED_TYPE_IPV6); } /** Send a socks reply to stream <b>conn</b>, using the appropriate * socks version, etc. * Loading Loading @@ -631,6 +741,7 @@ int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) { log_fn(LOG_DEBUG,"Creating new exit connection."); n_stream = connection_new(CONN_TYPE_EXIT); n_stream->purpose = EXIT_PURPOSE_CONNECT; n_stream->stream_id = rh.stream_id; n_stream->port = atoi(colon+1); Loading Loading @@ -694,6 +805,52 @@ int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) { return 0; } /** * Called when we receive a RELAY_RESOLVE cell 'cell' along the circuit 'circ'; * begin resolving the hostname, and (eventually) reply with a RESOLVED cell. */ int connection_exit_begin_resolve(cell_t *cell, circuit_t *circ) { connection_t *dummy_conn; relay_header_t rh; assert_circuit_ok(circ); relay_header_unpack(&rh, cell->payload); /* This 'dummy_conn' only exists to remember the stream ID * associated with the resolve request; and to make the * implementation of dns.c more uniform. (We really only need to * remember the circuit, the stream ID, and the hostname to be * resolved; but if we didn't store them in a connection like this, * the housekeeping in dns.c would get way more complicated.) */ dummy_conn = connection_new(CONN_TYPE_EXIT); dummy_conn->stream_id = rh.stream_id; dummy_conn->address = tor_strndup(cell->payload+RELAY_HEADER_SIZE, rh.length); dummy_conn->port = 0; dummy_conn->state = EXIT_CONN_STATE_RESOLVEFAILED; dummy_conn->purpose = EXIT_PURPOSE_RESOLVE; /* send it off to the gethostbyname farm */ switch(dns_resolve(dummy_conn)) { case 1: /* resolve worked; resolved cell was sent. */ connection_free(dummy_conn); return 0; case -1: /* resolve failed; resolved cell was sent. */ log_fn(LOG_INFO,"Resolve failed (%s).",dummy_conn->address); connection_free(dummy_conn); break; case 0: /* resolve added to pending list */ /* add it into the linked list of resolving_streams on this circuit */ dummy_conn->next_stream = circ->resolving_streams; circ->resolving_streams = dummy_conn; assert_circuit_ok(circ); ; } return 0; } /** Connect to conn's specified addr and port. If it worked, conn * has now been added to the connection_array. * Loading Loading @@ -776,6 +933,12 @@ int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit) log_fn(LOG_DEBUG,"considering nickname %s, for address %s / port %d:", exit->nickname, conn->socks_request->address, conn->socks_request->port); if (conn->socks_request->command == SOCKS_COMMAND_RESOLVE) { /* 0.0.7 servers and earlier don't support DNS resolution. There are no * ORs running code before 0.0.7, so we only worry about 0.0.7. Once all * servers are running 0.0.8, remove this check. */ return strncmp(exit->platform, "Tor 0.0.7", 9) ? 1 : 0; } addr = client_dns_lookup_entry(conn->socks_request->address); return router_compare_addr_to_exit_policy(addr, conn->socks_request->port, exit->exit_policy); Loading src/or/dns.c +54 −5 Changes for src/or/dns.c: 54 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -71,6 +71,7 @@ static void dns_found_answer(char *address, uint32_t addr, char outcome); static int dnsworker_main(void *data); static int spawn_dnsworker(void); static void spawn_enough_dnsworkers(void); static void send_resolved_cell(connection_t *conn, uint8_t answer_type); /** Splay tree of cached_resolve objects. */ static SPLAY_HEAD(cache_tree, cached_resolve) cache_root; Loading Loading @@ -141,6 +142,34 @@ static void purge_expired_resolves(uint32_t now) { } } static void send_resolved_cell(connection_t *conn, uint8_t answer_type) { char buf[RELAY_PAYLOAD_SIZE]; int buflen; buf[0] = answer_type; switch (answer_type) { case RESOLVED_TYPE_IPV4: buf[1] = 4; set_uint32(buf+2, htonl(conn->addr)); buflen = 6; break; case RESOLVED_TYPE_ERROR_TRANSIENT: case RESOLVED_TYPE_ERROR: buf[1] = 24; /* length of "error resolving hostname" */ strcpy(buf+2, "error resolving hostname"); buflen = 26; break; default: tor_assert(0); } connection_edge_send_command(conn, circuit_get_by_conn(conn), RELAY_COMMAND_RESOLVED, buf, buflen, conn->cpath_layer); } /** See if we have a cache entry for <b>exitconn</b>-\>address. if so, * if resolve valid, put it into <b>exitconn</b>-\>addr and return 1. * If resolve failed, return -1. Loading Loading @@ -179,7 +208,8 @@ int dns_resolve(connection_t *exitconn) { switch(resolve->state) { case CACHE_STATE_PENDING: /* add us to the pending list */ pending_connection = tor_malloc(sizeof(struct pending_connection_t)); pending_connection = tor_malloc_zero( sizeof(struct pending_connection_t)); pending_connection->conn = exitconn; pending_connection->next = resolve->pending_connections; resolve->pending_connections = pending_connection; Loading @@ -191,8 +221,12 @@ int dns_resolve(connection_t *exitconn) { exitconn->addr = resolve->addr; log_fn(LOG_DEBUG,"Connection (fd %d) found cached answer for '%s'", exitconn->s, exitconn->address); if (exitconn->purpose == EXIT_PURPOSE_RESOLVE) send_resolved_cell(exitconn, RESOLVED_TYPE_IPV4); return 1; case CACHE_STATE_FAILED: if (exitconn->purpose == EXIT_PURPOSE_RESOLVE) send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR); return -1; } tor_assert(0); Loading @@ -205,7 +239,7 @@ int dns_resolve(connection_t *exitconn) { resolve->address[MAX_ADDRESSLEN-1] = 0; /* add us to the pending list */ pending_connection = tor_malloc(sizeof(struct pending_connection_t)); pending_connection = tor_malloc_zero(sizeof(struct pending_connection_t)); pending_connection->conn = exitconn; pending_connection->next = NULL; resolve->pending_connections = pending_connection; Loading Loading @@ -240,6 +274,7 @@ static int assign_to_dnsworker(connection_t *exitconn) { if(!dnsconn) { log_fn(LOG_WARN,"no idle dns workers. Failing."); dns_cancel_pending_resolve(exitconn->address); send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR_TRANSIENT); return -1; } Loading Loading @@ -453,21 +488,25 @@ static void dns_found_answer(char *address, uint32_t addr, char outcome) { pend = resolve->pending_connections; assert_connection_ok(pend->conn,time(NULL)); pend->conn->addr = resolve->addr; if(resolve->state == CACHE_STATE_FAILED) { pendconn = pend->conn; /* don't pass complex things to the connection_mark_for_close macro */ if(resolve->state == CACHE_STATE_FAILED) { /* prevent double-remove. */ pendconn->state = EXIT_CONN_STATE_RESOLVEFAILED; circuit_detach_stream(circuit_get_by_conn(pendconn), pendconn); if (pendconn->purpose == EXIT_PURPOSE_CONNECT) connection_edge_end(pendconn, END_STREAM_REASON_MISC, pendconn->cpath_layer); else send_resolved_cell(pendconn, RESOLVED_TYPE_ERROR); connection_free(pendconn); } else { if (pendconn->purpose == EXIT_PURPOSE_CONNECT) { /* prevent double-remove. */ pend->conn->state = EXIT_CONN_STATE_CONNECTING; circ = circuit_get_by_conn(pend->conn); assert(circ); tor_assert(circ); /* unlink pend->conn from resolving_streams, */ circuit_detach_stream(circ, pend->conn); /* and link it to n_streams */ Loading @@ -475,6 +514,16 @@ static void dns_found_answer(char *address, uint32_t addr, char outcome) { circ->n_streams = pend->conn; connection_exit_connect(pend->conn); } else { /* prevent double-remove. This isn't really an accurate state, * but it does the right thing. */ pendconn->state = EXIT_CONN_STATE_RESOLVEFAILED; send_resolved_cell(pendconn, RESOLVED_TYPE_IPV4); circ = circuit_get_by_conn(pendconn); tor_assert(circ); circuit_detach_stream(circ, pendconn); connection_free(pendconn); } } resolve->pending_connections = pend->next; tor_free(pend); Loading Loading
src/or/buffers.c +16 −5 Changes for src/or/buffers.c: 16 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -409,6 +409,9 @@ int fetch_from_buf_http(buf_t *buf, return 1; } #define SOCKS_COMMAND_CONNECT 0x01 #define SOCKS_COMMAND_RESOLVE 0xF0 /** There is a (possibly incomplete) socks handshake on <b>buf</b>, of one * of the forms * - socks4: "socksheader username\\0" Loading Loading @@ -467,8 +470,12 @@ int fetch_from_buf_socks(buf_t *buf, socks_request_t *req) { log_fn(LOG_DEBUG,"socks5: checking request"); if(buf->datalen < 8) /* basic info plus >=2 for addr plus 2 for port */ return 0; /* not yet */ if(*(buf->mem+1) != 1) { /* not a connect? we don't support it. */ log_fn(LOG_WARN,"socks5: command %d not '1'. Rejecting.",*(buf->mem+1)); req->command = (unsigned char) *(buf->mem+1); if(req->command != SOCKS_COMMAND_CONNECT && req->command != SOCKS_COMMAND_RESOLVE) { /* not a connect or resolve? we don't support it. */ log_fn(LOG_WARN,"socks5: command %d not recognized. Rejecting.", req->command); return -1; } switch(*(buf->mem+3)) { /* address type */ Loading Loading @@ -516,14 +523,18 @@ int fetch_from_buf_socks(buf_t *buf, socks_request_t *req) { if(buf->datalen < SOCKS4_NETWORK_LEN) /* basic info available? */ return 0; /* not yet */ if(*(buf->mem+1) != 1) { /* not a connect? we don't support it. */ log_fn(LOG_WARN,"socks4: command %d not '1'. Rejecting.",*(buf->mem+1)); req->command = (unsigned char) *(buf->mem+1); if(req->command != SOCKS_COMMAND_CONNECT && req->command != SOCKS_COMMAND_RESOLVE) { /* not a connect or resolve? we don't support it. */ log_fn(LOG_WARN,"socks4: command %d not recognized. Rejecting.", req->command); return -1; } req->port = ntohs(*(uint16_t*)(buf->mem+2)); destip = ntohl(*(uint32_t*)(buf->mem+4)); if(!req->port || !destip) { if((!req->port && req->command!=SOCKS_COMMAND_RESOLVE) || !destip) { log_fn(LOG_WARN,"socks4: Port or DestIP is zero. Rejecting."); return -1; } Loading
src/or/circuituse.c +16 −3 Changes for src/or/circuituse.c: 16 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -73,7 +73,14 @@ static int circuit_is_acceptable(circuit_t *circ, return 0; /* this circuit is screwed and doesn't know it yet */ } if(purpose == CIRCUIT_PURPOSE_C_GENERAL) { if (conn->socks_request && conn->socks_request->command == SOCKS_COMMAND_RESOLVE) { /* 0.0.7 servers and earlier don't support DNS resolution. There are no * ORs running code before 0.0.7, so we only worry about 0.0.7. Once all * servers are running 0.0.8, remove this check. */ if (!strncmp(exitrouter->platform, "Tor 0.0.7", 9)) return 0; } else if(purpose == CIRCUIT_PURPOSE_C_GENERAL) { if(connection_ap_can_use_exit(conn, exitrouter) == ADDR_POLICY_REJECTED) { /* can't exit from this router */ return 0; Loading Loading @@ -618,10 +625,12 @@ circuit_get_open_circ_or_launch(connection_t *conn, circuit_t **circp) { circuit_t *circ; uint32_t addr; int is_resolve; tor_assert(conn); tor_assert(circp); tor_assert(conn->state == AP_CONN_STATE_CIRCUIT_WAIT); is_resolve = conn->socks_request->command == SOCKS_COMMAND_RESOLVE; circ = circuit_get_best(conn, 1, desired_circuit_purpose); Loading @@ -630,7 +639,8 @@ circuit_get_open_circ_or_launch(connection_t *conn, return 1; /* we're happy */ } if(!connection_edge_is_rendezvous_stream(conn)) { /* general purpose circ */ /* Do we need to check exit policy? */ if(!is_resolve && !connection_edge_is_rendezvous_stream(conn)) { addr = client_dns_lookup_entry(conn->socks_request->address); if(router_exit_policy_all_routers_reject(addr, conn->socks_request->port)) { log_fn(LOG_WARN,"No Tor server exists that allows exit to %s:%d. Rejecting.", Loading Loading @@ -742,10 +752,13 @@ int connection_ap_handshake_attach_circuit(connection_t *conn) { circ->timestamp_dirty = time(NULL); link_apconn_to_circ(conn, circ); tor_assert(conn->socks_request); if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) connection_ap_handshake_send_begin(conn, circ); else connection_ap_handshake_send_resolve(conn, circ); return 1; } else { /* we're a rendezvous conn */ circuit_t *rendcirc=NULL, *introcirc=NULL; Loading
src/or/connection.c +4 −1 Changes for src/or/connection.c: 4 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -1276,7 +1276,10 @@ void assert_connection_ok(connection_t *conn, time_t now) } else { tor_assert(!conn->socks_request); } if(conn->type != CONN_TYPE_DIR) { if (conn->type == CONN_TYPE_EXIT) { tor_assert(conn->purpose == EXIT_PURPOSE_CONNECT || conn->purpose == EXIT_PURPOSE_RESOLVE); } else if(conn->type != CONN_TYPE_DIR) { tor_assert(!conn->purpose); /* only used for dir types currently */ } Loading
src/or/connection_edge.c +163 −0 Changes for src/or/connection_edge.c: 163 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -371,6 +371,23 @@ static int connection_ap_handshake_process_socks(connection_t *conn) { return sockshere; } /* else socks handshake is done, continue processing */ if (socks->command == SOCKS_COMMAND_RESOLVE) { /* Reply to resolves immediately if we can. */ if (strlen(socks->address) > RELAY_PAYLOAD_SIZE) { connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,0,NULL); conn->socks_request->has_finished = 1; connection_mark_for_close(conn); } uint32_t answer = htonl(client_dns_lookup_entry(socks->address)); if (answer) { connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_IPV4,4, (char*)&answer); conn->socks_request->has_finished = 1; connection_mark_for_close(conn); return 0; } } /* this call _modifies_ socks->address iff it's a hidden-service request */ if (rend_parse_rendezvous_address(socks->address) < 0) { /* normal request */ Loading Loading @@ -487,6 +504,46 @@ int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ) return 0; } /** Write a relay resolve cell, using destaddr and destport from ap_conn's * socks_request field, and send it down circ. * * If ap_conn is broken, mark it for close and return -1. Else return 0. */ int connection_ap_handshake_send_resolve(connection_t *ap_conn, circuit_t *circ) { int payload_len; const char *string_addr; tor_assert(ap_conn->type == CONN_TYPE_AP); tor_assert(ap_conn->state == AP_CONN_STATE_CIRCUIT_WAIT); tor_assert(ap_conn->socks_request); tor_assert(ap_conn->socks_request->command == SOCKS_COMMAND_RESOLVE); tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_GENERAL); ap_conn->stream_id = get_unique_stream_id_by_circ(circ); if (ap_conn->stream_id==0) { /* Don't send end: there is no 'other side' yet */ ap_conn->has_sent_end = 1; connection_mark_for_close(ap_conn); circuit_mark_for_close(circ); return -1; } string_addr = ap_conn->socks_request->address; payload_len = strlen(string_addr); tor_assert(strlen(string_addr) <= RELAY_PAYLOAD_SIZE); log_fn(LOG_DEBUG,"Sending relay cell to begin stream %d.",ap_conn->stream_id); if(connection_edge_send_command(ap_conn, circ, RELAY_COMMAND_RESOLVE, string_addr, payload_len, ap_conn->cpath_layer) < 0) return -1; /* circuit is closed, don't continue */ ap_conn->state = AP_CONN_STATE_RESOLVE_WAIT; log_fn(LOG_INFO,"Address sent for resolve, ap socket %d, n_circ_id %d",ap_conn->s,circ->n_circ_id); return 0; } /** Make an AP connection_t, do a socketpair and attach one side * to the conn, connection_add it, initialize it to circuit_wait, * and call connection_ap_handshake_attach_circuit(conn) on it. Loading Loading @@ -544,6 +601,59 @@ int connection_ap_make_bridge(char *address, uint16_t port) { return fd[1]; } void connection_ap_handshake_socks_resolved(connection_t *conn, int answer_type, int answer_len, const char *answer) { char buf[256]; int replylen; if (answer_type == RESOLVED_TYPE_IPV4) { uint32_t a = get_uint32(answer); client_dns_set_entry(conn->socks_request->address, ntohl(a)); } if (conn->socks_request->socks_version == 4) { buf[0] = 0x00; /* version */ if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) { buf[1] = 90; /* "Granted" */ set_uint16(buf+2, 0); memcpy(buf+4, answer, 4); /* address */ replylen = SOCKS4_NETWORK_LEN; } else { buf[1] = 91; /* "error" */ memset(buf+2, 0, 6); replylen = SOCKS4_NETWORK_LEN; } } else { /* SOCKS5 */ buf[0] = 0x05; /* version */ if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) { buf[1] = 0; /* succeeded */ buf[2] = 0; /* reserved */ buf[3] = 0x01; /* IPv4 address type */ memcpy(buf+4, answer, 4); /* address */ set_uint16(buf+8, 0); /* port == 0. */ replylen = 10; } else if (answer_type == RESOLVED_TYPE_IPV6 && answer_len == 16) { buf[1] = 0; /* succeeded */ buf[2] = 0; /* reserved */ buf[3] = 0x04; /* IPv6 address type */ memcpy(buf+4, answer, 16); /* address */ set_uint16(buf+20, 0); /* port == 0. */ replylen = 22; } else { buf[1] = 0x04; /* host unreachable */ memset(buf+2, 0, 8); replylen = 10; } } connection_ap_handshake_socks_reply(conn, buf, replylen, answer_type == RESOLVED_TYPE_IPV4 || answer_type == RESOLVED_TYPE_IPV6); } /** Send a socks reply to stream <b>conn</b>, using the appropriate * socks version, etc. * Loading Loading @@ -631,6 +741,7 @@ int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) { log_fn(LOG_DEBUG,"Creating new exit connection."); n_stream = connection_new(CONN_TYPE_EXIT); n_stream->purpose = EXIT_PURPOSE_CONNECT; n_stream->stream_id = rh.stream_id; n_stream->port = atoi(colon+1); Loading Loading @@ -694,6 +805,52 @@ int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) { return 0; } /** * Called when we receive a RELAY_RESOLVE cell 'cell' along the circuit 'circ'; * begin resolving the hostname, and (eventually) reply with a RESOLVED cell. */ int connection_exit_begin_resolve(cell_t *cell, circuit_t *circ) { connection_t *dummy_conn; relay_header_t rh; assert_circuit_ok(circ); relay_header_unpack(&rh, cell->payload); /* This 'dummy_conn' only exists to remember the stream ID * associated with the resolve request; and to make the * implementation of dns.c more uniform. (We really only need to * remember the circuit, the stream ID, and the hostname to be * resolved; but if we didn't store them in a connection like this, * the housekeeping in dns.c would get way more complicated.) */ dummy_conn = connection_new(CONN_TYPE_EXIT); dummy_conn->stream_id = rh.stream_id; dummy_conn->address = tor_strndup(cell->payload+RELAY_HEADER_SIZE, rh.length); dummy_conn->port = 0; dummy_conn->state = EXIT_CONN_STATE_RESOLVEFAILED; dummy_conn->purpose = EXIT_PURPOSE_RESOLVE; /* send it off to the gethostbyname farm */ switch(dns_resolve(dummy_conn)) { case 1: /* resolve worked; resolved cell was sent. */ connection_free(dummy_conn); return 0; case -1: /* resolve failed; resolved cell was sent. */ log_fn(LOG_INFO,"Resolve failed (%s).",dummy_conn->address); connection_free(dummy_conn); break; case 0: /* resolve added to pending list */ /* add it into the linked list of resolving_streams on this circuit */ dummy_conn->next_stream = circ->resolving_streams; circ->resolving_streams = dummy_conn; assert_circuit_ok(circ); ; } return 0; } /** Connect to conn's specified addr and port. If it worked, conn * has now been added to the connection_array. * Loading Loading @@ -776,6 +933,12 @@ int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit) log_fn(LOG_DEBUG,"considering nickname %s, for address %s / port %d:", exit->nickname, conn->socks_request->address, conn->socks_request->port); if (conn->socks_request->command == SOCKS_COMMAND_RESOLVE) { /* 0.0.7 servers and earlier don't support DNS resolution. There are no * ORs running code before 0.0.7, so we only worry about 0.0.7. Once all * servers are running 0.0.8, remove this check. */ return strncmp(exit->platform, "Tor 0.0.7", 9) ? 1 : 0; } addr = client_dns_lookup_entry(conn->socks_request->address); return router_compare_addr_to_exit_policy(addr, conn->socks_request->port, exit->exit_policy); Loading
src/or/dns.c +54 −5 Changes for src/or/dns.c: 54 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -71,6 +71,7 @@ static void dns_found_answer(char *address, uint32_t addr, char outcome); static int dnsworker_main(void *data); static int spawn_dnsworker(void); static void spawn_enough_dnsworkers(void); static void send_resolved_cell(connection_t *conn, uint8_t answer_type); /** Splay tree of cached_resolve objects. */ static SPLAY_HEAD(cache_tree, cached_resolve) cache_root; Loading Loading @@ -141,6 +142,34 @@ static void purge_expired_resolves(uint32_t now) { } } static void send_resolved_cell(connection_t *conn, uint8_t answer_type) { char buf[RELAY_PAYLOAD_SIZE]; int buflen; buf[0] = answer_type; switch (answer_type) { case RESOLVED_TYPE_IPV4: buf[1] = 4; set_uint32(buf+2, htonl(conn->addr)); buflen = 6; break; case RESOLVED_TYPE_ERROR_TRANSIENT: case RESOLVED_TYPE_ERROR: buf[1] = 24; /* length of "error resolving hostname" */ strcpy(buf+2, "error resolving hostname"); buflen = 26; break; default: tor_assert(0); } connection_edge_send_command(conn, circuit_get_by_conn(conn), RELAY_COMMAND_RESOLVED, buf, buflen, conn->cpath_layer); } /** See if we have a cache entry for <b>exitconn</b>-\>address. if so, * if resolve valid, put it into <b>exitconn</b>-\>addr and return 1. * If resolve failed, return -1. Loading Loading @@ -179,7 +208,8 @@ int dns_resolve(connection_t *exitconn) { switch(resolve->state) { case CACHE_STATE_PENDING: /* add us to the pending list */ pending_connection = tor_malloc(sizeof(struct pending_connection_t)); pending_connection = tor_malloc_zero( sizeof(struct pending_connection_t)); pending_connection->conn = exitconn; pending_connection->next = resolve->pending_connections; resolve->pending_connections = pending_connection; Loading @@ -191,8 +221,12 @@ int dns_resolve(connection_t *exitconn) { exitconn->addr = resolve->addr; log_fn(LOG_DEBUG,"Connection (fd %d) found cached answer for '%s'", exitconn->s, exitconn->address); if (exitconn->purpose == EXIT_PURPOSE_RESOLVE) send_resolved_cell(exitconn, RESOLVED_TYPE_IPV4); return 1; case CACHE_STATE_FAILED: if (exitconn->purpose == EXIT_PURPOSE_RESOLVE) send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR); return -1; } tor_assert(0); Loading @@ -205,7 +239,7 @@ int dns_resolve(connection_t *exitconn) { resolve->address[MAX_ADDRESSLEN-1] = 0; /* add us to the pending list */ pending_connection = tor_malloc(sizeof(struct pending_connection_t)); pending_connection = tor_malloc_zero(sizeof(struct pending_connection_t)); pending_connection->conn = exitconn; pending_connection->next = NULL; resolve->pending_connections = pending_connection; Loading Loading @@ -240,6 +274,7 @@ static int assign_to_dnsworker(connection_t *exitconn) { if(!dnsconn) { log_fn(LOG_WARN,"no idle dns workers. Failing."); dns_cancel_pending_resolve(exitconn->address); send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR_TRANSIENT); return -1; } Loading Loading @@ -453,21 +488,25 @@ static void dns_found_answer(char *address, uint32_t addr, char outcome) { pend = resolve->pending_connections; assert_connection_ok(pend->conn,time(NULL)); pend->conn->addr = resolve->addr; if(resolve->state == CACHE_STATE_FAILED) { pendconn = pend->conn; /* don't pass complex things to the connection_mark_for_close macro */ if(resolve->state == CACHE_STATE_FAILED) { /* prevent double-remove. */ pendconn->state = EXIT_CONN_STATE_RESOLVEFAILED; circuit_detach_stream(circuit_get_by_conn(pendconn), pendconn); if (pendconn->purpose == EXIT_PURPOSE_CONNECT) connection_edge_end(pendconn, END_STREAM_REASON_MISC, pendconn->cpath_layer); else send_resolved_cell(pendconn, RESOLVED_TYPE_ERROR); connection_free(pendconn); } else { if (pendconn->purpose == EXIT_PURPOSE_CONNECT) { /* prevent double-remove. */ pend->conn->state = EXIT_CONN_STATE_CONNECTING; circ = circuit_get_by_conn(pend->conn); assert(circ); tor_assert(circ); /* unlink pend->conn from resolving_streams, */ circuit_detach_stream(circ, pend->conn); /* and link it to n_streams */ Loading @@ -475,6 +514,16 @@ static void dns_found_answer(char *address, uint32_t addr, char outcome) { circ->n_streams = pend->conn; connection_exit_connect(pend->conn); } else { /* prevent double-remove. This isn't really an accurate state, * but it does the right thing. */ pendconn->state = EXIT_CONN_STATE_RESOLVEFAILED; send_resolved_cell(pendconn, RESOLVED_TYPE_IPV4); circ = circuit_get_by_conn(pendconn); tor_assert(circ); circuit_detach_stream(circ, pendconn); connection_free(pendconn); } } resolve->pending_connections = pend->next; tor_free(pend); Loading