diff options
Diffstat (limited to 'src/or/connection_edge.c')
-rw-r--r-- | src/or/connection_edge.c | 61 |
1 files changed, 48 insertions, 13 deletions
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 9859cc26ea..d8f397bd90 100644 --- a/src/or/connection_edge.c +++ b/src/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-2014, The Tor Project, Inc. */ + * Copyright (c) 2007-2015, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -46,6 +46,19 @@ #ifdef HAVE_LINUX_NETFILTER_IPV4_H #include <linux/netfilter_ipv4.h> #define TRANS_NETFILTER +#define TRANS_NETFILTER_IPV4 +#endif + +#ifdef HAVE_LINUX_IF_H +#include <linux/if.h> +#endif + +#ifdef HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H +#include <linux/netfilter_ipv6/ip6_tables.h> +#if defined(IP6T_SO_ORIGINAL_DST) +#define TRANS_NETFILTER +#define TRANS_NETFILTER_IPV6 +#endif #endif #if defined(HAVE_NET_IF_H) && defined(HAVE_NET_PFVAR_H) @@ -745,14 +758,6 @@ connection_ap_fail_onehop(const char *failed_digest, tor_addr_t addr; if (!build_state || !build_state->chosen_exit || !entry_conn->socks_request) { - /* clang thinks that an array midway through a structure - * will never have a NULL address, under either: - * -Wpointer-bool-conversion if using !, or - * -Wtautological-pointer-compare if using == or != - * It's probably right (unless pointers overflow and wrap), - * so we just skip this check - || !entry_conn->socks_request->address - */ continue; } if (tor_addr_parse(&addr, entry_conn->socks_request->address)<0 || @@ -1409,10 +1414,29 @@ destination_from_socket(entry_connection_t *conn, socks_request_t *req) struct sockaddr_storage orig_dst; socklen_t orig_dst_len = sizeof(orig_dst); tor_addr_t addr; + int rv; #ifdef TRANS_NETFILTER - if (getsockopt(ENTRY_TO_CONN(conn)->s, SOL_IP, SO_ORIGINAL_DST, - (struct sockaddr*)&orig_dst, &orig_dst_len) < 0) { + switch (ENTRY_TO_CONN(conn)->socket_family) { +#ifdef TRANS_NETFILTER_IPV4 + case AF_INET: + rv = getsockopt(ENTRY_TO_CONN(conn)->s, SOL_IP, SO_ORIGINAL_DST, + (struct sockaddr*)&orig_dst, &orig_dst_len); + break; +#endif +#ifdef TRANS_NETFILTER_IPV6 + case AF_INET6: + rv = getsockopt(ENTRY_TO_CONN(conn)->s, SOL_IPV6, IP6T_SO_ORIGINAL_DST, + (struct sockaddr*)&orig_dst, &orig_dst_len); + break; +#endif + default: + log_warn(LD_BUG, + "Received transparent data from an unsuported socket family %d", + ENTRY_TO_CONN(conn)->socket_family); + return -1; + } + if (rv < 0) { int e = tor_socket_errno(ENTRY_TO_CONN(conn)->s); log_warn(LD_NET, "getsockopt() failed: %s", tor_socket_strerror(e)); return -1; @@ -2589,12 +2613,23 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) if (rend_service_set_connection_addr_port(n_stream, origin_circ) < 0) { log_info(LD_REND,"Didn't find rendezvous service (port %d)", n_stream->base_.port); + /* 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, + * return DONE and kill the circuit. That way, a user (malicious or + * not) needs one circuit per bad port unless it matches the policy of + * the hidden service. */ relay_send_end_cell_from_edge(rh.stream_id, circ, - END_STREAM_REASON_EXITPOLICY, + END_STREAM_REASON_DONE, origin_circ->cpath->prev); connection_free(TO_CONN(n_stream)); tor_free(address); - return 0; + + /* Drop the circuit here since it might be someone deliberately + * scanning the hidden service ports. Note that this mitigates port + * scanning by adding more work on the attacker side to successfully + * scan but does not fully solve it. */ + return END_CIRC_AT_ORIGIN; } assert_circuit_ok(circ); log_debug(LD_REND,"Finished assigning addr/port"); |