mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-11 05:33:47 +01:00
Merge remote-tracking branch 'asn/bug3594_rebased_and_fixed'
Conflicts: src/common/util.c src/or/entrynodes.h
This commit is contained in:
commit
c101ecc8dc
3
changes/bug3594
Normal file
3
changes/bug3594
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
o Major bugfixes:
|
||||||
|
- Add support for passing arguments to managed pluggable transport
|
||||||
|
proxies. Implements ticket #3594.
|
@ -865,6 +865,39 @@ tor_digest_is_zero(const char *digest)
|
|||||||
return tor_memeq(digest, ZERO_DIGEST, DIGEST_LEN);
|
return tor_memeq(digest, ZERO_DIGEST, DIGEST_LEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Return true if <b>string</b> is a valid '<key>=[<value>]' string.
|
||||||
|
* <value> is optional, to indicate the empty string. Log at logging
|
||||||
|
* <b>severity</b> if something ugly happens. */
|
||||||
|
int
|
||||||
|
string_is_key_value(int severity, const char *string)
|
||||||
|
{
|
||||||
|
/* position of equal sign in string */
|
||||||
|
const char *equal_sign_pos = NULL;
|
||||||
|
|
||||||
|
tor_assert(string);
|
||||||
|
|
||||||
|
if (strlen(string) < 2) { /* "x=" is shortest args string */
|
||||||
|
tor_log(severity, LD_GENERAL, "'%s' is too short to be a k=v value.",
|
||||||
|
escaped(string));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
equal_sign_pos = strchr(string, '=');
|
||||||
|
if (!equal_sign_pos) {
|
||||||
|
tor_log(severity, LD_GENERAL, "'%s' is not a k=v value.", escaped(string));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* validate that the '=' is not in the beginning of the string. */
|
||||||
|
if (equal_sign_pos == string) {
|
||||||
|
tor_log(severity, LD_GENERAL, "'%s' is not a valid k=v value.",
|
||||||
|
escaped(string));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/** Return true iff the DIGEST256_LEN bytes in digest are all zero. */
|
/** Return true iff the DIGEST256_LEN bytes in digest are all zero. */
|
||||||
int
|
int
|
||||||
tor_digest256_is_zero(const char *digest)
|
tor_digest256_is_zero(const char *digest)
|
||||||
@ -1176,6 +1209,46 @@ escaped(const char *s)
|
|||||||
return escaped_val_;
|
return escaped_val_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Escape every ";" or "\" character of <b>string</b>. Use
|
||||||
|
* <b>escape_char</b> as the character to use for escaping.
|
||||||
|
* The returned string is allocated on the heap and it's the
|
||||||
|
* responsibility of the caller to free it. */
|
||||||
|
char *
|
||||||
|
tor_escape_str_for_socks_arg(const char *string)
|
||||||
|
{
|
||||||
|
char *new_string = NULL;
|
||||||
|
char *new_cp = NULL;
|
||||||
|
size_t length, new_length;
|
||||||
|
static const char *chars_to_escape = ";\\";
|
||||||
|
|
||||||
|
tor_assert(string);
|
||||||
|
|
||||||
|
length = strlen(string);
|
||||||
|
|
||||||
|
if (!length) /* If we were given the empty string, return the same. */
|
||||||
|
return tor_strdup("");
|
||||||
|
/* (new_length > SIZE_MAX) => ((length * 2) + 1 > SIZE_MAX) =>
|
||||||
|
(length*2 > SIZE_MAX - 1) => (length > (SIZE_MAX - 1)/2) */
|
||||||
|
if (length > (SIZE_MAX - 1)/2) /* check for overflow */
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* this should be enough even if all characters must be escaped */
|
||||||
|
new_length = (length * 2) + 1;
|
||||||
|
|
||||||
|
new_string = new_cp = tor_malloc(new_length);
|
||||||
|
|
||||||
|
while (*string) {
|
||||||
|
if (strchr(chars_to_escape, *string))
|
||||||
|
*new_cp++ = '\\';
|
||||||
|
|
||||||
|
*new_cp++ = *string++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*new_cp = '\0'; /* NUL-terminate the new string */
|
||||||
|
|
||||||
|
return new_string;
|
||||||
|
}
|
||||||
|
|
||||||
/* =====
|
/* =====
|
||||||
* Time
|
* Time
|
||||||
* ===== */
|
* ===== */
|
||||||
|
@ -208,12 +208,16 @@ const char *find_whitespace_eos(const char *s, const char *eos);
|
|||||||
const char *find_str_at_start_of_line(const char *haystack,
|
const char *find_str_at_start_of_line(const char *haystack,
|
||||||
const char *needle);
|
const char *needle);
|
||||||
int string_is_C_identifier(const char *string);
|
int string_is_C_identifier(const char *string);
|
||||||
|
int string_is_key_value(int severity, const char *string);
|
||||||
|
|
||||||
int tor_mem_is_zero(const char *mem, size_t len);
|
int tor_mem_is_zero(const char *mem, size_t len);
|
||||||
int tor_digest_is_zero(const char *digest);
|
int tor_digest_is_zero(const char *digest);
|
||||||
int tor_digest256_is_zero(const char *digest);
|
int tor_digest256_is_zero(const char *digest);
|
||||||
char *esc_for_log(const char *string) ATTR_MALLOC;
|
char *esc_for_log(const char *string) ATTR_MALLOC;
|
||||||
const char *escaped(const char *string);
|
const char *escaped(const char *string);
|
||||||
|
|
||||||
|
char *tor_escape_str_for_socks_arg(const char *string);
|
||||||
|
|
||||||
struct smartlist_t;
|
struct smartlist_t;
|
||||||
int tor_vsscanf(const char *buf, const char *pattern, va_list ap)
|
int tor_vsscanf(const char *buf, const char *pattern, va_list ap)
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
|
160
src/or/config.c
160
src/or/config.c
@ -484,7 +484,6 @@ static int options_transition_affects_descriptor(
|
|||||||
const or_options_t *old_options, const or_options_t *new_options);
|
const or_options_t *old_options, const or_options_t *new_options);
|
||||||
static int check_nickname_list(const char *lst, const char *name, char **msg);
|
static int check_nickname_list(const char *lst, const char *name, char **msg);
|
||||||
|
|
||||||
static int parse_bridge_line(const char *line, int validate_only);
|
|
||||||
static int parse_client_transport_line(const char *line, int validate_only);
|
static int parse_client_transport_line(const char *line, int validate_only);
|
||||||
|
|
||||||
static int parse_server_transport_line(const char *line, int validate_only);
|
static int parse_server_transport_line(const char *line, int validate_only);
|
||||||
@ -1299,11 +1298,13 @@ options_act(const or_options_t *old_options)
|
|||||||
if (options->Bridges) {
|
if (options->Bridges) {
|
||||||
mark_bridge_list();
|
mark_bridge_list();
|
||||||
for (cl = options->Bridges; cl; cl = cl->next) {
|
for (cl = options->Bridges; cl; cl = cl->next) {
|
||||||
if (parse_bridge_line(cl->value, 0)<0) {
|
bridge_line_t *bridge_line = parse_bridge_line(cl->value);
|
||||||
|
if (!bridge_line) {
|
||||||
log_warn(LD_BUG,
|
log_warn(LD_BUG,
|
||||||
"Previously validated Bridge line could not be added!");
|
"Previously validated Bridge line could not be added!");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
bridge_add_from_config(bridge_line);
|
||||||
}
|
}
|
||||||
sweep_bridge_list();
|
sweep_bridge_list();
|
||||||
}
|
}
|
||||||
@ -2946,14 +2947,14 @@ options_validate(or_options_t *old_options, or_options_t *options,
|
|||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
len = strlen(options->Socks5ProxyUsername);
|
len = strlen(options->Socks5ProxyUsername);
|
||||||
if (len < 1 || len > 255)
|
if (len < 1 || len > MAX_SOCKS5_AUTH_FIELD_SIZE)
|
||||||
REJECT("Socks5ProxyUsername must be between 1 and 255 characters.");
|
REJECT("Socks5ProxyUsername must be between 1 and 255 characters.");
|
||||||
|
|
||||||
if (!options->Socks5ProxyPassword)
|
if (!options->Socks5ProxyPassword)
|
||||||
REJECT("Socks5ProxyPassword must be included with Socks5ProxyUsername.");
|
REJECT("Socks5ProxyPassword must be included with Socks5ProxyUsername.");
|
||||||
|
|
||||||
len = strlen(options->Socks5ProxyPassword);
|
len = strlen(options->Socks5ProxyPassword);
|
||||||
if (len < 1 || len > 255)
|
if (len < 1 || len > MAX_SOCKS5_AUTH_FIELD_SIZE)
|
||||||
REJECT("Socks5ProxyPassword must be between 1 and 255 characters.");
|
REJECT("Socks5ProxyPassword must be between 1 and 255 characters.");
|
||||||
} else if (options->Socks5ProxyPassword)
|
} else if (options->Socks5ProxyPassword)
|
||||||
REJECT("Socks5ProxyPassword must be included with Socks5ProxyUsername.");
|
REJECT("Socks5ProxyPassword must be included with Socks5ProxyUsername.");
|
||||||
@ -3037,8 +3038,10 @@ options_validate(or_options_t *old_options, or_options_t *options,
|
|||||||
REJECT("If you set UseBridges, you must set TunnelDirConns.");
|
REJECT("If you set UseBridges, you must set TunnelDirConns.");
|
||||||
|
|
||||||
for (cl = options->Bridges; cl; cl = cl->next) {
|
for (cl = options->Bridges; cl; cl = cl->next) {
|
||||||
if (parse_bridge_line(cl->value, 1)<0)
|
bridge_line_t *bridge_line = parse_bridge_line(cl->value);
|
||||||
|
if (!bridge_line)
|
||||||
REJECT("Bridge line did not parse. See logs for details.");
|
REJECT("Bridge line did not parse. See logs for details.");
|
||||||
|
bridge_line_free(bridge_line);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (cl = options->ClientTransportPlugin; cl; cl = cl->next) {
|
for (cl = options->ClientTransportPlugin; cl; cl = cl->next) {
|
||||||
@ -4096,21 +4099,72 @@ options_init_logs(or_options_t *options, int validate_only)
|
|||||||
return ok?0:-1;
|
return ok?0:-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Given a smartlist of SOCKS arguments to be passed to a transport
|
||||||
|
* proxy in <b>args</b>, validate them and return -1 if they are
|
||||||
|
* corrupted. Return 0 if they seem OK. */
|
||||||
|
static int
|
||||||
|
validate_transport_socks_arguments(const smartlist_t *args)
|
||||||
|
{
|
||||||
|
char *socks_string = NULL;
|
||||||
|
size_t socks_string_len;
|
||||||
|
|
||||||
|
tor_assert(args);
|
||||||
|
tor_assert(smartlist_len(args) > 0);
|
||||||
|
|
||||||
|
SMARTLIST_FOREACH_BEGIN(args, const char *, s) {
|
||||||
|
if (!string_is_key_value(LOG_WARN, s)) { /* items should be k=v items */
|
||||||
|
log_warn(LD_CONFIG, "'%s' is not a k=v item.", s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} SMARTLIST_FOREACH_END(s);
|
||||||
|
|
||||||
|
socks_string = pt_stringify_socks_args(args);
|
||||||
|
if (!socks_string)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
socks_string_len = strlen(socks_string);
|
||||||
|
tor_free(socks_string);
|
||||||
|
|
||||||
|
if (socks_string_len > MAX_SOCKS5_AUTH_SIZE_TOTAL) {
|
||||||
|
log_warn(LD_CONFIG, "SOCKS arguments can't be more than %u bytes (%lu).",
|
||||||
|
MAX_SOCKS5_AUTH_SIZE_TOTAL,
|
||||||
|
(unsigned long) socks_string_len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Deallocate a bridge_line_t structure. */
|
||||||
|
/* private */ void
|
||||||
|
bridge_line_free(bridge_line_t *bridge_line)
|
||||||
|
{
|
||||||
|
if (!bridge_line)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (bridge_line->socks_args) {
|
||||||
|
SMARTLIST_FOREACH(bridge_line->socks_args, char*, s, tor_free(s));
|
||||||
|
smartlist_free(bridge_line->socks_args);
|
||||||
|
}
|
||||||
|
tor_free(bridge_line->transport_name);
|
||||||
|
tor_free(bridge_line);
|
||||||
|
}
|
||||||
|
|
||||||
/** Read the contents of a Bridge line from <b>line</b>. Return 0
|
/** Read the contents of a Bridge line from <b>line</b>. Return 0
|
||||||
* if the line is well-formed, and -1 if it isn't. If
|
* if the line is well-formed, and -1 if it isn't. If
|
||||||
* <b>validate_only</b> is 0, and the line is well-formed, then add
|
* <b>validate_only</b> is 0, and the line is well-formed, then add
|
||||||
* the bridge described in the line to our internal bridge list. */
|
* the bridge described in the line to our internal bridge list.
|
||||||
static int
|
*
|
||||||
parse_bridge_line(const char *line, int validate_only)
|
* Bridge line format:
|
||||||
|
* Bridge [transport] IP:PORT [id-fingerprint] [k=v] [k=v] ...
|
||||||
|
*/
|
||||||
|
/* private */ bridge_line_t *
|
||||||
|
parse_bridge_line(const char *line)
|
||||||
{
|
{
|
||||||
smartlist_t *items = NULL;
|
smartlist_t *items = NULL;
|
||||||
int r;
|
|
||||||
char *addrport=NULL, *fingerprint=NULL;
|
char *addrport=NULL, *fingerprint=NULL;
|
||||||
char *transport_name=NULL;
|
char *field=NULL;
|
||||||
char *field1=NULL;
|
bridge_line_t *bridge_line = tor_malloc_zero(sizeof(bridge_line_t));
|
||||||
tor_addr_t addr;
|
|
||||||
uint16_t port = 0;
|
|
||||||
char digest[DIGEST_LEN];
|
|
||||||
|
|
||||||
items = smartlist_new();
|
items = smartlist_new();
|
||||||
smartlist_split_string(items, line, NULL,
|
smartlist_split_string(items, line, NULL,
|
||||||
@ -4120,68 +4174,102 @@ parse_bridge_line(const char *line, int validate_only)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* field1 is either a transport name or addrport */
|
/* first field is either a transport name or addrport */
|
||||||
field1 = smartlist_get(items, 0);
|
field = smartlist_get(items, 0);
|
||||||
smartlist_del_keeporder(items, 0);
|
smartlist_del_keeporder(items, 0);
|
||||||
|
|
||||||
if (!(strstr(field1, ".") || strstr(field1, ":"))) {
|
if (string_is_C_identifier(field)) {
|
||||||
/* new-style bridge line */
|
/* It's a transport name. */
|
||||||
transport_name = field1;
|
bridge_line->transport_name = field;
|
||||||
if (smartlist_len(items) < 1) {
|
if (smartlist_len(items) < 1) {
|
||||||
log_warn(LD_CONFIG, "Too few items to Bridge line.");
|
log_warn(LD_CONFIG, "Too few items to Bridge line.");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
addrport = smartlist_get(items, 0);
|
addrport = smartlist_get(items, 0); /* Next field is addrport then. */
|
||||||
smartlist_del_keeporder(items, 0);
|
smartlist_del_keeporder(items, 0);
|
||||||
} else {
|
} else {
|
||||||
addrport = field1;
|
addrport = field;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tor_addr_port_lookup(addrport, &addr, &port)<0) {
|
/* Parse addrport. */
|
||||||
|
if (tor_addr_port_lookup(addrport,
|
||||||
|
&bridge_line->addr, &bridge_line->port)<0) {
|
||||||
log_warn(LD_CONFIG, "Error parsing Bridge address '%s'", addrport);
|
log_warn(LD_CONFIG, "Error parsing Bridge address '%s'", addrport);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
if (!port) {
|
if (!bridge_line->port) {
|
||||||
log_info(LD_CONFIG,
|
log_info(LD_CONFIG,
|
||||||
"Bridge address '%s' has no port; using default port 443.",
|
"Bridge address '%s' has no port; using default port 443.",
|
||||||
addrport);
|
addrport);
|
||||||
port = 443;
|
bridge_line->port = 443;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If transports are enabled, next field could be a fingerprint or a
|
||||||
|
socks argument. If transports are disabled, next field must be
|
||||||
|
a fingerprint. */
|
||||||
if (smartlist_len(items)) {
|
if (smartlist_len(items)) {
|
||||||
|
if (bridge_line->transport_name) { /* transports enabled: */
|
||||||
|
field = smartlist_get(items, 0);
|
||||||
|
smartlist_del_keeporder(items, 0);
|
||||||
|
|
||||||
|
/* If it's a key=value pair, then it's a SOCKS argument for the
|
||||||
|
transport proxy... */
|
||||||
|
if (string_is_key_value(LOG_DEBUG, field)) {
|
||||||
|
bridge_line->socks_args = smartlist_new();
|
||||||
|
smartlist_add(bridge_line->socks_args, field);
|
||||||
|
} else { /* ...otherwise, it's the bridge fingerprint. */
|
||||||
|
fingerprint = field;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { /* transports disabled: */
|
||||||
fingerprint = smartlist_join_strings(items, "", 0, NULL);
|
fingerprint = smartlist_join_strings(items, "", 0, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle fingerprint, if it was provided. */
|
||||||
|
if (fingerprint) {
|
||||||
if (strlen(fingerprint) != HEX_DIGEST_LEN) {
|
if (strlen(fingerprint) != HEX_DIGEST_LEN) {
|
||||||
log_warn(LD_CONFIG, "Key digest for Bridge is wrong length.");
|
log_warn(LD_CONFIG, "Key digest for Bridge is wrong length.");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
if (base16_decode(digest, DIGEST_LEN, fingerprint, HEX_DIGEST_LEN)<0) {
|
if (base16_decode(bridge_line->digest, DIGEST_LEN,
|
||||||
|
fingerprint, HEX_DIGEST_LEN)<0) {
|
||||||
log_warn(LD_CONFIG, "Unable to decode Bridge key digest.");
|
log_warn(LD_CONFIG, "Unable to decode Bridge key digest.");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!validate_only) {
|
/* If we are using transports, any remaining items in the smartlist
|
||||||
log_debug(LD_DIR, "Bridge at %s (transport: %s) (%s)",
|
should be k=v values. */
|
||||||
fmt_addrport(&addr, port),
|
if (bridge_line->transport_name && smartlist_len(items)) {
|
||||||
transport_name ? transport_name : "no transport",
|
if (!bridge_line->socks_args)
|
||||||
fingerprint ? fingerprint : "no key listed");
|
bridge_line->socks_args = smartlist_new();
|
||||||
bridge_add_from_config(&addr, port,
|
|
||||||
fingerprint ? digest : NULL, transport_name);
|
/* append remaining items of 'items' to 'socks_args' */
|
||||||
|
smartlist_add_all(bridge_line->socks_args, items);
|
||||||
|
smartlist_clear(items);
|
||||||
|
|
||||||
|
tor_assert(smartlist_len(bridge_line->socks_args) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bridge_line->socks_args) {
|
||||||
|
if (validate_transport_socks_arguments(bridge_line->socks_args) < 0)
|
||||||
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = 0;
|
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
r = -1;
|
bridge_line_free(bridge_line);
|
||||||
|
bridge_line = NULL;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
SMARTLIST_FOREACH(items, char*, s, tor_free(s));
|
SMARTLIST_FOREACH(items, char*, s, tor_free(s));
|
||||||
smartlist_free(items);
|
smartlist_free(items);
|
||||||
tor_free(addrport);
|
tor_free(addrport);
|
||||||
tor_free(transport_name);
|
|
||||||
tor_free(fingerprint);
|
tor_free(fingerprint);
|
||||||
return r;
|
|
||||||
|
return bridge_line;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Read the contents of a ClientTransportPlugin line from
|
/** Read the contents of a ClientTransportPlugin line from
|
||||||
|
@ -98,5 +98,19 @@ int addressmap_register_auto(const char *from, const char *to,
|
|||||||
addressmap_entry_source_t addrmap_source,
|
addressmap_entry_source_t addrmap_source,
|
||||||
const char **msg);
|
const char **msg);
|
||||||
|
|
||||||
|
/** Represents the information stored in a torrc Bridge line. */
|
||||||
|
typedef struct bridge_line_t {
|
||||||
|
tor_addr_t addr; /* The IP address of the bridge. */
|
||||||
|
uint16_t port; /* The TCP port of the bridge. */
|
||||||
|
char *transport_name; /* The name of the pluggable transport that
|
||||||
|
should be used to connect to the bridge. */
|
||||||
|
char digest[DIGEST_LEN]; /* The bridge's identity key digest. */
|
||||||
|
smartlist_t *socks_args;; /* SOCKS arguments for the pluggable
|
||||||
|
transport proxy. */
|
||||||
|
} bridge_line_t;
|
||||||
|
|
||||||
|
void bridge_line_free(bridge_line_t *bridge_line);
|
||||||
|
bridge_line_t *parse_bridge_line(const char *line);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
#include "router.h"
|
#include "router.h"
|
||||||
#include "transports.h"
|
#include "transports.h"
|
||||||
#include "routerparse.h"
|
#include "routerparse.h"
|
||||||
|
#include "transports.h"
|
||||||
|
|
||||||
#ifdef USE_BUFFEREVENTS
|
#ifdef USE_BUFFEREVENTS
|
||||||
#include <event2/event.h>
|
#include <event2/event.h>
|
||||||
@ -1574,6 +1575,32 @@ connection_proxy_state_to_string(int state)
|
|||||||
return states[state];
|
return states[state];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the global proxy type used by tor. Use this function for
|
||||||
|
* logging or high-level purposes, don't use it to fill the
|
||||||
|
* <b>proxy_type</b> field of or_connection_t; use the actual proxy
|
||||||
|
* protocol instead.*/
|
||||||
|
static int
|
||||||
|
get_proxy_type(void)
|
||||||
|
{
|
||||||
|
const or_options_t *options = get_options();
|
||||||
|
|
||||||
|
if (options->HTTPSProxy)
|
||||||
|
return PROXY_CONNECT;
|
||||||
|
else if (options->Socks4Proxy)
|
||||||
|
return PROXY_SOCKS4;
|
||||||
|
else if (options->Socks5Proxy)
|
||||||
|
return PROXY_SOCKS5;
|
||||||
|
else if (options->ClientTransportPlugin)
|
||||||
|
return PROXY_PLUGGABLE;
|
||||||
|
else
|
||||||
|
return PROXY_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* One byte for the version, one for the command, two for the
|
||||||
|
port, and four for the addr... and, one more for the
|
||||||
|
username NUL: */
|
||||||
|
#define SOCKS4_STANDARD_BUFFER_SIZE (1 + 1 + 2 + 4 + 1)
|
||||||
|
|
||||||
/** Write a proxy request of <b>type</b> (socks4, socks5, https) to conn
|
/** Write a proxy request of <b>type</b> (socks4, socks5, https) to conn
|
||||||
* for conn->addr:conn->port, authenticating with the auth details given
|
* for conn->addr:conn->port, authenticating with the auth details given
|
||||||
* in the configuration (if available). SOCKS 5 and HTTP CONNECT proxies
|
* in the configuration (if available). SOCKS 5 and HTTP CONNECT proxies
|
||||||
@ -1628,17 +1655,45 @@ connection_proxy_connect(connection_t *conn, int type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case PROXY_SOCKS4: {
|
case PROXY_SOCKS4: {
|
||||||
unsigned char buf[9];
|
unsigned char *buf;
|
||||||
uint16_t portn;
|
uint16_t portn;
|
||||||
uint32_t ip4addr;
|
uint32_t ip4addr;
|
||||||
|
size_t buf_size = 0;
|
||||||
|
char *socks_args_string = NULL;
|
||||||
|
|
||||||
/* Send a SOCKS4 connect request with empty user id */
|
/* Send a SOCKS4 connect request */
|
||||||
|
|
||||||
if (tor_addr_family(&conn->addr) != AF_INET) {
|
if (tor_addr_family(&conn->addr) != AF_INET) {
|
||||||
log_warn(LD_NET, "SOCKS4 client is incompatible with IPv6");
|
log_warn(LD_NET, "SOCKS4 client is incompatible with IPv6");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ /* If we are here because we are trying to connect to a
|
||||||
|
pluggable transport proxy, check if we have any SOCKS
|
||||||
|
arguments to transmit. If we do, compress all arguments to
|
||||||
|
a single string in 'socks_args_string': */
|
||||||
|
|
||||||
|
if (get_proxy_type() == PROXY_PLUGGABLE) {
|
||||||
|
socks_args_string =
|
||||||
|
pt_get_socks_args_for_proxy_addrport(&conn->addr, conn->port);
|
||||||
|
if (socks_args_string)
|
||||||
|
log_debug(LD_NET, "Sending out '%s' as our SOCKS argument string.",
|
||||||
|
socks_args_string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /* Figure out the buffer size we need for the SOCKS message: */
|
||||||
|
|
||||||
|
buf_size = SOCKS4_STANDARD_BUFFER_SIZE;
|
||||||
|
|
||||||
|
/* If we have a SOCKS argument string, consider its size when
|
||||||
|
calculating the buffer size: */
|
||||||
|
if (socks_args_string)
|
||||||
|
buf_size += strlen(socks_args_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = tor_malloc_zero(buf_size);
|
||||||
|
|
||||||
ip4addr = tor_addr_to_ipv4n(&conn->addr);
|
ip4addr = tor_addr_to_ipv4n(&conn->addr);
|
||||||
portn = htons(conn->port);
|
portn = htons(conn->port);
|
||||||
|
|
||||||
@ -1646,9 +1701,23 @@ connection_proxy_connect(connection_t *conn, int type)
|
|||||||
buf[1] = SOCKS_COMMAND_CONNECT; /* command */
|
buf[1] = SOCKS_COMMAND_CONNECT; /* command */
|
||||||
memcpy(buf + 2, &portn, 2); /* port */
|
memcpy(buf + 2, &portn, 2); /* port */
|
||||||
memcpy(buf + 4, &ip4addr, 4); /* addr */
|
memcpy(buf + 4, &ip4addr, 4); /* addr */
|
||||||
buf[8] = 0; /* userid (empty) */
|
|
||||||
|
|
||||||
connection_write_to_buf((char *)buf, sizeof(buf), conn);
|
/* Next packet field is the userid. If we have pluggable
|
||||||
|
transport SOCKS arguments, we have to embed them
|
||||||
|
there. Otherwise, we use an empty userid. */
|
||||||
|
if (socks_args_string) { /* place the SOCKS args string: */
|
||||||
|
tor_assert(strlen(socks_args_string) > 0);
|
||||||
|
tor_assert(buf_size >=
|
||||||
|
SOCKS4_STANDARD_BUFFER_SIZE + strlen(socks_args_string));
|
||||||
|
strlcpy((char *)buf + 8, socks_args_string, buf_size - 8);
|
||||||
|
tor_free(socks_args_string);
|
||||||
|
} else {
|
||||||
|
buf[8] = 0; /* no userid */
|
||||||
|
}
|
||||||
|
|
||||||
|
connection_write_to_buf((char *)buf, buf_size, conn);
|
||||||
|
tor_free(buf);
|
||||||
|
|
||||||
conn->proxy_state = PROXY_SOCKS4_WANT_CONNECT_OK;
|
conn->proxy_state = PROXY_SOCKS4_WANT_CONNECT_OK;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1660,8 +1729,13 @@ connection_proxy_connect(connection_t *conn, int type)
|
|||||||
|
|
||||||
buf[0] = 5; /* version */
|
buf[0] = 5; /* version */
|
||||||
|
|
||||||
|
/* We have to use SOCKS5 authentication, if we have a
|
||||||
|
Socks5ProxyUsername or if we want to pass arguments to our
|
||||||
|
pluggable transport proxy: */
|
||||||
|
if ((options->Socks5ProxyUsername) ||
|
||||||
|
(get_proxy_type() == PROXY_PLUGGABLE &&
|
||||||
|
(get_socks_args_by_bridge_addrport(&conn->addr, conn->port)))) {
|
||||||
/* number of auth methods */
|
/* number of auth methods */
|
||||||
if (options->Socks5ProxyUsername) {
|
|
||||||
buf[1] = 2;
|
buf[1] = 2;
|
||||||
buf[2] = 0x00; /* no authentication */
|
buf[2] = 0x00; /* no authentication */
|
||||||
buf[3] = 0x02; /* rfc1929 Username/Passwd auth */
|
buf[3] = 0x02; /* rfc1929 Username/Passwd auth */
|
||||||
@ -1855,15 +1929,49 @@ connection_read_proxy_handshake(connection_t *conn)
|
|||||||
unsigned char buf[1024];
|
unsigned char buf[1024];
|
||||||
size_t reqsize, usize, psize;
|
size_t reqsize, usize, psize;
|
||||||
const char *user, *pass;
|
const char *user, *pass;
|
||||||
|
char *socks_args_string = NULL;
|
||||||
|
|
||||||
|
if (get_proxy_type() == PROXY_PLUGGABLE) {
|
||||||
|
socks_args_string =
|
||||||
|
pt_get_socks_args_for_proxy_addrport(&conn->addr, conn->port);
|
||||||
|
if (!socks_args_string) {
|
||||||
|
log_warn(LD_NET, "Could not create SOCKS args string.");
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug(LD_NET, "SOCKS5 arguments: %s", socks_args_string);
|
||||||
|
tor_assert(strlen(socks_args_string) > 0);
|
||||||
|
tor_assert(strlen(socks_args_string) <= MAX_SOCKS5_AUTH_SIZE_TOTAL);
|
||||||
|
|
||||||
|
if (strlen(socks_args_string) > MAX_SOCKS5_AUTH_FIELD_SIZE) {
|
||||||
|
user = socks_args_string;
|
||||||
|
usize = MAX_SOCKS5_AUTH_FIELD_SIZE;
|
||||||
|
pass = socks_args_string + MAX_SOCKS5_AUTH_FIELD_SIZE;
|
||||||
|
psize = strlen(socks_args_string) - MAX_SOCKS5_AUTH_FIELD_SIZE;
|
||||||
|
} else {
|
||||||
|
user = socks_args_string;
|
||||||
|
usize = strlen(socks_args_string);
|
||||||
|
pass = "\0";
|
||||||
|
psize = 1;
|
||||||
|
}
|
||||||
|
} else if (get_options()->Socks5ProxyUsername) {
|
||||||
user = get_options()->Socks5ProxyUsername;
|
user = get_options()->Socks5ProxyUsername;
|
||||||
pass = get_options()->Socks5ProxyPassword;
|
pass = get_options()->Socks5ProxyPassword;
|
||||||
tor_assert(user && pass);
|
tor_assert(user && pass);
|
||||||
|
|
||||||
/* XXX len of user and pass must be <= 255 !!! */
|
|
||||||
usize = strlen(user);
|
usize = strlen(user);
|
||||||
psize = strlen(pass);
|
psize = strlen(pass);
|
||||||
tor_assert(usize <= 255 && psize <= 255);
|
} else {
|
||||||
|
log_err(LD_BUG, "We entered %s for no reason!", __func__);
|
||||||
|
tor_fragile_assert();
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Username and password lengths should have been checked
|
||||||
|
above and during torrc parsing. */
|
||||||
|
tor_assert(usize <= MAX_SOCKS5_AUTH_FIELD_SIZE &&
|
||||||
|
psize <= MAX_SOCKS5_AUTH_FIELD_SIZE);
|
||||||
reqsize = 3 + usize + psize;
|
reqsize = 3 + usize + psize;
|
||||||
|
|
||||||
buf[0] = 1; /* negotiation version */
|
buf[0] = 1; /* negotiation version */
|
||||||
@ -1872,6 +1980,9 @@ connection_read_proxy_handshake(connection_t *conn)
|
|||||||
buf[2 + usize] = psize;
|
buf[2 + usize] = psize;
|
||||||
memcpy(buf + 3 + usize, pass, psize);
|
memcpy(buf + 3 + usize, pass, psize);
|
||||||
|
|
||||||
|
if (socks_args_string)
|
||||||
|
tor_free(socks_args_string);
|
||||||
|
|
||||||
connection_write_to_buf((char *)buf, reqsize, conn);
|
connection_write_to_buf((char *)buf, reqsize, conn);
|
||||||
|
|
||||||
conn->proxy_state = PROXY_SOCKS5_WANT_AUTH_RFC1929_OK;
|
conn->proxy_state = PROXY_SOCKS5_WANT_AUTH_RFC1929_OK;
|
||||||
@ -4338,7 +4449,7 @@ get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type,
|
|||||||
options->Bridges) {
|
options->Bridges) {
|
||||||
const transport_t *transport = NULL;
|
const transport_t *transport = NULL;
|
||||||
int r;
|
int r;
|
||||||
r = find_transport_by_bridge_addrport(&conn->addr, conn->port, &transport);
|
r = get_transport_by_bridge_addrport(&conn->addr, conn->port, &transport);
|
||||||
if (r<0)
|
if (r<0)
|
||||||
return -1;
|
return -1;
|
||||||
if (transport) { /* transport found */
|
if (transport) { /* transport found */
|
||||||
@ -4353,24 +4464,6 @@ get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the global proxy type used by tor. */
|
|
||||||
static int
|
|
||||||
get_proxy_type(void)
|
|
||||||
{
|
|
||||||
const or_options_t *options = get_options();
|
|
||||||
|
|
||||||
if (options->HTTPSProxy)
|
|
||||||
return PROXY_CONNECT;
|
|
||||||
else if (options->Socks4Proxy)
|
|
||||||
return PROXY_SOCKS4;
|
|
||||||
else if (options->Socks5Proxy)
|
|
||||||
return PROXY_SOCKS5;
|
|
||||||
else if (options->ClientTransportPlugin)
|
|
||||||
return PROXY_PLUGGABLE;
|
|
||||||
else
|
|
||||||
return PROXY_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Log a failed connection to a proxy server.
|
/** Log a failed connection to a proxy server.
|
||||||
* <b>conn</b> is the connection we use the proxy server for. */
|
* <b>conn</b> is the connection we use the proxy server for. */
|
||||||
void
|
void
|
||||||
|
@ -89,6 +89,14 @@ int connection_connect(connection_t *conn, const char *address,
|
|||||||
const tor_addr_t *addr,
|
const tor_addr_t *addr,
|
||||||
uint16_t port, int *socket_error);
|
uint16_t port, int *socket_error);
|
||||||
|
|
||||||
|
/** Maximum size of information that we can fit into SOCKS5 username
|
||||||
|
or password fields. */
|
||||||
|
#define MAX_SOCKS5_AUTH_FIELD_SIZE 255
|
||||||
|
|
||||||
|
/** Total maximum size of information that we can fit into SOCKS5
|
||||||
|
username and password fields. */
|
||||||
|
#define MAX_SOCKS5_AUTH_SIZE_TOTAL 2*MAX_SOCKS5_AUTH_FIELD_SIZE
|
||||||
|
|
||||||
int connection_proxy_connect(connection_t *conn, int type);
|
int connection_proxy_connect(connection_t *conn, int type);
|
||||||
int connection_read_proxy_handshake(connection_t *conn);
|
int connection_read_proxy_handshake(connection_t *conn);
|
||||||
void log_failed_proxy_connection(connection_t *conn);
|
void log_failed_proxy_connection(connection_t *conn);
|
||||||
|
@ -53,6 +53,10 @@ typedef struct {
|
|||||||
|
|
||||||
/** When should we next try to fetch a descriptor for this bridge? */
|
/** When should we next try to fetch a descriptor for this bridge? */
|
||||||
download_status_t fetch_status;
|
download_status_t fetch_status;
|
||||||
|
|
||||||
|
/** A smartlist of k=v values to be passed to the SOCKS proxy, if
|
||||||
|
transports are used for this bridge. */
|
||||||
|
smartlist_t *socks_args;
|
||||||
} bridge_info_t;
|
} bridge_info_t;
|
||||||
|
|
||||||
/** A list of our chosen entry guards. */
|
/** A list of our chosen entry guards. */
|
||||||
@ -1513,6 +1517,11 @@ bridge_free(bridge_info_t *bridge)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
tor_free(bridge->transport_name);
|
tor_free(bridge->transport_name);
|
||||||
|
if (bridge->socks_args) {
|
||||||
|
SMARTLIST_FOREACH(bridge->socks_args, char*, s, tor_free(s));
|
||||||
|
smartlist_free(bridge->socks_args);
|
||||||
|
}
|
||||||
|
|
||||||
tor_free(bridge);
|
tor_free(bridge);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1691,30 +1700,52 @@ bridge_resolve_conflicts(const tor_addr_t *addr, uint16_t port,
|
|||||||
} SMARTLIST_FOREACH_END(bridge);
|
} SMARTLIST_FOREACH_END(bridge);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Remember a new bridge at <b>addr</b>:<b>port</b>. If <b>digest</b>
|
/** Register the bridge information in <b>bridge_line</b> to the
|
||||||
* is set, it tells us the identity key too. If we already had the
|
* bridge subsystem. Steals reference of <b>bridge_line</b>. */
|
||||||
* bridge in our list, unmark it, and don't actually add anything new.
|
|
||||||
* If <b>transport_name</b> is non-NULL - the bridge is associated with a
|
|
||||||
* pluggable transport - we assign the transport to the bridge. */
|
|
||||||
void
|
void
|
||||||
bridge_add_from_config(const tor_addr_t *addr, uint16_t port,
|
bridge_add_from_config(bridge_line_t *bridge_line)
|
||||||
const char *digest, const char *transport_name)
|
|
||||||
{
|
{
|
||||||
bridge_info_t *b;
|
bridge_info_t *b;
|
||||||
|
|
||||||
bridge_resolve_conflicts(addr, port, digest, transport_name);
|
{ /* Log the bridge we are about to register: */
|
||||||
|
log_debug(LD_GENERAL, "Registering bridge at %s (transport: %s) (%s)",
|
||||||
|
fmt_addrport(&bridge_line->addr, bridge_line->port),
|
||||||
|
bridge_line->transport_name ?
|
||||||
|
bridge_line->transport_name : "no transport",
|
||||||
|
tor_digest_is_zero(bridge_line->digest) ?
|
||||||
|
"no key listed" : hex_str(bridge_line->digest, DIGEST_LEN));
|
||||||
|
|
||||||
|
if (bridge_line->socks_args) { /* print socks arguments */
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
tor_assert(smartlist_len(bridge_line->socks_args) > 0);
|
||||||
|
|
||||||
|
log_debug(LD_GENERAL, "Bridge uses %d SOCKS arguments:",
|
||||||
|
smartlist_len(bridge_line->socks_args));
|
||||||
|
SMARTLIST_FOREACH(bridge_line->socks_args, const char *, arg,
|
||||||
|
log_debug(LD_CONFIG, "%d: %s", ++i, arg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bridge_resolve_conflicts(&bridge_line->addr,
|
||||||
|
bridge_line->port,
|
||||||
|
bridge_line->digest,
|
||||||
|
bridge_line->transport_name);
|
||||||
|
|
||||||
b = tor_malloc_zero(sizeof(bridge_info_t));
|
b = tor_malloc_zero(sizeof(bridge_info_t));
|
||||||
tor_addr_copy(&b->addr, addr);
|
tor_addr_copy(&b->addr, &bridge_line->addr);
|
||||||
b->port = port;
|
b->port = bridge_line->port;
|
||||||
if (digest)
|
if (bridge_line->digest)
|
||||||
memcpy(b->identity, digest, DIGEST_LEN);
|
memcpy(b->identity, bridge_line->digest, DIGEST_LEN);
|
||||||
if (transport_name)
|
if (bridge_line->transport_name)
|
||||||
b->transport_name = tor_strdup(transport_name);
|
b->transport_name = bridge_line->transport_name;
|
||||||
b->fetch_status.schedule = DL_SCHED_BRIDGE;
|
b->fetch_status.schedule = DL_SCHED_BRIDGE;
|
||||||
|
b->socks_args = bridge_line->socks_args;
|
||||||
if (!bridge_list)
|
if (!bridge_list)
|
||||||
bridge_list = smartlist_new();
|
bridge_list = smartlist_new();
|
||||||
|
|
||||||
|
tor_free(bridge_line); /* Deallocate bridge_line now. */
|
||||||
|
|
||||||
smartlist_add(bridge_list, b);
|
smartlist_add(bridge_list, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1775,7 +1806,7 @@ find_transport_name_by_bridge_addrport(const tor_addr_t *addr, uint16_t port)
|
|||||||
* transport, but the transport could not be found.
|
* transport, but the transport could not be found.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
|
get_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
|
||||||
const transport_t **transport)
|
const transport_t **transport)
|
||||||
{
|
{
|
||||||
*transport = NULL;
|
*transport = NULL;
|
||||||
@ -1802,6 +1833,17 @@ find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Return a smartlist containing all the SOCKS arguments that we
|
||||||
|
* should pass to the SOCKS proxy. */
|
||||||
|
const smartlist_t *
|
||||||
|
get_socks_args_by_bridge_addrport(const tor_addr_t *addr, uint16_t port)
|
||||||
|
{
|
||||||
|
bridge_info_t *bridge = get_configured_bridge_by_addr_port_digest(addr,
|
||||||
|
port,
|
||||||
|
NULL);
|
||||||
|
return bridge ? bridge->socks_args : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/** We need to ask <b>bridge</b> for its server descriptor. */
|
/** We need to ask <b>bridge</b> for its server descriptor. */
|
||||||
static void
|
static void
|
||||||
launch_direct_bridge_descriptor_fetch(bridge_info_t *bridge)
|
launch_direct_bridge_descriptor_fetch(bridge_info_t *bridge)
|
||||||
|
@ -97,9 +97,8 @@ int routerinfo_is_a_configured_bridge(const routerinfo_t *ri);
|
|||||||
int node_is_a_configured_bridge(const node_t *node);
|
int node_is_a_configured_bridge(const node_t *node);
|
||||||
void learned_router_identity(const tor_addr_t *addr, uint16_t port,
|
void learned_router_identity(const tor_addr_t *addr, uint16_t port,
|
||||||
const char *digest);
|
const char *digest);
|
||||||
void bridge_add_from_config(const tor_addr_t *addr, uint16_t port,
|
struct bridge_line_t;
|
||||||
const char *digest,
|
void bridge_add_from_config(struct bridge_line_t *bridge_line);
|
||||||
const char *transport_name);
|
|
||||||
void retry_bridge_descriptor_fetch_directly(const char *digest);
|
void retry_bridge_descriptor_fetch_directly(const char *digest);
|
||||||
void fetch_bridge_descriptors(const or_options_t *options, time_t now);
|
void fetch_bridge_descriptors(const or_options_t *options, time_t now);
|
||||||
void learned_bridge_descriptor(routerinfo_t *ri, int from_cache);
|
void learned_bridge_descriptor(routerinfo_t *ri, int from_cache);
|
||||||
@ -109,13 +108,17 @@ int entries_known_but_down(const or_options_t *options);
|
|||||||
void entries_retry_all(const or_options_t *options);
|
void entries_retry_all(const or_options_t *options);
|
||||||
|
|
||||||
int any_bridge_supports_microdescriptors(void);
|
int any_bridge_supports_microdescriptors(void);
|
||||||
|
const smartlist_t *get_socks_args_by_bridge_addrport(const tor_addr_t *addr,
|
||||||
|
uint16_t port);
|
||||||
|
|
||||||
|
int any_bridges_dont_support_microdescriptors(void);
|
||||||
|
|
||||||
void entry_guards_free_all(void);
|
void entry_guards_free_all(void);
|
||||||
|
|
||||||
const char *find_transport_name_by_bridge_addrport(const tor_addr_t *addr,
|
const char *find_transport_name_by_bridge_addrport(const tor_addr_t *addr,
|
||||||
uint16_t port);
|
uint16_t port);
|
||||||
struct transport_t;
|
struct transport_t;
|
||||||
int find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
|
int get_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
|
||||||
const struct transport_t **transport);
|
const struct transport_t **transport);
|
||||||
|
|
||||||
int validate_pluggable_transports_config(void);
|
int validate_pluggable_transports_config(void);
|
||||||
|
@ -238,7 +238,9 @@ typedef enum {
|
|||||||
#define PROXY_SOCKS5 3
|
#define PROXY_SOCKS5 3
|
||||||
/* !!!! If there is ever a PROXY_* type over 2, we must grow the proxy_type
|
/* !!!! If there is ever a PROXY_* type over 2, we must grow the proxy_type
|
||||||
* field in or_connection_t */
|
* field in or_connection_t */
|
||||||
/* pluggable transports proxy type */
|
|
||||||
|
/* Pluggable transport proxy type. Don't use this in or_connection_t,
|
||||||
|
* instead use the actual underlying proxy type (see above). */
|
||||||
#define PROXY_PLUGGABLE 4
|
#define PROXY_PLUGGABLE 4
|
||||||
|
|
||||||
/* Proxy client handshake states */
|
/* Proxy client handshake states */
|
||||||
|
@ -95,6 +95,7 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "router.h"
|
#include "router.h"
|
||||||
#include "statefile.h"
|
#include "statefile.h"
|
||||||
|
#include "entrynodes.h"
|
||||||
|
|
||||||
static process_environment_t *
|
static process_environment_t *
|
||||||
create_managed_proxy_environment(const managed_proxy_t *mp);
|
create_managed_proxy_environment(const managed_proxy_t *mp);
|
||||||
@ -1420,6 +1421,57 @@ pt_get_extra_info_descriptor_string(void)
|
|||||||
return the_string;
|
return the_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Stringify the SOCKS arguments in <b>socks_args</b> according to
|
||||||
|
* 180_pluggable_transport.txt. The string is allocated on the heap
|
||||||
|
* and it's the responsibility of the caller to free it after use. */
|
||||||
|
char *
|
||||||
|
pt_stringify_socks_args(const smartlist_t *socks_args)
|
||||||
|
{
|
||||||
|
/* tmp place to store escaped socks arguments, so that we can
|
||||||
|
concatenate them up afterwards */
|
||||||
|
smartlist_t *sl_tmp = NULL;
|
||||||
|
char *escaped_string = NULL;
|
||||||
|
char *new_string = NULL;
|
||||||
|
|
||||||
|
tor_assert(socks_args);
|
||||||
|
tor_assert(smartlist_len(socks_args) > 0);
|
||||||
|
|
||||||
|
sl_tmp = smartlist_new();
|
||||||
|
|
||||||
|
SMARTLIST_FOREACH_BEGIN(socks_args, const char *, s) {
|
||||||
|
/* Escape ';' and '\'. */
|
||||||
|
escaped_string = tor_escape_str_for_socks_arg(s);
|
||||||
|
if (!escaped_string)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
smartlist_add(sl_tmp, escaped_string);
|
||||||
|
} SMARTLIST_FOREACH_END(s);
|
||||||
|
|
||||||
|
new_string = smartlist_join_strings(sl_tmp, ";", 0, NULL);
|
||||||
|
|
||||||
|
done:
|
||||||
|
SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s));
|
||||||
|
smartlist_free(sl_tmp);
|
||||||
|
|
||||||
|
return new_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return a string of the SOCKS arguments that we should pass to the
|
||||||
|
* pluggable transports proxy in <b>addr</b>:<b>port</b> according to
|
||||||
|
* 180_pluggable_transport.txt. The string is allocated on the heap
|
||||||
|
* and it's the responsibility of the caller to free it after use. */
|
||||||
|
char *
|
||||||
|
pt_get_socks_args_for_proxy_addrport(const tor_addr_t *addr, uint16_t port)
|
||||||
|
{
|
||||||
|
const smartlist_t *socks_args = NULL;
|
||||||
|
|
||||||
|
socks_args = get_socks_args_by_bridge_addrport(addr, port);
|
||||||
|
if (!socks_args)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return pt_stringify_socks_args(socks_args);
|
||||||
|
}
|
||||||
|
|
||||||
/** The tor config was read.
|
/** The tor config was read.
|
||||||
* Destroy all managed proxies that were marked by a previous call to
|
* Destroy all managed proxies that were marked by a previous call to
|
||||||
* prepare_proxy_list_for_config_read() and are not used by the new
|
* prepare_proxy_list_for_config_read() and are not used by the new
|
||||||
|
@ -55,6 +55,10 @@ void pt_prepare_proxy_list_for_config_read(void);
|
|||||||
void sweep_proxy_list(void);
|
void sweep_proxy_list(void);
|
||||||
|
|
||||||
smartlist_t *get_transport_proxy_ports(void);
|
smartlist_t *get_transport_proxy_ports(void);
|
||||||
|
char *pt_stringify_socks_args(const smartlist_t *socks_args);
|
||||||
|
|
||||||
|
char *pt_get_socks_args_for_proxy_addrport(const tor_addr_t *addr,
|
||||||
|
uint16_t port);
|
||||||
|
|
||||||
#ifdef PT_PRIVATE
|
#ifdef PT_PRIVATE
|
||||||
/** State of the managed proxy configuration protocol. */
|
/** State of the managed proxy configuration protocol. */
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
#include "confparse.h"
|
#include "confparse.h"
|
||||||
#include "connection_edge.h"
|
#include "connection_edge.h"
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "address.h"
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_config_addressmap(void *arg)
|
test_config_addressmap(void *arg)
|
||||||
@ -169,11 +171,159 @@ test_config_addressmap(void *arg)
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Test helper function: Make sure that a bridge line gets parsed
|
||||||
|
* properly. Also make sure that the resulting bridge_line_t structure
|
||||||
|
* has its fields set correctly. */
|
||||||
|
static void
|
||||||
|
good_bridge_line_test(const char *string, const char *test_addrport,
|
||||||
|
const char *test_digest, const char *test_transport,
|
||||||
|
const smartlist_t *test_socks_args)
|
||||||
|
{
|
||||||
|
char *tmp = NULL;
|
||||||
|
bridge_line_t *bridge_line = parse_bridge_line(string);
|
||||||
|
test_assert(bridge_line);
|
||||||
|
|
||||||
|
/* test addrport */
|
||||||
|
tmp = tor_strdup(fmt_addrport(&bridge_line->addr, bridge_line->port));
|
||||||
|
test_streq(test_addrport, tmp);
|
||||||
|
tor_free(tmp);
|
||||||
|
|
||||||
|
/* If we were asked to validate a digest, but we did not get a
|
||||||
|
digest after parsing, we failed. */
|
||||||
|
if (test_digest && tor_digest_is_zero(bridge_line->digest))
|
||||||
|
test_assert(0);
|
||||||
|
|
||||||
|
/* If we were not asked to validate a digest, and we got a digest
|
||||||
|
after parsing, we failed again. */
|
||||||
|
if (!test_digest && !tor_digest_is_zero(bridge_line->digest))
|
||||||
|
test_assert(0);
|
||||||
|
|
||||||
|
/* If we were asked to validate a digest, and we got a digest after
|
||||||
|
parsing, make sure it's correct. */
|
||||||
|
if (test_digest) {
|
||||||
|
tmp = tor_strdup(hex_str(bridge_line->digest, DIGEST_LEN));
|
||||||
|
tor_strlower(tmp);
|
||||||
|
test_streq(test_digest, tmp);
|
||||||
|
tor_free(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we were asked to validate a transport name, make sure tha it
|
||||||
|
matches with the transport name that was parsed. */
|
||||||
|
if (test_transport && !bridge_line->transport_name)
|
||||||
|
test_assert(0);
|
||||||
|
if (!test_transport && bridge_line->transport_name)
|
||||||
|
test_assert(0);
|
||||||
|
if (test_transport)
|
||||||
|
test_streq(test_transport, bridge_line->transport_name);
|
||||||
|
|
||||||
|
/* Validate the SOCKS argument smartlist. */
|
||||||
|
if (test_socks_args && !bridge_line->socks_args)
|
||||||
|
test_assert(0);
|
||||||
|
if (!test_socks_args && bridge_line->socks_args)
|
||||||
|
test_assert(0);
|
||||||
|
if (test_socks_args)
|
||||||
|
test_assert(smartlist_strings_eq(test_socks_args,
|
||||||
|
bridge_line->socks_args));
|
||||||
|
|
||||||
|
done:
|
||||||
|
tor_free(tmp);
|
||||||
|
bridge_line_free(bridge_line);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test helper function: Make sure that a bridge line is
|
||||||
|
* unparseable. */
|
||||||
|
static void
|
||||||
|
bad_bridge_line_test(const char *string)
|
||||||
|
{
|
||||||
|
bridge_line_t *bridge_line = parse_bridge_line(string);
|
||||||
|
test_assert(!bridge_line);
|
||||||
|
|
||||||
|
done:
|
||||||
|
bridge_line_free(bridge_line);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_config_parse_bridge_line(void *arg)
|
||||||
|
{
|
||||||
|
(void) arg;
|
||||||
|
good_bridge_line_test("192.0.2.1:4123",
|
||||||
|
"192.0.2.1:4123", NULL, NULL, NULL);
|
||||||
|
|
||||||
|
good_bridge_line_test("192.0.2.1",
|
||||||
|
"192.0.2.1:443", NULL, NULL, NULL);
|
||||||
|
|
||||||
|
good_bridge_line_test("transport [::1]",
|
||||||
|
"[::1]:443", NULL, "transport", NULL);
|
||||||
|
|
||||||
|
good_bridge_line_test("transport 192.0.2.1:12 "
|
||||||
|
"4352e58420e68f5e40bf7c74faddccd9d1349413",
|
||||||
|
"192.0.2.1:12",
|
||||||
|
"4352e58420e68f5e40bf7c74faddccd9d1349413",
|
||||||
|
"transport", NULL);
|
||||||
|
|
||||||
|
{
|
||||||
|
smartlist_t *sl_tmp = smartlist_new();
|
||||||
|
smartlist_add_asprintf(sl_tmp, "twoandtwo=five");
|
||||||
|
|
||||||
|
good_bridge_line_test("transport 192.0.2.1:12 "
|
||||||
|
"4352e58420e68f5e40bf7c74faddccd9d1349413 twoandtwo=five",
|
||||||
|
"192.0.2.1:12", "4352e58420e68f5e40bf7c74faddccd9d1349413",
|
||||||
|
"transport", sl_tmp);
|
||||||
|
|
||||||
|
SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s));
|
||||||
|
smartlist_free(sl_tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
smartlist_t *sl_tmp = smartlist_new();
|
||||||
|
smartlist_add_asprintf(sl_tmp, "twoandtwo=five");
|
||||||
|
smartlist_add_asprintf(sl_tmp, "z=z");
|
||||||
|
|
||||||
|
good_bridge_line_test("transport 192.0.2.1:12 twoandtwo=five z=z",
|
||||||
|
"192.0.2.1:12", NULL, "transport", sl_tmp);
|
||||||
|
|
||||||
|
SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s));
|
||||||
|
smartlist_free(sl_tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
good_bridge_line_test("192.0.2.1:1231 "
|
||||||
|
"4352e58420e68f5e40bf7c74faddccd9d1349413",
|
||||||
|
"192.0.2.1:1231",
|
||||||
|
"4352e58420e68f5e40bf7c74faddccd9d1349413",
|
||||||
|
NULL, NULL);
|
||||||
|
|
||||||
|
/* Empty line */
|
||||||
|
bad_bridge_line_test("");
|
||||||
|
/* bad transport name */
|
||||||
|
bad_bridge_line_test("tr$n_sp0r7 190.20.2.2");
|
||||||
|
/* weird ip address */
|
||||||
|
bad_bridge_line_test("a.b.c.d");
|
||||||
|
/* invalid fpr */
|
||||||
|
bad_bridge_line_test("2.2.2.2:1231 4352e58420e68f5e40bf7c74faddccd9d1349");
|
||||||
|
/* no k=v in the end */
|
||||||
|
bad_bridge_line_test("obfs2 2.2.2.2:1231 "
|
||||||
|
"4352e58420e68f5e40bf7c74faddccd9d1349413 what");
|
||||||
|
/* no addrport */
|
||||||
|
bad_bridge_line_test("asdw");
|
||||||
|
/* huge k=v value that can't fit in SOCKS fields */
|
||||||
|
bad_bridge_line_test(
|
||||||
|
"obfs2 2.2.2.2:1231 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||||
|
"aa=b");
|
||||||
|
}
|
||||||
|
|
||||||
#define CONFIG_TEST(name, flags) \
|
#define CONFIG_TEST(name, flags) \
|
||||||
{ #name, test_config_ ## name, flags, NULL, NULL }
|
{ #name, test_config_ ## name, flags, NULL, NULL }
|
||||||
|
|
||||||
struct testcase_t config_tests[] = {
|
struct testcase_t config_tests[] = {
|
||||||
CONFIG_TEST(addressmap, 0),
|
CONFIG_TEST(addressmap, 0),
|
||||||
|
CONFIG_TEST(parse_bridge_line, 0),
|
||||||
END_OF_TESTCASES
|
END_OF_TESTCASES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -796,6 +796,64 @@ test_util_expand_filename(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** Test tor_escape_str_for_socks_arg(). */
|
||||||
|
static void
|
||||||
|
test_util_escape_string_socks(void)
|
||||||
|
{
|
||||||
|
char *escaped_string = NULL;
|
||||||
|
|
||||||
|
/** Simple backslash escape. */
|
||||||
|
escaped_string = tor_escape_str_for_socks_arg("This is a backslash: \\");
|
||||||
|
test_assert(escaped_string);
|
||||||
|
test_streq(escaped_string, "This is a backslash: \\\\");
|
||||||
|
tor_free(escaped_string);
|
||||||
|
|
||||||
|
/** Simple semicolon escape. */
|
||||||
|
escaped_string = tor_escape_str_for_socks_arg("First rule: Do not use ;");
|
||||||
|
test_assert(escaped_string);
|
||||||
|
test_streq(escaped_string, "First rule: Do not use \\;");
|
||||||
|
tor_free(escaped_string);
|
||||||
|
|
||||||
|
/** Empty string. */
|
||||||
|
escaped_string = tor_escape_str_for_socks_arg("");
|
||||||
|
test_assert(escaped_string);
|
||||||
|
test_streq(escaped_string, "");
|
||||||
|
tor_free(escaped_string);
|
||||||
|
|
||||||
|
/** Escape all characters. */
|
||||||
|
escaped_string = tor_escape_str_for_socks_arg(";\\;\\");
|
||||||
|
test_assert(escaped_string);
|
||||||
|
test_streq(escaped_string, "\\;\\\\\\;\\\\");
|
||||||
|
tor_free(escaped_string);
|
||||||
|
|
||||||
|
escaped_string = tor_escape_str_for_socks_arg(";");
|
||||||
|
test_assert(escaped_string);
|
||||||
|
test_streq(escaped_string, "\\;");
|
||||||
|
tor_free(escaped_string);
|
||||||
|
|
||||||
|
done:
|
||||||
|
tor_free(escaped_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_util_string_is_key_value(void *ptr)
|
||||||
|
{
|
||||||
|
(void)ptr;
|
||||||
|
test_assert(string_is_key_value(LOG_WARN, "key=value"));
|
||||||
|
test_assert(string_is_key_value(LOG_WARN, "k=v"));
|
||||||
|
test_assert(string_is_key_value(LOG_WARN, "key="));
|
||||||
|
test_assert(string_is_key_value(LOG_WARN, "x="));
|
||||||
|
test_assert(string_is_key_value(LOG_WARN, "xx="));
|
||||||
|
test_assert(!string_is_key_value(LOG_WARN, "=value"));
|
||||||
|
test_assert(!string_is_key_value(LOG_WARN, "=x"));
|
||||||
|
test_assert(!string_is_key_value(LOG_WARN, "="));
|
||||||
|
|
||||||
|
/* ??? */
|
||||||
|
/* test_assert(!string_is_key_value(LOG_WARN, "===")); */
|
||||||
|
done:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
/** Test basic string functionality. */
|
/** Test basic string functionality. */
|
||||||
static void
|
static void
|
||||||
test_util_strmisc(void)
|
test_util_strmisc(void)
|
||||||
@ -3263,6 +3321,8 @@ struct testcase_t util_tests[] = {
|
|||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
UTIL_LEGACY(expand_filename),
|
UTIL_LEGACY(expand_filename),
|
||||||
#endif
|
#endif
|
||||||
|
UTIL_LEGACY(escape_string_socks),
|
||||||
|
UTIL_LEGACY(string_is_key_value),
|
||||||
UTIL_LEGACY(strmisc),
|
UTIL_LEGACY(strmisc),
|
||||||
UTIL_LEGACY(pow2),
|
UTIL_LEGACY(pow2),
|
||||||
UTIL_LEGACY(gzip),
|
UTIL_LEGACY(gzip),
|
||||||
|
Loading…
Reference in New Issue
Block a user