diff options
Diffstat (limited to 'src/or')
-rw-r--r-- | src/or/circuitbuild.c | 9 | ||||
-rw-r--r-- | src/or/config.c | 244 | ||||
-rw-r--r-- | src/or/config.h | 10 | ||||
-rw-r--r-- | src/or/confparse.c | 55 | ||||
-rw-r--r-- | src/or/confparse.h | 15 | ||||
-rw-r--r-- | src/or/control.c | 5 | ||||
-rw-r--r-- | src/or/dirvote.c | 14 | ||||
-rw-r--r-- | src/or/dirvote.h | 2 | ||||
-rw-r--r-- | src/or/main.c | 2 | ||||
-rw-r--r-- | src/or/microdesc.c | 1 | ||||
-rw-r--r-- | src/or/or.h | 5 | ||||
-rw-r--r-- | src/or/router.c | 81 | ||||
-rw-r--r-- | src/or/routerlist.c | 18 | ||||
-rw-r--r-- | src/or/routerlist.h | 2 | ||||
-rw-r--r-- | src/or/shared_random.c | 2 | ||||
-rw-r--r-- | src/or/shared_random_state.c | 5 | ||||
-rw-r--r-- | src/or/statefile.c | 3 |
17 files changed, 409 insertions, 64 deletions
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index b07ddab945..14d40150db 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -1770,6 +1770,8 @@ pick_tor2web_rendezvous_node(router_crn_flags_t flags, const node_t *rp_node = NULL; const int allow_invalid = (flags & CRN_ALLOW_INVALID) != 0; const int need_desc = (flags & CRN_NEED_DESC) != 0; + const int pref_addr = (flags & CRN_PREF_ADDR) != 0; + const int direct_conn = (flags & CRN_DIRECT_CONN) != 0; smartlist_t *whitelisted_live_rps = smartlist_new(); smartlist_t *all_live_nodes = smartlist_new(); @@ -1780,7 +1782,9 @@ pick_tor2web_rendezvous_node(router_crn_flags_t flags, router_add_running_nodes_to_smartlist(all_live_nodes, allow_invalid, 0, 0, 0, - need_desc, 0); + need_desc, + pref_addr, + direct_conn); /* Filter all_live_nodes to only add live *and* whitelisted RPs to * the list whitelisted_live_rps. */ @@ -2148,7 +2152,8 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state) const or_options_t *options = get_options(); /* If possible, choose an entry server with a preferred address, * otherwise, choose one with an allowed address */ - router_crn_flags_t flags = CRN_NEED_GUARD|CRN_NEED_DESC|CRN_PREF_ADDR; + router_crn_flags_t flags = (CRN_NEED_GUARD|CRN_NEED_DESC|CRN_PREF_ADDR| + CRN_DIRECT_CONN); const node_t *node; if (state && options->UseEntryGuards && diff --git a/src/or/config.c b/src/or/config.c index df85bc3534..31bf81877d 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -546,7 +546,7 @@ static const config_var_t testing_tor_network_defaults[] = { "0, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 16, 32, 60"), V(ClientBootstrapConsensusMaxDownloadTries, UINT, "80"), V(ClientBootstrapConsensusAuthorityOnlyMaxDownloadTries, UINT, "80"), - V(ClientDNSRejectInternalAddresses, BOOL,"0"), + V(ClientDNSRejectInternalAddresses, BOOL,"0"), // deprecated in 0.2.9.2-alpha V(ClientRejectInternalAddresses, BOOL, "0"), V(CountPrivateBandwidth, BOOL, "1"), V(ExitPolicyRejectPrivate, BOOL, "0"), @@ -589,6 +589,45 @@ static const config_var_t testing_tor_network_defaults[] = { #undef V #undef OBSOLETE +static const config_deprecation_t option_deprecation_notes_[] = { + /* Deprecated since 0.2.9.2-alpha... */ + { "AllowDotExit", "Unrestricted use of the .exit notation can be used for " + "a wide variety of application-level attacks." }, + { "AllowInvalidNodes", "There is no reason to enable this option; at best " + "it will make you easier to track." }, + { "AllowSingleHopCircuits", "Almost no relays actually allow single-hop " + "exits, making this option pointless." }, + { "AllowSingleHopExits", "Turning this on will make your relay easier " + "to abuse." }, + { "ClientDNSRejectInternalAddresses", "Turning this on makes your client " + "easier to fingerprint, and may open you to esoteric attacks." }, + { "ExcludeSingleHopRelays", "Turning it on makes your client easier to " + "fingerprint." }, + { "FastFirstHopPK", "Changing this option does not make your client more " + "secure, but does make it easier to fingerprint." }, + { "CloseHSClientCircuitsImmediatelyOnTimeout", "This option makes your " + "client easier to fingerprint." }, + { "CloseHSServiceRendCircuitsImmediatelyOnTimeout", "This option makes " + "your hidden services easier to fingerprint." }, + { "WarnUnsafeSocks", "Changing this option makes it easier for you " + "to accidentally lose your anonymity by leaking DNS information" }, + { "TLSECGroup", "The default is a nice secure choice; the other option " + "is less secure." }, + { "UseNTorHandshake", "The ntor handshake should always be used." }, + { "ControlListenAddress", "Use ControlPort instead." }, + { "DirListenAddress", "Use DirPort instead, possibly with the " + "NoAdvertise sub-option" }, + { "DNSListenAddress", "Use DNSPort instead." }, + { "SocksListenAddress", "Use SocksPort instead." }, + { "TransListenAddress", "Use TransPort instead." }, + { "NATDListenAddress", "Use NATDPort instead." }, + { "ORListenAddress", "Use ORPort instead, possibly with the " + "NoAdvertise sub-option" }, + /* End of options deprecated since 0.2.9.2-alpha. */ + + { NULL, NULL } +}; + #ifdef _WIN32 static char *get_windows_conf_root(void); #endif @@ -637,6 +676,7 @@ STATIC config_format_t options_format = { OR_OPTIONS_MAGIC, STRUCT_OFFSET(or_options_t, magic_), option_abbrevs_, + option_deprecation_notes_, option_vars_, options_validate_cb, NULL @@ -747,7 +787,7 @@ set_options(or_options_t *new_val, char **msg) } if (old_options != global_options) - config_free(&options_format, old_options); + or_options_free(old_options); return 0; } @@ -911,8 +951,8 @@ static const char *default_authorities[] = { "dizum orport=443 " "v3ident=E8A9C45EDE6D711294FADF8E7951F4DE6CA56B58 " "194.109.206.212:80 7EA6 EAD6 FD83 083C 538F 4403 8BBF A077 587D D755", - "Tonga orport=443 bridge " - "82.94.251.203:80 4A0C CD2D DC79 9508 3D73 F5D6 6710 0C8A 5831 F16D", + "Bifroest orport=443 bridge " + "37.218.247.217:80 1D8F 3A91 C37C 5D1C 4C19 B1AD 1D0C FBE8 BF72 D8E1", "gabelmoo orport=443 " "v3ident=ED03BB616EB2F60BEC80151114BB25CEF515B226 " "ipv6=[2001:638:a000:4140::ffff:189]:443 " @@ -2029,6 +2069,7 @@ static const struct { { "-h", TAKES_NO_ARGUMENT }, { "--help", TAKES_NO_ARGUMENT }, { "--list-torrc-options", TAKES_NO_ARGUMENT }, + { "--list-deprecated-options",TAKES_NO_ARGUMENT }, { "--nt-service", TAKES_NO_ARGUMENT }, { "-nt-service", TAKES_NO_ARGUMENT }, { NULL, 0 }, @@ -2165,31 +2206,30 @@ option_get_assignment(const or_options_t *options, const char *key) * what went wrong. */ setopt_err_t -options_trial_assign(config_line_t *list, int use_defaults, - int clear_first, char **msg) +options_trial_assign(config_line_t *list, unsigned flags, char **msg) { int r; or_options_t *trial_options = config_dup(&options_format, get_options()); if ((r=config_assign(&options_format, trial_options, - list, use_defaults, clear_first, msg)) < 0) { - config_free(&options_format, trial_options); + list, flags, msg)) < 0) { + or_options_free(trial_options); return r; } if (options_validate(get_options_mutable(), trial_options, global_default_options, 1, msg) < 0) { - config_free(&options_format, trial_options); + or_options_free(trial_options); return SETOPT_ERR_PARSE; /*XXX make this a separate return value. */ } if (options_transition_allowed(get_options(), trial_options, msg) < 0) { - config_free(&options_format, trial_options); + or_options_free(trial_options); return SETOPT_ERR_TRANSITION; } if (set_options(trial_options, msg)<0) { - config_free(&options_format, trial_options); + or_options_free(trial_options); return SETOPT_ERR_SETTING; } @@ -2215,7 +2255,6 @@ static void list_torrc_options(void) { int i; - smartlist_t *lines = smartlist_new(); for (i = 0; option_vars_[i].name; ++i) { const config_var_t *var = &option_vars_[i]; if (var->type == CONFIG_TYPE_OBSOLETE || @@ -2223,7 +2262,16 @@ list_torrc_options(void) continue; printf("%s\n", var->name); } - smartlist_free(lines); +} + +/** Print all deprecated but non-obsolete torrc options. */ +static void +list_deprecated_options(void) +{ + const config_deprecation_t *d; + for (d = option_deprecation_notes_; d->name; ++d) { + printf("%s\n", d->name); + } } /** Last value actually set by resolve_my_address. */ @@ -4677,10 +4725,15 @@ options_init_from_torrc(int argc, char **argv) exit(0); } if (config_line_find(cmdline_only_options, "--list-torrc-options")) { - /* For documenting validating whether we've documented everything. */ + /* For validating whether we've documented everything. */ list_torrc_options(); exit(0); } + if (config_line_find(cmdline_only_options, "--list-deprecated-options")) { + /* For validating whether what we have deprecated really exists. */ + list_deprecated_options(); + exit(0); + } if (config_line_find(cmdline_only_options, "--version")) { printf("Tor version %s.\n",get_version()); @@ -4859,7 +4912,8 @@ options_init_from_string(const char *cf_defaults, const char *cf, err = SETOPT_ERR_PARSE; goto err; } - retval = config_assign(&options_format, newoptions, cl, 0, 0, msg); + retval = config_assign(&options_format, newoptions, cl, + CAL_WARN_DEPRECATIONS, msg); config_free_lines(cl); if (retval < 0) { err = SETOPT_ERR_PARSE; @@ -4875,7 +4929,7 @@ options_init_from_string(const char *cf_defaults, const char *cf, /* Go through command-line variables too */ retval = config_assign(&options_format, newoptions, - global_cmdline_options, 0, 0, msg); + global_cmdline_options, CAL_WARN_DEPRECATIONS, msg); if (retval < 0) { err = SETOPT_ERR_PARSE; goto err; @@ -4900,11 +4954,17 @@ options_init_from_string(const char *cf_defaults, const char *cf, tor_assert(new_var); tor_assert(old_var); old_var->initvalue = new_var->initvalue; + + if ((config_find_deprecation(&options_format, new_var->name))) { + log_warn(LD_GENERAL, "Testing options override the deprecated " + "option %s. Is that intentional?", + new_var->name); + } } /* Clear newoptions and re-initialize them with new defaults. */ - config_free(&options_format, newoptions); - config_free(&options_format, newdefaultoptions); + or_options_free(newoptions); + or_options_free(newdefaultoptions); newdefaultoptions = NULL; newoptions = tor_malloc_zero(sizeof(or_options_t)); newoptions->magic_ = OR_OPTIONS_MAGIC; @@ -4923,7 +4983,7 @@ options_init_from_string(const char *cf_defaults, const char *cf, err = SETOPT_ERR_PARSE; goto err; } - retval = config_assign(&options_format, newoptions, cl, 0, 0, msg); + retval = config_assign(&options_format, newoptions, cl, 0, msg); config_free_lines(cl); if (retval < 0) { err = SETOPT_ERR_PARSE; @@ -4934,7 +4994,7 @@ options_init_from_string(const char *cf_defaults, const char *cf, } /* Assign command-line variables a second time too */ retval = config_assign(&options_format, newoptions, - global_cmdline_options, 0, 0, msg); + global_cmdline_options, 0, msg); if (retval < 0) { err = SETOPT_ERR_PARSE; goto err; @@ -4957,14 +5017,14 @@ options_init_from_string(const char *cf_defaults, const char *cf, err = SETOPT_ERR_SETTING; goto err; /* frees and replaces old options */ } - config_free(&options_format, global_default_options); + or_options_free(global_default_options); global_default_options = newdefaultoptions; return SETOPT_OK; err: - config_free(&options_format, newoptions); - config_free(&options_format, newdefaultoptions); + or_options_free(newoptions); + or_options_free(newdefaultoptions); if (*msg) { char *old_msg = *msg; tor_asprintf(msg, "Failed to parse/validate config: %s", old_msg); @@ -6146,6 +6206,20 @@ config_parse_unix_port(const char *addrport, char **path_out) } #endif /* defined(HAVE_SYS_UN_H) */ +static void +warn_client_dns_cache(const char *option, int disabling) +{ + if (disabling) + return; + + warn_deprecated_option(option, + "Client-side DNS cacheing enables a wide variety of route-" + "capture attacks. If a single bad exit node lies to you about " + "an IP address, cacheing that address would make you visit " + "an address of the attacker's choice every time you connected " + "to your destination."); +} + /** * Parse port configuration for a single port type. * @@ -6514,21 +6588,27 @@ parse_port_config(smartlist_t *out, } } if (!strcasecmp(elt, "CacheIPv4DNS")) { + warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha cache_ipv4 = ! no; continue; } else if (!strcasecmp(elt, "CacheIPv6DNS")) { + warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha cache_ipv6 = ! no; continue; } else if (!strcasecmp(elt, "CacheDNS")) { + warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha cache_ipv4 = cache_ipv6 = ! no; continue; } else if (!strcasecmp(elt, "UseIPv4Cache")) { + warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha use_cached_ipv4 = ! no; continue; } else if (!strcasecmp(elt, "UseIPv6Cache")) { + warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha use_cached_ipv6 = ! no; continue; } else if (!strcasecmp(elt, "UseDNSCache")) { + warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha use_cached_ipv4 = use_cached_ipv6 = ! no; continue; } else if (!strcasecmp(elt, "PreferIPv6Automap")) { @@ -6848,6 +6928,24 @@ parse_ports(or_options_t *options, int validate_only, return retval; } +/* Does port bind to IPv4? */ +static int +port_binds_ipv4(const port_cfg_t *port) +{ + return tor_addr_family(&port->addr) == AF_INET || + (tor_addr_family(&port->addr) == AF_UNSPEC + && !port->server_cfg.bind_ipv6_only); +} + +/* Does port bind to IPv6? */ +static int +port_binds_ipv6(const port_cfg_t *port) +{ + return tor_addr_family(&port->addr) == AF_INET6 || + (tor_addr_family(&port->addr) == AF_UNSPEC + && !port->server_cfg.bind_ipv4_only); +} + /** Given a list of <b>port_cfg_t</b> in <b>ports</b>, check them for internal * consistency and warn as appropriate. Set *<b>n_low_ports_out</b> to the * number of sub-1024 ports we will be binding. */ @@ -6873,9 +6971,7 @@ check_server_ports(const smartlist_t *ports, } else if (port->type == CONN_TYPE_OR_LISTENER) { if (! port->server_cfg.no_advertise) { ++n_orport_advertised; - if (tor_addr_family(&port->addr) == AF_INET || - (tor_addr_family(&port->addr) == AF_UNSPEC && - !port->server_cfg.bind_ipv6_only)) + if (port_binds_ipv4(port)) ++n_orport_advertised_ipv4; } if (! port->server_cfg.no_listen) @@ -7009,19 +7105,20 @@ get_first_listener_addrport_string(int listener_type) } /** Return the first advertised port of type <b>listener_type</b> in - <b>address_family</b>. */ + * <b>address_family</b>. Returns 0 when no port is found, and when passed + * AF_UNSPEC. */ int get_first_advertised_port_by_type_af(int listener_type, int address_family) { + if (address_family == AF_UNSPEC) + return 0; + const smartlist_t *conf_ports = get_configured_ports(); SMARTLIST_FOREACH_BEGIN(conf_ports, const port_cfg_t *, cfg) { if (cfg->type == listener_type && - !cfg->server_cfg.no_advertise && - (tor_addr_family(&cfg->addr) == address_family || - tor_addr_family(&cfg->addr) == AF_UNSPEC)) { - if (tor_addr_family(&cfg->addr) != AF_UNSPEC || - (address_family == AF_INET && !cfg->server_cfg.bind_ipv6_only) || - (address_family == AF_INET6 && !cfg->server_cfg.bind_ipv4_only)) { + !cfg->server_cfg.no_advertise) { + if ((address_family == AF_INET && port_binds_ipv4(cfg)) || + (address_family == AF_INET6 && port_binds_ipv6(cfg))) { return cfg->port; } } @@ -7029,6 +7126,87 @@ get_first_advertised_port_by_type_af(int listener_type, int address_family) return 0; } +/** Return the first advertised address of type <b>listener_type</b> in + * <b>address_family</b>. Returns NULL if there is no advertised address, + * and when passed AF_UNSPEC. */ +const tor_addr_t * +get_first_advertised_addr_by_type_af(int listener_type, int address_family) +{ + if (address_family == AF_UNSPEC) + return NULL; + if (!configured_ports) + return NULL; + SMARTLIST_FOREACH_BEGIN(configured_ports, const port_cfg_t *, cfg) { + if (cfg->type == listener_type && + !cfg->server_cfg.no_advertise) { + if ((address_family == AF_INET && port_binds_ipv4(cfg)) || + (address_family == AF_INET6 && port_binds_ipv6(cfg))) { + return &cfg->addr; + } + } + } SMARTLIST_FOREACH_END(cfg); + return NULL; +} + +/** Return 1 if a port exists of type <b>listener_type</b> on <b>addr</b> and + * <b>port</b>. If <b>check_wildcard</b> is true, INADDR[6]_ANY and AF_UNSPEC + * addresses match any address of the appropriate family; and port -1 matches + * any port. + * To match auto ports, pass CFG_PORT_AUTO. (Does not match on the actual + * automatically chosen listener ports.) */ +int +port_exists_by_type_addr_port(int listener_type, const tor_addr_t *addr, + int port, int check_wildcard) +{ + if (!configured_ports || !addr) + return 0; + SMARTLIST_FOREACH_BEGIN(configured_ports, const port_cfg_t *, cfg) { + if (cfg->type == listener_type) { + if (cfg->port == port || (check_wildcard && port == -1)) { + /* Exact match */ + if (tor_addr_eq(&cfg->addr, addr)) { + return 1; + } + /* Skip wildcard matches if we're not doing them */ + if (!check_wildcard) { + continue; + } + /* Wildcard matches IPv4 */ + const int cfg_v4 = port_binds_ipv4(cfg); + const int cfg_any_v4 = tor_addr_is_null(&cfg->addr) && cfg_v4; + const int addr_v4 = tor_addr_family(addr) == AF_INET || + tor_addr_family(addr) == AF_UNSPEC; + const int addr_any_v4 = tor_addr_is_null(&cfg->addr) && addr_v4; + if ((cfg_any_v4 && addr_v4) || (cfg_v4 && addr_any_v4)) { + return 1; + } + /* Wildcard matches IPv6 */ + const int cfg_v6 = port_binds_ipv6(cfg); + const int cfg_any_v6 = tor_addr_is_null(&cfg->addr) && cfg_v6; + const int addr_v6 = tor_addr_family(addr) == AF_INET6 || + tor_addr_family(addr) == AF_UNSPEC; + const int addr_any_v6 = tor_addr_is_null(&cfg->addr) && addr_v6; + if ((cfg_any_v6 && addr_v6) || (cfg_v6 && addr_any_v6)) { + return 1; + } + } + } + } SMARTLIST_FOREACH_END(cfg); + return 0; +} + +/* Like port_exists_by_type_addr_port, but accepts a host-order IPv4 address + * instead. */ +int +port_exists_by_type_addr32h_port(int listener_type, uint32_t addr_ipv4h, + int port, int check_wildcard) +{ + tor_addr_t ipv4; + tor_addr_from_ipv4h(&ipv4, addr_ipv4h); + return port_exists_by_type_addr_port(listener_type, &ipv4, port, + check_wildcard); +} + /** Adjust the value of options->DataDirectory, or fill it in if it's * absent. Return 0 on success, -1 on failure. */ static int diff --git a/src/or/config.h b/src/or/config.h index a0fe6e4805..7db66a31b9 100644 --- a/src/or/config.h +++ b/src/or/config.h @@ -29,8 +29,8 @@ const char *escaped_safe_str_client(const char *address); const char *escaped_safe_str(const char *address); const char *get_version(void); const char *get_short_version(void); -setopt_err_t options_trial_assign(config_line_t *list, int use_defaults, - int clear_first, char **msg); +setopt_err_t options_trial_assign(config_line_t *list, unsigned flags, + char **msg); uint32_t get_last_resolved_addr(void); void reset_last_resolved_addr(void); @@ -89,6 +89,12 @@ int get_first_advertised_port_by_type_af(int listener_type, (get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER, AF_INET)) #define get_primary_dir_port() \ (get_first_advertised_port_by_type_af(CONN_TYPE_DIR_LISTENER, AF_INET)) +const tor_addr_t *get_first_advertised_addr_by_type_af(int listener_type, + int address_family); +int port_exists_by_type_addr_port(int listener_type, const tor_addr_t *addr, + int port, int check_wildcard); +int port_exists_by_type_addr32h_port(int listener_type, uint32_t addr_ipv4h, + int port, int check_wildcard); char *get_first_listener_addrport_string(int listener_type); diff --git a/src/or/confparse.c b/src/or/confparse.c index 3532b39d93..efcf4f981e 100644 --- a/src/or/confparse.c +++ b/src/or/confparse.c @@ -181,6 +181,26 @@ config_free_lines(config_line_t *front) } } +/** If <b>key</b> is a deprecated configuration option, return the message + * explaining why it is deprecated (which may be an empty string). Return NULL + * if it is not deprecated. The <b>key</b> field must be fully expanded. */ +const char * +config_find_deprecation(const config_format_t *fmt, const char *key) +{ + if (BUG(fmt == NULL) || BUG(key == NULL)) + return NULL; + if (fmt->deprecations == NULL) + return NULL; + + const config_deprecation_t *d; + for (d = fmt->deprecations; d->name; ++d) { + if (!strcasecmp(d->name, key)) { + return d->why_deprecated ? d->why_deprecated : ""; + } + } + return NULL; +} + /** As config_find_option, but return a non-const pointer. */ config_var_t * config_find_option_mutable(config_format_t *fmt, const char *key) @@ -463,6 +483,16 @@ config_mark_lists_fragile(const config_format_t *fmt, void *options) } } +void +warn_deprecated_option(const char *what, const char *why) +{ + const char *space = (why && strlen(why)) ? " " : ""; + log_warn(LD_CONFIG, "The %s option is deprecated, and will most likely " + "be removed in a future version of Tor.%s%s (If you think this is " + "a mistake, please let us know!)", + what, space, why); +} + /** If <b>c</b> is a syntactically valid configuration line, update * <b>options</b> with its value and return 0. Otherwise return -1 for bad * key, -2 for bad value. @@ -474,9 +504,12 @@ config_mark_lists_fragile(const config_format_t *fmt, void *options) */ static int config_assign_line(const config_format_t *fmt, void *options, - config_line_t *c, int use_defaults, - int clear_first, bitarray_t *options_seen, char **msg) + config_line_t *c, unsigned flags, + bitarray_t *options_seen, char **msg) { + const unsigned use_defaults = flags & CAL_USE_DEFAULTS; + const unsigned clear_first = flags & CAL_CLEAR_FIRST; + const unsigned warn_deprecations = flags & CAL_WARN_DEPRECATIONS; const config_var_t *var; CONFIG_CHECK(fmt, options); @@ -502,6 +535,12 @@ config_assign_line(const config_format_t *fmt, void *options, c->key = tor_strdup(var->name); } + const char *deprecation_msg; + if (warn_deprecations && + (deprecation_msg = config_find_deprecation(fmt, var->name))) { + warn_deprecated_option(var->name, deprecation_msg); + } + if (!strlen(c->value)) { /* reset or clear it, then return */ if (!clear_first) { @@ -604,7 +643,7 @@ config_lines_dup(const config_line_t *inp) * escape that value. Return NULL if no such key exists. */ config_line_t * config_get_assigned_option(const config_format_t *fmt, const void *options, - const char *key, int escape_val) + const char *key, int escape_val) { const config_var_t *var; const void *value; @@ -804,11 +843,13 @@ options_trial_assign() calls config_assign(1, 1) */ int config_assign(const config_format_t *fmt, void *options, config_line_t *list, - int use_defaults, int clear_first, char **msg) + unsigned config_assign_flags, char **msg) { config_line_t *p; bitarray_t *options_seen; const int n_options = config_count_options(fmt); + const unsigned clear_first = config_assign_flags & CAL_CLEAR_FIRST; + const unsigned use_defaults = config_assign_flags & CAL_USE_DEFAULTS; CONFIG_CHECK(fmt, options); @@ -832,8 +873,8 @@ config_assign(const config_format_t *fmt, void *options, config_line_t *list, /* pass 3: assign. */ while (list) { int r; - if ((r=config_assign_line(fmt, options, list, use_defaults, - clear_first, options_seen, msg))) { + if ((r=config_assign_line(fmt, options, list, config_assign_flags, + options_seen, msg))) { bitarray_free(options_seen); return r; } @@ -1029,7 +1070,7 @@ config_dup(const config_format_t *fmt, const void *old) line = config_get_assigned_option(fmt, old, fmt->vars[i].name, 0); if (line) { char *msg = NULL; - if (config_assign(fmt, newopts, line, 0, 0, &msg) < 0) { + if (config_assign(fmt, newopts, line, 0, &msg) < 0) { log_err(LD_BUG, "config_get_assigned_option() generated " "something we couldn't config_assign(): %s", msg); tor_free(msg); diff --git a/src/or/confparse.h b/src/or/confparse.h index ca6fb5ec43..8d915d266b 100644 --- a/src/or/confparse.h +++ b/src/or/confparse.h @@ -48,6 +48,11 @@ typedef struct config_abbrev_t { int warn; } config_abbrev_t; +typedef struct config_deprecation_t { + const char *name; + const char *why_deprecated; +} config_deprecation_t; + /* Handy macro for declaring "In the config file or on the command line, * you can abbreviate <b>tok</b>s as <b>tok</b>". */ #define PLURAL(tok) { #tok, #tok "s", 0, 0 } @@ -76,6 +81,7 @@ typedef struct config_format_t { off_t magic_offset; /**< Offset of the magic value within the struct. */ config_abbrev_t *abbrevs; /**< List of abbreviations that we expand when * parsing this format. */ + const config_deprecation_t *deprecations; /** List of deprecated options */ config_var_t *vars; /**< List of variables we recognize, their default * values, and where we stick them in the structure. */ validate_fn_t validate_fn; /**< Function to validate config. */ @@ -92,6 +98,10 @@ typedef struct config_format_t { *(uint32_t*)STRUCT_VAR_P(cfg,fmt->magic_offset)); \ STMT_END +#define CAL_USE_DEFAULTS (1u<<0) +#define CAL_CLEAR_FIRST (1u<<1) +#define CAL_WARN_DEPRECATIONS (1u<<2) + void *config_new(const config_format_t *fmt); void config_line_append(config_line_t **lst, const char *key, const char *val); @@ -114,9 +124,11 @@ char *config_dump(const config_format_t *fmt, const void *default_options, int comment_defaults); int config_assign(const config_format_t *fmt, void *options, config_line_t *list, - int use_defaults, int clear_first, char **msg); + unsigned flags, char **msg); config_var_t *config_find_option_mutable(config_format_t *fmt, const char *key); +const char *config_find_deprecation(const config_format_t *fmt, + const char *key); const config_var_t *config_find_option(const config_format_t *fmt, const char *key); @@ -125,6 +137,7 @@ void config_free_lines(config_line_t *front); const char *config_expand_abbrev(const config_format_t *fmt, const char *option, int command_line, int warn_obsolete); +void warn_deprecated_option(const char *what, const char *why); #endif diff --git a/src/or/control.c b/src/or/control.c index a67395e3c0..1337af4201 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -871,7 +871,8 @@ control_setconf_helper(control_connection_t *conn, uint32_t len, char *body, config_line_t *lines=NULL; char *start = body; char *errstring = NULL; - const int clear_first = 1; + const unsigned flags = + CAL_CLEAR_FIRST | (use_defaults ? CAL_USE_DEFAULTS : 0); char *config; smartlist_t *entries = smartlist_new(); @@ -931,7 +932,7 @@ control_setconf_helper(control_connection_t *conn, uint32_t len, char *body, } tor_free(config); - opt_err = options_trial_assign(lines, use_defaults, clear_first, &errstring); + opt_err = options_trial_assign(lines, flags, &errstring); { const char *msg; switch (opt_err) { diff --git a/src/or/dirvote.c b/src/or/dirvote.c index 94a13e365d..9748f4ae4d 100644 --- a/src/or/dirvote.c +++ b/src/or/dirvote.c @@ -2577,7 +2577,7 @@ get_next_valid_after_time(time_t now) tor_assert(new_voting_schedule); next_valid_after_time = new_voting_schedule->interval_starts; - tor_free(new_voting_schedule); + voting_schedule_free(new_voting_schedule); return next_valid_after_time; } @@ -2601,7 +2601,7 @@ dirvote_recalculate_timing(const or_options_t *options, time_t now) /* Fill in the global static struct now */ memcpy(&voting_schedule, new_voting_schedule, sizeof(voting_schedule)); - tor_free(new_voting_schedule); + voting_schedule_free(new_voting_schedule); } /* Populate and return a new voting_schedule_t that can be used to schedule @@ -2660,6 +2660,16 @@ get_voting_schedule(const or_options_t *options, time_t now, int severity) return new_voting_schedule; } +/** Frees a voting_schedule_t. This should be used instead of the generic + * tor_free. */ +void +voting_schedule_free(voting_schedule_t *voting_schedule_to_free) +{ + if (!voting_schedule_to_free) + return; + tor_free(voting_schedule_to_free); +} + /** Entry point: Take whatever voting actions are pending as of <b>now</b>. */ void dirvote_act(const or_options_t *options, time_t now) diff --git a/src/or/dirvote.h b/src/or/dirvote.h index 2a83802307..a1f71ce4bb 100644 --- a/src/or/dirvote.h +++ b/src/or/dirvote.h @@ -157,6 +157,8 @@ typedef struct { voting_schedule_t *get_voting_schedule(const or_options_t *options, time_t now, int severity); +void voting_schedule_free(voting_schedule_t *voting_schedule_to_free); + void dirvote_get_preferred_voting_intervals(vote_timing_t *timing_out); time_t dirvote_get_start_of_next_interval(time_t now, int interval, diff --git a/src/or/main.c b/src/or/main.c index a1b5954aaf..03c2b7ed58 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -2817,7 +2817,7 @@ tor_init(int argc, char *argv[]) { const char *version = get_version(); - log_notice(LD_GENERAL, "Tor v%s running on %s with Libevent %s, " + log_notice(LD_GENERAL, "Tor %s running on %s with Libevent %s, " "OpenSSL %s and Zlib %s.", version, get_uname(), tor_libevent_get_version_str(), diff --git a/src/or/microdesc.c b/src/or/microdesc.c index 130259a29f..a81dc54628 100644 --- a/src/or/microdesc.c +++ b/src/or/microdesc.c @@ -108,6 +108,7 @@ dump_microdescriptor(int fd, microdesc_t *md, size_t *annotation_len_out) md->off = tor_fd_getpos(fd); written = write_all(fd, md->body, md->bodylen, 0); if (written != (ssize_t)md->bodylen) { + written = written < 0 ? 0 : written; log_warn(LD_DIR, "Couldn't dump microdescriptor (wrote %ld out of %lu): %s", (long)written, (unsigned long)md->bodylen, diff --git a/src/or/or.h b/src/or/or.h index 7eaeac8ecd..be58fa0d0a 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -5233,7 +5233,10 @@ typedef enum { CRN_WEIGHT_AS_EXIT = 1<<5, CRN_NEED_DESC = 1<<6, /* On clients, only provide nodes that satisfy ClientPreferIPv6OR */ - CRN_PREF_ADDR = 1<<7 + CRN_PREF_ADDR = 1<<7, + /* On clients, only provide nodes that we can connect to directly, based on + * our firewall rules */ + CRN_DIRECT_CONN = 1<<8 } router_crn_flags_t; /** Return value for router_add_to_routerlist() and dirserv_add_descriptor() */ diff --git a/src/or/router.c b/src/or/router.c index bfc2d125fb..e9961d4594 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -1963,6 +1963,83 @@ router_pick_published_address,(const or_options_t *options, uint32_t *addr)) return 0; } +/* Like router_check_descriptor_address_consistency, but specifically for the + * ORPort or DirPort. + * listener_type is either CONN_TYPE_OR_LISTENER or CONN_TYPE_DIR_LISTENER. */ +static void +router_check_descriptor_address_port_consistency(uint32_t ipv4h_desc_addr, + int listener_type) +{ + tor_assert(listener_type == CONN_TYPE_OR_LISTENER || + listener_type == CONN_TYPE_DIR_LISTENER); + + /* The first advertised Port may be the magic constant CFG_AUTO_PORT. + */ + int port_v4_cfg = get_first_advertised_port_by_type_af(listener_type, + AF_INET); + if (port_v4_cfg != 0 && + !port_exists_by_type_addr32h_port(listener_type, + ipv4h_desc_addr, port_v4_cfg, 1)) { + const tor_addr_t *port_addr = get_first_advertised_addr_by_type_af( + listener_type, + AF_INET); + /* If we're building a descriptor with no advertised address, + * something is terribly wrong. */ + tor_assert(port_addr); + + tor_addr_t desc_addr; + char port_addr_str[TOR_ADDR_BUF_LEN]; + char desc_addr_str[TOR_ADDR_BUF_LEN]; + + tor_addr_to_str(port_addr_str, port_addr, TOR_ADDR_BUF_LEN, 0); + + tor_addr_from_ipv4h(&desc_addr, ipv4h_desc_addr); + tor_addr_to_str(desc_addr_str, &desc_addr, TOR_ADDR_BUF_LEN, 0); + + const char *listener_str = (listener_type == CONN_TYPE_OR_LISTENER ? + "OR" : "Dir"); + log_warn(LD_CONFIG, "The IPv4 %sPort address %s does not match the " + "descriptor address %s. If you have a static public IPv4 " + "address, use 'Address <IPv4>' and 'OutboundBindAddress " + "<IPv4>'. If you are behind a NAT, use two %sPort lines: " + "'%sPort <PublicPort> NoListen' and '%sPort <InternalPort> " + "NoAdvertise'.", + listener_str, port_addr_str, desc_addr_str, listener_str, + listener_str, listener_str); + } +} + +/* Tor relays only have one IPv4 address in the descriptor, which is derived + * from the Address torrc option, or guessed using various methods in + * router_pick_published_address(). + * Warn the operator if there is no ORPort on the descriptor address + * ipv4h_desc_addr. + * Warn the operator if there is no DirPort on the descriptor address. + * This catches a few common config errors: + * - operators who expect ORPorts and DirPorts to be advertised on the + * ports' listen addresses, rather than the torrc Address (or guessed + * addresses in the absence of an Address config). This includes + * operators who attempt to put their ORPort and DirPort on different + * addresses; + * - discrepancies between guessed addresses and configured listen + * addresses (when the Address option isn't set). + * If a listener is listening on all IPv4 addresses, it is assumed that it + * is listening on the configured Address, and no messages are logged. + * If an operators has specified NoAdvertise ORPorts in a NAT setting, + * no messages are logged, unless they have specified other advertised + * addresses. + * The message tells operators to configure an ORPort and DirPort that match + * the Address (using NoListen if needed). + */ +static void +router_check_descriptor_address_consistency(uint32_t ipv4h_desc_addr) +{ + router_check_descriptor_address_port_consistency(ipv4h_desc_addr, + CONN_TYPE_OR_LISTENER); + router_check_descriptor_address_port_consistency(ipv4h_desc_addr, + CONN_TYPE_DIR_LISTENER); +} + /** Build a fresh routerinfo, signed server descriptor, and extra-info document * for this OR. Set r to the generated routerinfo, e to the generated * extra-info document. Return 0 on success, -1 on temporary error. Failure to @@ -1985,6 +2062,10 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e) return -1; } + /* Log a message if the address in the descriptor doesn't match the ORPort + * and DirPort addresses configured by the operator. */ + router_check_descriptor_address_consistency(addr); + ri = tor_malloc_zero(sizeof(routerinfo_t)); ri->cache_info.routerlist_index = -1; ri->nickname = tor_strdup(options->Nickname); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index d713fe4854..1773f1d05c 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -2245,7 +2245,7 @@ void router_add_running_nodes_to_smartlist(smartlist_t *sl, int allow_invalid, int need_uptime, int need_capacity, int need_guard, int need_desc, - int pref_addr) + int pref_addr, int direct_conn) { const int check_reach = !router_skip_or_reachability(get_options(), pref_addr); @@ -2260,10 +2260,10 @@ router_add_running_nodes_to_smartlist(smartlist_t *sl, int allow_invalid, continue; if (node_is_unreliable(node, need_uptime, need_capacity, need_guard)) continue; - /* Choose a node with an OR address that matches the firewall rules */ - if (check_reach && !fascist_firewall_allows_node(node, - FIREWALL_OR_CONNECTION, - pref_addr)) + /* Choose a node with an OR address that matches the firewall rules, + * if we are making a direct connection */ + if (direct_conn && check_reach && + !fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION, pref_addr)) continue; smartlist_add(sl, (void *)node); @@ -2717,6 +2717,7 @@ router_choose_random_node(smartlist_t *excludedsmartlist, const int weight_for_exit = (flags & CRN_WEIGHT_AS_EXIT) != 0; const int need_desc = (flags & CRN_NEED_DESC) != 0; const int pref_addr = (flags & CRN_PREF_ADDR) != 0; + const int direct_conn = (flags & CRN_DIRECT_CONN) != 0; smartlist_t *sl=smartlist_new(), *excludednodes=smartlist_new(); @@ -2742,7 +2743,8 @@ router_choose_random_node(smartlist_t *excludedsmartlist, router_add_running_nodes_to_smartlist(sl, allow_invalid, need_uptime, need_capacity, - need_guard, need_desc, pref_addr); + need_guard, need_desc, pref_addr, + direct_conn); log_debug(LD_CIRC, "We found %d running nodes.", smartlist_len(sl)); @@ -4544,10 +4546,10 @@ dir_server_new(int is_authority, if (nickname) tor_asprintf(&ent->description, "directory server \"%s\" at %s:%d", - nickname, hostname, (int)dir_port); + nickname, hostname_, (int)dir_port); else tor_asprintf(&ent->description, "directory server at %s:%d", - hostname, (int)dir_port); + hostname_, (int)dir_port); ent->fake_status.addr = ent->addr; tor_addr_copy(&ent->fake_status.ipv6_addr, &ent->ipv6_addr); diff --git a/src/or/routerlist.h b/src/or/routerlist.h index 9765ee7ff4..72ab6d9bf3 100644 --- a/src/or/routerlist.h +++ b/src/or/routerlist.h @@ -65,7 +65,7 @@ int routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2); void router_add_running_nodes_to_smartlist(smartlist_t *sl, int allow_invalid, int need_uptime, int need_capacity, int need_guard, int need_desc, - int pref_addr); + int pref_addr, int direct_conn); const routerinfo_t *routerlist_find_my_routerinfo(void); uint32_t router_get_advertised_bandwidth(const routerinfo_t *router); diff --git a/src/or/shared_random.c b/src/or/shared_random.c index 0a1f24a974..19564f5924 100644 --- a/src/or/shared_random.c +++ b/src/or/shared_random.c @@ -1328,7 +1328,7 @@ sr_act_post_consensus(const networkstatus_t *consensus) get_voting_schedule(options,time(NULL), LOG_NOTICE); time_t interval_starts = voting_schedule->interval_starts; sr_state_update(interval_starts); - tor_free(voting_schedule); + voting_schedule_free(voting_schedule); } } diff --git a/src/or/shared_random_state.c b/src/or/shared_random_state.c index 52a0034db7..87db9031ee 100644 --- a/src/or/shared_random_state.c +++ b/src/or/shared_random_state.c @@ -86,6 +86,7 @@ static const config_format_t state_format = { SR_DISK_STATE_MAGIC, STRUCT_OFFSET(sr_disk_state_t, magic_), NULL, + NULL, state_vars, disk_state_validate_cb, &state_extra_var, @@ -150,7 +151,7 @@ get_start_time_of_current_round(time_t now) voting_interval, options->TestingV3AuthVotingStartOffset); - tor_free(new_voting_schedule); + voting_schedule_free(new_voting_schedule); return curr_start; } @@ -700,7 +701,7 @@ disk_state_load_from_disk_impl(const char *fname) } disk_state = disk_state_new(time(NULL)); - config_assign(&state_format, disk_state, lines, 0, 0, &errmsg); + config_assign(&state_format, disk_state, lines, 0, &errmsg); config_free_lines(lines); if (errmsg) { log_warn(LD_DIR, "SR: Reading state error: %s", errmsg); diff --git a/src/or/statefile.c b/src/or/statefile.c index 9594d9cec3..adf9d9f038 100644 --- a/src/or/statefile.c +++ b/src/or/statefile.c @@ -121,6 +121,7 @@ static const config_format_t state_format = { OR_STATE_MAGIC, STRUCT_OFFSET(or_state_t, magic_), state_abbrevs_, + NULL, state_vars_, or_state_validate_cb, &state_extra_var, @@ -349,7 +350,7 @@ or_state_load(void) if (config_get_lines(contents, &lines, 0)<0) goto done; assign_retval = config_assign(&state_format, new_state, - lines, 0, 0, &errmsg); + lines, 0, &errmsg); config_free_lines(lines); if (assign_retval<0) badstate = 1; |