[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[or-cvs] r7007: Patch from Tup to add support for transparent AP connections (in tor/trunk: . src/or)
- To: or-cvs@xxxxxxxxxxxxx
- Subject: [or-cvs] r7007: Patch from Tup to add support for transparent AP connections (in tor/trunk: . src/or)
- From: nickm@xxxxxxxx
- Date: Thu, 10 Aug 2006 05:01:39 -0400 (EDT)
- Delivered-to: archiver@seul.org
- Delivered-to: or-cvs-outgoing@seul.org
- Delivered-to: or-cvs@seul.org
- Delivery-date: Thu, 10 Aug 2006 05:01:51 -0400
- Reply-to: or-talk@xxxxxxxxxxxxx
- Sender: owner-or-cvs@xxxxxxxxxxxxx
Author: nickm
Date: 2006-08-10 05:01:37 -0400 (Thu, 10 Aug 2006)
New Revision: 7007
Modified:
tor/trunk/
tor/trunk/configure.in
tor/trunk/src/or/config.c
tor/trunk/src/or/connection.c
tor/trunk/src/or/connection_edge.c
tor/trunk/src/or/control.c
tor/trunk/src/or/hibernate.c
tor/trunk/src/or/or.h
tor/trunk/src/or/relay.c
Log:
r7299@Kushana: nickm | 2006-08-10 01:08:58 -0700
Patch from Tup to add support for transparent AP connections: this basically bundles the functionality of trans-proxy-tor into the tor mainline. Now hosts with compliant pf/netfilter implementations can redirect TCP connections straight to Tor without diverting through SOCKS.
Property changes on: tor/trunk
___________________________________________________________________
Name: svk:merge
- 17f730b7-d419-0410-b50f-85ee4b70197a:/local/or/tor/trunk:8245
1f724f9b-111a-0410-b636-93f1a77c1813:/local/or/tor/trunk:8207
96637b51-b116-0410-a10e-9941ebb49b64:/tor/branches/spec:7005
c95137ef-5f19-0410-b913-86e773d04f59:/tor/branches/eventdns:7014
c95137ef-5f19-0410-b913-86e773d04f59:/tor/branches/mmap:7030
c95137ef-5f19-0410-b913-86e773d04f59:/tor/branches/oo-connections:6950
+ 17f730b7-d419-0410-b50f-85ee4b70197a:/local/or/tor/trunk:8245
1f724f9b-111a-0410-b636-93f1a77c1813:/local/or/tor/trunk:8207
96637b51-b116-0410-a10e-9941ebb49b64:/tor/branches/spec:7005
c95137ef-5f19-0410-b913-86e773d04f59:/tor/branches/eventdns:7014
c95137ef-5f19-0410-b913-86e773d04f59:/tor/branches/mmap:7030
c95137ef-5f19-0410-b913-86e773d04f59:/tor/branches/oo-connections:6950
c95137ef-5f19-0410-b913-86e773d04f59:/tor/branches/trans-ap:7299
Modified: tor/trunk/configure.in
===================================================================
--- tor/trunk/configure.in 2006-08-10 08:13:41 UTC (rev 7006)
+++ tor/trunk/configure.in 2006-08-10 09:01:37 UTC (rev 7007)
@@ -56,6 +56,26 @@
AC_DEFINE([USE_EVENTDNS], 1, "Define to 1 if we'll be using eventdns.c")
fi
+AC_ARG_ENABLE(transparent,
+ AC_HELP_STRING(--disable-transparent, disable transparent proxy support),
+ [case "${enableval}" in
+ yes) transparent=true ;;
+ no) transparent=false ;;
+ *) AC_MSG_ERROR(bad value for --enable-transparent) ;;
+ esac], [transparent=true])
+if test x$transparent = xtrue; then
+ AC_DEFINE(USE_TRANSPARENT, 1, "Define to enable transparent proxy support")
+ case $host in
+ *-*-linux* )
+ AC_DEFINE(TRANS_NETFILTER, 1, "Define for transparent netfilter") ;;
+ *-*-openbsd*)
+ AC_DEFINE(TRANS_PF, 1, "Define for transparent pf")
+ AC_DEFINE(OPENBSD, 1, "Define to handle pf on OpenBSD properly") ;;
+ *-*-*bsd* )
+ AC_DEFINE(TRANS_PF, 1, "Define for transparent pf") ;;
+ esac
+fi
+
case $host in
*-*-solaris* )
AC_DEFINE(_REENTRANT, 1, [Define on some platforms to activate x_r() functions in time.h])
Modified: tor/trunk/src/or/config.c
===================================================================
--- tor/trunk/src/or/config.c 2006-08-10 08:13:41 UTC (rev 7006)
+++ tor/trunk/src/or/config.c 2006-08-10 09:01:37 UTC (rev 7007)
@@ -235,6 +235,8 @@
VAR("TrackHostExits", CSV, TrackHostExits, NULL),
VAR("TrackHostExitsExpire",INTERVAL, TrackHostExitsExpire, "30 minutes"),
OBSOLETE("TrafficShaping"),
+ VAR("TransListenAddress", LINELIST, TransListenAddress, NULL),
+ VAR("TransPort", UINT, TransPort, "0"),
VAR("UseEntryGuards", BOOL, UseEntryGuards, "1"),
VAR("User", STRING, User, NULL),
VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir, "0"),
@@ -2067,6 +2069,7 @@
REJECT("SocksPort must be defined if SocksListenAddress is defined.");
#endif
+ /* XXX TransListenAddress should be checked here as well */
if (options->SocksListenAddress) {
config_line_t *line = NULL;
char *address = NULL;
@@ -2144,15 +2147,24 @@
if (options->SocksPort < 0 || options->SocksPort > 65535)
REJECT("SocksPort option out of bounds.");
- if (options->SocksPort == 0 && options->ORPort == 0)
- REJECT("SocksPort and ORPort are both undefined? Quitting.");
+ if (options->TransPort < 0 || options->TransPort > 65535)
+ REJECT("TransPort option out of bounds.");
+ if (options->SocksPort == 0 && options->TransPort == 0 &&
+ options->ORPort == 0)
+ REJECT("SocksPort, TransPort, and ORPort are all undefined? Quitting.");
+
if (options->ControlPort < 0 || options->ControlPort > 65535)
REJECT("ControlPort option out of bounds.");
if (options->DirPort < 0 || options->DirPort > 65535)
REJECT("DirPort option out of bounds.");
+#ifndef USE_TRANSPARENT
+ if (options->TransPort || options->TransListenAddress)
+ REJECT("TransPort and TransListenAddress are disabled in this build.");
+#endif
+
if (options->StrictExitNodes &&
(!options->ExitNodes || !strlen(options->ExitNodes)) &&
(!old_options ||
Modified: tor/trunk/src/or/connection.c
===================================================================
--- tor/trunk/src/or/connection.c 2006-08-10 08:13:41 UTC (rev 7006)
+++ tor/trunk/src/or/connection.c 2006-08-10 09:01:37 UTC (rev 7007)
@@ -16,7 +16,8 @@
static connection_t *connection_create_listener(const char *listenaddress,
uint16_t listenport, int type);
-static int connection_init_accepted_conn(connection_t *conn);
+static int connection_init_accepted_conn(connection_t *conn,
+ uint8_t listener_type);
static int connection_handle_listener_read(connection_t *conn, int new_type);
static int connection_receiver_bucket_should_increase(or_connection_t *conn);
static int connection_finished_flushing(connection_t *conn);
@@ -44,6 +45,7 @@
case CONN_TYPE_OR: return "OR";
case CONN_TYPE_EXIT: return "Exit";
case CONN_TYPE_AP_LISTENER: return "Socks listener";
+ case CONN_TYPE_AP_TRANS_LISTENER: return "Transparent listener";
case CONN_TYPE_AP: return "Socks";
case CONN_TYPE_DIR_LISTENER: return "Directory listener";
case CONN_TYPE_DIR: return "Directory";
@@ -69,6 +71,7 @@
switch (type) {
case CONN_TYPE_OR_LISTENER:
case CONN_TYPE_AP_LISTENER:
+ case CONN_TYPE_AP_TRANS_LISTENER:
case CONN_TYPE_DIR_LISTENER:
case CONN_TYPE_CONTROL_LISTENER:
if (state == LISTENER_STATE_READY)
@@ -93,6 +96,7 @@
break;
case CONN_TYPE_AP:
switch (state) {
+ case AP_CONN_STATE_ORIGDST_WAIT:
case AP_CONN_STATE_SOCKS_WAIT: return "waiting for dest info";
case AP_CONN_STATE_RENDDESC_WAIT: return "waiting for rendezvous desc";
case AP_CONN_STATE_CONTROLLER_WAIT: return "waiting for controller";
@@ -786,7 +790,7 @@
return 0; /* no need to tear down the parent */
}
- if (connection_init_accepted_conn(newconn) < 0) {
+ if (connection_init_accepted_conn(newconn, conn->type) < 0) {
connection_mark_for_close(newconn);
return 0;
}
@@ -797,7 +801,7 @@
* If conn is an OR, start the tls handshake.
*/
static int
-connection_init_accepted_conn(connection_t *conn)
+connection_init_accepted_conn(connection_t *conn, uint8_t listener_type)
{
connection_start_reading(conn);
@@ -806,7 +810,14 @@
control_event_or_conn_status(TO_OR_CONN(conn), OR_CONN_EVENT_NEW);
return connection_tls_start_handshake(TO_OR_CONN(conn), 1);
case CONN_TYPE_AP:
- conn->state = AP_CONN_STATE_SOCKS_WAIT;
+ switch (listener_type) {
+ case CONN_TYPE_AP_LISTENER:
+ conn->state = AP_CONN_STATE_SOCKS_WAIT;
+ break;
+ case CONN_TYPE_AP_TRANS_LISTENER:
+ conn->state = AP_CONN_STATE_ORIGDST_WAIT;
+ break;
+ }
break;
case CONN_TYPE_DIR:
conn->purpose = DIR_PURPOSE_SERVER;
@@ -1046,6 +1057,10 @@
options->SocksPort, "127.0.0.1", force,
replaced_conns, new_conns, 0)<0)
return -1;
+ if (retry_listeners(CONN_TYPE_AP_TRANS_LISTENER, options->TransListenAddress,
+ options->TransPort, "127.0.0.1", force,
+ replaced_conns, new_conns, 0)<0)
+ return -1;
if (retry_listeners(CONN_TYPE_CONTROL_LISTENER,
options->ControlListenAddress,
options->ControlPort, "127.0.0.1", force,
@@ -1260,6 +1275,7 @@
case CONN_TYPE_OR_LISTENER:
return connection_handle_listener_read(conn, CONN_TYPE_OR);
case CONN_TYPE_AP_LISTENER:
+ case CONN_TYPE_AP_TRANS_LISTENER:
return connection_handle_listener_read(conn, CONN_TYPE_AP);
case CONN_TYPE_DIR_LISTENER:
return connection_handle_listener_read(conn, CONN_TYPE_DIR);
@@ -1896,6 +1912,7 @@
{
if (conn->type == CONN_TYPE_OR_LISTENER ||
conn->type == CONN_TYPE_AP_LISTENER ||
+ conn->type == CONN_TYPE_AP_TRANS_LISTENER ||
conn->type == CONN_TYPE_DIR_LISTENER ||
conn->type == CONN_TYPE_CONTROL_LISTENER)
return 1;
@@ -2248,6 +2265,7 @@
{
case CONN_TYPE_OR_LISTENER:
case CONN_TYPE_AP_LISTENER:
+ case CONN_TYPE_AP_TRANS_LISTENER:
case CONN_TYPE_DIR_LISTENER:
case CONN_TYPE_CONTROL_LISTENER:
tor_assert(conn->state == LISTENER_STATE_READY);
Modified: tor/trunk/src/or/connection_edge.c
===================================================================
--- tor/trunk/src/or/connection_edge.c 2006-08-10 08:13:41 UTC (rev 7006)
+++ tor/trunk/src/or/connection_edge.c 2006-08-10 09:01:37 UTC (rev 7007)
@@ -17,6 +17,7 @@
static smartlist_t *redirect_exit_list = NULL;
static int connection_ap_handshake_process_socks(edge_connection_t *conn);
+static int connection_ap_process_transparent(edge_connection_t *conn);
/** An AP stream has failed/finished. If it hasn't already sent back
* a socks reply, send one now (based on endreason). Also set
@@ -80,6 +81,7 @@
/** Handle new bytes on conn->inbuf based on state:
* - If it's waiting for socks info, try to read another step of the
* socks handshake out of conn->inbuf.
+ * - If it's waiting for the original destination, fetch it.
* - If it's open, then package more relay cells from the stream.
* - Else, leave the bytes on inbuf alone for now.
*
@@ -98,6 +100,12 @@
return -1;
}
return 0;
+ case AP_CONN_STATE_ORIGDST_WAIT:
+ if (connection_ap_process_transparent(conn) < 0) {
+ /* already marked */
+ return -1;
+ }
+ return 0;
case AP_CONN_STATE_OPEN:
case EXIT_CONN_STATE_OPEN:
if (connection_edge_package_raw_inbuf(conn, package_partial) < 0) {
@@ -234,6 +242,7 @@
connection_edge_consider_sending_sendme(conn);
return 0;
case AP_CONN_STATE_SOCKS_WAIT:
+ case AP_CONN_STATE_ORIGDST_WAIT:
case AP_CONN_STATE_RENDDESC_WAIT:
case AP_CONN_STATE_CIRCUIT_WAIT:
case AP_CONN_STATE_CONNECT_WAIT:
@@ -1216,6 +1225,89 @@
return 0; /* unreached but keeps the compiler happy */
}
+/** 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(edge_connection_t *conn,
+ socks_request_t *req)
+{
+#ifdef TRANS_NETFILTER
+ /* Linux 2.4+ */
+ struct sockaddr_in orig_dst;
+ socklen_t orig_dst_len = sizeof(orig_dst);
+ char tmpbuf[INET_NTOA_BUF_LEN];
+
+ if (getsockopt(conn->_base.s, SOL_IP, SO_ORIGINAL_DST,
+ (struct sockaddr*)&orig_dst, &orig_dst_len) < 0) {
+ int e = tor_socket_errno(conn->_base.s);
+ log_warn(LD_NET, "getsockopt() failed: %s", tor_socket_strerror(e));
+ return -1;
+ }
+
+ tor_inet_ntoa(&orig_dst.sin_addr, tmpbuf, sizeof(tmpbuf));
+ strlcpy(req->address, tmpbuf, sizeof(req->address));
+ req->port = ntohs(orig_dst.sin_port);
+#endif
+
+#ifdef TRANS_PF
+ struct sockaddr_in proxy_addr;
+ socklen_t proxy_addr_len = sizeof(proxy_addr);
+ char tmpbuf[INET_NTOA_BUF_LEN];
+ struct pfioc_natlook pnl;
+ int pf = -1;
+
+ if (getsockname(conn->_base.s, (struct sockaddr*)&proxy_addr,
+ &proxy_addr_len) < 0) {
+ int e = tor_socket_errno(conn->_base.s);
+ log_warn(LD_NET, "getsockname() failed: %s", tor_socket_strerror(e));
+ return -1;
+ }
+
+ memset(&pnl, 0, sizeof(pnl));
+ pnl.af = AF_INET;
+ pnl.proto = IPPROTO_TCP;
+ pnl.direction = PF_OUT;
+ pnl.saddr.v4.s_addr = htonl(conn->_base.addr);
+ pnl.sport = htons(conn->_base.port);
+ pnl.daddr.v4.s_addr = proxy_addr.sin_addr.s_addr;
+ pnl.dport = proxy_addr.sin_port;
+
+ /* XXX We should open the /dev/pf device once and close it at cleanup time
+ * instead of reopening it for every connection. Ideally, it should be
+ * opened before dropping privs. */
+#ifdef OPENBSD
+ /* only works on OpenBSD */
+ pf = open("/dev/pf", O_RDONLY);
+#else
+ /* works on NetBSD and FreeBSD */
+ pf = open("/dev/pf", O_RDWR);
+#endif
+
+ if (pf < 0) {
+ log_warn(LD_NET, "open(\"/dev/pf\") failed: %s", strerror(errno));
+ return -1;
+ }
+
+ if (ioctl(pf, DIOCNATLOOK, &pnl) < 0) {
+ log_warn(LD_NET, "ioctl(DIOCNATLOOK) failed: %s", strerror(errno));
+ close(pf);
+ return -1;
+ }
+ close(pf);
+
+ tor_inet_ntoa(&pnl.rdaddr.v4, tmpbuf, sizeof(tmpbuf));
+ strlcpy(req->address, tmpbuf, sizeof(req->address));
+ req->port = ntohs(pnl.rdport);
+#endif
+
+ return 0;
+}
+
/** connection_edge_process_inbuf() found a conn in state
* socks_wait. See if conn->inbuf has the right bytes to proceed with
* the socks handshake.
@@ -1278,6 +1370,48 @@
return connection_ap_handshake_rewrite_and_attach(conn, NULL);
}
+/** connection_edge_process_inbuf() found a conn in state
+ * origdst_wait. Get the original destination and
+ * send it to connection_ap_handshake_rewrite_and_attach().
+ *
+ * Return -1 if an unexpected error with conn (and it should be marked
+ * for close), else return 0.
+ */
+static int
+connection_ap_process_transparent(edge_connection_t *conn)
+{
+ socks_request_t *socks;
+ or_options_t *options = get_options();
+
+ tor_assert(conn);
+ tor_assert(conn->_base.type == CONN_TYPE_AP);
+ tor_assert(conn->_base.state == AP_CONN_STATE_ORIGDST_WAIT);
+ tor_assert(conn->socks_request);
+ socks = conn->socks_request;
+
+ /* pretend that a socks handshake completed so we don't try to
+ * send a socks reply down a transparent conn */
+ socks->command = SOCKS_COMMAND_CONNECT;
+ socks->has_finished = 1;
+
+ log_debug(LD_APP,"entered.");
+
+ if (connection_ap_get_original_destination(conn, socks) < 0) {
+ log_warn(LD_APP,"Fetching original destination failed. Closing.");
+ connection_mark_unattached_ap(conn, 0);
+ return -1;
+ }
+ /* we have the original destination */
+
+ control_event_stream_status(conn, STREAM_EVENT_NEW);
+
+ if (options->LeaveStreamsUnattached) {
+ conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT;
+ return 0;
+ }
+ return connection_ap_handshake_rewrite_and_attach(conn, NULL);
+}
+
/** Iterate over the two bytes of stream_id until we get one that is not
* already in use; return it. Return 0 if can't get a unique stream_id.
*/
Modified: tor/trunk/src/or/control.c
===================================================================
--- tor/trunk/src/or/control.c 2006-08-10 08:13:41 UTC (rev 7006)
+++ tor/trunk/src/or/control.c 2006-08-10 09:01:37 UTC (rev 7007)
@@ -1423,7 +1423,8 @@
origin_circuit_t *origin_circ = NULL;
if (conns[i]->type != CONN_TYPE_AP ||
conns[i]->marked_for_close ||
- conns[i]->state == AP_CONN_STATE_SOCKS_WAIT)
+ conns[i]->state == AP_CONN_STATE_SOCKS_WAIT ||
+ conns[i]->state == AP_CONN_STATE_ORIGDST_WAIT)
continue;
conn = TO_EDGE_CONN(conns[i]);
switch (conn->_base.state)
Modified: tor/trunk/src/or/hibernate.c
===================================================================
--- tor/trunk/src/or/hibernate.c 2006-08-10 08:13:41 UTC (rev 7006)
+++ tor/trunk/src/or/hibernate.c 2006-08-10 09:01:37 UTC (rev 7007)
@@ -712,6 +712,7 @@
/* close listeners. leave control listener(s). */
while ((conn = connection_get_by_type(CONN_TYPE_OR_LISTENER)) ||
(conn = connection_get_by_type(CONN_TYPE_AP_LISTENER)) ||
+ (conn = connection_get_by_type(CONN_TYPE_AP_TRANS_LISTENER)) ||
(conn = connection_get_by_type(CONN_TYPE_DIR_LISTENER))) {
log_info(LD_NET,"Closing listener type %d", conn->type);
connection_mark_for_close(conn);
Modified: tor/trunk/src/or/or.h
===================================================================
--- tor/trunk/src/or/or.h 2006-08-10 08:13:41 UTC (rev 7006)
+++ tor/trunk/src/or/or.h 2006-08-10 09:01:37 UTC (rev 7007)
@@ -113,6 +113,15 @@
#error "Tor requires libevent to build."
#endif
+#ifdef TRANS_NETFILTER
+#include <linux/netfilter_ipv4.h>
+#endif
+
+#ifdef TRANS_PF
+#include <net/if.h>
+#include <net/pfvar.h>
+#endif
+
#include "../common/crypto.h"
#include "../common/tortls.h"
#include "../common/log.h"
@@ -215,7 +224,9 @@
#define CONN_TYPE_CONTROL_LISTENER 12
/** Type for connections from user interface process. */
#define CONN_TYPE_CONTROL 13
-#define _CONN_TYPE_MAX 13
+/** Type for sockets listening for transparent proxy connections. */
+#define CONN_TYPE_AP_TRANS_LISTENER 14
+#define _CONN_TYPE_MAX 14
#define CONN_IS_EDGE(x) \
((x)->type == CONN_TYPE_EXIT || (x)->type == CONN_TYPE_AP)
@@ -283,7 +294,10 @@
#define AP_CONN_STATE_RESOLVE_WAIT 10
/** State for a SOCKS connection: ready to send and receive. */
#define AP_CONN_STATE_OPEN 11
-#define _AP_CONN_STATE_MAX 11
+/** State for a transparent proxy connection: waiting for original
+ * destination. */
+#define AP_CONN_STATE_ORIGDST_WAIT 12
+#define _AP_CONN_STATE_MAX 12
#define _DIR_CONN_STATE_MIN 1
/** State for connection to directory server: waiting for connect(). */
@@ -1386,6 +1400,8 @@
config_line_t *DirPolicy; /**< Lists of dir policy components */
/** Addresses to bind for listening for SOCKS connections. */
config_line_t *SocksListenAddress;
+ /** Addresses to bind for listening for transparent connections. */
+ config_line_t *TransListenAddress;
/** Addresses to bind for listening for OR connections. */
config_line_t *ORListenAddress;
/** Addresses to bind for listening for directory connections. */
@@ -1407,6 +1423,7 @@
* length (alpha in geometric distribution). */
int ORPort; /**< Port to listen on for OR connections. */
int SocksPort; /**< Port to listen on for SOCKS connections. */
+ int TransPort; /**< Port to listen on for transparent connections. */
int ControlPort; /**< Port to listen on for control connections. */
int DirPort; /**< Port to listen on for directory connections. */
int AssumeReachable; /**< Whether to publish our descriptor regardless. */
Modified: tor/trunk/src/or/relay.c
===================================================================
--- tor/trunk/src/or/relay.c 2006-08-10 08:13:41 UTC (rev 7006)
+++ tor/trunk/src/or/relay.c 2006-08-10 09:01:37 UTC (rev 7007)
@@ -845,7 +845,9 @@
conn->chosen_exit_name, ttl);
}
circuit_log_path(LOG_INFO,LD_APP,TO_ORIGIN_CIRCUIT(circ));
- connection_ap_handshake_socks_reply(conn, NULL, 0, SOCKS5_SUCCEEDED);
+ /* don't send a socks reply to transparent conns */
+ if (!conn->socks_request->has_finished)
+ connection_ap_handshake_socks_reply(conn, NULL, 0, SOCKS5_SUCCEEDED);
/* handle anything that might have queued */
if (connection_edge_package_raw_inbuf(conn, 1) < 0) {
/* (We already sent an end cell if possible) */