aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/or/config.c20
-rw-r--r--src/or/connection.c20
-rw-r--r--src/or/connection_edge.c82
-rw-r--r--src/or/or.h7
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