diff options
Diffstat (limited to 'src/core/or/connection_edge.c')
-rw-r--r-- | src/core/or/connection_edge.c | 412 |
1 files changed, 298 insertions, 114 deletions
diff --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c index 84b80313ce..a33c64fe19 100644 --- a/src/core/or/connection_edge.c +++ b/src/core/or/connection_edge.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -19,7 +19,7 @@ * TCP application socket that has arrived via (e.g.) a SOCKS request, or an * exit connection. * - * Not every instance of edge_connection_t truly represents an edge connction, + * Not every instance of edge_connection_t truly represents an edge connection, * however. (Sorry!) We also create edge_connection_t objects for streams that * we will not be handling with TCP. The types of these streams are: * <ul> @@ -62,21 +62,25 @@ #include "app/config/config.h" #include "core/mainloop/connection.h" #include "core/mainloop/mainloop.h" +#include "core/mainloop/netstatus.h" #include "core/or/channel.h" #include "core/or/circuitbuild.h" #include "core/or/circuitlist.h" #include "core/or/circuituse.h" +#include "core/or/circuitpadding.h" #include "core/or/connection_edge.h" #include "core/or/connection_or.h" +#include "core/or/extendinfo.h" #include "core/or/policies.h" #include "core/or/reasons.h" #include "core/or/relay.h" +#include "core/or/sendme.h" #include "core/proto/proto_http.h" #include "core/proto/proto_socks.h" #include "feature/client/addressmap.h" #include "feature/client/circpathbias.h" #include "feature/client/dnsserv.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/dircache/dirserv.h" #include "feature/dircommon/directory.h" #include "feature/hibernate/hibernate.h" @@ -97,7 +101,7 @@ #include "feature/rend/rendservice.h" #include "feature/stats/predict_ports.h" #include "feature/stats/rephist.h" -#include "lib/container/buffers.h" +#include "lib/buf/buffers.h" #include "lib/crypt_ops/crypto_util.h" #include "core/or/cell_st.h" @@ -162,8 +166,12 @@ static int connection_exit_connect_dir(edge_connection_t *exitconn); static int consider_plaintext_ports(entry_connection_t *conn, uint16_t port); static int connection_ap_supports_optimistic_data(const entry_connection_t *); -/** Convert a connection_t* to an edge_connection_t*; assert if the cast is - * invalid. */ +/** + * Cast a `connection_t *` to an `edge_connection_t *`. + * + * Exit with an assertion failure if the input is not an + * `edge_connection_t`. + **/ edge_connection_t * TO_EDGE_CONN(connection_t *c) { @@ -172,6 +180,24 @@ TO_EDGE_CONN(connection_t *c) return DOWNCAST(edge_connection_t, c); } +/** + * Cast a `const connection_t *` to a `const edge_connection_t *`. + * + * Exit with an assertion failure if the input is not an + * `edge_connection_t`. + **/ +const edge_connection_t * +CONST_TO_EDGE_CONN(const connection_t *c) +{ + return TO_EDGE_CONN((connection_t *)c); +} + +/** + * Cast a `connection_t *` to an `entry_connection_t *`. + * + * Exit with an assertion failure if the input is not an + * `entry_connection_t`. + **/ entry_connection_t * TO_ENTRY_CONN(connection_t *c) { @@ -179,6 +205,24 @@ TO_ENTRY_CONN(connection_t *c) return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_.base_); } +/** + * Cast a `const connection_t *` to a `const entry_connection_t *`. + * + * Exit with an assertion failure if the input is not an + * `entry_connection_t`. + **/ +const entry_connection_t * +CONST_TO_ENTRY_CONN(const connection_t *c) +{ + return TO_ENTRY_CONN((connection_t*) c); +} + +/** + * Cast an `edge_connection_t *` to an `entry_connection_t *`. + * + * Exit with an assertion failure if the input is not an + * `entry_connection_t`. + **/ entry_connection_t * EDGE_TO_ENTRY_CONN(edge_connection_t *c) { @@ -186,6 +230,18 @@ EDGE_TO_ENTRY_CONN(edge_connection_t *c) return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_); } +/** + * Cast a `const edge_connection_t *` to a `const entry_connection_t *`. + * + * Exit with an assertion failure if the input is not an + * `entry_connection_t`. + **/ +const entry_connection_t * +CONST_EDGE_TO_ENTRY_CONN(const edge_connection_t *c) +{ + return EDGE_TO_ENTRY_CONN((edge_connection_t*)c); +} + /** An AP stream has failed/finished. If it hasn't already sent back * a socks reply, send one now (based on endreason). Also set * has_sent_end to 1, and mark the conn. @@ -300,6 +356,11 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial) } return 0; case AP_CONN_STATE_OPEN: + if (! conn->base_.linked) { + note_user_activity(approx_time()); + } + + FALLTHROUGH; case EXIT_CONN_STATE_OPEN: if (connection_edge_package_raw_inbuf(conn, package_partial, NULL) < 0) { /* (We already sent an end cell if possible) */ @@ -415,15 +476,28 @@ warn_if_hs_unreachable(const edge_connection_t *conn, uint8_t reason) char *m; if ((m = rate_limit_log(&warn_limit, approx_time()))) { log_warn(LD_EDGE, "Onion service connection to %s failed (%s)", - (conn->base_.socket_family == AF_UNIX) ? - safe_str(conn->base_.address) : - safe_str(fmt_addrport(&conn->base_.addr, conn->base_.port)), + connection_describe_peer(TO_CONN(conn)), stream_end_reason_to_string(reason)); tor_free(m); } } } +/** Given a TTL (in seconds) from a DNS response or from a relay, determine + * what TTL clients and relays should actually use for caching it. */ +uint32_t +clip_dns_ttl(uint32_t ttl) +{ + /* This logic is a defense against "DefectTor" DNS-based traffic + * confirmation attacks, as in https://nymity.ch/tor-dns/tor-dns.pdf . + * We only give two values: a "low" value and a "high" value. + */ + if (ttl < MIN_DNS_TTL) + return MIN_DNS_TTL; + else + return MAX_DNS_TTL; +} + /** Send a relay end cell from stream <b>conn</b> down conn's circuit, and * remember that we've done so. If this is not a client connection, set the * relay end cell's reason for closing as <b>reason</b>. @@ -472,7 +546,7 @@ connection_edge_end(edge_connection_t *conn, uint8_t reason) memcpy(payload+1, tor_addr_to_in6_addr8(&conn->base_.addr), 16); addrlen = 16; } - set_uint32(payload+1+addrlen, htonl(dns_clip_ttl(conn->address_ttl))); + set_uint32(payload+1+addrlen, htonl(clip_dns_ttl(conn->address_ttl))); payload_len += 4+addrlen; } @@ -504,8 +578,8 @@ connection_edge_end(edge_connection_t *conn, uint8_t reason) /** * Helper function for bsearch. * - * As per smartlist_bsearch, return < 0 if key preceeds member, - * > 0 if member preceeds key, and 0 if they are equal. + * As per smartlist_bsearch, return < 0 if key precedes member, + * > 0 if member precedes key, and 0 if they are equal. * * This is equivalent to subtraction of the values of key - member * (why does no one ever say that explicitly?). @@ -754,8 +828,13 @@ connection_edge_flushed_some(edge_connection_t *conn) { switch (conn->base_.state) { case AP_CONN_STATE_OPEN: + if (! conn->base_.linked) { + note_user_activity(approx_time()); + } + + FALLTHROUGH; case EXIT_CONN_STATE_OPEN: - connection_edge_consider_sending_sendme(conn); + sendme_connection_edge_consider_sending(conn); break; } return 0; @@ -779,7 +858,7 @@ connection_edge_finished_flushing(edge_connection_t *conn) switch (conn->base_.state) { case AP_CONN_STATE_OPEN: case EXIT_CONN_STATE_OPEN: - connection_edge_consider_sending_sendme(conn); + sendme_connection_edge_consider_sending(conn); return 0; case AP_CONN_STATE_SOCKS_WAIT: case AP_CONN_STATE_NATD_WAIT: @@ -832,7 +911,7 @@ connected_cell_format_payload(uint8_t *payload_out, return -1; } - set_uint32(payload_out + connected_payload_len, htonl(dns_clip_ttl(ttl))); + set_uint32(payload_out + connected_payload_len, htonl(clip_dns_ttl(ttl))); connected_payload_len += 4; tor_assert(connected_payload_len <= MAX_CONNECTED_CELL_PAYLOAD_LEN); @@ -893,9 +972,8 @@ connection_edge_finished_connecting(edge_connection_t *edge_conn) conn = TO_CONN(edge_conn); tor_assert(conn->state == EXIT_CONN_STATE_CONNECTING); - log_info(LD_EXIT,"Exit connection to %s:%u (%s) established.", - escaped_safe_str(conn->address), conn->port, - safe_str(fmt_and_decorate_addr(&conn->addr))); + log_info(LD_EXIT,"%s established.", + connection_describe(conn)); rep_hist_note_exit_stream_opened(conn->port); @@ -1127,6 +1205,7 @@ connection_ap_expire_beginning(void) } if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL && + circ->purpose != CIRCUIT_PURPOSE_CONTROLLER && circ->purpose != CIRCUIT_PURPOSE_C_HSDIR_GET && circ->purpose != CIRCUIT_PURPOSE_S_HSDIR_POST && circ->purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT && @@ -1211,7 +1290,7 @@ connection_ap_rescan_and_attach_pending(void) entry_conn->marked_pending_circ_line = 0; \ entry_conn->marked_pending_circ_file = 0; \ } while (0) -#else /* !(defined(DEBUGGING_17659)) */ +#else /* !defined(DEBUGGING_17659) */ #define UNMARK() do { } while (0) #endif /* defined(DEBUGGING_17659) */ @@ -1416,8 +1495,8 @@ connection_ap_fail_onehop(const char *failed_digest, continue; } if (tor_addr_parse(&addr, entry_conn->socks_request->address)<0 || - !tor_addr_eq(&build_state->chosen_exit->addr, &addr) || - build_state->chosen_exit->port != entry_conn->socks_request->port) + !extend_info_has_orport(build_state->chosen_exit, &addr, + entry_conn->socks_request->port)) continue; } log_info(LD_APP, "Closing one-hop stream to '%s/%s' because the OR conn " @@ -1475,6 +1554,16 @@ circuit_discard_optional_exit_enclaves(extend_info_t *info) } SMARTLIST_FOREACH_END(conn); } +/** Set the connection state to CONTROLLER_WAIT and send an control port event. + */ +void +connection_entry_set_controller_wait(entry_connection_t *conn) +{ + CONNECTION_AP_EXPECT_NONPENDING(conn); + ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_CONTROLLER_WAIT; + control_event_stream_status(conn, STREAM_EVENT_CONTROLLER_WAIT, 0); +} + /** The AP connection <b>conn</b> has just failed while attaching or * sending a BEGIN or resolving on <b>circ</b>, but another circuit * might work. Detach the circuit, and either reattach it, launch a @@ -1506,8 +1595,7 @@ connection_ap_detach_retriable(entry_connection_t *conn, circuit_detach_stream(TO_CIRCUIT(circ),ENTRY_TO_EDGE_CONN(conn)); connection_ap_mark_as_pending_circuit(conn); } else { - CONNECTION_AP_EXPECT_NONPENDING(conn); - ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_CONTROLLER_WAIT; + connection_entry_set_controller_wait(conn); circuit_detach_stream(TO_CIRCUIT(circ),ENTRY_TO_EDGE_CONN(conn)); } return 0; @@ -1540,6 +1628,107 @@ consider_plaintext_ports(entry_connection_t *conn, uint16_t port) return 0; } +/** Parse the given hostname in address. Returns true if the parsing was + * successful and type_out contains the type of the hostname. Else, false is + * returned which means it was not recognized and type_out is set to + * BAD_HOSTNAME. + * + * The possible recognized forms are (where true is returned): + * + * If address is of the form "y.onion" with a well-formed handle y: + * Put a NUL after y, lower-case it, and return ONION_V2_HOSTNAME or + * ONION_V3_HOSTNAME depending on the HS version. + * + * If address is of the form "x.y.onion" with a well-formed handle x: + * Drop "x.", put a NUL after y, lower-case it, and return + * ONION_V2_HOSTNAME or ONION_V3_HOSTNAME depending on the HS version. + * + * If address is of the form "y.onion" with a badly-formed handle y: + * Return BAD_HOSTNAME and log a message. + * + * If address is of the form "y.exit": + * Put a NUL after y and return EXIT_HOSTNAME. + * + * Otherwise: + * Return NORMAL_HOSTNAME and change nothing. + */ +STATIC bool +parse_extended_hostname(char *address, hostname_type_t *type_out) +{ + char *s; + char *q; + char query[HS_SERVICE_ADDR_LEN_BASE32+1]; + + s = strrchr(address,'.'); + if (!s) { + *type_out = NORMAL_HOSTNAME; /* no dot, thus normal */ + goto success; + } + if (!strcmp(s+1,"exit")) { + *s = 0; /* NUL-terminate it */ + *type_out = EXIT_HOSTNAME; /* .exit */ + goto success; + } + if (strcmp(s+1,"onion")) { + *type_out = NORMAL_HOSTNAME; /* neither .exit nor .onion, thus normal */ + goto success; + } + + /* so it is .onion */ + *s = 0; /* NUL-terminate it */ + /* locate a 'sub-domain' component, in order to remove it */ + q = strrchr(address, '.'); + if (q == address) { + *type_out = BAD_HOSTNAME; + goto failed; /* reject sub-domain, as DNS does */ + } + q = (NULL == q) ? address : q + 1; + if (strlcpy(query, q, HS_SERVICE_ADDR_LEN_BASE32+1) >= + HS_SERVICE_ADDR_LEN_BASE32+1) { + *type_out = BAD_HOSTNAME; + goto failed; + } + if (q != address) { + memmove(address, q, strlen(q) + 1 /* also get \0 */); + } + /* v2 onion address check. */ + if (strlen(query) == REND_SERVICE_ID_LEN_BASE32) { + *type_out = ONION_V2_HOSTNAME; + if (rend_valid_v2_service_id(query)) { + goto success; + } + goto failed; + } + + /* v3 onion address check. */ + if (strlen(query) == HS_SERVICE_ADDR_LEN_BASE32) { + *type_out = ONION_V3_HOSTNAME; + if (hs_address_is_valid(query)) { + goto success; + } + goto failed; + } + + /* Reaching this point, nothing was recognized. */ + *type_out = BAD_HOSTNAME; + goto failed; + + success: + return true; + failed: + /* otherwise, return to previous state and return 0 */ + *s = '.'; + const bool is_onion = (*type_out == ONION_V2_HOSTNAME) || + (*type_out == ONION_V3_HOSTNAME); + log_warn(LD_APP, "Invalid %shostname %s; rejecting", + is_onion ? "onion " : "", + safe_str_client(address)); + if (*type_out == ONION_V3_HOSTNAME) { + *type_out = BAD_HOSTNAME; + } + return false; +} + /** How many times do we try connecting with an exit configured via * TrackHostExits before concluding that it won't work any more and trying a * different one? */ @@ -1559,8 +1748,7 @@ connection_ap_rewrite_and_attach_if_allowed,(entry_connection_t *conn, const or_options_t *options = get_options(); if (options->LeaveStreamsUnattached) { - CONNECTION_AP_EXPECT_NONPENDING(conn); - ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_CONTROLLER_WAIT; + connection_entry_set_controller_wait(conn); return 0; } return connection_ap_handshake_rewrite_and_attach(conn, circ, cpath); @@ -1878,7 +2066,7 @@ connection_ap_handle_onion(entry_connection_t *conn, log_info(LD_GENERAL, "Found %s descriptor in cache for %s. %s.", (descriptor_is_usable) ? "usable" : "unusable", safe_str_client(onion_address), - (descriptor_is_usable) ? "Not fetching." : "Refecting."); + (descriptor_is_usable) ? "Not fetching." : "Refetching."); } else { rend_cache_lookup_result = -ENOENT; } @@ -2007,16 +2195,15 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, const int automap = rr.automap; const addressmap_entry_source_t exit_source = rr.exit_source; - /* Now, we parse the address to see if it's an .onion or .exit or - * other special address. - */ - const hostname_type_t addresstype = parse_extended_hostname(socks->address); - /* Now see whether the hostname is bogus. This could happen because of an * onion hostname whose format we don't recognize. */ - if (addresstype == BAD_HOSTNAME) { + hostname_type_t addresstype; + if (!parse_extended_hostname(socks->address, &addresstype)) { control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s", escaped(socks->address)); + if (addresstype == BAD_HOSTNAME) { + conn->socks_request->socks_extended_error_code = SOCKS5_HS_BAD_ADDRESS; + } connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); return -1; } @@ -2468,8 +2655,8 @@ destination_from_socket(entry_connection_t *conn, socks_request_t *req) break; #endif /* defined(TRANS_NETFILTER_IPV6) */ default: - log_warn(LD_BUG, - "Received transparent data from an unsuported socket family %d", + log_warn(LD_BUG, "Received transparent data from an unsupported " + "socket family %d", ENTRY_TO_CONN(conn)->socket_family); return -1; } @@ -2803,6 +2990,31 @@ connection_ap_process_natd(entry_connection_t *conn) return connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL); } +static const char HTTP_CONNECT_IS_NOT_AN_HTTP_PROXY_MSG[] = + "HTTP/1.0 405 Method Not Allowed\r\n" + "Content-Type: text/html; charset=iso-8859-1\r\n\r\n" + "<html>\n" + "<head>\n" + "<title>This is an HTTP CONNECT tunnel, not a full HTTP Proxy</title>\n" + "</head>\n" + "<body>\n" + "<h1>This is an HTTP CONNECT tunnel, not an HTTP proxy.</h1>\n" + "<p>\n" + "It appears you have configured your web browser to use this Tor port as\n" + "an HTTP proxy.\n" + "</p><p>\n" + "This is not correct: This port is configured as a CONNECT tunnel, not\n" + "an HTTP proxy. Please configure your client accordingly. You can also\n" + "use HTTPS; then the client should automatically use HTTP CONNECT." + "</p>\n" + "<p>\n" + "See <a href=\"https://www.torproject.org/documentation.html\">" + "https://www.torproject.org/documentation.html</a> for more " + "information.\n" + "</p>\n" + "</body>\n" + "</html>\n"; + /** Called on an HTTP CONNECT entry connection when some bytes have arrived, * but we have not yet received a full HTTP CONNECT request. Try to parse an * HTTP CONNECT request from the connection's inbuf. On success, set up the @@ -2843,7 +3055,7 @@ connection_ap_process_http_connect(entry_connection_t *conn) tor_assert(command); tor_assert(addrport); if (strcasecmp(command, "connect")) { - errmsg = "HTTP/1.0 405 Method Not Allowed\r\n\r\n"; + errmsg = HTTP_CONNECT_IS_NOT_AN_HTTP_PROXY_MSG; goto err; } @@ -3055,7 +3267,8 @@ connection_ap_handshake_send_begin,(entry_connection_t *ap_conn)) edge_conn->begincell_flags = connection_ap_get_begincell_flags(ap_conn); tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:%d", - (circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL) ? + (circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL || + circ->base_.purpose == CIRCUIT_PURPOSE_CONTROLLER) ? ap_conn->socks_request->address : "", ap_conn->socks_request->port); payload_len = (int)strlen(payload)+1; @@ -3309,8 +3522,9 @@ tell_controller_about_resolved_result(entry_connection_t *conn, expires = time(NULL) + ttl; if (answer_type == RESOLVED_TYPE_IPV4 && answer_len >= 4) { char *cp = tor_dup_ip(ntohl(get_uint32(answer))); - control_event_address_mapped(conn->socks_request->address, - cp, expires, NULL, 0); + if (cp) + control_event_address_mapped(conn->socks_request->address, + cp, expires, NULL, 0); tor_free(cp); } else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256) { char *cp = tor_strndup(answer, answer_len); @@ -3383,7 +3597,7 @@ connection_ap_handshake_socks_resolved,(entry_connection_t *conn, } } else if (answer_type == RESOLVED_TYPE_IPV6 && answer_len == 16) { tor_addr_t a; - tor_addr_from_ipv6_bytes(&a, (char*)answer); + tor_addr_from_ipv6_bytes(&a, answer); if (! tor_addr_is_null(&a)) { client_dns_set_addressmap(conn, conn->socks_request->address, &a, @@ -3484,11 +3698,17 @@ connection_ap_handshake_socks_reply(entry_connection_t *conn, char *reply, size_t replylen, int endreason) { char buf[256]; - socks5_reply_status_t status = - stream_end_reason_to_socks5_response(endreason); + socks5_reply_status_t status; tor_assert(conn->socks_request); /* make sure it's an AP stream */ + if (conn->socks_request->socks_use_extended_errors && + conn->socks_request->socks_extended_error_code != 0) { + status = conn->socks_request->socks_extended_error_code; + } else { + status = stream_end_reason_to_socks5_response(endreason); + } + if (!SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command)) { control_event_stream_status(conn, status==SOCKS5_SUCCEEDED ? STREAM_EVENT_SUCCEEDED : STREAM_EVENT_FAILED, @@ -3679,8 +3899,8 @@ handle_hs_exit_conn(circuit_t *circ, edge_connection_t *conn) return -1; } if (ret < 0) { - log_info(LD_REND, "Didn't find rendezvous service (addr%s, port %d)", - fmt_addr(&TO_CONN(conn)->addr), TO_CONN(conn)->port); + log_info(LD_REND, "Didn't find rendezvous service at %s", + connection_describe_peer(TO_CONN(conn))); /* Send back reason DONE because we want to make hidden service port * scanning harder thus instead of returning that the exit policy * didn't match, which makes it obvious that the port is closed, @@ -3706,6 +3926,10 @@ handle_hs_exit_conn(circuit_t *circ, edge_connection_t *conn) /* Link the circuit and the connection crypt path. */ conn->cpath_layer = origin_circ->cpath->prev; + /* If this is the first stream on this circuit, tell circpad */ + if (!origin_circ->p_streams) + circpad_machine_event_circ_has_streams(origin_circ); + /* Add it into the linked list of p_streams on this circuit */ conn->next_stream = origin_circ->p_streams; origin_circ->p_streams = conn; @@ -3796,6 +4020,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) if (! bcell.is_begindir) { /* Steal reference */ + tor_assert(bcell.address); address = bcell.address; port = bcell.port; @@ -3810,7 +4035,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) * proxies. */ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Attempt by %s to open a stream %s. Closing.", - safe_str(channel_get_canonical_remote_descr(or_circ->p_chan)), + safe_str(channel_describe_peer(or_circ->p_chan)), client_chan ? "on first hop of circuit" : "from unknown relay"); relay_send_end_cell_from_edge(rh.stream_id, circ, @@ -3833,10 +4058,13 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) * caller might want to know whether the remote IP address has changed, * and we might already have corrected base_.addr[ess] for the relay's * canonical IP address. */ - if (or_circ && or_circ->p_chan) - address = tor_strdup(channel_get_actual_remote_address(or_circ->p_chan)); - else + tor_addr_t chan_addr; + if (or_circ && or_circ->p_chan && + channel_get_addr_if_possible(or_circ->p_chan, &chan_addr)) { + address = tor_addr_to_str_dup(&chan_addr); + } else { address = tor_strdup("127.0.0.1"); + } port = 1; /* XXXX This value is never actually used anywhere, and there * isn't "really" a connection here. But we * need to set it to something nonzero. */ @@ -4035,8 +4263,8 @@ connection_exit_connect(edge_connection_t *edge_conn) &why_failed_exit_policy)) { if (BUG(!why_failed_exit_policy)) why_failed_exit_policy = ""; - log_info(LD_EXIT,"%s:%d failed exit policy%s. Closing.", - escaped_safe_str_client(conn->address), conn->port, + log_info(LD_EXIT,"%s failed exit policy%s. Closing.", + connection_describe(conn), why_failed_exit_policy); connection_edge_end(edge_conn, END_STREAM_REASON_EXITPOLICY); circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn); @@ -4063,9 +4291,8 @@ connection_exit_connect(edge_connection_t *edge_conn) if (!connection_edge_is_rendezvous_stream(edge_conn) && !network_reentry_is_allowed() && nodelist_reentry_contains(&conn->addr, conn->port)) { - log_info(LD_EXIT, "%s:%d tried to connect back to a known relay address. " - "Closing.", escaped_safe_str_client(conn->address), - conn->port); + log_info(LD_EXIT, "%s tried to connect back to a known relay address. " + "Closing.", connection_describe(conn)); connection_edge_end(edge_conn, END_STREAM_REASON_CONNECTREFUSED); circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn); connection_free(conn); @@ -4300,68 +4527,6 @@ connection_ap_can_use_exit(const entry_connection_t *conn, return 1; } -/** If address is of the form "y.onion" with a well-formed handle y: - * Put a NUL after y, lower-case it, and return ONION_V2_HOSTNAME or - * ONION_V3_HOSTNAME depending on the HS version. - * - * If address is of the form "x.y.onion" with a well-formed handle x: - * Drop "x.", put a NUL after y, lower-case it, and return - * ONION_V2_HOSTNAME or ONION_V3_HOSTNAME depending on the HS version. - * - * If address is of the form "y.onion" with a badly-formed handle y: - * Return BAD_HOSTNAME and log a message. - * - * If address is of the form "y.exit": - * Put a NUL after y and return EXIT_HOSTNAME. - * - * Otherwise: - * Return NORMAL_HOSTNAME and change nothing. - */ -hostname_type_t -parse_extended_hostname(char *address) -{ - char *s; - char *q; - char query[HS_SERVICE_ADDR_LEN_BASE32+1]; - - s = strrchr(address,'.'); - if (!s) - return NORMAL_HOSTNAME; /* no dot, thus normal */ - if (!strcmp(s+1,"exit")) { - *s = 0; /* NUL-terminate it */ - return EXIT_HOSTNAME; /* .exit */ - } - if (strcmp(s+1,"onion")) - return NORMAL_HOSTNAME; /* neither .exit nor .onion, thus normal */ - - /* so it is .onion */ - *s = 0; /* NUL-terminate it */ - /* locate a 'sub-domain' component, in order to remove it */ - q = strrchr(address, '.'); - if (q == address) { - goto failed; /* reject sub-domain, as DNS does */ - } - q = (NULL == q) ? address : q + 1; - if (strlcpy(query, q, HS_SERVICE_ADDR_LEN_BASE32+1) >= - HS_SERVICE_ADDR_LEN_BASE32+1) - goto failed; - if (q != address) { - memmove(address, q, strlen(q) + 1 /* also get \0 */); - } - if (rend_valid_v2_service_id(query)) { - return ONION_V2_HOSTNAME; /* success */ - } - if (hs_address_is_valid(query)) { - return ONION_V3_HOSTNAME; - } - failed: - /* otherwise, return to previous state and return 0 */ - *s = '.'; - log_warn(LD_APP, "Invalid onion hostname %s; rejecting", - safe_str_client(address)); - return BAD_HOSTNAME; -} - /** Return true iff the (possibly NULL) <b>alen</b>-byte chunk of memory at * <b>a</b> is equal to the (possibly NULL) <b>blen</b>-byte chunk of memory * at <b>b</b>. */ @@ -4565,6 +4730,25 @@ circuit_clear_isolation(origin_circuit_t *circ) circ->socks_username_len = circ->socks_password_len = 0; } +/** Send an END and mark for close the given edge connection conn using the + * given reason that has to be a stream reason. + * + * Note: We don't unattached the AP connection (if applicable) because we + * don't want to flush the remaining data. This function aims at ending + * everything quickly regardless of the connection state. + * + * This function can't fail and does nothing if conn is NULL. */ +void +connection_edge_end_close(edge_connection_t *conn, uint8_t reason) +{ + if (!conn) { + return; + } + + connection_edge_end(conn, reason); + connection_mark_for_close(TO_CONN(conn)); +} + /** Free all storage held in module-scoped variables for connection_edge.c */ void connection_edge_free_all(void) |