#include "orconfig.h"
#define RELAY_TRANSPORT_CONFIG_PRIVATE
#include "feature/relay/transport_config.h"
#include "lib/encoding/confline.h"
#include "lib/encoding/keyval.h"
#include "lib/container/smartlist.h"
#include "core/or/or.h"
#include "app/config/config.h"
#include "feature/relay/ext_orport.h"
#include "feature/relay/routermode.h"
#define REJECT(arg) \
STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END
static char *
get_bindaddr_from_transport_listen_line(const char *line,
const char *transport)
{
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 && strcmp(transport, parsed_transport))
goto err;
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;
}
char *
pt_get_bindaddr_from_config(const char *transport)
{
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;
}
STATIC smartlist_t *
get_options_from_transport_options_line(const char *line,
const char *transport)
{
smartlist_t *items = smartlist_new();
smartlist_t *pt_options = smartlist_new();
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 && strcmp(transport, parsed_transport))
goto err;
SMARTLIST_FOREACH_BEGIN(items, const char *, option) {
if (option_sl_idx == 0)
continue;
if (!string_is_key_value(LOG_WARN, option)) {
log_warn(LD_CONFIG, "%s is not a k=v value.", escaped(option));
goto err;
}
smartlist_add_strdup(pt_options, option);
log_debug(LD_CONFIG, "Added %s to the list of options", escaped(option));
} SMARTLIST_FOREACH_END(option);
goto done;
err:
SMARTLIST_FOREACH(pt_options, char*, s, tor_free(s));
smartlist_free(pt_options);
pt_options = NULL;
done:
SMARTLIST_FOREACH(items, char*, s, tor_free(s));
smartlist_free(items);
return pt_options;
}
smartlist_t *
pt_get_options_for_server_transport(const char *transport)
{
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;
}
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));
}
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) {
if (pt_parse_transport_line(options, cl->value, 1, 1) < 0)
REJECT("Invalid server transport line. See logs for details.");
}
for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) {
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) {
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;
}
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 (options->ServerTransportPlugin &&
!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 (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) {
if (options->ServerTransportPlugin) {
for (cl = options->ServerTransportPlugin; cl; cl = cl->next) {
if (pt_parse_transport_line(options, cl->value, 0, 1) < 0) {
log_warn(LD_BUG,
"Previously validated ServerTransportPlugin line "
"could not be added!");
return -1;
}
}
}
}
return 0;
}