diff --git a/src/or/config.c b/src/or/config.c
index 31695baa73..3e7535966c 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -4036,10 +4036,11 @@ parse_bridge_line(const char *line, int validate_only)
int r;
char *addrport=NULL, *fingerprint=NULL;
char *transport_name=NULL;
- char *field1=NULL;
+ char *field=NULL;
tor_addr_t addr;
uint16_t port = 0;
char digest[DIGEST_LEN];
+ smartlist_t *socks_args = NULL;
items = smartlist_new();
smartlist_split_string(items, line, NULL,
@@ -4049,13 +4050,13 @@ parse_bridge_line(const char *line, int validate_only)
goto err;
}
- /* field1 is either a transport name or addrport */
- field1 = smartlist_get(items, 0);
+ /* field is either a transport name or addrport */
+ field = smartlist_get(items, 0);
smartlist_del_keeporder(items, 0);
- if (!(strstr(field1, ".") || strstr(field1, ":"))) {
+ if (!(strstr(field, ".") || strstr(field, ":"))) {
/* new-style bridge line */
- transport_name = field1;
+ transport_name = field;
if (smartlist_len(items) < 1) {
log_warn(LD_CONFIG, "Too few items to Bridge line.");
goto err;
@@ -4063,7 +4064,7 @@ parse_bridge_line(const char *line, int validate_only)
addrport = smartlist_get(items, 0);
smartlist_del_keeporder(items, 0);
} else {
- addrport = field1;
+ addrport = field;
}
if (tor_addr_port_lookup(addrport, &addr, &port)<0) {
@@ -4077,8 +4078,28 @@ parse_bridge_line(const char *line, int validate_only)
port = 443;
}
+ /* If transports are enabled, next field could be a fingerprint or a
+ socks argument. If transports are disabled, next field should be
+ a fingerprint. */
if (smartlist_len(items)) {
- fingerprint = smartlist_join_strings(items, "", 0, NULL);
+ if (transport_name) { /* transports enabled: */
+ field = smartlist_get(items, 0);
+ smartlist_del_keeporder(items, 0);
+
+ /* If '=', it's a k=v value pair. */
+ if (strchr(field, '=')) {
+ socks_args = smartlist_new();
+ smartlist_add(socks_args, field);
+ } else { /* If no '=', it's the fingerprint. */
+ fingerprint = field;
+ }
+
+ } else { /* transports disabled: */
+ fingerprint = smartlist_join_strings(items, "", 0, NULL);
+ }
+ }
+
+ if (fingerprint) {
if (strlen(fingerprint) != HEX_DIGEST_LEN) {
log_warn(LD_CONFIG, "Key digest for Bridge is wrong length.");
goto err;
@@ -4089,13 +4110,39 @@ parse_bridge_line(const char *line, int validate_only)
}
}
+ /* If we are using transports, any remaining items in the smartlist
+ must be k=v values. */
+ if (transport_name && smartlist_len(items)) {
+ if (!socks_args)
+ socks_args = smartlist_new();
+
+ /* append remaining items of 'items' to 'socks_args' */
+ smartlist_add_all(socks_args, items);
+ smartlist_clear(items);
+
+ tor_assert(smartlist_len(socks_args) > 0);
+ }
+
if (!validate_only) {
log_debug(LD_DIR, "Bridge at %s (transport: %s) (%s)",
fmt_addrport(&addr, port),
transport_name ? transport_name : "no transport",
fingerprint ? fingerprint : "no key listed");
+
+ if (socks_args) { /* print socks arguments */
+ int i = 0;
+
+ tor_assert(smartlist_len(socks_args) > 0);
+
+ log_debug(LD_DIR, "Bridge uses %d SOCKS arguments:",
+ smartlist_len(socks_args));
+ SMARTLIST_FOREACH(socks_args, const char *, arg,
+ log_debug(LD_CONFIG, "%d: %s", ++i, arg));
+ }
+
bridge_add_from_config(&addr, port,
- fingerprint ? digest : NULL, transport_name);
+ fingerprint ? digest : NULL,
+ transport_name, socks_args);
}
r = 0;
@@ -4110,6 +4157,14 @@ parse_bridge_line(const char *line, int validate_only)
tor_free(addrport);
tor_free(transport_name);
tor_free(fingerprint);
+
+ /* We only have to free socks_args if we are validating, since
+ otherwise bridge_add_from_config() steals its reference. */
+ if (socks_args && validate_only) {
+ SMARTLIST_FOREACH(socks_args, char*, s, tor_free(s));
+ smartlist_free(socks_args);
+ }
+
return r;
}
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 4ca56cbacf..63545ce9b8 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -52,6 +52,10 @@ typedef struct {
/** When should we next try to fetch a descriptor for this bridge? */
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;
/** A list of our chosen entry guards. */
@@ -1446,6 +1450,11 @@ bridge_free(bridge_info_t *bridge)
return;
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);
}
@@ -1628,10 +1637,16 @@ bridge_resolve_conflicts(const tor_addr_t *addr, uint16_t port,
* is set, it tells us the identity key too. If we already had the
* bridge in our list, unmark it, and don't actually add anything new.
* If transport_name is non-NULL - the bridge is associated with a
- * pluggable transport - we assign the transport to the bridge. */
+ * pluggable transport - we assign the transport to the bridge.
+ * If transport_name is non-NULL - the bridge is associated
+ * with a pluggable transport - we assign the transport to the bridge.
+ * If socks_args is non-NULL, it's a smartlist carrying
+ * key=value pairs to be passed to the pluggable transports
+ * proxy. This function steals reference of the smartlist. */
void
bridge_add_from_config(const tor_addr_t *addr, uint16_t port,
- const char *digest, const char *transport_name)
+ const char *digest, const char *transport_name,
+ smartlist_t *socks_args)
{
bridge_info_t *b;
@@ -1645,6 +1660,7 @@ bridge_add_from_config(const tor_addr_t *addr, uint16_t port,
if (transport_name)
b->transport_name = tor_strdup(transport_name);
b->fetch_status.schedule = DL_SCHED_BRIDGE;
+ b->socks_args = socks_args;
if (!bridge_list)
bridge_list = smartlist_new();
diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h
index b673d02681..6865231f57 100644
--- a/src/or/entrynodes.h
+++ b/src/or/entrynodes.h
@@ -97,9 +97,11 @@ int routerinfo_is_a_configured_bridge(const routerinfo_t *ri);
int node_is_a_configured_bridge(const node_t *node);
void learned_router_identity(const tor_addr_t *addr, uint16_t port,
const char *digest);
+struct smartlist_t;
void bridge_add_from_config(const tor_addr_t *addr, uint16_t port,
const char *digest,
- const char *transport_name);
+ const char *transport_name,
+ struct smartlist_t *socks_args);
void retry_bridge_descriptor_fetch_directly(const char *digest);
void fetch_bridge_descriptors(const or_options_t *options, time_t now);
void learned_bridge_descriptor(routerinfo_t *ri, int from_cache);