diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/or/config.c | 20 | ||||
-rw-r--r-- | src/or/connection.c | 20 | ||||
-rw-r--r-- | src/or/connection_edge.c | 82 | ||||
-rw-r--r-- | src/or/or.h | 7 |
4 files changed, 114 insertions, 15 deletions
diff --git a/src/or/config.c b/src/or/config.c index b686b6606..a5407dd4e 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1095,7 +1095,8 @@ options_act_reversible(const or_options_t *old_options, char **msg) #if defined(HAVE_NET_IF_H) && defined(HAVE_NET_PFVAR_H) /* Open /dev/pf before dropping privileges. */ - if (options->TransPort_set) { + if (options->TransPort_set && + options->TransProxyType_parsed == TPT_DEFAULT) { if (get_pf_socket() < 0) { *msg = tor_strdup("Unable to open /dev/pf for transparent proxy."); goto rollback; @@ -1186,10 +1187,13 @@ options_act_reversible(const or_options_t *old_options, char **msg) SMARTLIST_FOREACH(replaced_listeners, connection_t *, conn, { + int marked = conn->marked_for_close; log_notice(LD_NET, "Closing old %s on %s:%d", conn_type_to_string(conn->type), conn->address, conn->port); connection_close_immediate(conn); - connection_mark_for_close(conn); + if (!marked) { + connection_mark_for_close(conn); + } }); goto done; @@ -2562,12 +2566,24 @@ options_validate(or_options_t *old_options, or_options_t *options, if (options->TransProxyType) { if (!strcasecmp(options->TransProxyType, "default")) { options->TransProxyType_parsed = TPT_DEFAULT; + } else if (!strcasecmp(options->TransProxyType, "pf-divert")) { +#ifndef __OpenBSD__ + REJECT("pf-divert is a OpenBSD-specific feature."); +#else + options->TransProxyType_parsed = TPT_PF_DIVERT; +#endif } else if (!strcasecmp(options->TransProxyType, "tproxy")) { #ifndef __linux__ REJECT("TPROXY is a Linux-specific feature."); #else options->TransProxyType_parsed = TPT_TPROXY; #endif + } else if (!strcasecmp(options->TransProxyType, "ipfw")) { +#ifndef __FreeBSD__ + REJECT("ipfw is a FreeBSD-specific feature."); +#else + options->TransProxyType_parsed = TPT_IPFW; +#endif } else { REJECT("Unrecognized value for TransProxyType"); } diff --git a/src/or/connection.c b/src/or/connection.c index 1be4c45dd..2e72e6b39 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -2359,6 +2359,20 @@ connection_mark_all_noncontrol_connections(void) connection_mark_unattached_ap(TO_ENTRY_CONN(conn), END_STREAM_REASON_HIBERNATING); break; + case CONN_TYPE_OR: + { + or_connection_t *orconn = TO_OR_CONN(conn); + if (orconn->chan) { + connection_or_close_normally(orconn, 0); + } else { + /* + * There should have been one, but mark for close and hope + * for the best.. + */ + connection_mark_for_close(conn); + } + } + break; default: connection_mark_for_close(conn); break; @@ -4009,6 +4023,12 @@ connection_write_to_buf_impl_,(const char *string, size_t len, "write_to_buf failed. Closing circuit (fd %d).", (int)conn->s); circuit_mark_for_close(circuit_get_by_edge_conn(TO_EDGE_CONN(conn)), END_CIRC_REASON_INTERNAL); + } else if (conn->type == CONN_TYPE_OR) { + or_connection_t *orconn = TO_OR_CONN(conn); + log_warn(LD_NET, + "write_to_buf failed on an orconn; notifying of error " + "(fd %d)", (int)(conn->s)); + connection_or_close_for_error(orconn, 0); } else { log_warn(LD_NET, "write_to_buf failed. Closing connection (fd %d).", diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 41ca6119b..a8ad9ec2e 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -1391,35 +1391,48 @@ get_pf_socket(void) } #endif -/** Fetch the original destination address and port from a - * system-specific interface and put them into a - * socks_request_t as if they came from a socks request. - * - * Return -1 if an error prevents fetching the destination, - * else return 0. - */ +#if defined(TRANS_NETFILTER) || defined(TRANS_PF) +/** Try fill in the address of <b>req</b> from the socket configured + * with <b>conn</b>. */ static int -connection_ap_get_original_destination(entry_connection_t *conn, - socks_request_t *req) +destination_from_socket(entry_connection_t *conn, socks_request_t *req) { -#ifdef TRANS_NETFILTER - /* Linux 2.4+ */ struct sockaddr_storage orig_dst; socklen_t orig_dst_len = sizeof(orig_dst); tor_addr_t addr; +#ifdef TRANS_NETFILTER if (getsockopt(ENTRY_TO_CONN(conn)->s, SOL_IP, SO_ORIGINAL_DST, (struct sockaddr*)&orig_dst, &orig_dst_len) < 0) { int e = tor_socket_errno(ENTRY_TO_CONN(conn)->s); log_warn(LD_NET, "getsockopt() failed: %s", tor_socket_strerror(e)); return -1; } +#elif defined(TRANS_PF) + if (getsockname(ENTRY_TO_CONN(conn)->s, (struct sockaddr*)&orig_dst, + &orig_dst_len) < 0) { + int e = tor_socket_errno(ENTRY_TO_CONN(conn)->s); + log_warn(LD_NET, "getsockname() failed: %s", tor_socket_strerror(e)); + return -1; + } +#else + (void)conn; + (void)req; + log_warn(LD_BUG, "Unable to determine destination from socket."); + return -1; +#endif tor_addr_from_sockaddr(&addr, (struct sockaddr*)&orig_dst, &req->port); tor_addr_to_str(req->address, &addr, sizeof(req->address), 1); return 0; -#elif defined(TRANS_PF) +} +#endif + +#ifdef TRANS_PF +static int +destination_from_pf(entry_connection_t *conn, socks_request_t *req) +{ struct sockaddr_storage proxy_addr; socklen_t proxy_addr_len = sizeof(proxy_addr); struct sockaddr *proxy_sa = (struct sockaddr*) &proxy_addr; @@ -1435,6 +1448,21 @@ connection_ap_get_original_destination(entry_connection_t *conn, return -1; } +#ifdef __FreeBSD__ + if (get_options()->TransProxyType_parsed == TPT_IPFW) { + /* ipfw(8) is used and in this case getsockname returned the original + destination */ + if (tor_addr_from_sockaddr(&addr, proxy_sa, &req->port) < 0) { + tor_fragile_assert(); + return -1; + } + + tor_addr_to_str(req->address, &addr, sizeof(req->address), 0); + + return 0; + } +#endif + memset(&pnl, 0, sizeof(pnl)); pnl.proto = IPPROTO_TCP; pnl.direction = PF_OUT; @@ -1481,6 +1509,36 @@ connection_ap_get_original_destination(entry_connection_t *conn, req->port = ntohs(pnl.rdport); return 0; +} +#endif + +/** Fetch the original destination address and port from a + * system-specific interface and put them into a + * socks_request_t as if they came from a socks request. + * + * Return -1 if an error prevents fetching the destination, + * else return 0. + */ +static int +connection_ap_get_original_destination(entry_connection_t *conn, + socks_request_t *req) +{ +#ifdef TRANS_NETFILTER + return destination_from_socket(conn, req); +#elif defined(TRANS_PF) + const or_options_t *options = get_options(); + + if (options->TransProxyType_parsed == TPT_PF_DIVERT) + return destination_from_socket(conn, req); + + if (options->TransProxyType_parsed == TPT_DEFAULT) + return destination_from_pf(conn, req); + + (void)conn; + (void)req; + log_warn(LD_BUG, "Proxy destination determination mechanism %s unknown.", + options->TransProxyType); + return -1; #else (void)conn; (void)req; diff --git a/src/or/or.h b/src/or/or.h index 19a1c99a9..4ca7ecc60 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -3473,7 +3473,12 @@ typedef struct { const char *TransProxyType; /**< What kind of transparent proxy * implementation are we using? */ /** Parsed value of TransProxyType. */ - enum { TPT_DEFAULT, TPT_TPROXY } TransProxyType_parsed; + enum { + TPT_DEFAULT, + TPT_PF_DIVERT, + TPT_IPFW, + TPT_TPROXY, + } TransProxyType_parsed; config_line_t *NATDPort_lines; /**< Ports to listen on for transparent natd * connections. */ config_line_t *ControlPort_lines; /**< Ports to listen on for control |