/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2019, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * @file relay_config.c * @brief Code to interpret the user's configuration of Tor's relay module. **/ #include "orconfig.h" #include "feature/relay/relay_config.h" #include "lib/encoding/confline.h" #include "lib/confmgt/confmgt.h" #include "lib/container/smartlist.h" #include "lib/process/setuid.h" /* Required for dirinfo_type_t in or_options_t */ #include "core/or/or.h" #include "app/config/config.h" #include "core/mainloop/connection.h" #include "core/or/port_cfg_st.h" #include "feature/relay/dns.h" #include "feature/relay/ext_orport.h" #include "feature/relay/routermode.h" /** Given a list of port_cfg_t in ports, check them for internal * consistency and warn as appropriate. On Unix-based OSes, set * *n_low_ports_out to the number of sub-1024 ports we will be * binding, and warn if we may be unable to re-bind after hibernation. */ static int check_server_ports(const smartlist_t *ports, const or_options_t *options, int *n_low_ports_out) { if (BUG(!ports)) return -1; if (BUG(!options)) return -1; if (BUG(!n_low_ports_out)) return -1; int n_orport_advertised = 0; int n_orport_advertised_ipv4 = 0; int n_orport_listeners = 0; int n_dirport_advertised = 0; int n_dirport_listeners = 0; int n_low_port = 0; int r = 0; SMARTLIST_FOREACH_BEGIN(ports, const port_cfg_t *, port) { if (port->type == CONN_TYPE_DIR_LISTENER) { if (! port->server_cfg.no_advertise) ++n_dirport_advertised; if (! port->server_cfg.no_listen) ++n_dirport_listeners; } else if (port->type == CONN_TYPE_OR_LISTENER) { if (! port->server_cfg.no_advertise) { ++n_orport_advertised; if (port_binds_ipv4(port)) ++n_orport_advertised_ipv4; } if (! port->server_cfg.no_listen) ++n_orport_listeners; } else { continue; } #ifndef _WIN32 if (!port->server_cfg.no_listen && port->port < 1024) ++n_low_port; #endif } SMARTLIST_FOREACH_END(port); if (n_orport_advertised && !n_orport_listeners) { log_warn(LD_CONFIG, "We are advertising an ORPort, but not actually " "listening on one."); r = -1; } if (n_orport_listeners && !n_orport_advertised) { log_warn(LD_CONFIG, "We are listening on an ORPort, but not advertising " "any ORPorts. This will keep us from building a %s " "descriptor, and make us impossible to use.", options->BridgeRelay ? "bridge" : "router"); r = -1; } if (n_dirport_advertised && !n_dirport_listeners) { log_warn(LD_CONFIG, "We are advertising a DirPort, but not actually " "listening on one."); r = -1; } if (n_dirport_advertised > 1) { log_warn(LD_CONFIG, "Can't advertise more than one DirPort."); r = -1; } if (n_orport_advertised && !n_orport_advertised_ipv4 && !options->BridgeRelay) { log_warn(LD_CONFIG, "Configured public relay to listen only on an IPv6 " "address. Tor needs to listen on an IPv4 address too."); r = -1; } if (n_low_port && options->AccountingMax && (!have_capability_support() || options->KeepBindCapabilities == 0)) { const char *extra = ""; if (options->KeepBindCapabilities == 0 && have_capability_support()) extra = ", and you have disabled KeepBindCapabilities."; log_warn(LD_CONFIG, "You have set AccountingMax to use hibernation. You have also " "chosen a low DirPort or OrPort%s." "This combination can make Tor stop " "working when it tries to re-attach the port after a period of " "hibernation. Please choose a different port or turn off " "hibernation unless you know this combination will work on your " "platform.", extra); } if (n_low_ports_out) *n_low_ports_out = n_low_port; return r; } /** Parse all relay ports from options. On success, add parsed ports to * ports, and return 0. On failure, set *msg to a description * of the problem and return -1. **/ int parse_ports_relay(or_options_t *options, char **msg, smartlist_t *ports_out, int *have_low_ports_out) { int retval = -1; smartlist_t *ports = smartlist_new(); if (BUG(!options)) goto err; if (BUG(!msg)) goto err; if (BUG(!ports_out)) goto err; if (BUG(!have_low_ports_out)) goto err; if (! options->ClientOnly) { if (parse_port_config(ports, options->ORPort_lines, "OR", CONN_TYPE_OR_LISTENER, "0.0.0.0", 0, CL_PORT_SERVER_OPTIONS) < 0) { *msg = tor_strdup("Invalid ORPort configuration"); goto err; } if (parse_port_config(ports, options->ExtORPort_lines, "ExtOR", CONN_TYPE_EXT_OR_LISTENER, "127.0.0.1", 0, CL_PORT_SERVER_OPTIONS|CL_PORT_WARN_NONLOCAL) < 0) { *msg = tor_strdup("Invalid ExtORPort configuration"); goto err; } if (parse_port_config(ports, options->DirPort_lines, "Dir", CONN_TYPE_DIR_LISTENER, "0.0.0.0", 0, CL_PORT_SERVER_OPTIONS) < 0) { *msg = tor_strdup("Invalid DirPort configuration"); goto err; } } int n_low_ports = 0; if (check_server_ports(ports, options, &n_low_ports) < 0) { *msg = tor_strdup("Misconfigured server ports"); goto err; } if (*have_low_ports_out < 0) *have_low_ports_out = (n_low_ports > 0); smartlist_add_all(ports_out, ports); smartlist_free(ports); ports = NULL; retval = 0; err: if (ports) { SMARTLIST_FOREACH(ports, port_cfg_t *, p, port_cfg_free(p)); smartlist_free(ports); } return retval; } /** Update the relay *Port_set values in options from ports. */ void update_port_set_relay(or_options_t *options, const smartlist_t *ports) { if (BUG(!options)) return; if (BUG(!ports)) return; /* Update the relay *Port_set options. The !! here is to force a boolean * out of an integer. */ options->ORPort_set = !! count_real_listeners(ports, CONN_TYPE_OR_LISTENER, 0); options->DirPort_set = !! count_real_listeners(ports, CONN_TYPE_DIR_LISTENER, 0); options->ExtORPort_set = !! count_real_listeners(ports, CONN_TYPE_EXT_OR_LISTENER, 0); }