Merge remote-tracking branch 'origin/maint-0.2.4'

This commit is contained in:
Nick Mathewson 2013-04-11 01:40:31 -04:00
commit 3dfd1ebf12
6 changed files with 57 additions and 7 deletions

13
changes/bug8117 Normal file
View file

@ -0,0 +1,13 @@
o Major bugfixes:
- Many SOCKS5 clients, when configured to offer a username/password,
offer both username/password authentication and "no authentication".
Tor had previously preferred no authentication, but this was
problematic when trying to make applications get proper stream
isolation with IsolateSOCKSAuth. Now, on any SOCKS port with
IsolateSOCKSAuth turned on (which is the default), Tor selects
username/password authentication if it's offered. If this confuses your
application, you can disable it on a per-SOCKSPort basis via
PreferSOCKSNoAuth. Fixes bug 8117; bugfix on 0.2.3.3-alpha.

View file

@ -972,6 +972,15 @@ The following options are useful only for clients (that is, if
should get automapped (according to AutomapHostsOnResove), should get automapped (according to AutomapHostsOnResove),
if we could return either an IPv4 or an IPv6 answer, prefer if we could return either an IPv4 or an IPv6 answer, prefer
an IPv6 answer. (On by default.) an IPv6 answer. (On by default.)
**PreferSOCKSNoAuth**;;
Ordinarily, when an application offers both "username/password
authentication" and "no authentication" to Tor via SOCKS5, Tor
selects username/password authentication so that IsolateSOCKSAuth can
work. This can confuse some applications, if they offer a
username/password combination then get confused when asked for
one. You can disable this behavior, so that Tor will select "No
authentication" when IsolateSOCKSAuth is disabled, or when this
option is set.
**SOCKSListenAddress** __IP__[:__PORT__]:: **SOCKSListenAddress** __IP__[:__PORT__]::
Bind to this address to listen for connections from Socks-speaking Bind to this address to listen for connections from Socks-speaking

View file

@ -1781,6 +1781,7 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req,
if (req->socks_version != 5) { /* we need to negotiate a method */ if (req->socks_version != 5) { /* we need to negotiate a method */
unsigned char nummethods = (unsigned char)*(data+1); unsigned char nummethods = (unsigned char)*(data+1);
int have_user_pass, have_no_auth;
int r=0; int r=0;
tor_assert(!req->socks_version); tor_assert(!req->socks_version);
if (datalen < 2u+nummethods) { if (datalen < 2u+nummethods) {
@ -1791,19 +1792,21 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req,
return -1; return -1;
req->replylen = 2; /* 2 bytes of response */ req->replylen = 2; /* 2 bytes of response */
req->reply[0] = 5; /* socks5 reply */ req->reply[0] = 5; /* socks5 reply */
if (memchr(data+2, SOCKS_NO_AUTH, nummethods)) { have_user_pass = (memchr(data+2, SOCKS_USER_PASS, nummethods) !=NULL);
req->reply[1] = SOCKS_NO_AUTH; /* tell client to use "none" auth have_no_auth = (memchr(data+2, SOCKS_NO_AUTH, nummethods) !=NULL);
method */ if (have_user_pass && !(have_no_auth && req->socks_prefer_no_auth)) {
req->socks_version = 5; /* remember we've already negotiated auth */
log_debug(LD_APP,"socks5: accepted method 0 (no authentication)");
r=0;
} else if (memchr(data+2, SOCKS_USER_PASS, nummethods)) {
req->auth_type = SOCKS_USER_PASS; req->auth_type = SOCKS_USER_PASS;
req->reply[1] = SOCKS_USER_PASS; /* tell client to use "user/pass" req->reply[1] = SOCKS_USER_PASS; /* tell client to use "user/pass"
auth method */ auth method */
req->socks_version = 5; /* remember we've already negotiated auth */ req->socks_version = 5; /* remember we've already negotiated auth */
log_debug(LD_APP,"socks5: accepted method 2 (username/password)"); log_debug(LD_APP,"socks5: accepted method 2 (username/password)");
r=0; r=0;
} else if (have_no_auth) {
req->reply[1] = SOCKS_NO_AUTH; /* tell client to use "none" auth
method */
req->socks_version = 5; /* remember we've already negotiated auth */
log_debug(LD_APP,"socks5: accepted method 0 (no authentication)");
r=0;
} else { } else {
log_warn(LD_APP, log_warn(LD_APP,
"socks5: offered methods don't include 'no auth' or " "socks5: offered methods don't include 'no auth' or "

View file

@ -5097,6 +5097,7 @@ parse_port_config(smartlist_t *out,
int port; int port;
int sessiongroup = SESSION_GROUP_UNSET; int sessiongroup = SESSION_GROUP_UNSET;
unsigned isolation = ISO_DEFAULT; unsigned isolation = ISO_DEFAULT;
int prefer_no_auth = 0;
char *addrport; char *addrport;
uint16_t ptmp=0; uint16_t ptmp=0;
@ -5264,6 +5265,9 @@ parse_port_config(smartlist_t *out,
} else if (!strcasecmp(elt, "PreferIPv6Automap")) { } else if (!strcasecmp(elt, "PreferIPv6Automap")) {
prefer_ipv6_automap = ! no; prefer_ipv6_automap = ! no;
continue; continue;
} else if (!strcasecmp(elt, "PreferSOCKSNoAuth")) {
prefer_no_auth = ! no;
continue;
} }
if (!strcasecmpend(elt, "s")) if (!strcasecmpend(elt, "s"))
@ -5323,6 +5327,9 @@ parse_port_config(smartlist_t *out,
cfg->use_cached_ipv4_answers = use_cached_ipv4; cfg->use_cached_ipv4_answers = use_cached_ipv4;
cfg->use_cached_ipv6_answers = use_cached_ipv6; cfg->use_cached_ipv6_answers = use_cached_ipv6;
cfg->prefer_ipv6_virtaddr = prefer_ipv6_automap; cfg->prefer_ipv6_virtaddr = prefer_ipv6_automap;
cfg->socks_prefer_no_auth = prefer_no_auth;
if (! (isolation & ISO_SOCKSAUTH))
cfg->socks_prefer_no_auth = 1;
smartlist_add(out, cfg); smartlist_add(out, cfg);
} }

View file

@ -1146,6 +1146,7 @@ connection_listener_new(const struct sockaddr *listensockaddr,
lis_conn->use_cached_ipv4_answers = port_cfg->use_cached_ipv4_answers; lis_conn->use_cached_ipv4_answers = port_cfg->use_cached_ipv4_answers;
lis_conn->use_cached_ipv6_answers = port_cfg->use_cached_ipv6_answers; lis_conn->use_cached_ipv6_answers = port_cfg->use_cached_ipv6_answers;
lis_conn->prefer_ipv6_virtaddr = port_cfg->prefer_ipv6_virtaddr; lis_conn->prefer_ipv6_virtaddr = port_cfg->prefer_ipv6_virtaddr;
lis_conn->socks_prefer_no_auth = port_cfg->socks_prefer_no_auth;
if (connection_add(conn) < 0) { /* no space, forget it */ if (connection_add(conn) < 0) { /* no space, forget it */
log_warn(LD_NET,"connection_add for listener failed. Giving up."); log_warn(LD_NET,"connection_add for listener failed. Giving up.");
@ -1326,6 +1327,11 @@ connection_handle_listener_read(connection_t *conn, int new_type)
newconn->port = port; newconn->port = port;
newconn->address = tor_dup_addr(&addr); newconn->address = tor_dup_addr(&addr);
if (new_type == CONN_TYPE_AP) {
TO_ENTRY_CONN(newconn)->socks_request->socks_prefer_no_auth =
TO_LISTENER_CONN(conn)->socks_prefer_no_auth;
}
} else if (conn->socket_family == AF_UNIX) { } else if (conn->socket_family == AF_UNIX) {
/* For now only control ports can be Unix domain sockets /* For now only control ports can be Unix domain sockets
* and listeners at the same time */ * and listeners at the same time */

View file

@ -1249,6 +1249,10 @@ typedef struct listener_connection_t {
/** One or more ISO_ flags to describe how to isolate streams. */ /** One or more ISO_ flags to describe how to isolate streams. */
uint8_t isolation_flags; uint8_t isolation_flags;
/**@}*/ /**@}*/
/** For SOCKS connections only: If this is set, we will choose "no
* authentication" instead of "username/password" authentication if both
* are offered. Used as input to parse_socks. */
unsigned int socks_prefer_no_auth : 1;
/** For a SOCKS listeners, these fields describe whether we should /** For a SOCKS listeners, these fields describe whether we should
* allow IPv4 and IPv6 addresses from our exit nodes, respectively. * allow IPv4 and IPv6 addresses from our exit nodes, respectively.
@ -3241,6 +3245,10 @@ typedef struct port_cfg_t {
uint8_t isolation_flags; /**< Zero or more isolation flags */ uint8_t isolation_flags; /**< Zero or more isolation flags */
int session_group; /**< A session group, or -1 if this port is not in a int session_group; /**< A session group, or -1 if this port is not in a
* session group. */ * session group. */
/* Socks only: */
/** When both no-auth and user/pass are advertised by a SOCKS client, select
* no-auth. */
unsigned int socks_prefer_no_auth : 1;
/* Server port types (or, dir) only: */ /* Server port types (or, dir) only: */
unsigned int no_advertise : 1; unsigned int no_advertise : 1;
@ -4157,6 +4165,10 @@ struct socks_request_t {
* make sure we send back a socks reply for * make sure we send back a socks reply for
* every connection. */ * every connection. */
unsigned int got_auth : 1; /**< Have we received any authentication data? */ unsigned int got_auth : 1; /**< Have we received any authentication data? */
/** If this is set, we will choose "no authentication" instead of
* "username/password" authentication if both are offered. Used as input to
* parse_socks. */
unsigned int socks_prefer_no_auth : 1;
/** Number of bytes in username; 0 if username is NULL */ /** Number of bytes in username; 0 if username is NULL */
size_t usernamelen; size_t usernamelen;