2019-10-29 07:25:08 +01:00
|
|
|
/* Copyright (c) 2001 Matej Pfajfar.
|
|
|
|
* Copyright (c) 2001-2004, Roger Dingledine.
|
|
|
|
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
2021-03-12 17:39:23 +01:00
|
|
|
* Copyright (c) 2007-2021, The Tor Project, Inc. */
|
2019-10-29 07:25:08 +01:00
|
|
|
/* See LICENSE for licensing information */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @file transport_config.c
|
|
|
|
* @brief Code to interpret the user's configuration of Tor's server
|
|
|
|
* pluggable transports.
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include "orconfig.h"
|
2019-10-30 15:18:22 +01:00
|
|
|
#define RELAY_TRANSPORT_CONFIG_PRIVATE
|
2019-10-29 07:25:08 +01:00
|
|
|
#include "feature/relay/transport_config.h"
|
|
|
|
|
|
|
|
#include "lib/encoding/confline.h"
|
|
|
|
#include "lib/encoding/keyval.h"
|
|
|
|
|
|
|
|
#include "lib/container/smartlist.h"
|
|
|
|
|
|
|
|
/* Required for dirinfo_type_t in or_options_t */
|
|
|
|
#include "core/or/or.h"
|
|
|
|
#include "app/config/config.h"
|
|
|
|
|
|
|
|
#include "feature/relay/ext_orport.h"
|
|
|
|
#include "feature/relay/routermode.h"
|
|
|
|
|
|
|
|
/* Copied from config.c, we will refactor later in 29211. */
|
|
|
|
#define REJECT(arg) \
|
|
|
|
STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END
|
|
|
|
|
|
|
|
/** Given a ServerTransportListenAddr <b>line</b>, return its
|
|
|
|
* <address:port> string. Return NULL if the line was not
|
|
|
|
* well-formed.
|
|
|
|
*
|
|
|
|
* If <b>transport</b> is set, return NULL if the line is not
|
|
|
|
* referring to <b>transport</b>.
|
|
|
|
*
|
|
|
|
* The returned string is allocated on the heap and it's the
|
|
|
|
* responsibility of the caller to free it. */
|
|
|
|
static char *
|
2019-10-31 03:28:07 +01:00
|
|
|
get_bindaddr_from_transport_listen_line(const char *line,
|
|
|
|
const char *transport)
|
2019-10-29 07:25:08 +01:00
|
|
|
{
|
|
|
|
smartlist_t *items = NULL;
|
|
|
|
const char *parsed_transport = NULL;
|
|
|
|
char *addrport = NULL;
|
|
|
|
tor_addr_t addr;
|
|
|
|
uint16_t port = 0;
|
|
|
|
|
|
|
|
items = smartlist_new();
|
|
|
|
smartlist_split_string(items, line, NULL,
|
|
|
|
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
|
|
|
|
|
|
|
|
if (smartlist_len(items) < 2) {
|
|
|
|
log_warn(LD_CONFIG,"Too few arguments on ServerTransportListenAddr line.");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
parsed_transport = smartlist_get(items, 0);
|
|
|
|
addrport = tor_strdup(smartlist_get(items, 1));
|
|
|
|
|
|
|
|
/* If 'transport' is given, check if it matches the one on the line */
|
|
|
|
if (transport && strcmp(transport, parsed_transport))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
/* Validate addrport */
|
|
|
|
if (tor_addr_port_parse(LOG_WARN, addrport, &addr, &port, -1)<0) {
|
|
|
|
log_warn(LD_CONFIG, "Error parsing ServerTransportListenAddr "
|
|
|
|
"address '%s'", addrport);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
err:
|
|
|
|
tor_free(addrport);
|
|
|
|
addrport = NULL;
|
|
|
|
|
|
|
|
done:
|
|
|
|
SMARTLIST_FOREACH(items, char*, s, tor_free(s));
|
|
|
|
smartlist_free(items);
|
|
|
|
|
|
|
|
return addrport;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Given the name of a pluggable transport in <b>transport</b>, check
|
|
|
|
* the configuration file to see if the user has explicitly asked for
|
|
|
|
* it to listen on a specific port. Return a <address:port> string if
|
|
|
|
* so, otherwise NULL. */
|
|
|
|
char *
|
2019-11-05 02:28:57 +01:00
|
|
|
pt_get_bindaddr_from_config(const char *transport)
|
2019-10-29 07:25:08 +01:00
|
|
|
{
|
|
|
|
config_line_t *cl;
|
|
|
|
const or_options_t *options = get_options();
|
|
|
|
|
|
|
|
for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) {
|
|
|
|
char *bindaddr =
|
|
|
|
get_bindaddr_from_transport_listen_line(cl->value, transport);
|
|
|
|
if (bindaddr)
|
|
|
|
return bindaddr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Given a ServerTransportOptions <b>line</b>, return a smartlist
|
|
|
|
* with the options. Return NULL if the line was not well-formed.
|
|
|
|
*
|
|
|
|
* If <b>transport</b> is set, return NULL if the line is not
|
|
|
|
* referring to <b>transport</b>.
|
|
|
|
*
|
|
|
|
* The returned smartlist and its strings are allocated on the heap
|
|
|
|
* and it's the responsibility of the caller to free it. */
|
2019-10-30 15:18:22 +01:00
|
|
|
STATIC smartlist_t *
|
2019-10-31 03:28:07 +01:00
|
|
|
get_options_from_transport_options_line(const char *line,
|
|
|
|
const char *transport)
|
2019-10-29 07:25:08 +01:00
|
|
|
{
|
|
|
|
smartlist_t *items = smartlist_new();
|
2019-10-31 03:28:07 +01:00
|
|
|
smartlist_t *pt_options = smartlist_new();
|
2019-10-29 07:25:08 +01:00
|
|
|
const char *parsed_transport = NULL;
|
|
|
|
|
|
|
|
smartlist_split_string(items, line, NULL,
|
|
|
|
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
|
|
|
|
|
|
|
|
if (smartlist_len(items) < 2) {
|
|
|
|
log_warn(LD_CONFIG,"Too few arguments on ServerTransportOptions line.");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
parsed_transport = smartlist_get(items, 0);
|
|
|
|
/* If 'transport' is given, check if it matches the one on the line */
|
|
|
|
if (transport && strcmp(transport, parsed_transport))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
SMARTLIST_FOREACH_BEGIN(items, const char *, option) {
|
|
|
|
if (option_sl_idx == 0) /* skip the transport field (first field)*/
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* validate that it's a k=v value */
|
|
|
|
if (!string_is_key_value(LOG_WARN, option)) {
|
|
|
|
log_warn(LD_CONFIG, "%s is not a k=v value.", escaped(option));
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add it to the options smartlist */
|
2019-10-31 03:28:07 +01:00
|
|
|
smartlist_add_strdup(pt_options, option);
|
2019-10-29 07:25:08 +01:00
|
|
|
log_debug(LD_CONFIG, "Added %s to the list of options", escaped(option));
|
|
|
|
} SMARTLIST_FOREACH_END(option);
|
|
|
|
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
err:
|
2019-10-31 03:28:07 +01:00
|
|
|
SMARTLIST_FOREACH(pt_options, char*, s, tor_free(s));
|
|
|
|
smartlist_free(pt_options);
|
|
|
|
pt_options = NULL;
|
2019-10-29 07:25:08 +01:00
|
|
|
|
|
|
|
done:
|
|
|
|
SMARTLIST_FOREACH(items, char*, s, tor_free(s));
|
|
|
|
smartlist_free(items);
|
|
|
|
|
2019-10-31 03:28:07 +01:00
|
|
|
return pt_options;
|
2019-10-29 07:25:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Given the name of a pluggable transport in <b>transport</b>, check
|
|
|
|
* the configuration file to see if the user has asked us to pass any
|
|
|
|
* parameters to the pluggable transport. Return a smartlist
|
|
|
|
* containing the parameters, otherwise NULL. */
|
|
|
|
smartlist_t *
|
2019-11-05 02:28:57 +01:00
|
|
|
pt_get_options_for_server_transport(const char *transport)
|
2019-10-29 07:25:08 +01:00
|
|
|
{
|
|
|
|
config_line_t *cl;
|
|
|
|
const or_options_t *options = get_options();
|
|
|
|
|
|
|
|
for (cl = options->ServerTransportOptions; cl; cl = cl->next) {
|
|
|
|
smartlist_t *options_sl =
|
|
|
|
get_options_from_transport_options_line(cl->value, transport);
|
|
|
|
if (options_sl)
|
|
|
|
return options_sl;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Legacy validation/normalization function for the server transport options.
|
|
|
|
* Uses old_options as the previous options.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, returns -1 and sets *msg to a newly allocated string
|
|
|
|
* on error.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
options_validate_server_transport(const or_options_t *old_options,
|
|
|
|
or_options_t *options,
|
|
|
|
char **msg)
|
|
|
|
{
|
|
|
|
(void)old_options;
|
|
|
|
|
|
|
|
if (BUG(!options))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (BUG(!msg))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
config_line_t *cl;
|
|
|
|
|
|
|
|
if (options->ServerTransportPlugin && !server_mode(options)) {
|
|
|
|
log_notice(LD_GENERAL, "Tor is not configured as a relay but you specified"
|
|
|
|
" a ServerTransportPlugin line (%s). The ServerTransportPlugin "
|
|
|
|
"line will be ignored.",
|
|
|
|
escaped(options->ServerTransportPlugin->value));
|
|
|
|
}
|
|
|
|
|
2019-10-31 03:28:07 +01:00
|
|
|
if (options->ServerTransportListenAddr && !options->ServerTransportPlugin) {
|
|
|
|
log_notice(LD_GENERAL, "You need at least a single managed-proxy to "
|
|
|
|
"specify a transport listen address. The "
|
|
|
|
"ServerTransportListenAddr line will be ignored.");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (cl = options->ServerTransportPlugin; cl; cl = cl->next) {
|
2019-11-05 02:28:57 +01:00
|
|
|
if (pt_parse_transport_line(options, cl->value, 1, 1) < 0)
|
2019-10-31 03:28:07 +01:00
|
|
|
REJECT("Invalid server transport line. See logs for details.");
|
|
|
|
}
|
|
|
|
|
2019-10-29 07:25:08 +01:00
|
|
|
for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) {
|
|
|
|
/** If get_bindaddr_from_transport_listen_line() fails with
|
|
|
|
'transport' being NULL, it means that something went wrong
|
|
|
|
while parsing the ServerTransportListenAddr line. */
|
|
|
|
char *bindaddr = get_bindaddr_from_transport_listen_line(cl->value, NULL);
|
|
|
|
if (!bindaddr)
|
|
|
|
REJECT("ServerTransportListenAddr did not parse. See logs for details.");
|
|
|
|
tor_free(bindaddr);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (cl = options->ServerTransportOptions; cl; cl = cl->next) {
|
|
|
|
/** If get_options_from_transport_options_line() fails with
|
|
|
|
'transport' being NULL, it means that something went wrong
|
|
|
|
while parsing the ServerTransportOptions line. */
|
|
|
|
smartlist_t *options_sl =
|
|
|
|
get_options_from_transport_options_line(cl->value, NULL);
|
|
|
|
if (!options_sl)
|
|
|
|
REJECT("ServerTransportOptions did not parse. See logs for details.");
|
|
|
|
|
|
|
|
SMARTLIST_FOREACH(options_sl, char *, cp, tor_free(cp));
|
|
|
|
smartlist_free(options_sl);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2019-10-30 04:55:49 +01:00
|
|
|
|
|
|
|
/** Fetch the active option list, and take server pluggable transport actions
|
|
|
|
* based on it. All of the things we do should survive being done repeatedly.
|
|
|
|
* If present, <b>old_options</b> contains the previous value of the options.
|
|
|
|
*
|
|
|
|
* Return 0 if all goes well, return -1 if it's time to die.
|
|
|
|
*
|
|
|
|
* Note: We haven't moved all the "act on new configuration" logic
|
|
|
|
* into the options_act* functions yet. Some is still in do_hup() and other
|
|
|
|
* places.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
options_act_server_transport(const or_options_t *old_options)
|
|
|
|
{
|
|
|
|
(void)old_options;
|
|
|
|
|
|
|
|
config_line_t *cl;
|
|
|
|
const or_options_t *options = get_options();
|
|
|
|
int running_tor = options->command == CMD_RUN_TOR;
|
|
|
|
|
|
|
|
/* If we are a bridge with a pluggable transport proxy but no
|
|
|
|
Extended ORPort, inform the user that they are missing out. */
|
2019-10-31 03:28:07 +01:00
|
|
|
if (options->ServerTransportPlugin &&
|
2019-10-30 04:55:49 +01:00
|
|
|
!options->ExtORPort_lines) {
|
|
|
|
log_notice(LD_CONFIG, "We use pluggable transports but the Extended "
|
|
|
|
"ORPort is disabled. Tor and your pluggable transports proxy "
|
|
|
|
"communicate with each other via the Extended ORPort so it "
|
|
|
|
"is suggested you enable it: it will also allow your Bridge "
|
|
|
|
"to collect statistics about its clients that use pluggable "
|
|
|
|
"transports. Please enable it using the ExtORPort torrc option "
|
|
|
|
"(e.g. set 'ExtORPort auto').");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we have an ExtORPort, initialize its auth cookie. */
|
|
|
|
if (running_tor &&
|
|
|
|
init_ext_or_cookie_authentication(!!options->ExtORPort_lines) < 0) {
|
|
|
|
log_warn(LD_CONFIG,"Error creating Extended ORPort cookie file.");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!options->DisableNetwork) {
|
2019-10-31 03:28:07 +01:00
|
|
|
if (options->ServerTransportPlugin) {
|
2019-10-30 04:55:49 +01:00
|
|
|
for (cl = options->ServerTransportPlugin; cl; cl = cl->next) {
|
2019-11-05 02:28:57 +01:00
|
|
|
if (pt_parse_transport_line(options, cl->value, 0, 1) < 0) {
|
2019-10-30 04:55:49 +01:00
|
|
|
// LCOV_EXCL_START
|
|
|
|
log_warn(LD_BUG,
|
|
|
|
"Previously validated ServerTransportPlugin line "
|
|
|
|
"could not be added!");
|
|
|
|
return -1;
|
|
|
|
// LCOV_EXCL_STOP
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|