Merge branch '10267_plus_10896_rebased_twice'

This commit is contained in:
Nick Mathewson 2014-04-16 23:03:41 -04:00
commit 973661394a
6 changed files with 115 additions and 18 deletions

4
changes/10267_tproxy Normal file
View File

@ -0,0 +1,4 @@
o Minor features:
- Support the ipfw firewall interface for transparent proxy support on
FreeBSD. To enable it, set "TransProxyType ipfw" in your torrc.
Resolves ticket 10267; patch from "yurivict".

8
changes/10896 Normal file
View File

@ -0,0 +1,8 @@
o Minor features:
- Support OpenBSD's divert-to rules with the pf firewall, when
"TransProxyType pf-divert" is specified. This allows Tor to run a
TransPort transparent proxy port on OpenBSD 4.4 or later without
root privileges. See the pf.conf(5) manual page for information on
configuring pf to use divert-to rules. Closes ticket 10896; patch
from Dana Koch.

View File

@ -1196,20 +1196,29 @@ The following options are useful only for clients (that is, if
compatibility, TransListenAddress is only allowed when TransPort is just
a port number.)
[[TransProxyType]] **TransProxyTYpe** **default**|**TPROXY**::
[[TransProxyType]] **TransProxyTYpe** **default**|**TPROXY**|**ipfw**|**pf-divert**::
TransProxyType may only be enabled when there is transparent proxy listener
enabled.
+
Set this to TPROXY if you wish to be able to use the TPROXY Linux module to
transparently proxy connections that are configured using the TransPort
Set this to "TPROXY" if you wish to be able to use the TPROXY Linux module
to transparently proxy connections that are configured using the TransPort
option. This setting lets the listener on the TransPort accept connections
for all addresses, even when the TransListenAddress is configured for an
internal address. Detailed information on how to configure the TPROXY
feature can be found in the Linux kernel source tree in the file
Documentation/networking/tproxy.txt.
+
Set this option to "ipfw" to use the FreeBSD ipfw interface.
+
On *BSD operating systems when using pf, set this to "pf-divert" to take
advantage of +divert-to+ rules, which do not modify the packets like
+rdr-to+ rules do. Detailed information on how to configure pf to use
+divert-to+ rules can be found in the pf.conf(5) manual page. On OpenBSD,
+divert-to+ is available to use on versions greater than or equal to
OpenBSD 4.4.
+
Set this to "default", or leave it unconfigured, to use regular IPTables
on Linux, or to use pf on the *BSD operating systems.
on Linux, or to use pf +rdr-to+ rules on *BSD systems.
+
(Default: "default".)

View File

@ -1089,7 +1089,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;
@ -2553,11 +2554,23 @@ 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");

View File

@ -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;

View File

@ -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