From 411ec3c0f8cd4786233a3bc274cb2b766d4bfe7c Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 25 Jan 2011 20:39:44 -0500 Subject: Add client code to detect attempts to connect to 127.0.0.1 etc We detect and reject said attempts if there is no chosen exit node or circuit: connecting to a private addr via a randomly chosen exit node will usually fail (if all exits reject private addresses), is always ill-defined (you're not asking for any particular host or service), and usually an error (you've configured all requests to go over Tor when you really wanted to configure all _remote_ requests to go over Tor). This can also help detect forwarding loop requests. Found as part of bug2279. --- changes/bug2279 | 8 ++++++++ doc/spec/control-spec.txt | 6 +++++- src/or/connection.c | 2 ++ src/or/connection_edge.c | 21 +++++++++++++++++++++ src/or/or.h | 7 +++++++ src/or/reasons.c | 5 +++++ 6 files changed, 48 insertions(+), 1 deletion(-) diff --git a/changes/bug2279 b/changes/bug2279 index b796cda76..e0c23b360 100644 --- a/changes/bug2279 +++ b/changes/bug2279 @@ -3,3 +3,11 @@ transparent proxy connection. Fixes bug 2279. Bugfix on Tor 0.1.2.1 alpha. + o Minor features + - Detect attempts at the client side to open connections to private + IP addresses (like 127.0.0.1, 10.0.0.1, and so on) with a randomly + chosen exit node. Attempts to do so are always ill-defined, generally + prevented by exit policies, and usually in error. This will also + help to detect loops in transparent proxy configurations. + + diff --git a/doc/spec/control-spec.txt b/doc/spec/control-spec.txt index 255adf00a..109624557 100644 --- a/doc/spec/control-spec.txt +++ b/doc/spec/control-spec.txt @@ -1070,7 +1070,8 @@ Reason = "MISC" / "RESOLVEFAILED" / "CONNECTREFUSED" / "EXITPOLICY" / "DESTROY" / "DONE" / "TIMEOUT" / "NOROUTE" / "HIBERNATING" / "INTERNAL"/ "RESOURCELIMIT" / - "CONNRESET" / "TORPROTOCOL" / "NOTDIRECTORY" / "END" + "CONNRESET" / "TORPROTOCOL" / "NOTDIRECTORY" / "END" / + "PRIVATE_ADDR" The "REASON" field is provided only for FAILED, CLOSED, and DETACHED events, and only if extended events are enabled (see 3.19). Clients MUST @@ -1079,7 +1080,10 @@ END (We received a RELAY_END cell from the other side of this stream.) + PRIVATE_ADDR (The client tried to connect to a private address like + 127.0.0.1 or 10.0.0.1 over Tor.) [XXXX document more. -NM] + The "REMOTE_REASON" field is provided only when we receive a RELAY_END cell, and only if extended events are enabled. It contains the actual diff --git a/src/or/connection.c b/src/or/connection.c index 55a9557ef..fd30ac8cb 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -1205,9 +1205,11 @@ connection_init_accepted_conn(connection_t *conn, uint8_t listener_type) conn->state = AP_CONN_STATE_SOCKS_WAIT; break; case CONN_TYPE_AP_TRANS_LISTENER: + TO_EDGE_CONN(conn)->is_transparent_ap = 1; conn->state = AP_CONN_STATE_CIRCUIT_WAIT; return connection_ap_process_transparent(TO_EDGE_CONN(conn)); case CONN_TYPE_AP_NATD_LISTENER: + TO_EDGE_CONN(conn)->is_transparent_ap = 1; conn->state = AP_CONN_STATE_NATD_WAIT; break; } diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 73ed9fb5c..a85943f69 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -1659,6 +1659,27 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn, connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); return -1; } + if (!conn->use_begindir && !conn->chosen_exit_name && !circ) { + tor_addr_t addr; + if (tor_addr_from_str(&addr, socks->address) >= 0 && + tor_addr_is_internal(&addr, 0)) { + /* If this is an explicit private address with no chosen exit node, + * then we really don't want to try to connect to it. That's + * probably an error. */ + if (conn->is_transparent_ap) { + log_warn(LD_NET, + "Rejecting request for anonymous connection to private " + "address %s on a TransPort or NatdPort. Possible loop " + "in your NAT rules?", safe_str_client(socks->address)); + } else { + log_warn(LD_NET, + "Rejecting SOCKS request for anonymous connection to " + "private address %s", safe_str_client(socks->address)); + } + connection_mark_unattached_ap(conn, END_STREAM_REASON_PRIVATE_ADDR); + return -1; + } + } if (!conn->use_begindir && !conn->chosen_exit_name && !circ) { /* see if we can find a suitable enclave exit */ diff --git a/src/or/or.h b/src/or/or.h index 22c8498b6..a3ec71a92 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -583,6 +583,9 @@ typedef enum { /** This is a connection on the NATD port, and the destination IP:Port was * either ill-formed or out-of-range. */ #define END_STREAM_REASON_INVALID_NATD_DEST 261 +/** The target address is in a private network (like 127.0.0.1 or 10.0.0.1); + * you don't want to do that over a randomly chosen exit */ +#define END_STREAM_REASON_PRIVATE_ADDR 262 /** Bitwise-and this value with endreason to mask out all flags. */ #define END_STREAM_REASON_MASK 511 @@ -1170,6 +1173,10 @@ typedef struct edge_connection_t { * zero, abandon the associated mapaddress. */ unsigned int chosen_exit_retries:3; + /** True iff this is an AP connection that came from a transparent or + * NATd connection */ + unsigned int is_transparent_ap:1; + /** If this is a DNSPort connection, this field holds the pending DNS * request that we're going to try to answer. */ struct evdns_server_request *dns_server_request; diff --git a/src/or/reasons.c b/src/or/reasons.c index 140155222..304ea9fcf 100644 --- a/src/or/reasons.c +++ b/src/or/reasons.c @@ -40,6 +40,8 @@ stream_end_reason_to_control_string(int reason) case END_STREAM_REASON_NET_UNREACHABLE: return "NET_UNREACHABLE"; case END_STREAM_REASON_SOCKSPROTOCOL: return "SOCKS_PROTOCOL"; + case END_STREAM_REASON_PRIVATE_ADDR: return "PRIVATE_ADDR"; + default: return NULL; } } @@ -125,6 +127,9 @@ stream_end_reason_to_socks5_response(int reason) return SOCKS5_NET_UNREACHABLE; case END_STREAM_REASON_SOCKSPROTOCOL: return SOCKS5_GENERAL_ERROR; + case END_STREAM_REASON_PRIVATE_ADDR: + return SOCKS5_GENERAL_ERROR; + default: log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Reason for ending (%d) not recognized; " -- cgit v1.2.3