diff options
Diffstat (limited to 'src')
133 files changed, 3629 insertions, 1963 deletions
diff --git a/src/app/config/config.c b/src/app/config/config.c index f4172bd84e..23f280891b 100644 --- a/src/app/config/config.c +++ b/src/app/config/config.c @@ -140,6 +140,7 @@ #include "lib/meminfo/meminfo.h" #include "lib/osinfo/uname.h" +#include "lib/osinfo/libc.h" #include "lib/process/daemon.h" #include "lib/process/pidfile.h" #include "lib/process/restrict.h" @@ -314,6 +315,7 @@ static const config_var_t option_vars_[] = { VAR("AccountingRule", STRING, AccountingRule_option, "max"), V(AccountingStart, STRING, NULL), V(Address, LINELIST, NULL), + V(AddressDisableIPv6, BOOL, "0"), OBSOLETE("AllowDotExit"), OBSOLETE("AllowInvalidNodes"), V(AllowNonRFC953Hostnames, BOOL, "0"), @@ -1736,8 +1738,8 @@ options_rollback_listener_transaction(listener_transaction_t *xn) SMARTLIST_FOREACH(xn->new_listeners, connection_t *, conn, { - log_notice(LD_NET, "Closing partially-constructed %s on %s:%d", - conn_type_to_string(conn->type), conn->address, conn->port); + log_notice(LD_NET, "Closing partially-constructed %s", + connection_describe(conn)); connection_close_immediate(conn); connection_mark_for_close(conn); }); @@ -2466,6 +2468,8 @@ static const struct { { .name="--key-expiration", .takes_argument=ARGUMENT_OPTIONAL, .command=CMD_KEY_EXPIRATION }, + { .name="--format", + .takes_argument=ARGUMENT_NECESSARY }, { .name="--newpass" }, { .name="--no-passphrase" }, { .name="--passphrase-fd", @@ -4365,6 +4369,12 @@ options_init_from_torrc(int argc, char **argv) tor_compress_version_str(ZSTD_METHOD), tor_compress_header_version_str(ZSTD_METHOD)); } + if (tor_libc_get_name()) { + printf("%-7s \t\t%-15s\t\t%s\n", + tor_libc_get_name(), + tor_libc_get_header_version_str(), + tor_libc_get_version_str()); + } //TODO: Hex versions? return 1; } @@ -4417,6 +4427,38 @@ options_init_from_torrc(int argc, char **argv) } } + const config_line_t *format_line = config_line_find(cmdline_only_options, + "--format"); + if (format_line) { + if (command == CMD_KEY_EXPIRATION) { + const char *v = format_line->value; + // keep the same order as enum key_expiration_format + const char *formats[] = { "iso8601", "timestamp" }; + int format = -1; + for (unsigned i = 0; i < ARRAY_LENGTH(formats); i++) { + if (!strcmp(v, formats[i])) { + format = i; + break; + } + } + + if (format < 0) { + log_err(LD_CONFIG, "Invalid --format value %s", escaped(v)); + retval = -1; + goto err; + } else { + get_options_mutable()->key_expiration_format = format; + } + } else { + log_err(LD_CONFIG, "--format specified without --key-expiration!"); + retval = -1; + goto err; + } + } else { + get_options_mutable()->key_expiration_format = + KEY_EXPIRATION_FORMAT_ISO8601; + } + if (config_line_find(cmdline_only_options, "--newpass")) { if (command == CMD_KEYGEN) { get_options_mutable()->change_key_passphrase = 1; @@ -5823,6 +5865,15 @@ port_parse_config(smartlist_t *out, int got_zero_port=0, got_nonzero_port=0; char *unix_socket_path = NULL; port_cfg_t *cfg = NULL; + bool addr_is_explicit = false; + int family = -1; + + /* Parse default address. This can fail for Unix socket for instance so + * family can be -1 and the default_addr will be made UNSPEC. */ + tor_addr_t default_addr = TOR_ADDR_NULL; + if (defaultaddr) { + family = tor_addr_parse(&default_addr, defaultaddr); + } /* If there's no FooPort, then maybe make a default one. */ if (! ports) { @@ -5899,8 +5950,8 @@ port_parse_config(smartlist_t *out, port = 1; } else if (!strcasecmp(addrport, "auto")) { port = CFG_AUTO_PORT; - int af = tor_addr_parse(&addr, defaultaddr); - tor_assert(af >= 0); + tor_assert(family >= 0); + tor_addr_copy(&addr, &default_addr); } else if (!strcasecmpend(addrport, ":auto")) { char *addrtmp = tor_strndup(addrport, strlen(addrport)-5); port = CFG_AUTO_PORT; @@ -5916,14 +5967,20 @@ port_parse_config(smartlist_t *out, "9050" might be a valid address. */ port = (int) tor_parse_long(addrport, 10, 0, 65535, &ok, NULL); if (ok) { - int af = tor_addr_parse(&addr, defaultaddr); - tor_assert(af >= 0); + tor_assert(family >= 0); + tor_addr_copy(&addr, &default_addr); } else if (tor_addr_port_lookup(addrport, &addr, &ptmp) == 0) { if (ptmp == 0) { log_warn(LD_CONFIG, "%sPort line has address but no port", portname); goto err; } + if (family != -1 && tor_addr_family(&addr) != family) { + /* This means we are parsing another ORPort family but we are + * attempting to find the default address' family ORPort. */ + goto ignore; + } port = ptmp; + addr_is_explicit = true; } else { log_warn(LD_CONFIG, "Couldn't parse address %s for %sPort", escaped(addrport), portname); @@ -5934,6 +5991,7 @@ port_parse_config(smartlist_t *out, /* Default port_cfg_t object initialization */ cfg = port_cfg_new(unix_socket_path ? strlen(unix_socket_path) : 0); + cfg->explicit_addr = addr_is_explicit; if (unix_socket_path && default_to_group_writable) cfg->is_group_writable = 1; @@ -5976,15 +6034,25 @@ port_parse_config(smartlist_t *out, } if (cfg->server_cfg.bind_ipv4_only && tor_addr_family(&addr) != AF_INET) { - log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv4", - portname); - goto err; + if (cfg->explicit_addr) { + log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv4", + portname); + goto err; + } + /* This ORPort is IPv4Only but the default address is IPv6, ignore it + * since this will be configured with an IPv4 default address. */ + goto ignore; } if (cfg->server_cfg.bind_ipv6_only && tor_addr_family(&addr) != AF_INET6) { - log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv6", - portname); - goto err; + if (cfg->explicit_addr) { + log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv6", + portname); + goto err; + } + /* This ORPort is IPv6Only but the default address is IPv4, ignore it + * since this will be configured with an IPv6 default address. */ + goto ignore; } } else { /* This is a client port; parse isolation options */ @@ -6197,9 +6265,10 @@ port_parse_config(smartlist_t *out, smartlist_add(out, cfg); /* out owns cfg now, don't re-use or free it */ cfg = NULL; - } else { - tor_free(cfg); } + + ignore: + tor_free(cfg); SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp)); smartlist_clear(elts); tor_free(addrport); @@ -6496,14 +6565,13 @@ get_first_listener_addrport_string(int listener_type) return NULL; } -/** Return the first advertised port of type <b>listener_type</b> in - * <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) +/** Find and return the first configured advertised `port_cfg_t` of type @a + * listener_type in @a address_family. */ +static const port_cfg_t * +portconf_get_first_advertised(int listener_type, int address_family) { if (address_family == AF_UNSPEC) - return 0; + return NULL; const smartlist_t *conf_ports = get_configured_ports(); SMARTLIST_FOREACH_BEGIN(conf_ports, const port_cfg_t *, cfg) { @@ -6511,33 +6579,35 @@ get_first_advertised_port_by_type_af(int listener_type, int address_family) !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; + return cfg; } } } SMARTLIST_FOREACH_END(cfg); - return 0; + return NULL; +} + +/** Return the first advertised port of type <b>listener_type</b> in + * <b>address_family</b>. Returns 0 when no port is found, and when passed + * AF_UNSPEC. */ +int +portconf_get_first_advertised_port(int listener_type, int address_family) +{ + const port_cfg_t *cfg; + cfg = portconf_get_first_advertised(listener_type, address_family); + + return cfg ? cfg->port : 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) +portconf_get_first_advertised_addr(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; + const port_cfg_t *cfg; + cfg = portconf_get_first_advertised(listener_type, address_family); + + return cfg ? &cfg->addr : NULL; } /** Return 1 if a port exists of type <b>listener_type</b> on <b>addr</b> and diff --git a/src/app/config/config.h b/src/app/config/config.h index f7d4e49f6f..ee39490072 100644 --- a/src/app/config/config.h +++ b/src/app/config/config.h @@ -159,13 +159,11 @@ int get_num_cpus(const or_options_t *options); MOCK_DECL(const smartlist_t *,get_configured_ports,(void)); int port_binds_ipv4(const port_cfg_t *port); int port_binds_ipv6(const port_cfg_t *port); -int get_first_advertised_port_by_type_af(int listener_type, - int address_family); -#define get_primary_or_port() \ - (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 portconf_get_first_advertised_port(int listener_type, + int address_family); +#define portconf_get_primary_dir_port() \ + (portconf_get_first_advertised_port(CONN_TYPE_DIR_LISTENER, AF_INET)) +const tor_addr_t *portconf_get_first_advertised_addr(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); diff --git a/src/app/config/fallback_dirs.inc b/src/app/config/fallback_dirs.inc index ba7e848715..a7ef39bb96 100644 --- a/src/app/config/fallback_dirs.inc +++ b/src/app/config/fallback_dirs.inc @@ -1,65 +1,35 @@ /* type=fallback */ -/* version=2.0.0 */ -/* timestamp=20190625114911 */ -/* timestamp0=20190625114911 */ -/* timestamp1=20190628085927 */ -/* source=allowlist */ -/* ===== */ -/* 0: Allowlist excluded 1550 of 1711 candidates. */ -/* 1: Allowlist excluded 1601 of 1765 candidates. */ +/* version=3.0.0 */ +/* timestamp=20200723133610 */ +/* source=offer-list */ +/* ===== */ +/* Offer list excluded 1807 of 1978 candidates. */ /* Checked IPv4 DirPorts served a consensus within 15.0s. */ /* -0: -Final Count: 140 (Eligible 161, Target 414 (2072 * 0.20), Max 200) -Excluded: 21 (Same Operator 16, Failed/Skipped Download 3, Excess 2) -Bandwidth Range: 0.5 - 54.5 MByte/s - -MERGED WITH: - -1: -Final Count: 140 (Eligible 164, Target 414 (2073 * 0.20), Max 200) -Excluded: 24 (Same Operator 16, Failed/Skipped Download 4, Excess 4) -Bandwidth Range: 0.8 - 54.5 MByte/s +Final Count: 144 (Eligible 171, Target 447 (2239 * 0.20), Max 200) +Excluded: 27 (Same Operator 15, Failed/Skipped Download 6, Excess 6) +Bandwidth Range: 0.6 - 96.1 MByte/s */ /* -): -Onionoo Source: details Date: 2019-06-25 10:00:00 Version: 7.0 -URL: https:onionoo.torproject.orgdetails?fieldsfingerprint%2Cnickname%2Ccontact%2Clast_changed_address_or_port%2Cconsensus_weight%2Cadvertised_bandwidth%2Cor_addresses%2Cdir_address%2Crecommended_version%2Cflags%2Ceffective_family%2Cplatform&flagV2Dir&typerelay&last_seen_days-0&first_seen_days90- - -MERGED WITH: - -1: -Onionoo Source: details Date: 2019-06-28 07:00:00 Version: 7.0 -URL: https:onionoo.torproject.orgdetails?fieldsfingerprint%2Cnickname%2Ccontact%2Clast_changed_address_or_port%2Cconsensus_weight%2Cadvertised_bandwidth%2Cor_addresses%2Cdir_address%2Crecommended_version%2Cflags%2Ceffective_family%2Cplatform&last_seen_days-0&flagV2Dir&first_seen_days90-&typerelay&order-consensus_weight%2Cfirst_seen +Onionoo Source: details Date: 2020-07-23 13:00:00 Version: 8.0 +URL: https:onionoo.torproject.orgdetails?fieldsfingerprint%2Cnickname%2Ccontact%2Clast_changed_address_or_port%2Cconsensus_weight%2Cadvertised_bandwidth%2Cor_addresses%2Cdir_address%2Crecommended_version%2Cflags%2Ceffective_family%2Cplatform&typerelay&first_seen_days90-&last_seen_days-0&flagV2Dir&order-consensus_weight%2Cfirst_seen */ /* -0: -Onionoo Source: uptime Date: 2019-06-25 10:00:00 Version: 7.0 -URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&last_seen_days-0 - -MERGED WITH: - -1: -Onionoo Source: uptime Date: 2019-06-28 07:00:00 Version: 7.0 -URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&order-consensus_weight%2Cfirst_seen&last_seen_days-0 +Onionoo Source: uptime Date: 2020-07-23 13:00:00 Version: 8.0 +URL: https:onionoo.torproject.orguptime?typerelay&first_seen_days90-&last_seen_days-0&flagV2Dir&order-consensus_weight%2Cfirst_seen */ /* ===== */ -"185.13.39.197:80 orport=443 id=001524DD403D729F08F7E5D77813EF12756CFA8D" -/* nickname=Neldoreth */ -/* extrainfo=0 */ -/* ===== */ -, -"185.100.85.61:80 orport=443 id=025B66CEBC070FCB0519D206CF0CF4965C20C96E" -/* nickname=nibbana */ -/* extrainfo=0 */ -/* ===== */ -, "185.225.17.3:80 orport=443 id=0338F9F55111FE8E3570E7DE117EF3AF999CC1D7" " ipv6=[2a0a:c800:1:5::3]:443" /* nickname=Nebuchadnezzar */ /* extrainfo=0 */ /* ===== */ , +"81.7.10.193:9002 orport=993 id=03C3069E814E296EB18776EB61B1ECB754ED89FE" +/* nickname=Ichotolot61 */ +/* extrainfo=1 */ +/* ===== */ +, "163.172.149.155:80 orport=443 id=0B85617241252517E8ECF2CFC7F4C1A32DCD153F" /* nickname=niij02 */ /* extrainfo=0 */ @@ -70,8 +40,19 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"37.252.185.182:9030 orport=8080 id=113143469021882C3A4B82F084F8125B08EE471E" -" ipv6=[2a00:63c1:a:182::2]:8080" +"81.7.18.7:9030 orport=9001 id=0C475BA4D3AA3C289B716F95954CAD616E50C4E5" +/* nickname=Freebird32 */ +/* extrainfo=1 */ +/* ===== */ +, +"193.234.15.60:80 orport=443 id=0F6E5CA4BF5565D9AA9FDDCA165AFC6A5305763D" +" ipv6=[2a00:1c20:4089:1234:67bc:79f3:61c0:6e49]:443" +/* nickname=jaures3 */ +/* extrainfo=0 */ +/* ===== */ +, +"93.177.67.71:9030 orport=8080 id=113143469021882C3A4B82F084F8125B08EE471E" +" ipv6=[2a03:4000:38:559::2]:8080" /* nickname=parasol */ /* extrainfo=0 */ /* ===== */ @@ -82,11 +63,6 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"95.85.8.226:80 orport=443 id=1211AC1BBB8A1AF7CBA86BCE8689AA3146B86423" -/* nickname=ccrelaycc */ -/* extrainfo=0 */ -/* ===== */ -, "193.11.114.43:9030 orport=9001 id=12AD30E5D25AA67F519780E2111E611A455FDC89" " ipv6=[2001:6b0:30:1000::99]:9050" /* nickname=mdfnet1 */ @@ -98,27 +74,23 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"217.182.51.248:80 orport=443 id=183005F78229D94EE51CE7795A42280070A48D0D" -/* nickname=Cosworth02 */ +"193.234.15.61:80 orport=443 id=158581827034DEF1BAB1FC248D180165452E53D3" +" ipv6=[2a00:1c20:4089:1234:2712:a3d0:666b:88a6]:443" +/* nickname=bakunin3 */ /* extrainfo=0 */ /* ===== */ , -"171.25.193.25:80 orport=443 id=185663B7C12777F052B2C2D23D7A239D8DA88A0F" -" ipv6=[2001:67c:289c::25]:443" -/* nickname=DFRI5 */ +"51.15.78.0:9030 orport=9001 id=15BE17C99FACE24470D40AF782D6A9C692AB36D6" +" ipv6=[2001:bc8:1824:c4b::1]:9001" +/* nickname=rofltor07 */ /* extrainfo=0 */ /* ===== */ , -"149.56.141.138:9030 orport=9001 id=1938EBACBB1A7BFA888D9623C90061130E63BB3F" -/* nickname=Aerodynamik04 */ +"204.11.50.131:9030 orport=9001 id=185F2A57B0C4620582602761097D17DB81654F70" +/* nickname=BoingBoing */ /* extrainfo=0 */ /* ===== */ , -"81.7.14.253:9001 orport=443 id=1AE039EE0B11DB79E4B4B29CBA9F752864A0259E" -/* nickname=Ichotolot60 */ -/* extrainfo=1 */ -/* ===== */ -, "50.7.74.171:9030 orport=9001 id=1CD17CB202063C51C7DAD3BACEF87ECE81C2350F" " ipv6=[2001:49f0:d002:2::51]:443" /* nickname=theia1 */ @@ -132,7 +104,7 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* ===== */ , "212.47.229.2:9030 orport=9001 id=20462CBA5DA4C2D963567D17D0B7249718114A68" -" ipv6=[2001:bc8:4400:2100::f03]:9001" +" ipv6=[2001:bc8:47ac:23a::1]:9001" /* nickname=scaletor */ /* extrainfo=0 */ /* ===== */ @@ -147,13 +119,37 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , +"193.234.15.57:80 orport=443 id=24D0491A2ADAAB52C17625FBC926D84477AEA322" +" ipv6=[2a00:1c20:4089:1234:7825:2c5d:1ecd:c66f]:443" +/* nickname=bakunin */ +/* extrainfo=0 */ +/* ===== */ +, +"185.220.101.137:20137 orport=10137 id=28F4F392F8F19E3FBDE09616D9DB8143A1E2DDD3" +" ipv6=[2a0b:f4c2:1::137]:10137" +/* nickname=niftycottonmouse */ +/* extrainfo=0 */ +/* ===== */ +, +"138.201.250.33:9012 orport=9011 id=2BA2C8E96B2590E1072AECE2BDB5C48921BF8510" +/* nickname=storm */ +/* extrainfo=0 */ +/* ===== */ +, +"5.181.50.99:80 orport=443 id=2BB85DC5BD3C6F0D81A4F2B5882176C6BF7ECF5A" +" ipv6=[2a03:4000:3f:16c:3851:6bff:fe07:bd2]:443" +/* nickname=AlanTuring */ +/* extrainfo=0 */ +/* ===== */ +, "97.74.237.196:9030 orport=9001 id=2F0F32AB1E5B943CA7D062C03F18960C86E70D94" /* nickname=Minotaur */ /* extrainfo=0 */ /* ===== */ , -"212.83.154.33:8080 orport=8443 id=322C6E3A973BC10FC36DE3037AD27BC89F14723B" -/* nickname=bauruine204 */ +"94.230.208.147:8080 orport=8443 id=311A4533F7A2415F42346A6C8FA77E6FD279594C" +" ipv6=[2a02:418:6017::147]:8443" +/* nickname=DigiGesTor3e2 */ /* extrainfo=0 */ /* ===== */ , @@ -169,18 +165,13 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"37.157.255.35:9030 orport=9090 id=361D33C96D0F161275EE67E2C91EE10B276E778B" -/* nickname=cxx4freedom */ -/* extrainfo=0 */ -/* ===== */ -, "64.79.152.132:80 orport=443 id=375DCBB2DBD94E5263BC0C015F0C9E756669617E" /* nickname=ebola */ /* extrainfo=0 */ /* ===== */ , -"213.183.60.21:9030 orport=443 id=39F91959416763AFD34DBEEC05474411B964B2DC" -/* nickname=angeltest11 */ +"198.50.191.95:80 orport=443 id=39F096961ED2576975C866D450373A9913AFDC92" +/* nickname=shhovh */ /* extrainfo=0 */ /* ===== */ , @@ -190,9 +181,9 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"199.249.230.83:80 orport=443 id=3CA0D15567024D2E0B557DC0CF3E962B37999A79" -" ipv6=[2620:7:6001::ffff:c759:e653]:80" -/* nickname=QuintexAirVPN30 */ +"212.83.154.33:8888 orport=443 id=3C79699D4FBC37DE1A212D5033B56DAE079AC0EF" +" ipv6=[2001:bc8:31d3:1dd::1]:443" +/* nickname=bauruine203 */ /* extrainfo=0 */ /* ===== */ , @@ -202,6 +193,12 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , +"95.216.211.81:80 orport=443 id=3CCF9573F59137E52787D9C322AC19D2BD090B70" +" ipv6=[2a01:4f9:c010:4dfa::1]:443" +/* nickname=BurningMan */ +/* extrainfo=0 */ +/* ===== */ +, "217.79.179.177:9030 orport=9001 id=3E53D3979DB07EFD736661C934A1DED14127B684" " ipv6=[2001:4ba0:fff9:131:6c4f::90d3]:9001" /* nickname=Unnamed */ @@ -224,24 +221,14 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"195.123.245.141:9030 orport=443 id=465D17C6FC297E3857B5C6F152006A1E212944EA" -/* nickname=angeltest14 */ -/* extrainfo=0 */ -/* ===== */ -, -"31.31.78.49:80 orport=443 id=46791D156C9B6C255C2665D4D8393EC7DBAA7798" -/* nickname=KrigHaBandolo */ -/* extrainfo=0 */ -/* ===== */ -, "193.70.43.76:9030 orport=9001 id=484A10BA2B8D48A5F0216674C8DD50EF27BC32F3" /* nickname=Aerodynamik03 */ /* extrainfo=0 */ /* ===== */ , -"37.187.102.186:9030 orport=9001 id=489D94333DF66D57FFE34D9D59CC2D97E2CB0053" -" ipv6=[2001:41d0:a:26ba::1]:9001" -/* nickname=txtfileTorNode65536 */ +"109.70.100.4:80 orport=443 id=4BFC9C631A93FF4BA3AA84BC6931B4310C38A263" +" ipv6=[2a03:e600:100::4]:443" +/* nickname=karotte */ /* extrainfo=0 */ /* ===== */ , @@ -262,38 +249,36 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=1 */ /* ===== */ , -"81.7.16.182:80 orport=443 id=51E1CF613FD6F9F11FE24743C91D6F9981807D82" -" ipv6=[2a02:180:1:1::517:10b6]:993" -/* nickname=torpidsDEisppro3 */ +"69.30.215.42:80 orport=443 id=510176C07005D47B23E6796F02C93241A29AA0E9" +" ipv6=[2604:4300:a:2e:21b:21ff:fe11:392]:443" +/* nickname=torpidsUSwholesale */ /* extrainfo=0 */ /* ===== */ , -"192.160.102.166:80 orport=9001 id=547DA56F6B88B6C596B3E3086803CDA4F0EF8F21" -" ipv6=[2620:132:300c:c01d::6]:9002" -/* nickname=chaucer */ +"176.223.141.106:80 orport=443 id=5262556D44A7F2434990FDE1AE7973C67DF49E58" +/* nickname=Theoden */ /* extrainfo=0 */ /* ===== */ , -"192.160.102.170:80 orport=9001 id=557ACEC850F54EEE65839F83CACE2B0825BE811E" -" ipv6=[2620:132:300c:c01d::a]:9002" -/* nickname=ogopogo */ +"85.25.159.65:995 orport=80 id=52BFADA8BEAA01BA46C8F767F83C18E2FE50C1B9" +/* nickname=BeastieJoy63 */ /* extrainfo=0 */ /* ===== */ , -"50.7.74.170:80 orport=443 id=5BF17163CBE73D8CD9FDBE030C944EA05707DA93" -" ipv6=[2001:49f0:d002:2::58]:443" -/* nickname=theia8 */ +"193.234.15.59:80 orport=443 id=562434D987CF49D45649B76ADCA993BEA8F78471" +" ipv6=[2a00:1c20:4089:1234:bff6:e1bb:1ce3:8dc6]:443" +/* nickname=bakunin2 */ /* extrainfo=0 */ /* ===== */ , -"172.98.193.43:80 orport=443 id=5E56738E7F97AA81DEEF59AF28494293DFBFCCDF" -/* nickname=Backplane */ +"89.234.157.254:80 orport=443 id=578E007E5E4535FBFEF7758D8587B07B4C8C5D06" +" ipv6=[2001:67c:2608::1]:443" +/* nickname=marylou1 */ /* extrainfo=0 */ /* ===== */ , -"95.128.43.164:80 orport=443 id=616081EC829593AF4232550DE6FFAA1D75B37A90" -" ipv6=[2a02:ec0:209:10::4]:443" -/* nickname=AquaRayTerminus */ +"172.98.193.43:80 orport=443 id=5E56738E7F97AA81DEEF59AF28494293DFBFCCDF" +/* nickname=Backplane */ /* extrainfo=0 */ /* ===== */ , @@ -302,26 +287,14 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"94.130.186.5:80 orport=443 id=6A7551EEE18F78A9813096E82BF84F740D32B911" -" ipv6=[2a01:4f8:1c0c:45f7::1]:443" +"95.217.16.212:80 orport=443 id=6A7551EEE18F78A9813096E82BF84F740D32B911" +" ipv6=[2a01:4f9:c010:609a::1]:443" /* nickname=TorMachine */ /* extrainfo=0 */ /* ===== */ , -"80.127.137.19:80 orport=443 id=6EF897645B79B6CB35E853B32506375014DE3621" -" ipv6=[2001:981:47c1:1::6]:443" -/* nickname=d6relay */ -/* extrainfo=0 */ -/* ===== */ -, -"37.139.8.104:9030 orport=9001 id=7088D485934E8A403B81531F8C90BDC75FA43C98" -" ipv6=[2a03:b0c0:0:1010::24c:1001]:9001" -/* nickname=Basil */ -/* extrainfo=0 */ -/* ===== */ -, -"188.138.88.42:80 orport=443 id=70C55A114C0EF3DC5784A4FAEE64388434A3398F" -/* nickname=torpidsFRplusserver */ +"78.156.110.135:9093 orport=9092 id=7262B9D2EDE0B6A266C4B43D6202209BF6BBA888" +/* nickname=SkynetRenegade */ /* extrainfo=0 */ /* ===== */ , @@ -337,9 +310,14 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"50.7.74.173:9030 orport=9001 id=745369332749021C6FAF100D327BC3BF1DF4707B" -" ipv6=[2001:49f0:d002:2::55]:443" -/* nickname=theia5 */ +"81.7.14.31:9001 orport=443 id=7600680249A22080ECC6173FBBF64D6FCF330A61" +/* nickname=Ichotolot62 */ +/* extrainfo=1 */ +/* ===== */ +, +"62.171.144.155:80 orport=443 id=7614EF326635DA810638E2F5D449D10AE2BB7158" +" ipv6=[2a02:c207:3004:8874::1]:443" +/* nickname=Nicenstein */ /* extrainfo=0 */ /* ===== */ , @@ -359,6 +337,12 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , +"82.223.21.74:9030 orport=9001 id=7A32C9519D80CA458FC8B034A28F5F6815649A98" +" ipv6=[2001:ba0:1800:6c::1]:9001" +/* nickname=silentrocket */ +/* extrainfo=0 */ +/* ===== */ +, "51.254.136.195:80 orport=443 id=7BB70F8585DFC27E75D692970C0EEB0F22983A63" /* nickname=torproxy02 */ /* extrainfo=0 */ @@ -369,11 +353,6 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"185.220.101.48:10048 orport=20048 id=7E281CD2C315C4F7A84BC7C8721C3BC974DDBFA3" -/* nickname=niftyporcupine */ -/* extrainfo=0 */ -/* ===== */ -, "193.11.114.45:9031 orport=9002 id=80AAF8D5956A43C197104CEF2550CD42D165C6FB" /* nickname=mdfnet2 */ /* extrainfo=0 */ @@ -385,14 +364,14 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"192.42.116.16:80 orport=443 id=81B75D534F91BFB7C57AB67DA10BCEF622582AE8" -/* nickname=hviv104 */ +"152.89.106.147:9030 orport=9001 id=8111FEB45EF2950EB8F84BFD8FF070AB07AEE9DD" +" ipv6=[2a03:4000:39:605:c4f2:c9ff:fe64:c215]:9001" +/* nickname=TugaOnionMR3 */ /* extrainfo=0 */ /* ===== */ , -"192.160.102.164:80 orport=9001 id=823AA81E277F366505545522CEDC2F529CE4DC3F" -" ipv6=[2620:132:300c:c01d::4]:9002" -/* nickname=snowfall */ +"192.42.116.16:80 orport=443 id=81B75D534F91BFB7C57AB67DA10BCEF622582AE8" +/* nickname=hviv104 */ /* extrainfo=0 */ /* ===== */ , @@ -402,12 +381,7 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"62.210.254.132:80 orport=443 id=8456DFA94161CDD99E480C2A2992C366C6564410" -/* nickname=turingmachine */ -/* extrainfo=0 */ -/* ===== */ -, -"85.230.178.139:9030 orport=443 id=855BC2DABE24C861CD887DB9B2E950424B49FC34" +"85.228.136.92:9030 orport=443 id=855BC2DABE24C861CD887DB9B2E950424B49FC34" /* nickname=Logforme */ /* extrainfo=0 */ /* ===== */ @@ -417,42 +391,37 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"185.96.88.29:80 orport=443 id=86C281AD135058238D7A337D546C902BE8505DDE" -" ipv6=[2a00:4020::185:96:88:29]:443" -/* nickname=TykRelay05 */ -/* extrainfo=0 */ -/* ===== */ -, "163.172.194.53:9030 orport=9001 id=8C00FA7369A7A308F6A137600F0FA07990D9D451" " ipv6=[2001:bc8:225f:142:6c69:7461:7669:73]:9001" /* nickname=GrmmlLitavis */ /* extrainfo=0 */ /* ===== */ , -"5.189.169.190:8030 orport=8080 id=8D79F73DCD91FC4F5017422FAC70074D6DB8DD81" -/* nickname=thanatosDE */ +"188.138.102.98:465 orport=443 id=8CAA470B905758742203E3EB45941719FCA9FEEC" +/* nickname=BeastieJoy64 */ /* extrainfo=0 */ /* ===== */ , -"81.7.11.96:9030 orport=9001 id=8FA37B93397015B2BC5A525C908485260BE9F422" -/* nickname=Doedel22 */ +"109.70.100.6:80 orport=443 id=8CF987FF43FB7F3D9AA4C4F3D96FFDF247A9A6C2" +" ipv6=[2a03:e600:100::6]:443" +/* nickname=zucchini */ /* extrainfo=0 */ /* ===== */ , -"54.37.139.118:9030 orport=9001 id=90A5D1355C4B5840E950EB61E673863A6AE3ACA1" -" ipv6=[2001:41d0:601:1100::1b8]:9001" -/* nickname=rofltor09 */ +"5.189.169.190:8030 orport=8080 id=8D79F73DCD91FC4F5017422FAC70074D6DB8DD81" +/* nickname=thanatosDE */ /* extrainfo=0 */ /* ===== */ , -"37.187.20.59:80 orport=443 id=91D23D8A539B83D2FB56AA67ECD4D75CC093AC55" -" ipv6=[2001:41d0:a:143b::1]:993" -/* nickname=torpidsFRovh */ +"80.67.172.162:80 orport=443 id=8E6EDA78D8E3ABA88D877C3E37D6D4F0938C7B9F" +" ipv6=[2001:910:1410:600::1]:443" +/* nickname=AlGrothendieck */ /* extrainfo=0 */ /* ===== */ , -"173.255.245.116:9030 orport=9001 id=91E4015E1F82DAF0121D62267E54A1F661AB6DC7" -/* nickname=IWorshipHisShadow */ +"54.37.139.118:9030 orport=9001 id=90A5D1355C4B5840E950EB61E673863A6AE3ACA1" +" ipv6=[2001:41d0:601:1100::1b8]:9001" +/* nickname=rofltor09 */ /* extrainfo=0 */ /* ===== */ , @@ -461,29 +430,21 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"92.38.163.21:9030 orport=443 id=9288B75B5FF8861EFF32A6BE8825CC38A4F9F8C2" -/* nickname=angeltest9 */ +"109.70.100.5:80 orport=443 id=9661AC95717798884F3E3727D360DD98D66727CC" +" ipv6=[2a03:e600:100::5]:443" +/* nickname=erdapfel */ /* extrainfo=0 */ /* ===== */ , -"163.172.53.84:80 orport=443 id=935F589545B8A271A722E330445BB99F67DBB058" -" ipv6=[2001:bc8:24f8::]:443" -/* nickname=Multivac0 */ -/* extrainfo=0 */ -/* ===== */ -, -"204.8.156.142:80 orport=443 id=94C4B7B8C50C86A92B6A20107539EE2678CF9A28" -/* nickname=BostonUCompSci */ -/* extrainfo=0 */ -/* ===== */ -, -"37.153.1.10:9030 orport=9001 id=9772EFB535397C942C3AB8804FB35CFFAD012438" -/* nickname=smallsweatnode */ +"173.212.254.192:31336 orport=31337 id=99E246DB480B313A3012BC3363093CC26CD209C7" +" ipv6=[2a02:c207:3002:3972::1]:31337" +/* nickname=ViDiSrv */ /* extrainfo=0 */ /* ===== */ , -"173.212.254.192:31336 orport=31337 id=99E246DB480B313A3012BC3363093CC26CD209C7" -/* nickname=ViDiSrv */ +"188.127.69.60:80 orport=443 id=9B2BC7EFD661072AFADC533BE8DCF1C19D8C2DCC" +" ipv6=[2a02:29d0:8008:c0de:bad:beef::]:443" +/* nickname=MIGHTYWANG */ /* extrainfo=0 */ /* ===== */ , @@ -493,8 +454,9 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"185.220.101.49:10049 orport=20049 id=9B816A5B3EB20B8E4E9B9D1FBA299BD3F40F0320" -/* nickname=niftypygmyjerboa */ +"95.142.161.63:80 orport=443 id=9BA84E8C90083676F86C7427C8D105925F13716C" +" ipv6=[2001:4b98:dc0:47:216:3eff:fe3d:888c]:443" +/* nickname=ekumen */ /* extrainfo=0 */ /* ===== */ , @@ -503,11 +465,6 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"31.185.104.19:80 orport=443 id=9EAD5B2D3DBD96DBC80DCE423B0C345E920A758D" -/* nickname=Digitalcourage3ip1 */ -/* extrainfo=0 */ -/* ===== */ -, "46.28.110.244:80 orport=443 id=9F7D6E6420183C2B76D3CE99624EBC98A21A967E" /* nickname=Nivrim */ /* extrainfo=0 */ @@ -518,9 +475,10 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=1 */ /* ===== */ , -"81.7.3.67:993 orport=443 id=A2E6BB5C391CD46B38C55B4329C35304540771F1" -/* nickname=BeastieJoy62 */ -/* extrainfo=1 */ +"193.234.15.55:80 orport=443 id=A1B28D636A56AAFFE92ADCCA937AA4BD5333BB4C" +" ipv6=[2a00:1c20:4089:1234:7b2c:11c5:5221:903e]:443" +/* nickname=bakunin4 */ +/* extrainfo=0 */ /* ===== */ , "128.31.0.13:80 orport=443 id=A53C46F5B157DD83366D45A8E99A244934A14C46" @@ -528,8 +486,8 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"185.246.152.22:9030 orport=443 id=A86EC24F5B8B964F67AC7C27CE92842025983274" -/* nickname=angeltest19 */ +"212.47.233.86:9130 orport=9101 id=A68097FE97D3065B1A6F4CE7187D753F8B8513F5" +/* nickname=olabobamanmu */ /* extrainfo=0 */ /* ===== */ , @@ -543,26 +501,26 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"185.129.62.62:9030 orport=9001 id=ACDD9E85A05B127BA010466C13C8C47212E8A38F" -" ipv6=[2a06:d380:0:3700::62]:9001" -/* nickname=kramse */ +"195.154.164.243:80 orport=443 id=AC66FFA4AB35A59EBBF5BF4C70008BF24D8A7A5C" +" ipv6=[2001:bc8:399f:f000::1]:993" +/* nickname=torpidsFRonline3 */ /* extrainfo=0 */ /* ===== */ , -"31.185.104.20:80 orport=443 id=ADB2C26629643DBB9F8FE0096E7D16F9414B4F8D" -/* nickname=Digitalcourage3ip2 */ +"185.129.62.62:9030 orport=9001 id=ACDD9E85A05B127BA010466C13C8C47212E8A38F" +" ipv6=[2a06:d380:0:3700::62]:9001" +/* nickname=kramse */ /* extrainfo=0 */ /* ===== */ , -"45.79.108.130:9030 orport=9001 id=AEDAC7081AE14B8D241ECF0FF17A2858AB4383D0" -" ipv6=[2600:3c01:e000:131::8000:0]:9001" -/* nickname=linss */ +"188.40.128.246:9030 orport=9001 id=AD19490C7DBB26D3A68EFC824F67E69B0A96E601" +" ipv6=[2a01:4f8:221:1ac1:dead:beef:7005:9001]:9001" +/* nickname=sputnik */ /* extrainfo=0 */ /* ===== */ , -"5.9.147.226:9030 orport=9001 id=B0553175AADB0501E5A61FC61CEA3970BE130FF2" -" ipv6=[2a01:4f8:190:30e1::2]:9001" -/* nickname=zwiubel */ +"176.10.104.240:8080 orport=8443 id=AD86CD1A49573D52A7B6F4A35750F161AAD89C88" +/* nickname=DigiGesTor1e2 */ /* extrainfo=0 */ /* ===== */ , @@ -577,9 +535,9 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"199.249.230.64:80 orport=443 id=B2197C23A4FF5D1C49EE45BA7688BA8BCCD89A0B" -" ipv6=[2620:7:6001::ffff:c759:e640]:80" -/* nickname=Quintex41 */ +"109.70.100.2:80 orport=443 id=B27CF1DCEECD50F7992B07D720D7F6BF0EDF9D40" +" ipv6=[2a03:e600:100::2]:443" +/* nickname=radieschen */ /* extrainfo=0 */ /* ===== */ , @@ -588,21 +546,11 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"212.47.233.86:9030 orport=9001 id=B4CAFD9CBFB34EC5DAAC146920DC7DFAFE91EA20" -/* nickname=netimanmu */ -/* extrainfo=0 */ -/* ===== */ -, "93.115.97.242:9030 orport=9001 id=B5212DB685A2A0FCFBAE425738E478D12361710D" /* nickname=firstor */ /* extrainfo=0 */ /* ===== */ , -"51.38.134.104:9030 orport=443 id=B57A87009FA838471FB2227DDE68165AB2A2FCC4" -/* nickname=angeltest5 */ -/* extrainfo=0 */ -/* ===== */ -, "193.11.114.46:9032 orport=9003 id=B83DC1558F0D34353BB992EF93AFEAFDB226A73E" /* nickname=mdfnet3 */ /* extrainfo=0 */ @@ -614,12 +562,8 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"81.7.11.186:1080 orport=443 id=B86137AE9681701901C6720E55C16805B46BD8E3" -/* nickname=BeastieJoy60 */ -/* extrainfo=1 */ -/* ===== */ -, "51.15.179.153:110 orport=995 id=BB60F5BA113A0B8B44B7B37DE3567FE561E92F78" +" ipv6=[2001:bc8:3fec:500:7ea::]:995" /* nickname=Casper04 */ /* extrainfo=0 */ /* ===== */ @@ -648,13 +592,7 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o , "212.47.233.250:9030 orport=9001 id=BF735F669481EE1CCC348F0731551C933D1E2278" " ipv6=[2001:bc8:4400:2b00::1c:629]:9001" -/* nickname=FreewaySca */ -/* extrainfo=0 */ -/* ===== */ -, -"192.160.102.169:80 orport=9001 id=C0192FF43E777250084175F4E59AC1BA2290CE38" -" ipv6=[2620:132:300c:c01d::9]:9002" -/* nickname=manipogo */ +/* nickname=freeway */ /* extrainfo=0 */ /* ===== */ , @@ -663,8 +601,9 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"31.185.104.21:80 orport=443 id=C2AAB088555850FC434E68943F551072042B85F1" -/* nickname=Digitalcourage3ip3 */ +"109.70.100.3:80 orport=443 id=C282248597D1C8522A2A7525E61C8B77BBC37614" +" ipv6=[2a03:e600:100::3]:443" +/* nickname=erbse */ /* extrainfo=0 */ /* ===== */ , @@ -674,15 +613,25 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , +"188.138.112.60:1433 orport=1521 id=C414F28FD2BEC1553024299B31D4E726BEB8E788" +/* nickname=zebra620 */ +/* extrainfo=0 */ +/* ===== */ +, +"178.20.55.18:80 orport=443 id=C656B41AEFB40A141967EBF49D6E69603C9B4A11" +/* nickname=marcuse2 */ +/* extrainfo=0 */ +/* ===== */ +, "85.248.227.163:443 orport=9001 id=C793AB88565DDD3C9E4C6F15CCB9D8C7EF964CE9" " ipv6=[2a00:1298:8011:212::163]:9003" /* nickname=ori */ /* extrainfo=0 */ /* ===== */ , -"192.160.102.165:80 orport=9001 id=C90CA3B7FE01A146B8268D56977DC4A2C024B9EA" -" ipv6=[2620:132:300c:c01d::5]:9002" -/* nickname=cowcat */ +"50.7.74.173:80 orport=443 id=C87A4D8B534F78FDF0F4639B55F121401FEF259C" +" ipv6=[2001:49f0:d002:2::54]:443" +/* nickname=theia4 */ /* extrainfo=0 */ /* ===== */ , @@ -691,8 +640,14 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"51.254.147.57:80 orport=443 id=D15AFF44BE641368B958A32FB6B071AC2136B8B1" -/* nickname=Cosworth01 */ +"193.234.15.62:80 orport=443 id=CD0F9AA1A5064430B1DE8E645CBA7A502B27ED5F" +" ipv6=[2a00:1c20:4089:1234:a6a4:2926:d0af:dfee]:443" +/* nickname=jaures4 */ +/* extrainfo=0 */ +/* ===== */ +, +"85.25.213.211:465 orport=80 id=CE47F0356D86CF0A1A2008D97623216D560FB0A8" +/* nickname=BeastieJoy61 */ /* extrainfo=0 */ /* ===== */ , @@ -702,9 +657,9 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"62.141.38.69:9030 orport=443 id=D379A1CB8285748FFF64AE94296CA89878F25B22" -" ipv6=[2001:4ba0:cafe:ac5::1]:443" -/* nickname=angeltest3 */ +"66.111.2.20:9030 orport=9001 id=D317C7889162E9EC4A1DA1A1095C2A0F377536D9" +" ipv6=[2610:1c0:0:5::20]:9001" +/* nickname=NYCBUG0 */ /* extrainfo=0 */ /* ===== */ , @@ -714,25 +669,13 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"50.7.74.174:80 orport=443 id=D50101A2ABD09DC245F7E96C0818D003CDD62351" -" ipv6=[2001:49f0:d002:2::56]:443" -/* nickname=theia6 */ +"12.235.151.200:9030 orport=9029 id=D5C33F3E203728EDF8361EA868B2939CCC43FAFB" +/* nickname=nx1tor */ /* extrainfo=0 */ /* ===== */ , -"37.187.115.157:9030 orport=9001 id=D5039E1EBFD96D9A3F9846BF99EC9F75EDDE902A" -/* nickname=Janky328891 */ -/* extrainfo=0 */ -/* ===== */ -, -"85.10.201.47:9030 orport=9001 id=D8B7A3A6542AA54D0946B9DC0257C53B6C376679" -" ipv6=[2a01:4f8:a0:43eb::beef]:9001" -/* nickname=sif */ -/* extrainfo=0 */ -/* ===== */ -, -"193.35.52.53:9030 orport=9001 id=DAA39FC00B196B353C2A271459C305C429AF09E4" -/* nickname=Arne */ +"212.83.166.62:80 orport=443 id=D7082DB97E7F0481CBF4B88CA5F5683399E196A3" +/* nickname=shhop */ /* extrainfo=0 */ /* ===== */ , @@ -741,26 +684,15 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"176.158.236.102:9030 orport=9001 id=DC163DDEF4B6F0C6BC226F9F6656A5A30C5C5686" -/* nickname=Underworld */ -/* extrainfo=0 */ -/* ===== */ -, -"178.33.183.251:80 orport=443 id=DD823AFB415380A802DCAEB9461AE637604107FB" -" ipv6=[2001:41d0:2:a683::251]:443" -/* nickname=grenouille */ -/* extrainfo=0 */ -/* ===== */ -, "171.25.193.20:80 orport=443 id=DD8BD7307017407FCC36F8D04A688F74A0774C02" " ipv6=[2001:67c:289c::20]:443" /* nickname=DFRI0 */ /* extrainfo=0 */ /* ===== */ , -"92.222.38.67:80 orport=443 id=DED6892FF89DBD737BA689698A171B2392EB3E82" -" ipv6=[2001:41d0:52:100::112a]:443" -/* nickname=ThorExit */ +"83.212.99.68:80 orport=443 id=DDBB2A38252ADDA53E4492DDF982CA6CC6E10EC0" +" ipv6=[2001:648:2ffc:1225:a800:bff:fe3d:67b5]:443" +/* nickname=zouzounella */ /* extrainfo=0 */ /* ===== */ , @@ -785,8 +717,13 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"131.188.40.188:1443 orport=80 id=EBE718E1A49EE229071702964F8DB1F318075FF8" -" ipv6=[2001:638:a000:4140::ffff:188]:80" +"195.154.105.170:9030 orport=9001 id=E947C029087FA1C3499BEF5D4372947C51223D8F" +/* nickname=dgplug */ +/* extrainfo=0 */ +/* ===== */ +, +"131.188.40.188:1443 orport=11180 id=EBE718E1A49EE229071702964F8DB1F318075FF8" +" ipv6=[2001:638:a000:4140::ffff:188]:11180" /* nickname=fluxe4 */ /* extrainfo=1 */ /* ===== */ @@ -797,9 +734,8 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"37.252.187.111:9030 orport=443 id=EE4AF632058F0734C1426B1AD689F47445CA2056" -" ipv6=[2a00:63c1:c:111::2]:443" -/* nickname=angeltest7 */ +"178.20.55.16:80 orport=443 id=EFAE44728264982224445E96214C15F9075DEE1D" +/* nickname=marcuse1 */ /* extrainfo=0 */ /* ===== */ , @@ -808,8 +744,15 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"193.70.112.165:80 orport=443 id=F10BDE279AE71515DDCCCC61DC19AC8765F8A3CC" -/* nickname=ParkBenchInd001 */ +"193.234.15.58:80 orport=443 id=F24F8BEA2779A79111F33F6832B062BED306B9CB" +" ipv6=[2a00:1c20:4089:1234:cdae:1b3e:cc38:3d45]:443" +/* nickname=jaures2 */ +/* extrainfo=0 */ +/* ===== */ +, +"129.13.131.140:80 orport=443 id=F2DFE5FA1E4CF54F8E761A6D304B9B4EC69BDAE8" +" ipv6=[2a00:1398:5:f604:cafe:cafe:cafe:9001]:443" +/* nickname=AlleKochenKaffee */ /* extrainfo=0 */ /* ===== */ , @@ -824,9 +767,9 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , -"192.160.102.168:80 orport=9001 id=F6A358DD367B3282D6EF5824C9D45E1A19C7E815" -" ipv6=[2620:132:300c:c01d::8]:9002" -/* nickname=prawksi */ +"163.172.154.162:9030 orport=9001 id=F741E5124CB12700DA946B78C9B2DD175D6CD2A1" +" ipv6=[2001:bc8:47a0:162a::1]:9001" +/* nickname=rofltor06 */ /* extrainfo=0 */ /* ===== */ , @@ -836,10 +779,9 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=1 */ /* ===== */ , -"185.96.180.29:80 orport=443 id=F93D8F37E35C390BCAD9F9069E13085B745EC216" -" ipv6=[2a00:4820::185:96:180:29]:443" -/* nickname=TykRelay06 */ -/* extrainfo=0 */ +"91.143.88.62:80 orport=443 id=F9246DEF2B653807236DA134F2AEAB103D58ABFE" +/* nickname=Freebird31 */ +/* extrainfo=1 */ /* ===== */ , "149.56.45.200:9030 orport=9001 id=FE296180018833AF03A8EACD5894A614623D3F76" @@ -848,6 +790,12 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&o /* extrainfo=0 */ /* ===== */ , +"62.141.38.69:80 orport=443 id=FF9FC6D130FA26AE3AE8B23688691DC419F0F22E" +" ipv6=[2001:4ba0:cafe:ac5::]:443" +/* nickname=rinderwahnRelay3L */ +/* extrainfo=0 */ +/* ===== */ +, "193.11.164.243:9030 orport=9001 id=FFA72BD683BC2FCF988356E6BEC1E490F313FB07" " ipv6=[2001:6b0:7:125::243]:9001" /* nickname=Lule */ diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h index 07126cc6ce..3b84e5e1f2 100644 --- a/src/app/config/or_options_st.h +++ b/src/app/config/or_options_st.h @@ -35,6 +35,12 @@ typedef enum { TCP_PROXY_PROTOCOL_HAPROXY } tcp_proxy_protocol_t; +/** Enumeration of available time formats for output of --key-expiration */ +typedef enum { + KEY_EXPIRATION_FORMAT_ISO8601 = 0, + KEY_EXPIRATION_FORMAT_TIMESTAMP +} key_expiration_format_t; + /** Configuration options for a Tor process. */ struct or_options_t { uint32_t magic_; @@ -75,6 +81,10 @@ struct or_options_t { * options is accepted as in IPv4 and IPv6. */ struct config_line_t *Address; + /** Boolean: If set, disable IPv6 address resolution, IPv6 ORPorts, IPv6 + * reachability checks, and publishing an IPv6 ORPort in its descriptor. */ + int AddressDisableIPv6; + char *PidFile; /**< Where to store PID of Tor process. */ struct routerset_t *ExitNodes; /**< Structure containing nicknames, digests, @@ -658,7 +668,7 @@ struct or_options_t { int ClientUseIPv4; /** If true, clients may connect over IPv6. If false, they will avoid * connecting over IPv4. We enforce this for OR and Dir connections. - * Use fascist_firewall_use_ipv6() instead of accessing this value + * Use reachable_addr_use_ipv6() instead of accessing this value * directly. */ int ClientUseIPv6; /** If true, prefer an IPv6 OR port over an IPv4 one for entry node @@ -668,7 +678,7 @@ struct or_options_t { int ClientPreferIPv6ORPort; /** If true, prefer an IPv6 directory port over an IPv4 one for direct * directory connections. If auto, bridge clients prefer IPv6, and other - * clients prefer IPv4. Use fascist_firewall_prefer_ipv6_dirport() instead of + * clients prefer IPv4. Use reachable_addr_prefer_ipv6_dirport() instead of * accessing this value directly. */ int ClientPreferIPv6DirPort; @@ -940,6 +950,8 @@ struct or_options_t { * ed25519 identity key except from tor --keygen */ int OfflineMasterKey; + key_expiration_format_t key_expiration_format; + enum { FORCE_PASSPHRASE_AUTO=0, FORCE_PASSPHRASE_ON, diff --git a/src/app/config/resolve_addr.c b/src/app/config/resolve_addr.c index 7ec5ae565a..a153d63974 100644 --- a/src/app/config/resolve_addr.c +++ b/src/app/config/resolve_addr.c @@ -14,6 +14,7 @@ #include "core/mainloop/mainloop.h" #include "feature/control/control_events.h" +#include "feature/dirauth/authmode.h" #include "lib/encoding/confline.h" #include "lib/net/gethostname.h" @@ -54,6 +55,11 @@ static tor_addr_t last_suggested_addrs[] = { TOR_ADDR_NULL, TOR_ADDR_NULL, TOR_ADDR_NULL }; CTASSERT(ARRAY_LENGTH(last_suggested_addrs) == IDX_SIZE); +/** True iff the address was found to be configured that is from the + * configuration file either using Address or ORPort. */ +static bool last_addrs_configured[] = { false, false, false }; +CTASSERT(ARRAY_LENGTH(last_addrs_configured) == IDX_SIZE); + static inline int af_to_idx(const int family) { @@ -70,6 +76,41 @@ af_to_idx(const int family) } } +/** Return string representation of the given method. */ +const char * +resolved_addr_method_to_str(const resolved_addr_method_t method) +{ + switch (method) { + case RESOLVED_ADDR_NONE: + return "NONE"; + case RESOLVED_ADDR_CONFIGURED: + return "CONFIGURED"; + case RESOLVED_ADDR_CONFIGURED_ORPORT: + return "CONFIGURED_ORPORT"; + case RESOLVED_ADDR_GETHOSTNAME: + return "GETHOSTNAME"; + case RESOLVED_ADDR_INTERFACE: + return "INTERFACE"; + case RESOLVED_ADDR_RESOLVED: + return "RESOLVED"; + default: + tor_assert_nonfatal_unreached(); + return "???"; + } +} + +/** Return true if the last address of family was configured or not. An + * address is considered configured if it was found in the Address or ORPort + * statement. + * + * This applies to the address returned by the function + * resolved_addr_get_last() which is the cache of discovered addresses. */ +bool +resolved_addr_is_configured(int family) +{ + return last_addrs_configured[af_to_idx(family)]; +} + /** Copy the last suggested address of family into addr_out. * * If no last suggested address exists, the addr_out is a null address (use @@ -177,8 +218,8 @@ address_can_be_used(const tor_addr_t *addr, const or_options_t *options, * @param options Global configuration options. * @param warn_severity Log level that should be used on error. * @param family IP address family. Only AF_INET and AF_INET6 are supported. - * @param method_out OUT: String denoting by which method the address was - * found. This is described in the control-spec.txt as + * @param method_out OUT: Method denoting how the address was found. + * This is described in the control-spec.txt as * actions for "STATUS_SERVER". * @param hostname_out OUT: String containing the hostname gotten from the * Address value if any. @@ -190,11 +231,11 @@ address_can_be_used(const tor_addr_t *addr, const or_options_t *options, */ static fn_address_ret_t get_address_from_config(const or_options_t *options, int warn_severity, - int family, const char **method_out, + int family, resolved_addr_method_t *method_out, char **hostname_out, tor_addr_t *addr_out) { int ret; - bool explicit_ip = false; + bool explicit_ip = false, resolve_failure = false; int num_valid_addr = 0; tor_assert(options); @@ -204,7 +245,7 @@ get_address_from_config(const or_options_t *options, int warn_severity, /* Set them to NULL for safety reasons. */ *hostname_out = NULL; - *method_out = NULL; + *method_out = RESOLVED_ADDR_NONE; log_debug(LD_CONFIG, "Attempting to get address from configuration"); @@ -222,7 +263,7 @@ get_address_from_config(const or_options_t *options, int warn_severity, af = tor_addr_parse(&addr, cfg->value); if (af == family) { tor_addr_copy(addr_out, &addr); - *method_out = "CONFIGURED"; + *method_out = RESOLVED_ADDR_CONFIGURED; explicit_ip = true; num_valid_addr++; continue; @@ -236,7 +277,7 @@ get_address_from_config(const or_options_t *options, int warn_severity, * do a DNS lookup. */ if (!tor_addr_lookup(cfg->value, family, &addr)) { tor_addr_copy(addr_out, &addr); - *method_out = "RESOLVED"; + *method_out = RESOLVED_ADDR_RESOLVED; if (*hostname_out) { tor_free(*hostname_out); } @@ -246,6 +287,7 @@ get_address_from_config(const or_options_t *options, int warn_severity, continue; } else { /* Hostname that can't be resolved, this is a fatal error. */ + resolve_failure = true; log_fn(warn_severity, LD_CONFIG, "Could not resolve local Address '%s'. Failing.", cfg->value); continue; @@ -253,13 +295,16 @@ get_address_from_config(const or_options_t *options, int warn_severity, } if (!num_valid_addr) { - log_fn(warn_severity, LD_CONFIG, - "No Address option found for family %s in configuration.", - fmt_af_family(family)); - /* No Address statement for family but one exists since Address is not - * NULL thus we have to stop now and not attempt to send back a guessed - * address. */ - return FN_RET_BAIL; + if (resolve_failure) { + /* We found no address but we got a resolution failure. This means we + * can know if the hostname given was v4 or v6 so we can't continue. */ + return FN_RET_BAIL; + } + log_info(LD_CONFIG, + "No Address option found for family %s in configuration.", + fmt_af_family(family)); + /* No Address statement for family so move on to try next method. */ + return FN_RET_NEXT; } if (num_valid_addr >= MAX_CONFIG_ADDRESS) { @@ -283,8 +328,8 @@ get_address_from_config(const or_options_t *options, int warn_severity, } /* Address can be used. We are done. */ - log_fn(warn_severity, LD_CONFIG, "Address found in configuration: %s", - fmt_addr(addr_out)); + log_info(LD_CONFIG, "Address found in configuration: %s", + fmt_addr(addr_out)); return FN_RET_OK; } @@ -294,8 +339,8 @@ get_address_from_config(const or_options_t *options, int warn_severity, * @param options Global configuration options. * @param warn_severity Log level that should be used on error. * @param family IP address family. Only AF_INET and AF_INET6 are supported. - * @param method_out OUT: String denoting by which method the address was - * found. This is described in the control-spec.txt as + * @param method_out OUT: Method denoting how the address was found. + * This is described in the control-spec.txt as * actions for "STATUS_SERVER". * @param hostname_out OUT: String containing the local hostname. * @param addr_out OUT: Tor address resolved from the local hostname. @@ -305,7 +350,7 @@ get_address_from_config(const or_options_t *options, int warn_severity, */ static fn_address_ret_t get_address_from_hostname(const or_options_t *options, int warn_severity, - int family, const char **method_out, + int family, resolved_addr_method_t *method_out, char **hostname_out, tor_addr_t *addr_out) { int ret; @@ -316,7 +361,7 @@ get_address_from_hostname(const or_options_t *options, int warn_severity, /* Set them to NULL for safety reasons. */ *hostname_out = NULL; - *method_out = NULL; + *method_out = RESOLVED_ADDR_NONE; log_debug(LD_CONFIG, "Attempting to get address from local hostname"); @@ -342,12 +387,12 @@ get_address_from_hostname(const or_options_t *options, int warn_severity, } /* addr_out contains the address of the local hostname. */ - *method_out = "GETHOSTNAME"; + *method_out = RESOLVED_ADDR_GETHOSTNAME; *hostname_out = tor_strdup(hostname); /* Found it! */ - log_fn(warn_severity, LD_CONFIG, "Address found from local hostname: %s", - fmt_addr(addr_out)); + log_info(LD_CONFIG, "Address found from local hostname: %s", + fmt_addr(addr_out)); return FN_RET_OK; } @@ -356,8 +401,9 @@ get_address_from_hostname(const or_options_t *options, int warn_severity, * @param options Global configuration options. * @param warn_severity Log level that should be used on error. * @param family IP address family. Only AF_INET and AF_INET6 are supported. - * @param method_out OUT: Always "INTERFACE" on success which is detailed in - * the control-spec.txt as actions for "STATUS_SERVER". + * @param method_out OUT: Always RESOLVED_ADDR_INTERFACE on success which + * is detailed in the control-spec.txt as actions + * for "STATUS_SERVER". * @param hostname_out OUT: String containing the local hostname. For this * function, it is always set to NULL. * @param addr_out OUT: Tor address found attached to the interface. @@ -367,7 +413,7 @@ get_address_from_hostname(const or_options_t *options, int warn_severity, */ static fn_address_ret_t get_address_from_interface(const or_options_t *options, int warn_severity, - int family, const char **method_out, + int family, resolved_addr_method_t *method_out, char **hostname_out, tor_addr_t *addr_out) { int ret; @@ -377,7 +423,7 @@ get_address_from_interface(const or_options_t *options, int warn_severity, tor_assert(addr_out); /* Set them to NULL for safety reasons. */ - *method_out = NULL; + *method_out = RESOLVED_ADDR_NONE; *hostname_out = NULL; log_debug(LD_CONFIG, "Attempting to get address from network interface"); @@ -395,11 +441,10 @@ get_address_from_interface(const or_options_t *options, int warn_severity, return FN_RET_NEXT; } - *method_out = "INTERFACE"; + *method_out = RESOLVED_ADDR_INTERFACE; /* Found it! */ - log_fn(warn_severity, LD_CONFIG, "Address found from interface: %s", - fmt_addr(addr_out)); + log_info(LD_CONFIG, "Address found from interface: %s", fmt_addr(addr_out)); return FN_RET_OK; } @@ -408,8 +453,8 @@ get_address_from_interface(const or_options_t *options, int warn_severity, * @param options Global configuration options. * @param warn_severity Log level that should be used on error. * @param family IP address family. Only AF_INET and AF_INET6 are supported. - * @param method_out OUT: Always "CONFIGURED_ORPORT" on success which is - * detailed in the control-spec.txt as actions + * @param method_out OUT: Always RESOLVED_ADDR_CONFIGURED_ORPORT on success + * which is detailed in the control-spec.txt as actions * for "STATUS_SERVER". * @param hostname_out OUT: String containing the ORPort hostname if any. * @param addr_out OUT: Tor address found if any. @@ -419,7 +464,7 @@ get_address_from_interface(const or_options_t *options, int warn_severity, */ static fn_address_ret_t get_address_from_orport(const or_options_t *options, int warn_severity, - int family, const char **method_out, + int family, resolved_addr_method_t *method_out, char **hostname_out, tor_addr_t *addr_out) { int ret; @@ -429,6 +474,10 @@ get_address_from_orport(const or_options_t *options, int warn_severity, tor_assert(hostname_out); tor_assert(addr_out); + /* Set them to NULL for safety reasons. */ + *method_out = RESOLVED_ADDR_NONE; + *hostname_out = NULL; + log_debug(LD_CONFIG, "Attempting to get address from ORPort"); if (!options->ORPort_set) { @@ -452,7 +501,7 @@ get_address_from_orport(const or_options_t *options, int warn_severity, } /* Found it! */ - *method_out = "CONFIGURED_ORPORT"; + *method_out = RESOLVED_ADDR_CONFIGURED_ORPORT; tor_addr_copy(addr_out, addr); log_fn(warn_severity, LD_CONFIG, "Address found from ORPort: %s", @@ -477,7 +526,8 @@ get_address_from_orport(const or_options_t *options, int warn_severity, * NULL. (for logging and control port). */ void -resolved_addr_set_last(const tor_addr_t *addr, const char *method_used, +resolved_addr_set_last(const tor_addr_t *addr, + const resolved_addr_method_t method_used, const char *hostname_used) { /** Have we done a first resolve. This is used to control logging. */ @@ -489,7 +539,6 @@ resolved_addr_set_last(const tor_addr_t *addr, const char *method_used, tor_addr_t *last_resolved; tor_assert(addr); - tor_assert(method_used); /* Do we have an hostname. */ have_hostname = (hostname_used != NULL); @@ -516,7 +565,8 @@ resolved_addr_set_last(const tor_addr_t *addr, const char *method_used, log_notice(LD_NET, "Your IP address seems to have changed to %s " "(METHOD=%s%s%s). Updating.", - fmt_addr(addr), method_used, + fmt_addr(addr), + resolved_addr_method_to_str(method_used), have_hostname ? " HOSTNAME=" : "", have_hostname ? hostname_used : ""); ip_address_changed(0); @@ -525,20 +575,32 @@ resolved_addr_set_last(const tor_addr_t *addr, const char *method_used, /* Notify control port. */ control_event_server_status(LOG_NOTICE, "EXTERNAL_ADDRESS ADDRESS=%s METHOD=%s%s%s", - fmt_addr(addr), method_used, + fmt_addr(addr), + resolved_addr_method_to_str(method_used), have_hostname ? " HOSTNAME=" : "", have_hostname ? hostname_used : ""); /* Copy address to cache. */ tor_addr_copy(last_resolved, addr); *done_one_resolve = true; + + /* Flag true if the address was configured. Else, indicate it was not. */ + last_addrs_configured[idx] = false; + if (method_used == RESOLVED_ADDR_CONFIGURED || + method_used == RESOLVED_ADDR_CONFIGURED_ORPORT) { + last_addrs_configured[idx] = true; + } } +/** Ease our lives. Typedef to the address discovery function signature. */ +typedef fn_address_ret_t + (*fn_address_t)( + const or_options_t *options, int warn_severity, int family, + resolved_addr_method_t *method_out, char **hostname_out, + tor_addr_t *addr_out); + /** Address discovery function table. The order matters as in the first one is * executed first and so on. */ -static fn_address_ret_t - (*fn_address_table[])( - const or_options_t *options, int warn_severity, int family, - const char **method_out, char **hostname_out, tor_addr_t *addr_out) = +static const fn_address_t fn_address_table[] = { /* These functions are in order for our find address algorithm. */ get_address_from_config, @@ -547,7 +609,23 @@ static fn_address_ret_t get_address_from_hostname, }; /** Length of address table as in how many functions. */ -static const size_t fn_address_table_len = ARRAY_LENGTH(fn_address_table); +static const size_t fn_address_table_len = + ARRAY_LENGTH(fn_address_table); + +/* Address discover function table for authorities (bridge or directory). + * + * They only discover their address from either the configuration file or the + * ORPort. They do not query the interface nor do any DNS resolution for + * security reasons. */ +static const fn_address_t fn_address_table_auth[] = +{ + /* These functions are in order for our find address algorithm. */ + get_address_from_config, + get_address_from_orport, +}; +/** Length of address table as in how many functions. */ +static const size_t fn_address_table_auth_len = + ARRAY_LENGTH(fn_address_table_auth); /** @brief Attempt to find our IP address that can be used as our external * reachable address. @@ -563,16 +641,16 @@ static const size_t fn_address_table_len = ARRAY_LENGTH(fn_address_table); * 1. Look at the configuration Address option. * If Address is a public address, True is returned and addr_out is set - * with it, the method_out is set to "CONFIGURED" and hostname_out is set - * to NULL. + * with it, the method_out is set to RESOLVED_ADDR_CONFIGURED and + * hostname_out is set to NULL. * * If Address is an internal address but NO custom authorities are used, * an error is returned. * * If Address is a hostname, that is it can't be converted to an address, * it is resolved. On success, addr_out is set with the address, - * method_out is set to "RESOLVED" and hostname_out is set to the resolved - * hostname. On failure to resolve, an error is returned. + * method_out is set to RESOLVED_ADDR_RESOLVED and hostname_out is set + * to the resolved hostname. On failure to resolve, an error is returned. * * If no given Address, fallback to the local hostname (see section 2). * @@ -583,14 +661,14 @@ static const size_t fn_address_table_len = ARRAY_LENGTH(fn_address_table); * * On failure, we attempt to look at the local hostname (3). * - * On success, addr_out is set with it, method_out is set to "INTERFACE" - * and hostname_out is set to NULL. + * On success, addr_out is set with it, method_out is set to + * RESOLVED_ADDR_INTERFACE and hostname_out is set to NULL. * * 3. Look at the local hostname. * * If the local hostname resolves to a non internal address, addr_out is - * set with it, method_out is set to "GETHOSTNAME" and hostname_out is set - * to the resolved hostname. + * set with it, method_out is set to RESOLVED_ADDR_GETHOSTNAME and + * hostname_out is set to the resolved hostname. * * If a local hostname can NOT be found, an error is returned. * @@ -603,11 +681,11 @@ static const size_t fn_address_table_len = ARRAY_LENGTH(fn_address_table); * @param family IP address family. Only AF_INET and AF_INET6 are supported. * @param warn_severity Logging level. * @param addr_out OUT: Set with the IP address found if any. - * @param method_out OUT: (optional) String denoting by which method the - * address was found. This is described in the - * control-spec.txt as actions for "STATUS_SERVER". + * @param method_out OUT: (optional) Method denoting how the address wa + * found. This is described in the control-spec.txt as + * actions for "STATUS_SERVER". * @param hostname_out OUT: String containing the hostname if any was used. - * Only be set for "RESOLVED" and "GETHOSTNAME" methods. + * Only be set for RESOLVED and GETHOSTNAME methods. * Else it is set to NULL. * * @return True if the address was found for the given family. False if not or @@ -615,29 +693,44 @@ static const size_t fn_address_table_len = ARRAY_LENGTH(fn_address_table); */ bool find_my_address(const or_options_t *options, int family, int warn_severity, - tor_addr_t *addr_out, const char **method_out, + tor_addr_t *addr_out, resolved_addr_method_t *method_out, char **hostname_out) { - const char *method_used = NULL; + resolved_addr_method_t method_used = RESOLVED_ADDR_NONE; char *hostname_used = NULL; tor_addr_t my_addr; + const fn_address_t *table = fn_address_table; + size_t table_len = fn_address_table_len; tor_assert(options); tor_assert(addr_out); /* Set them to NULL for safety reasons. */ - if (method_out) *method_out = NULL; + tor_addr_make_unspec(addr_out); + if (method_out) *method_out = RESOLVED_ADDR_NONE; if (hostname_out) *hostname_out = NULL; + /* If an IPv6 is requested, check if IPv6 address discovery is disabled and + * if so we always return a failure. It is done here so we don't populate + * the resolve cache or do any DNS resolution. */ + if (family == AF_INET6 && options->AddressDisableIPv6) { + return false; + } + + /* For authorities (bridge and directory), we use a different table. */ + if (authdir_mode(options)) { + table = fn_address_table_auth; + table_len = fn_address_table_auth_len; + } + /* - * Step 1: Discover address by attempting 3 different methods consecutively. + * Step 1: Discover address by calling methods from the function table. */ /* Go over the function table. They are in order. */ - for (size_t idx = 0; idx < fn_address_table_len; idx++) { - fn_address_ret_t ret = fn_address_table[idx](options, warn_severity, - family, &method_used, - &hostname_used, &my_addr); + for (size_t idx = 0; idx < table_len; idx++) { + fn_address_ret_t ret = table[idx](options, warn_severity, family, + &method_used, &hostname_used, &my_addr); if (ret == FN_RET_BAIL) { return false; } else if (ret == FN_RET_OK) { @@ -729,3 +822,13 @@ is_local_to_resolve_addr, (const tor_addr_t *addr)) return false; } } + +#ifdef TOR_UNIT_TESTS + +void +resolve_addr_reset_suggested(int family) +{ + tor_addr_make_unspec(&last_suggested_addrs[af_to_idx(family)]); +} + +#endif /* TOR_UNIT_TESTS */ diff --git a/src/app/config/resolve_addr.h b/src/app/config/resolve_addr.h index d9a3e28924..96c86eeeea 100644 --- a/src/app/config/resolve_addr.h +++ b/src/app/config/resolve_addr.h @@ -14,25 +14,53 @@ #include "app/config/or_options_st.h" +/** Method used to resolved an address. In other words, how was the address + * discovered by tor. */ +typedef enum { + /* Default value. Indiate that no method found the address. */ + RESOLVED_ADDR_NONE = 0, + /* Found from the "Address" configuration option. */ + RESOLVED_ADDR_CONFIGURED = 1, + /* Found from the "ORPort" configuration option. */ + RESOLVED_ADDR_CONFIGURED_ORPORT = 2, + /* Found by resolving the local hostname. */ + RESOLVED_ADDR_GETHOSTNAME = 3, + /* Found by querying the local interface(s). */ + RESOLVED_ADDR_INTERFACE = 4, + /* Found by resolving the hostname from the Address configuration option. */ + RESOLVED_ADDR_RESOLVED = 5, +} resolved_addr_method_t; + +const char *resolved_addr_method_to_str(const resolved_addr_method_t method); + #define get_orport_addr(family) \ - (get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER, family)) + (portconf_get_first_advertised_addr(CONN_TYPE_OR_LISTENER, family)) bool find_my_address(const or_options_t *options, int family, int warn_severity, tor_addr_t *addr_out, - const char **method_out, char **hostname_out); + resolved_addr_method_t *method_out, char **hostname_out); void resolved_addr_get_last(int family, tor_addr_t *addr_out); void resolved_addr_reset_last(int family); -void resolved_addr_set_last(const tor_addr_t *addr, const char *method_used, +void resolved_addr_set_last(const tor_addr_t *addr, + const resolved_addr_method_t method_used, const char *hostname_used); void resolved_addr_get_suggested(int family, tor_addr_t *addr_out); void resolved_addr_set_suggested(const tor_addr_t *addr); +bool resolved_addr_is_configured(int family); + MOCK_DECL(bool, is_local_to_resolve_addr, (const tor_addr_t *addr)); #ifdef RESOLVE_ADDR_PRIVATE +#ifdef TOR_UNIT_TESTS + +void resolve_addr_reset_suggested(int family); + +#endif /* TOR_UNIT_TESTS */ + #endif /* RESOLVE_ADDR_PRIVATE */ #endif /* TOR_CONFIG_RESOLVE_ADDR_H */ diff --git a/src/app/main/main.c b/src/app/main/main.c index 4b1308ddf0..31a4f141ad 100644 --- a/src/app/main/main.c +++ b/src/app/main/main.c @@ -67,6 +67,7 @@ #include "lib/meminfo/meminfo.h" #include "lib/osinfo/uname.h" +#include "lib/osinfo/libc.h" #include "lib/sandbox/sandbox.h" #include "lib/fs/lockfile.h" #include "lib/tls/tortls.h" @@ -338,16 +339,12 @@ dumpstats(int severity) SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) { int i = conn_sl_idx; tor_log(severity, LD_GENERAL, - "Conn %d (socket %d) type %d (%s), state %d (%s), created %d secs ago", - i, (int)conn->s, conn->type, conn_type_to_string(conn->type), - conn->state, conn_state_to_string(conn->type, conn->state), + "Conn %d (socket %d) is a %s, created %d secs ago", + i, (int)conn->s, + connection_describe(conn), (int)(now - conn->timestamp_created)); if (!connection_is_listener(conn)) { tor_log(severity,LD_GENERAL, - "Conn %d is to %s:%d.", i, - safe_str_client(conn->address), - conn->port); - tor_log(severity,LD_GENERAL, "Conn %d: %d bytes waiting on inbuf (len %d, last read %d secs ago)", i, (int)connection_get_inbuf_len(conn), @@ -578,7 +575,8 @@ tor_init(int argc, char *argv[]) const char *version = get_version(); log_notice(LD_GENERAL, "Tor %s running on %s with Libevent %s, " - "%s %s, Zlib %s, Liblzma %s, and Libzstd %s.", version, + "%s %s, Zlib %s, Liblzma %s, Libzstd %s and %s %s as libc.", + version, get_uname(), tor_libevent_get_version_str(), crypto_get_library_name(), @@ -588,7 +586,10 @@ tor_init(int argc, char *argv[]) tor_compress_supports_method(LZMA_METHOD) ? tor_compress_version_str(LZMA_METHOD) : "N/A", tor_compress_supports_method(ZSTD_METHOD) ? - tor_compress_version_str(ZSTD_METHOD) : "N/A"); + tor_compress_version_str(ZSTD_METHOD) : "N/A", + tor_libc_get_name() ? + tor_libc_get_name() : "Unknown", + tor_libc_get_version_str()); log_notice(LD_GENERAL, "Tor can't help you if you use it wrong! " "Learn how to be safe at " @@ -829,6 +830,9 @@ sandbox_init_filter(void) #define OPEN(name) \ sandbox_cfg_allow_open_filename(&cfg, tor_strdup(name)) +#define OPENDIR(dir) \ + sandbox_cfg_allow_opendir_dirname(&cfg, tor_strdup(dir)) + #define OPEN_DATADIR(name) \ sandbox_cfg_allow_open_filename(&cfg, get_datadir_fname(name)) @@ -845,8 +849,10 @@ sandbox_init_filter(void) OPEN_DATADIR2(name, name2 suffix); \ } while (0) +// KeyDirectory is a directory, but it is only opened in check_private_dir +// which calls open instead of opendir #define OPEN_KEY_DIRECTORY() \ - sandbox_cfg_allow_open_filename(&cfg, tor_strdup(options->KeyDirectory)) + OPEN(options->KeyDirectory) #define OPEN_CACHEDIR(name) \ sandbox_cfg_allow_open_filename(&cfg, get_cachedir_fname(name)) #define OPEN_CACHEDIR_SUFFIX(name, suffix) do { \ @@ -860,6 +866,8 @@ sandbox_init_filter(void) OPEN_KEYDIR(name suffix); \ } while (0) + // DataDirectory is a directory, but it is only opened in check_private_dir + // which calls open instead of opendir OPEN(options->DataDirectory); OPEN_KEY_DIRECTORY(); @@ -907,7 +915,11 @@ sandbox_init_filter(void) } SMARTLIST_FOREACH(options->FilesOpenedByIncludes, char *, f, { - OPEN(f); + if (file_status(f) == FN_DIR) { + OPENDIR(f); + } else { + OPEN(f); + } }); #define RENAME_SUFFIX(name, suffix) \ @@ -1020,7 +1032,7 @@ sandbox_init_filter(void) * directory that holds it. */ char *dirname = tor_strdup(port->unix_addr); if (get_parent_directory(dirname) == 0) { - OPEN(dirname); + OPENDIR(dirname); } tor_free(dirname); sandbox_cfg_allow_chmod_filename(&cfg, tor_strdup(port->unix_addr)); diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c index 1d53e077d1..7f4c6a5f48 100644 --- a/src/core/mainloop/connection.c +++ b/src/core/mainloop/connection.c @@ -220,8 +220,12 @@ static smartlist_t *outgoing_addrs = NULL; /**************************************************************/ -/** Convert a connection_t* to an listener_connection_t*; assert if the cast - * is invalid. */ +/** + * Cast a `connection_t *` to a `listener_connection_t *`. + * + * Exit with an assertion failure if the input is not a + * `listener_connection_t`. + **/ listener_connection_t * TO_LISTENER_CONN(connection_t *c) { @@ -229,6 +233,18 @@ TO_LISTENER_CONN(connection_t *c) return DOWNCAST(listener_connection_t, c); } +/** + * Cast a `const connection_t *` to a `const listener_connection_t *`. + * + * Exit with an assertion failure if the input is not a + * `listener_connection_t`. + **/ +const listener_connection_t * +CONST_TO_LISTENER_CONN(const connection_t *c) +{ + return TO_LISTENER_CONN((connection_t *)c); +} + size_t connection_get_inbuf_len(connection_t *conn) { @@ -352,13 +368,179 @@ conn_state_to_string(int type, int state) break; } + if (state == 0) { + return "uninitialized"; + } + log_warn(LD_BUG, "unknown connection state %d (type %d)", state, type); tor_snprintf(buf, sizeof(buf), "unknown state [%d] on unknown [%s] connection", state, conn_type_to_string(type)); + tor_assert_nonfatal_unreached_once(); return buf; } +/** + * Helper: describe the peer or address of connection @a conn in a + * human-readable manner. + * + * Returns a pointer to a static buffer; future calls to + * connection_describe_peer_internal() will invalidate this buffer. + * + * If <b>include_preposition</b> is true, include a preposition before the + * peer address. + * + * Nobody should parse the output of this function; it can and will change in + * future versions of tor. + **/ +static const char * +connection_describe_peer_internal(const connection_t *conn, + bool include_preposition) +{ + IF_BUG_ONCE(!conn) { + return "null peer"; + } + + static char peer_buf[256]; + const tor_addr_t *addr = &conn->addr; + const char *address = NULL; + const char *prep; + bool scrub = false; + char extra_buf[128]; + extra_buf[0] = 0; + + /* First, figure out the preposition to use */ + switch (conn->type) { + CASE_ANY_LISTENER_TYPE: + prep = "on"; + break; + case CONN_TYPE_EXIT: + prep = "to"; + break; + case CONN_TYPE_CONTROL: + case CONN_TYPE_AP: + case CONN_TYPE_EXT_OR: + prep = "from"; + break; + default: + prep = "with"; + break; + } + + /* Now figure out the address. */ + if (conn->socket_family == AF_UNIX) { + /* For unix sockets, we always use the `address` string. */ + address = conn->address ? conn->address : "unix socket"; + } else if (conn->type == CONN_TYPE_OR) { + /* For OR connections, we have a lot to do. */ + const or_connection_t *or_conn = CONST_TO_OR_CONN(conn); + /* We report the IDs we're talking to... */ + if (fast_digest_is_zero(or_conn->identity_digest)) { + // This could be a client, so scrub it. No identity to report. + scrub = true; + } else { + char id_buf[HEX_DIGEST_LEN+1]; + base16_encode(id_buf, sizeof(id_buf), + or_conn->identity_digest, DIGEST_LEN); + tor_snprintf(extra_buf, sizeof(extra_buf), + " ID=%s", id_buf); + } + if (! scrub && (! tor_addr_eq(addr, &or_conn->canonical_orport.addr) || + conn->port != or_conn->canonical_orport.port)) { + /* We report canonical address, if it's different */ + char canonical_addr_buf[TOR_ADDR_BUF_LEN]; + if (tor_addr_to_str(canonical_addr_buf, &or_conn->canonical_orport.addr, + sizeof(canonical_addr_buf), 1)) { + tor_snprintf(extra_buf+strlen(extra_buf), + sizeof(extra_buf)-strlen(extra_buf), + " canonical_addr=%s:%"PRIu16, + canonical_addr_buf, + or_conn->canonical_orport.port); + } + } + } else if (conn->type == CONN_TYPE_EXIT) { + scrub = true; /* This is a client's request; scrub it with SafeLogging. */ + if (tor_addr_is_null(addr)) { + address = conn->address; + strlcpy(extra_buf, " (DNS lookup pending)", sizeof(extra_buf)); + } + } + + char addr_buf[TOR_ADDR_BUF_LEN]; + if (address == NULL) { + if (tor_addr_family(addr) == 0) { + address = "<unset>"; + } else { + address = tor_addr_to_str(addr_buf, addr, sizeof(addr_buf), 1); + if (!address) { + address = "<can't format!>"; + tor_assert_nonfatal_unreached_once(); + } + } + } + + char portbuf[7]; + portbuf[0]=0; + if (scrub && get_options()->SafeLogging_ != SAFELOG_SCRUB_NONE) { + address = "[scrubbed]"; + } else { + /* Only set the port if we're not scrubbing the address. */ + if (conn->port != 0) { + tor_snprintf(portbuf, sizeof(portbuf), ":%d", conn->port); + } + } + + const char *sp = include_preposition ? " " : ""; + if (! include_preposition) + prep = ""; + + tor_snprintf(peer_buf, sizeof(peer_buf), + "%s%s%s%s%s", prep, sp, address, portbuf, extra_buf); + return peer_buf; +} + +/** + * Describe the peer or address of connection @a conn in a + * human-readable manner. + * + * Returns a pointer to a static buffer; future calls to + * connection_describe_peer() or connection_describe() will invalidate this + * buffer. + * + * Nobody should parse the output of this function; it can and will change in + * future versions of tor. + **/ +const char * +connection_describe_peer(const connection_t *conn) +{ + return connection_describe_peer_internal(conn, false); +} + +/** + * Describe a connection for logging purposes. + * + * Returns a pointer to a static buffer; future calls to connection_describe() + * will invalidate this buffer. + * + * Nobody should parse the output of this function; it can and will change in + * future versions of tor. + **/ +const char * +connection_describe(const connection_t *conn) +{ + IF_BUG_ONCE(!conn) { + return "null connection"; + } + static char desc_buf[256]; + const char *peer = connection_describe_peer_internal(conn, true); + tor_snprintf(desc_buf, sizeof(desc_buf), + "%s connection (%s) %s", + conn_type_to_string(conn->type), + conn_state_to_string(conn->type, conn->state), + peer); + return desc_buf; +} + /** Allocate and return a new dir_connection_t, initialized as by * connection_init(). */ dir_connection_t * @@ -384,10 +566,15 @@ or_connection_new(int type, int socket_family) tor_assert(type == CONN_TYPE_OR || type == CONN_TYPE_EXT_OR); connection_init(now, TO_CONN(or_conn), type, socket_family); + tor_addr_make_unspec(&or_conn->canonical_orport.addr); connection_or_set_canonical(or_conn, 0); - if (type == CONN_TYPE_EXT_OR) + if (type == CONN_TYPE_EXT_OR) { + /* If we aren't told an address for this connection, we should + * presume it isn't local, and should be rate-limited. */ + TO_CONN(or_conn)->always_rate_limit_as_remote = 1; connection_or_set_ext_or_identifier(or_conn); + } return or_conn; } @@ -644,7 +831,7 @@ connection_free_minimal(connection_t *conn) } } - tor_free(conn->address); + tor_str_wipe_and_free(conn->address); if (connection_speaks_cells(conn)) { or_connection_t *or_conn = TO_OR_CONN(conn); @@ -664,7 +851,7 @@ connection_free_minimal(connection_t *conn) } or_handshake_state_free(or_conn->handshake_state); or_conn->handshake_state = NULL; - tor_free(or_conn->nickname); + tor_str_wipe_and_free(or_conn->nickname); if (or_conn->chan) { /* Owww, this shouldn't happen, but... */ channel_t *base_chan = TLS_CHAN_TO_BASE(or_conn->chan); @@ -684,8 +871,8 @@ connection_free_minimal(connection_t *conn) } if (conn->type == CONN_TYPE_AP) { entry_connection_t *entry_conn = TO_ENTRY_CONN(conn); - tor_free(entry_conn->chosen_exit_name); - tor_free(entry_conn->original_dest_address); + tor_str_wipe_and_free(entry_conn->chosen_exit_name); + tor_str_wipe_and_free(entry_conn->original_dest_address); if (entry_conn->socks_request) socks_request_free(entry_conn->socks_request); if (entry_conn->pending_optimistic_data) { @@ -850,11 +1037,11 @@ connection_close_immediate(connection_t *conn) tor_fragile_assert(); return; } - if (conn->outbuf_flushlen) { - log_info(LD_NET,"fd %d, type %s, state %s, %d bytes on outbuf.", + if (connection_get_outbuf_len(conn)) { + log_info(LD_NET,"fd %d, type %s, state %s, %"TOR_PRIuSZ" bytes on outbuf.", (int)conn->s, conn_type_to_string(conn->type), conn_state_to_string(conn->type, conn->state), - (int)conn->outbuf_flushlen); + buf_datalen(conn->outbuf)); } connection_unregister_events(conn); @@ -870,7 +1057,6 @@ connection_close_immediate(connection_t *conn) conn->linked_conn_is_closed = 1; if (conn->outbuf) buf_clear(conn->outbuf); - conn->outbuf_flushlen = 0; } /** Mark <b>conn</b> to be closed next time we loop through @@ -1547,13 +1733,8 @@ connection_listener_new(const struct sockaddr *listensockaddr, */ connection_check_oos(get_n_open_sockets(), 0); - if (conn->socket_family == AF_UNIX) { - log_notice(LD_NET, "Opened %s on %s", - conn_type_to_string(type), conn->address); - } else { - log_notice(LD_NET, "Opened %s on %s", - conn_type_to_string(type), fmt_addrport(&addr, gotPort)); - } + log_notice(LD_NET, "Opened %s", connection_describe(conn)); + return conn; err: @@ -2065,22 +2246,13 @@ connection_connect_log_client_use_ip_version(const connection_t *conn) return; } - const int must_ipv4 = !fascist_firewall_use_ipv6(options); + const int must_ipv4 = !reachable_addr_use_ipv6(options); const int must_ipv6 = (options->ClientUseIPv4 == 0); const int pref_ipv6 = (conn->type == CONN_TYPE_OR - ? fascist_firewall_prefer_ipv6_orport(options) - : fascist_firewall_prefer_ipv6_dirport(options)); + ? reachable_addr_prefer_ipv6_orport(options) + : reachable_addr_prefer_ipv6_dirport(options)); tor_addr_t real_addr; - tor_addr_make_null(&real_addr, AF_UNSPEC); - - /* OR conns keep the original address in real_addr, as addr gets overwritten - * with the descriptor address */ - if (conn->type == CONN_TYPE_OR) { - const or_connection_t *or_conn = TO_OR_CONN((connection_t *)conn); - tor_addr_copy(&real_addr, &or_conn->real_addr); - } else if (conn->type == CONN_TYPE_DIR) { - tor_addr_copy(&real_addr, &conn->addr); - } + tor_addr_copy(&real_addr, &conn->addr); /* Check if we broke a mandatory address family restriction */ if ((must_ipv4 && tor_addr_family(&real_addr) == AF_INET6) @@ -2103,7 +2275,7 @@ connection_connect_log_client_use_ip_version(const connection_t *conn) return; } - if (fascist_firewall_use_ipv6(options)) { + if (reachable_addr_use_ipv6(options)) { log_info(LD_NET, "Our outgoing connection is using IPv%d.", tor_addr_family(&real_addr) == AF_INET6 ? 6 : 4); } @@ -2113,13 +2285,13 @@ connection_connect_log_client_use_ip_version(const connection_t *conn) || (pref_ipv6 && tor_addr_family(&real_addr) == AF_INET)) { log_info(LD_NET, "Outgoing connection to %s doesn't satisfy " "ClientPreferIPv6%sPort %d, with ClientUseIPv4 %d, and " - "fascist_firewall_use_ipv6 %d (ClientUseIPv6 %d and UseBridges " + "reachable_addr_use_ipv6 %d (ClientUseIPv6 %d and UseBridges " "%d).", fmt_addr(&real_addr), conn->type == CONN_TYPE_OR ? "OR" : "Dir", conn->type == CONN_TYPE_OR ? options->ClientPreferIPv6ORPort : options->ClientPreferIPv6DirPort, - options->ClientUseIPv4, fascist_firewall_use_ipv6(options), + options->ClientUseIPv4, reachable_addr_use_ipv6(options), options->ClientUseIPv6, options->UseBridges); } } @@ -2606,8 +2778,8 @@ connection_read_https_proxy_response(connection_t *conn) if (parse_http_response(headers, &status_code, &date_header, NULL, &reason) < 0) { log_warn(LD_NET, - "Unparseable headers from proxy (connecting to '%s'). Closing.", - conn->address); + "Unparseable headers from proxy (%s). Closing.", + connection_describe(conn)); tor_free(headers); return -1; } @@ -2616,8 +2788,8 @@ connection_read_https_proxy_response(connection_t *conn) if (status_code == 200) { log_info(LD_NET, - "HTTPS connect to '%s' successful! (200 %s) Starting TLS.", - conn->address, escaped(reason)); + "HTTPS connect for %s successful! (200 %s) Starting TLS.", + connection_describe(conn), escaped(reason)); tor_free(reason); return 1; } @@ -2833,16 +3005,16 @@ connection_read_proxy_handshake(connection_t *conn) if (ret < 0) { if (reason) { - log_warn(LD_NET, "Proxy Client: unable to connect to %s:%d (%s)", - conn->address, conn->port, escaped(reason)); + log_warn(LD_NET, "Proxy Client: unable to connect %s (%s)", + connection_describe(conn), escaped(reason)); tor_free(reason); } else { - log_warn(LD_NET, "Proxy Client: unable to connect to %s:%d", - conn->address, conn->port); + log_warn(LD_NET, "Proxy Client: unable to connect %s", + connection_describe(conn)); } } else if (ret == 1) { - log_info(LD_NET, "Proxy Client: connection to %s:%d successful", - conn->address, conn->port); + log_info(LD_NET, "Proxy Client: %s successful", + connection_describe(conn)); } return ret; @@ -2999,10 +3171,10 @@ retry_all_listeners(smartlist_t *new_conns, int close_all_noncontrol) smartlist_t *replacements = smartlist_new(); const or_options_t *options = get_options(); int retval = 0; - const uint16_t old_or_port = router_get_advertised_or_port(options); + const uint16_t old_or_port = routerconf_find_or_port(options, AF_INET); const uint16_t old_or_port_ipv6 = - router_get_advertised_or_port_by_af(options,AF_INET6); - const uint16_t old_dir_port = router_get_advertised_dir_port(options, 0); + routerconf_find_or_port(options,AF_INET6); + const uint16_t old_dir_port = routerconf_find_dir_port(options, 0); SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) { if (connection_is_listener(conn) && !conn->marked_for_close) @@ -3033,8 +3205,8 @@ retry_all_listeners(smartlist_t *new_conns, int close_all_noncontrol) connection_t *old_conn = r->old_conn; if (skip) { - log_debug(LD_NET, "Skipping creating new listener for %s:%d", - old_conn->address, old_conn->port); + log_debug(LD_NET, "Skipping creating new listener for %s", + connection_describe(old_conn)); continue; } @@ -3050,10 +3222,11 @@ retry_all_listeners(smartlist_t *new_conns, int close_all_noncontrol) smartlist_add(new_conns, new_conn); - log_notice(LD_NET, "Closed no-longer-configured %s on %s:%d " - "(replaced by %s:%d)", - conn_type_to_string(old_conn->type), old_conn->address, - old_conn->port, new_conn->address, new_conn->port); + char *old_desc = tor_strdup(connection_describe(old_conn)); + log_notice(LD_NET, "Closed no-longer-configured %s " + "(replaced by %s)", + old_desc, connection_describe(new_conn)); + tor_free(old_desc); } SMARTLIST_FOREACH_END(r); #endif /* defined(ENABLE_LISTENER_REBIND) */ @@ -3071,10 +3244,9 @@ retry_all_listeners(smartlist_t *new_conns, int close_all_noncontrol) SMARTLIST_FOREACH(replacements, listener_replacement_t *, r, tor_free(r)); smartlist_free(replacements); - if (old_or_port != router_get_advertised_or_port(options) || - old_or_port_ipv6 != router_get_advertised_or_port_by_af(options, - AF_INET6) || - old_dir_port != router_get_advertised_dir_port(options, 0)) { + if (old_or_port != routerconf_find_or_port(options, AF_INET) || + old_or_port_ipv6 != routerconf_find_or_port(options, AF_INET6) || + old_dir_port != routerconf_find_dir_port(options, 0)) { /* Our chosen ORPort or DirPort is not what it used to be: the * descriptor we had (if any) should be regenerated. (We won't * automatically notice this because of changes in the option, @@ -3148,6 +3320,7 @@ connection_is_rate_limited(const connection_t *conn) if (conn->linked) return 0; /* Internal connection */ else if (! options->CountPrivateBandwidth && + ! conn->always_rate_limit_as_remote && (tor_addr_family(&conn->addr) == AF_UNSPEC || /* no address */ tor_addr_family(&conn->addr) == AF_UNIX || /* no address */ tor_addr_is_internal(&conn->addr, 0))) @@ -3251,12 +3424,12 @@ connection_bucket_write_limit(connection_t *conn, time_t now) { int base = RELAY_PAYLOAD_SIZE; int priority = conn->type != CONN_TYPE_DIR; - size_t conn_bucket = conn->outbuf_flushlen; + size_t conn_bucket = buf_datalen(conn->outbuf); size_t global_bucket_val = token_bucket_rw_get_write(&global_bucket); if (!connection_is_rate_limited(conn)) { /* be willing to write to local conns even if our buckets are empty */ - return conn->outbuf_flushlen; + return conn_bucket; } if (connection_speaks_cells(conn)) { @@ -3861,17 +4034,14 @@ connection_buf_read_from_socket(connection_t *conn, ssize_t *max_to_read, switch (result) { case TOR_TLS_CLOSE: case TOR_TLS_ERROR_IO: - log_debug(LD_NET,"TLS connection closed %son read. Closing. " - "(Nickname %s, address %s)", - result == TOR_TLS_CLOSE ? "cleanly " : "", - or_conn->nickname ? or_conn->nickname : "not set", - conn->address); + log_debug(LD_NET,"TLS %s closed %son read. Closing.", + connection_describe(conn), + result == TOR_TLS_CLOSE ? "cleanly " : ""); return result; CASE_TOR_TLS_ERROR_ANY_NONIO: - log_debug(LD_NET,"tls error [%s]. breaking (nickname %s, address %s).", + log_debug(LD_NET,"tls error [%s] from %s. Breaking.", tor_tls_err_to_string(result), - or_conn->nickname ? or_conn->nickname : "not set", - conn->address); + connection_describe(conn)); return result; case TOR_TLS_WANTWRITE: connection_start_writing(conn); @@ -3912,12 +4082,7 @@ connection_buf_read_from_socket(connection_t *conn, ssize_t *max_to_read, result, (long)n_read, (long)n_written); } else if (conn->linked) { if (conn->linked_conn) { - result = buf_move_to_buf(conn->inbuf, conn->linked_conn->outbuf, - &conn->linked_conn->outbuf_flushlen); - if (BUG(result<0)) { - log_warn(LD_BUG, "reading from linked connection buffer failed."); - return -1; - } + result = (int) buf_move_all(conn->inbuf, conn->linked_conn->outbuf); } else { result = 0; } @@ -4021,12 +4186,11 @@ connection_fetch_from_buf_http(connection_t *conn, body_out, body_used, max_bodylen, force_complete); } -/** Return conn-\>outbuf_flushlen: how many bytes conn wants to flush - * from its outbuf. */ +/** Return true if this connection has data to flush. */ int connection_wants_to_flush(connection_t *conn) { - return conn->outbuf_flushlen > 0; + return connection_get_outbuf_len(conn) > 0; } /** Are there too many bytes on edge connection <b>conn</b>'s outbuf to @@ -4036,7 +4200,7 @@ connection_wants_to_flush(connection_t *conn) int connection_outbuf_too_full(connection_t *conn) { - return (conn->outbuf_flushlen > 10*CELL_PAYLOAD_SIZE); + return connection_get_outbuf_len(conn) > 10*CELL_PAYLOAD_SIZE; } /** @@ -4162,7 +4326,7 @@ connection_handle_write_impl(connection_t *conn, int force) return -1; } - max_to_write = force ? (ssize_t)conn->outbuf_flushlen + max_to_write = force ? (ssize_t)buf_datalen(conn->outbuf) : connection_bucket_write_limit(conn, now); if (connection_speaks_cells(conn) && @@ -4194,7 +4358,7 @@ connection_handle_write_impl(connection_t *conn, int force) /* else open, or closing */ initial_size = buf_datalen(conn->outbuf); result = buf_flush_to_tls(conn->outbuf, or_conn->tls, - max_to_write, &conn->outbuf_flushlen); + max_to_write); if (result >= 0) update_send_buffer_size(conn->s); @@ -4260,7 +4424,7 @@ connection_handle_write_impl(connection_t *conn, int force) } else { CONN_LOG_PROTECT(conn, result = buf_flush_to_socket(conn->outbuf, conn->s, - max_to_write, &conn->outbuf_flushlen)); + max_to_write)); if (result < 0) { if (CONN_IS_EDGE(conn)) connection_edge_end_errno(TO_EDGE_CONN(conn)); @@ -4416,10 +4580,10 @@ connection_write_to_buf_failed(connection_t *conn) /** Helper for connection_write_to_buf_impl and connection_write_buf_to_buf: * * Called when an attempt to add bytes on <b>conn</b>'s outbuf has succeeded: - * record the number of bytes added. + * start writing if appropriate. */ static void -connection_write_to_buf_commit(connection_t *conn, size_t len) +connection_write_to_buf_commit(connection_t *conn) { /* If we receive optimistic data in the EXIT_CONN_STATE_RESOLVING * state, we don't want to try to write it right away, since @@ -4428,7 +4592,6 @@ connection_write_to_buf_commit(connection_t *conn, size_t len) if (conn->write_event) { connection_start_writing(conn); } - conn->outbuf_flushlen += len; } /** Append <b>len</b> bytes of <b>string</b> onto <b>conn</b>'s @@ -4451,25 +4614,20 @@ connection_write_to_buf_impl_,(const char *string, size_t len, if (!connection_may_write_to_buf(conn)) return; - size_t written; - if (zlib) { - size_t old_datalen = buf_datalen(conn->outbuf); dir_connection_t *dir_conn = TO_DIR_CONN(conn); int done = zlib < 0; CONN_LOG_PROTECT(conn, r = buf_add_compress(conn->outbuf, dir_conn->compress_state, string, len, done)); - written = buf_datalen(conn->outbuf) - old_datalen; } else { CONN_LOG_PROTECT(conn, r = buf_add(conn->outbuf, string, len)); - written = len; } if (r < 0) { connection_write_to_buf_failed(conn); return; } - connection_write_to_buf_commit(conn, written); + connection_write_to_buf_commit(conn); } /** @@ -4514,7 +4672,7 @@ connection_buf_add_buf(connection_t *conn, buf_t *buf) return; buf_move_all(conn->outbuf, buf); - connection_write_to_buf_commit(conn, len); + connection_write_to_buf_commit(conn); } #define CONN_GET_ALL_TEMPLATE(var, test) \ @@ -4724,7 +4882,7 @@ any_other_active_or_conns(const or_connection_t *this_conn) connection_t *conn = connection_get_another_active_or_conn(this_conn); if (conn != NULL) { log_debug(LD_DIR, "%s: Found an OR connection: %s", - __func__, conn->address); + __func__, connection_describe(conn)); return 1; } @@ -5402,18 +5560,6 @@ assert_connection_ok(connection_t *conn, time_t now) if (conn->linked) tor_assert(!SOCKET_OK(conn->s)); - if (conn->outbuf_flushlen > 0) { - /* With optimistic data, we may have queued data in - * EXIT_CONN_STATE_RESOLVING while the conn is not yet marked to writing. - * */ - tor_assert((conn->type == CONN_TYPE_EXIT && - conn->state == EXIT_CONN_STATE_RESOLVING) || - connection_is_writing(conn) || - conn->write_blocked_on_bw || - (CONN_IS_EDGE(conn) && - TO_EDGE_CONN(conn)->edge_blocked_on_circ)); - } - if (conn->hold_open_until_flushed) tor_assert(conn->marked_for_close); diff --git a/src/core/mainloop/connection.h b/src/core/mainloop/connection.h index bcd3d590a5..ee3dce49f4 100644 --- a/src/core/mainloop/connection.h +++ b/src/core/mainloop/connection.h @@ -31,6 +31,8 @@ struct tor_addr_t; struct or_options_t; struct listener_connection_t *TO_LISTENER_CONN(struct connection_t *); +const struct listener_connection_t *CONST_TO_LISTENER_CONN( + const struct connection_t *); struct buf_t; @@ -116,6 +118,9 @@ const char *conn_type_to_string(int type); const char *conn_state_to_string(int type, int state); int conn_listener_type_supports_af_unix(int type); +const char *connection_describe(const connection_t *conn); +const char *connection_describe_peer(const connection_t *conn); + struct dir_connection_t *dir_connection_new(int socket_family); struct or_connection_t *or_connection_new(int type, int socket_family); struct edge_connection_t *edge_connection_new(int type, int socket_family); diff --git a/src/core/mainloop/mainloop.c b/src/core/mainloop/mainloop.c index 3bf9be566b..c75039b378 100644 --- a/src/core/mainloop/mainloop.c +++ b/src/core/mainloop/mainloop.c @@ -985,33 +985,29 @@ conn_close_if_marked(int i) if (!conn->hold_open_until_flushed) log_info(LD_NET, "Conn (addr %s, fd %d, type %s, state %d) marked, but wants " - "to flush %d bytes. (Marked at %s:%d)", + "to flush %"TOR_PRIuSZ" bytes. (Marked at %s:%d)", escaped_safe_str_client(conn->address), (int)conn->s, conn_type_to_string(conn->type), conn->state, - (int)conn->outbuf_flushlen, - conn->marked_for_close_file, conn->marked_for_close); + connection_get_outbuf_len(conn), + conn->marked_for_close_file, conn->marked_for_close); if (conn->linked_conn) { - retval = buf_move_to_buf(conn->linked_conn->inbuf, conn->outbuf, - &conn->outbuf_flushlen); + retval = (int) buf_move_all(conn->linked_conn->inbuf, conn->outbuf); if (retval >= 0) { /* The linked conn will notice that it has data when it notices that * we're gone. */ connection_start_reading_from_linked_conn(conn->linked_conn); } log_debug(LD_GENERAL, "Flushed last %d bytes from a linked conn; " - "%d left; flushlen %d; wants-to-flush==%d", retval, + "%d left; wants-to-flush==%d", retval, (int)connection_get_outbuf_len(conn), - (int)conn->outbuf_flushlen, connection_wants_to_flush(conn)); } else if (connection_speaks_cells(conn)) { if (conn->state == OR_CONN_STATE_OPEN) { - retval = buf_flush_to_tls(conn->outbuf, TO_OR_CONN(conn)->tls, sz, - &conn->outbuf_flushlen); + retval = buf_flush_to_tls(conn->outbuf, TO_OR_CONN(conn)->tls, sz); } else retval = -1; /* never flush non-open broken tls connections */ } else { - retval = buf_flush_to_socket(conn->outbuf, conn->s, sz, - &conn->outbuf_flushlen); + retval = buf_flush_to_socket(conn->outbuf, conn->s, sz); } if (retval >= 0 && /* Technically, we could survive things like TLS_WANT_WRITE here. But don't bother for now. */ diff --git a/src/core/or/channel.c b/src/core/or/channel.c index 20ccf41306..91f083ec00 100644 --- a/src/core/or/channel.c +++ b/src/core/or/channel.c @@ -71,6 +71,7 @@ #include "core/or/relay.h" #include "core/or/scheduler.h" #include "feature/client/entrynodes.h" +#include "feature/nodelist/dirlist.h" #include "feature/nodelist/networkstatus.h" #include "feature/nodelist/nodelist.h" #include "feature/nodelist/routerlist.h" @@ -748,6 +749,7 @@ channel_check_for_duplicates(void) { channel_idmap_entry_t **iter; channel_t *chan; + int total_dirauth_connections = 0, total_dirauths = 0; int total_relay_connections = 0, total_relays = 0, total_canonical = 0; int total_half_canonical = 0; int total_gt_one_connection = 0, total_gt_two_connections = 0; @@ -755,13 +757,18 @@ channel_check_for_duplicates(void) HT_FOREACH(iter, channel_idmap, &channel_identity_map) { int connections_to_relay = 0; + const char *id_digest = (char *) (*iter)->digest; /* Only consider relay connections */ - if (!connection_or_digest_is_known_relay((char*)(*iter)->digest)) + if (!connection_or_digest_is_known_relay(id_digest)) continue; total_relays++; + const bool is_dirauth = router_digest_is_trusted_dir(id_digest); + if (is_dirauth) + total_dirauths++; + for (chan = TOR_LIST_FIRST(&(*iter)->channel_list); chan; chan = channel_next_with_rsa_identity(chan)) { @@ -770,11 +777,12 @@ channel_check_for_duplicates(void) connections_to_relay++; total_relay_connections++; + if (is_dirauth) + total_dirauth_connections++; - if (chan->is_canonical(chan, 0)) total_canonical++; + if (chan->is_canonical(chan)) total_canonical++; - if (!chan->is_canonical_to_peer && chan->is_canonical(chan, 0) - && chan->is_canonical(chan, 1)) { + if (!chan->is_canonical_to_peer && chan->is_canonical(chan)) { total_half_canonical++; } } @@ -784,11 +792,28 @@ channel_check_for_duplicates(void) if (connections_to_relay > 4) total_gt_four_connections++; } -#define MIN_RELAY_CONNECTIONS_TO_WARN 5 + /* Don't bother warning about excessive connections unless we have + * at least this many connections, total. + */ +#define MIN_RELAY_CONNECTIONS_TO_WARN 25 + /* If the average number of connections for a regular relay is more than + * this, that's too high. + */ +#define MAX_AVG_RELAY_CONNECTIONS 1.5 + /* If the average number of connections for a dirauth is more than + * this, that's too high. + */ +#define MAX_AVG_DIRAUTH_CONNECTIONS 4 + + /* How many connections total would be okay, given the number of + * relays and dirauths that we have connections to? */ + const int max_tolerable_connections = (int)( + (total_relays-total_dirauths) * MAX_AVG_RELAY_CONNECTIONS + + total_dirauths * MAX_AVG_DIRAUTH_CONNECTIONS); /* If we average 1.5 or more connections per relay, something is wrong */ if (total_relays > MIN_RELAY_CONNECTIONS_TO_WARN && - total_relay_connections >= 1.5*total_relays) { + total_relay_connections > max_tolerable_connections) { log_notice(LD_OR, "Your relay has a very large number of connections to other relays. " "Is your outbound address the same as your relay address? " @@ -2424,21 +2449,9 @@ channel_get_for_extend,(const char *rsa_id_digest, continue; } - /* If the connection is using a recent link protocol, only return canonical - * connections, when the address is one of the addresses we wanted. - * - * The channel_is_canonical_is_reliable() function asks the lower layer - * if we should trust channel_is_canonical(). It only applies when - * the lower-layer transport is channel_tls_t. - * - * For old link protocols, we can't rely on is_canonical getting - * set properly if we're talking to the right address, since we might - * have an out-of-date descriptor, and we will get no NETINFO cell to - * tell us about the right address. - */ - if (!channel_is_canonical(chan) && - channel_is_canonical_is_reliable(chan) && - !matches_target) { + /* Only return canonical connections or connections where the address + * is the address we wanted. */ + if (!channel_is_canonical(chan) && !matches_target) { ++n_noncanonical; continue; } @@ -2553,7 +2566,7 @@ channel_dump_statistics, (channel_t *chan, int severity)) /* Handle remote address and descriptions */ have_remote_addr = channel_get_addr_if_possible(chan, &remote_addr); if (have_remote_addr) { - char *actual = tor_strdup(channel_get_actual_remote_descr(chan)); + char *actual = tor_strdup(channel_describe_peer(chan)); remote_addr_str = tor_addr_to_str_dup(&remote_addr); tor_log(severity, LD_GENERAL, " * Channel %"PRIu64 " says its remote address" @@ -2561,34 +2574,30 @@ channel_dump_statistics, (channel_t *chan, int severity)) "actual description of \"%s\"", (chan->global_identifier), safe_str(remote_addr_str), - safe_str(channel_get_canonical_remote_descr(chan)), + safe_str(channel_describe_peer(chan)), safe_str(actual)); tor_free(remote_addr_str); tor_free(actual); } else { - char *actual = tor_strdup(channel_get_actual_remote_descr(chan)); + char *actual = tor_strdup(channel_describe_peer(chan)); tor_log(severity, LD_GENERAL, " * Channel %"PRIu64 " does not know its remote " "address, but gives a canonical description of \"%s\" and an " "actual description of \"%s\"", (chan->global_identifier), - channel_get_canonical_remote_descr(chan), + channel_describe_peer(chan), actual); tor_free(actual); } /* Handle marks */ tor_log(severity, LD_GENERAL, - " * Channel %"PRIu64 " has these marks: %s %s %s " - "%s %s %s", + " * Channel %"PRIu64 " has these marks: %s %s %s %s %s", (chan->global_identifier), channel_is_bad_for_new_circs(chan) ? "bad_for_new_circs" : "!bad_for_new_circs", channel_is_canonical(chan) ? "canonical" : "!canonical", - channel_is_canonical_is_reliable(chan) ? - "is_canonical_is_reliable" : - "!is_canonical_is_reliable", channel_is_client(chan) ? "client" : "!client", channel_is_local(chan) ? @@ -2782,75 +2791,41 @@ channel_listener_dump_transport_statistics(channel_listener_t *chan_l, } /** - * Return text description of the remote endpoint. - * - * This function return a test provided by the lower layer of the remote - * endpoint for this channel; it should specify the actual address connected - * to/from. - * - * Subsequent calls to channel_get_{actual,canonical}_remote_{address,descr} - * may invalidate the return value from this function. - */ -const char * -channel_get_actual_remote_descr(channel_t *chan) -{ - tor_assert(chan); - tor_assert(chan->get_remote_descr); - - /* Param 1 indicates the actual description */ - return chan->get_remote_descr(chan, GRD_FLAG_ORIGINAL); -} - -/** - * Return the text address of the remote endpoint. - * - * Subsequent calls to channel_get_{actual,canonical}_remote_{address,descr} - * may invalidate the return value from this function. - */ -const char * -channel_get_actual_remote_address(channel_t *chan) -{ - /* Param 1 indicates the actual description */ - return chan->get_remote_descr(chan, GRD_FLAG_ORIGINAL|GRD_FLAG_ADDR_ONLY); -} - -/** * Return text description of the remote endpoint canonical address. * - * This function return a test provided by the lower layer of the remote - * endpoint for this channel; it should use the known canonical address for - * this OR's identity digest if possible. + * This function returns a human-readable string for logging; nothing + * should parse it or rely on a particular format. * - * Subsequent calls to channel_get_{actual,canonical}_remote_{address,descr} - * may invalidate the return value from this function. + * Subsequent calls to this function may invalidate its return value. */ MOCK_IMPL(const char *, -channel_get_canonical_remote_descr,(channel_t *chan)) +channel_describe_peer,(channel_t *chan)) { tor_assert(chan); - tor_assert(chan->get_remote_descr); + tor_assert(chan->describe_peer); - /* Param 0 indicates the canonicalized description */ - return chan->get_remote_descr(chan, 0); + return chan->describe_peer(chan); } /** - * Get remote address if possible. + * Get the remote address for this channel, if possible. * * Write the remote address out to a tor_addr_t if the underlying transport * supports this operation, and return 1. Return 0 if the underlying transport * doesn't let us do this. + * + * Always returns the "real" address of the peer -- the one we're connected to + * on the internet. */ MOCK_IMPL(int, -channel_get_addr_if_possible,(const channel_t *chan, tor_addr_t *addr_out)) +channel_get_addr_if_possible,(const channel_t *chan, + tor_addr_t *addr_out)) { tor_assert(chan); tor_assert(addr_out); + tor_assert(chan->get_remote_addr); - if (chan->get_remote_addr) - return chan->get_remote_addr(chan, addr_out); - /* Else no support, method not implemented */ - else return 0; + return chan->get_remote_addr(chan, addr_out); } /** @@ -2947,22 +2922,7 @@ channel_is_canonical(channel_t *chan) tor_assert(chan); tor_assert(chan->is_canonical); - return chan->is_canonical(chan, 0); -} - -/** - * Test if the canonical flag is reliable. - * - * This function asks if the lower layer thinks it's safe to trust the - * result of channel_is_canonical(). - */ -int -channel_is_canonical_is_reliable(channel_t *chan) -{ - tor_assert(chan); - tor_assert(chan->is_canonical); - - return chan->is_canonical(chan, 1); + return chan->is_canonical(chan); } /** @@ -3289,6 +3249,9 @@ channel_when_last_xmit(channel_t *chan) * * This function calls the lower layer and asks if this channel matches a * given extend_info_t. + * + * NOTE that this function only checks for an address/port match, and should + * be used only when no identity is available. */ int channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info) diff --git a/src/core/or/channel.h b/src/core/or/channel.h index 5fe1fb9cc4..10b80aa7d5 100644 --- a/src/core/or/channel.h +++ b/src/core/or/channel.h @@ -329,33 +329,25 @@ struct channel_t { */ double (*get_overhead_estimate)(channel_t *); /* - * Ask the underlying transport what the remote endpoint address is, in - * a tor_addr_t. This is optional and subclasses may leave this NULL. - * If they implement it, they should write the address out to the - * provided tor_addr_t *, and return 1 if successful or 0 if no address - * available. + * Ask the underlying transport what the remote endpoint address is, in a + * tor_addr_t. Write the address out to the provided tor_addr_t *, and + * return 1 if successful or 0 if no address available. */ int (*get_remote_addr)(const channel_t *, tor_addr_t *); int (*get_transport_name)(channel_t *chan, char **transport_out); -#define GRD_FLAG_ORIGINAL 1 -#define GRD_FLAG_ADDR_ONLY 2 /** - * Get a text description of the remote endpoint; canonicalized if the flag - * GRD_FLAG_ORIGINAL is not set, or the one we originally connected - * to/received from if it is. If GRD_FLAG_ADDR_ONLY is set, we return only - * the original address. + * Get a human-readable text description of the remote endpoint, for + * logging. */ - const char * (*get_remote_descr)(channel_t *, int); + const char * (*describe_peer)(const channel_t *); /** Check if the lower layer has queued writes */ int (*has_queued_writes)(channel_t *); /** - * If the second param is zero, ask the lower layer if this is - * 'canonical', for a transport-specific definition of canonical; if - * it is 1, ask if the answer to the preceding query is safe to rely - * on. + * Ask the lower layer if this is 'canonical', for a transport-specific + * definition of canonical. */ - int (*is_canonical)(channel_t *, int); + int (*is_canonical)(channel_t *); /** Check if this channel matches a specified extend_info_t */ int (*matches_extend_info)(channel_t *, extend_info_t *); /** Check if this channel matches a target address when extending */ @@ -724,16 +716,13 @@ channel_is_in_state(channel_t *chan, channel_state_t state) const char * channel_describe_transport(channel_t *chan); MOCK_DECL(void, channel_dump_statistics, (channel_t *chan, int severity)); void channel_dump_transport_statistics(channel_t *chan, int severity); -const char * channel_get_actual_remote_descr(channel_t *chan); -const char * channel_get_actual_remote_address(channel_t *chan); MOCK_DECL(int, channel_get_addr_if_possible, (const channel_t *chan, tor_addr_t *addr_out)); -MOCK_DECL(const char *, channel_get_canonical_remote_descr,(channel_t *chan)); +MOCK_DECL(const char *, channel_describe_peer,(channel_t *chan)); int channel_has_queued_writes(channel_t *chan); int channel_is_bad_for_new_circs(channel_t *chan); void channel_mark_bad_for_new_circs(channel_t *chan); int channel_is_canonical(channel_t *chan); -int channel_is_canonical_is_reliable(channel_t *chan); int channel_is_client(const channel_t *chan); int channel_is_local(channel_t *chan); int channel_is_incoming(channel_t *chan); diff --git a/src/core/or/channelpadding.c b/src/core/or/channelpadding.c index c754a58c42..d0c43e8bdc 100644 --- a/src/core/or/channelpadding.c +++ b/src/core/or/channelpadding.c @@ -265,7 +265,7 @@ channelpadding_update_padding_for_channel(channel_t *chan, log_fn_ratelim(&relay_limit,LOG_PROTOCOL_WARN,LD_PROTOCOL, "Got a PADDING_NEGOTIATE from relay at %s (%s). " "This should not happen.", - chan->get_remote_descr(chan, 0), + channel_describe_peer(chan), hex_str(chan->identity_digest, DIGEST_LEN)); return -1; } @@ -399,7 +399,7 @@ channelpadding_send_padding_cell_for_callback(channel_t *chan) "Sending netflow keepalive on %"PRIu64" to %s (%s) after " "%"PRId64" ms. Delta %"PRId64"ms", (chan->global_identifier), - safe_str_client(chan->get_remote_descr(chan, 0)), + safe_str_client(channel_describe_peer(chan)), safe_str_client(hex_str(chan->identity_digest, DIGEST_LEN)), (monotime_coarse_diff_msec(&chan->timestamp_xfer,&now)), ( diff --git a/src/core/or/channeltls.c b/src/core/or/channeltls.c index 6503c2ebb0..51b772728e 100644 --- a/src/core/or/channeltls.c +++ b/src/core/or/channeltls.c @@ -103,15 +103,13 @@ static void channel_tls_close_method(channel_t *chan); static const char * channel_tls_describe_transport_method(channel_t *chan); static void channel_tls_free_method(channel_t *chan); static double channel_tls_get_overhead_estimate_method(channel_t *chan); -static int -channel_tls_get_remote_addr_method(const channel_t *chan, - tor_addr_t *addr_out); +static int channel_tls_get_remote_addr_method(const channel_t *chan, + tor_addr_t *addr_out); static int channel_tls_get_transport_name_method(channel_t *chan, char **transport_out); -static const char * -channel_tls_get_remote_descr_method(channel_t *chan, int flags); +static const char *channel_tls_describe_peer_method(const channel_t *chan); static int channel_tls_has_queued_writes_method(channel_t *chan); -static int channel_tls_is_canonical_method(channel_t *chan, int req); +static int channel_tls_is_canonical_method(channel_t *chan); static int channel_tls_matches_extend_info_method(channel_t *chan, extend_info_t *extend_info); @@ -165,7 +163,7 @@ channel_tls_common_init(channel_tls_t *tlschan) chan->free_fn = channel_tls_free_method; chan->get_overhead_estimate = channel_tls_get_overhead_estimate_method; chan->get_remote_addr = channel_tls_get_remote_addr_method; - chan->get_remote_descr = channel_tls_get_remote_descr_method; + chan->describe_peer = channel_tls_describe_peer_method; chan->get_transport_name = channel_tls_get_transport_name_method; chan->has_queued_writes = channel_tls_has_queued_writes_method; chan->is_canonical = channel_tls_is_canonical_method; @@ -391,6 +389,25 @@ channel_tls_from_base(channel_t *chan) return (channel_tls_t *)(chan); } +/** + * Cast a const channel_tls_t to a const channel_t. + */ +const channel_t * +channel_tls_to_base_const(const channel_tls_t *tlschan) +{ + return channel_tls_to_base((channel_tls_t*) tlschan); +} + +/** + * Cast a const channel_t to a const channel_tls_t, with appropriate + * type-checking asserts. + */ +const channel_tls_t * +channel_tls_from_base_const(const channel_t *chan) +{ + return channel_tls_from_base((channel_t *)chan); +} + /******************************************** * Method implementations for channel_tls_t * *******************************************/ @@ -512,24 +529,29 @@ channel_tls_get_overhead_estimate_method(channel_t *chan) * Get the remote address of a channel_tls_t. * * This implements the get_remote_addr method for channel_tls_t; copy the - * remote endpoint of the channel to addr_out and return 1 (always - * succeeds for this transport). + * remote endpoint of the channel to addr_out and return 1. (Always + * succeeds if this channel is attached to an OR connection.) + * + * Always returns the real address of the peer, not the canonical address. */ static int -channel_tls_get_remote_addr_method(const channel_t *chan, tor_addr_t *addr_out) +channel_tls_get_remote_addr_method(const channel_t *chan, + tor_addr_t *addr_out) { - int rv = 0; - const channel_tls_t *tlschan = BASE_CHAN_TO_TLS((channel_t*) chan); + const channel_tls_t *tlschan = CONST_BASE_CHAN_TO_TLS(chan); tor_assert(tlschan); tor_assert(addr_out); - if (tlschan->conn) { - tor_addr_copy(addr_out, &(tlschan->conn->real_addr)); - rv = 1; - } else tor_addr_make_unspec(addr_out); + if (tlschan->conn == NULL) { + tor_addr_make_unspec(addr_out); + return 0; + } - return rv; + /* They want the real address, so give it to them. */ + tor_addr_copy(addr_out, &TO_CONN(tlschan->conn)->addr); + + return 1; } /** @@ -557,62 +579,22 @@ channel_tls_get_transport_name_method(channel_t *chan, char **transport_out) } /** - * Get endpoint description of a channel_tls_t. + * Get a human-readable endpoint description of a channel_tls_t. * - * This implements the get_remote_descr method for channel_tls_t; it returns - * a text description of the remote endpoint of the channel suitable for use - * in log messages. The req parameter is 0 for the canonical address or 1 for - * the actual address seen. + * This format is intended for logging, and may change in the future; + * nothing should parse or rely on its particular details. */ static const char * -channel_tls_get_remote_descr_method(channel_t *chan, int flags) +channel_tls_describe_peer_method(const channel_t *chan) { - static char buf[TOR_ADDRPORT_BUF_LEN]; - channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan); - connection_t *conn; - const char *answer = NULL; - char *addr_str; - + const channel_tls_t *tlschan = CONST_BASE_CHAN_TO_TLS(chan); tor_assert(tlschan); if (tlschan->conn) { - conn = TO_CONN(tlschan->conn); - switch (flags) { - case 0: - /* Canonical address with port*/ - tor_snprintf(buf, TOR_ADDRPORT_BUF_LEN, - "%s:%u", conn->address, conn->port); - answer = buf; - break; - case GRD_FLAG_ORIGINAL: - /* Actual address with port */ - addr_str = tor_addr_to_str_dup(&(tlschan->conn->real_addr)); - tor_snprintf(buf, TOR_ADDRPORT_BUF_LEN, "%s:%u", addr_str, conn->port); - tor_free(addr_str); - answer = buf; - break; - case GRD_FLAG_ADDR_ONLY: - /* Canonical address, no port */ - strlcpy(buf, conn->address, sizeof(buf)); - answer = buf; - break; - case GRD_FLAG_ORIGINAL|GRD_FLAG_ADDR_ONLY: - /* Actual address, no port */ - addr_str = tor_addr_to_str_dup(&(tlschan->conn->real_addr)); - strlcpy(buf, addr_str, sizeof(buf)); - tor_free(addr_str); - answer = buf; - break; - default: - /* Something's broken in channel.c */ - tor_assert_nonfatal_unreached_once(); - } + return connection_describe_peer(TO_CONN(tlschan->conn)); } else { - strlcpy(buf, "(No connection)", sizeof(buf)); - answer = buf; + return "(No connection)"; } - - return answer; } /** @@ -645,12 +627,11 @@ channel_tls_has_queued_writes_method(channel_t *chan) /** * Tell the upper layer if we're canonical. * - * This implements the is_canonical method for channel_tls_t; if req is zero, - * it returns whether this is a canonical channel, and if it is one it returns - * whether that can be relied upon. + * This implements the is_canonical method for channel_tls_t: + * it returns whether this is a canonical channel. */ static int -channel_tls_is_canonical_method(channel_t *chan, int req) +channel_tls_is_canonical_method(channel_t *chan) { int answer = 0; channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan); @@ -658,24 +639,13 @@ channel_tls_is_canonical_method(channel_t *chan, int req) tor_assert(tlschan); if (tlschan->conn) { - switch (req) { - case 0: - answer = tlschan->conn->is_canonical; - break; - case 1: - /* - * Is the is_canonical bit reliable? In protocols version 2 and up - * we get the canonical address from a NETINFO cell, but in older - * versions it might be based on an obsolete descriptor. - */ - answer = (tlschan->conn->link_proto >= 2); - break; - default: - /* This shouldn't happen; channel.c is broken if it does */ - tor_assert_nonfatal_unreached_once(); - } + /* If this bit is set to 0, and link_proto is sufficiently old, then we + * can't actually _rely_ on this being a non-canonical channel. + * Nonetheless, we're going to believe that this is a non-canonical + * channel in this case, since nobody should be using these link protocols + * any more. */ + answer = tlschan->conn->is_canonical; } - /* else return 0 for tlschan->conn == NULL */ return answer; } @@ -685,6 +655,9 @@ channel_tls_is_canonical_method(channel_t *chan, int req) * * This implements the matches_extend_info method for channel_tls_t; the upper * layer wants to know if this channel matches an extend_info_t. + * + * NOTE that this function only checks for an address/port match, and should + * be used only when no identify is available. */ static int channel_tls_matches_extend_info_method(channel_t *chan, @@ -704,6 +677,16 @@ channel_tls_matches_extend_info_method(channel_t *chan, return 0; } + const tor_addr_port_t *orport = &tlschan->conn->canonical_orport; + // If the canonical address is set, then we'll allow matches based on that. + if (! tor_addr_is_unspec(&orport->addr)) { + if (extend_info_has_orport(extend_info, &orport->addr, orport->port)) { + return 1; + } + } + + // We also want to match if the true address and port are listed in the + // extend info. return extend_info_has_orport(extend_info, &TO_CONN(tlschan->conn)->addr, TO_CONN(tlschan->conn)->port); @@ -734,8 +717,8 @@ channel_tls_matches_target_method(channel_t *chan, return 0; } - /* real_addr is the address this connection came from. - * base_.addr is updated by connection_or_init_conn_from_address() + /* addr is the address this connection came from. + * canonical_orport is updated by connection_or_init_conn_from_address() * to be the address in the descriptor. It may be tempting to * allow either address to be allowed, but if we did so, it would * enable someone who steals a relay's keys to covertly impersonate/MITM it @@ -746,7 +729,7 @@ channel_tls_matches_target_method(channel_t *chan, * An adversary who has stolen a relay's keys could also post a fake relay * descriptor, but that attack is easier to detect. */ - return tor_addr_eq(&(tlschan->conn->real_addr), target); + return tor_addr_eq(&TO_CONN(tlschan->conn)->addr, target); } /** @@ -1519,7 +1502,7 @@ channel_tls_process_versions_cell(var_cell_t *cell, channel_tls_t *chan) log_fn(LOG_WARN, LD_OR, "Negotiated link with non-2 protocol after doing a v2 TLS " "handshake with %s. Closing connection.", - fmt_addr(&chan->conn->base_.addr)); + connection_describe_peer(TO_CONN(chan->conn))); connection_or_close_for_error(chan->conn, 0); return; } @@ -1531,10 +1514,9 @@ channel_tls_process_versions_cell(var_cell_t *cell, channel_tls_t *chan) if (chan->conn->link_proto == 2) { log_info(LD_OR, - "Negotiated version %d with %s:%d; sending NETINFO.", + "Negotiated version %d on %s; sending NETINFO.", highest_supported_version, - safe_str_client(chan->conn->base_.address), - chan->conn->base_.port); + connection_describe(TO_CONN(chan->conn))); if (connection_or_send_netinfo(chan->conn) < 0) { connection_or_close_for_error(chan->conn, 0); @@ -1554,10 +1536,9 @@ channel_tls_process_versions_cell(var_cell_t *cell, channel_tls_t *chan) tor_assert(chan->conn->link_proto >= 3); log_info(LD_OR, - "Negotiated version %d with %s:%d; %s%s%s%s%s", + "Negotiated version %d with on %s; %s%s%s%s%s", highest_supported_version, - safe_str_client(chan->conn->base_.address), - chan->conn->base_.port, + connection_describe(TO_CONN(chan->conn)), send_any ? "Sending cells:" : "Waiting for CERTS cell", send_versions ? " VERSIONS" : "", send_certs ? " CERTS" : "", @@ -1897,7 +1878,7 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan) * might be doing something funny, but nobody else is doing a MITM * on the relay's TCP. */ - if (tor_addr_eq(&addr, &(chan->conn->real_addr))) { + if (tor_addr_eq(&addr, &TO_CONN(chan->conn)->addr)) { connection_or_set_canonical(chan->conn, 1); break; } @@ -1907,8 +1888,8 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan) if (me && !TLS_CHAN_TO_BASE(chan)->is_canonical_to_peer && channel_is_canonical(TLS_CHAN_TO_BASE(chan))) { - const char *descr = - TLS_CHAN_TO_BASE(chan)->get_remote_descr(TLS_CHAN_TO_BASE(chan), 0); + const char *descr = channel_describe_peer( + TLS_CHAN_TO_BASE(chan)); log_info(LD_OR, "We made a connection to a relay at %s (fp=%s) but we think " "they will not consider this connection canonical. They " @@ -1935,7 +1916,7 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan) * we were unable to resolve it previously. The endpoint address is passed * in order to make sure to never consider an address that is the same as * our endpoint. */ - relay_address_new_suggestion(&my_apparent_addr, &chan->conn->real_addr, + relay_address_new_suggestion(&my_apparent_addr, &TO_CONN(chan->conn)->addr, identity_digest); if (! chan->conn->handshake_state->sent_netinfo) { @@ -1950,18 +1931,16 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan) if (connection_or_set_state_open(chan->conn) < 0) { log_fn(LOG_PROTOCOL_WARN, LD_OR, - "Got good NETINFO cell from %s:%d; but " + "Got good NETINFO cell on %s; but " "was unable to make the OR connection become open.", - safe_str_client(chan->conn->base_.address), - chan->conn->base_.port); + connection_describe(TO_CONN(chan->conn))); connection_or_close_for_error(chan->conn, 0); } else { log_info(LD_OR, - "Got good NETINFO cell from %s:%d; OR connection is now " + "Got good NETINFO cell on %s; OR connection is now " "open, using protocol version %d. Its ID digest is %s. " "Our address is apparently %s.", - safe_str_client(chan->conn->base_.address), - chan->conn->base_.port, + connection_describe(TO_CONN(chan->conn)), (int)(chan->conn->link_proto), hex_str(identity_digest, DIGEST_LEN), tor_addr_is_null(&my_apparent_addr) ? @@ -2046,9 +2025,9 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan) #define ERR(s) \ do { \ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \ - "Received a bad CERTS cell from %s:%d: %s", \ - safe_str(chan->conn->base_.address), \ - chan->conn->base_.port, (s)); \ + "Received a bad CERTS cell on %s: %s", \ + connection_describe(TO_CONN(chan->conn)), \ + (s)); \ connection_or_close_for_error(chan->conn, 0); \ goto err; \ } while (0) @@ -2096,9 +2075,8 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan) tor_x509_cert_t *x509_cert = tor_x509_cert_decode(cert_body, cert_len); if (!x509_cert) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Received undecodable certificate in CERTS cell from %s:%d", - safe_str(chan->conn->base_.address), - chan->conn->base_.port); + "Received undecodable certificate in CERTS cell on %s", + connection_describe(TO_CONN(chan->conn))); } else { if (x509_certs[cert_type]) { tor_x509_cert_free(x509_cert); @@ -2114,9 +2092,8 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan) if (!ed_cert) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received undecodable Ed certificate " - "in CERTS cell from %s:%d", - safe_str(chan->conn->base_.address), - chan->conn->base_.port); + "in CERTS cell on %s", + connection_describe(TO_CONN(chan->conn))); } else { if (ed_certs[cert_type]) { tor_cert_free(ed_cert); @@ -2226,9 +2203,9 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan) ERR("Problem setting or checking peer id"); log_info(LD_HANDSHAKE, - "Got some good certificates from %s:%d: Authenticated it with " + "Got some good certificates on %s: Authenticated it with " "RSA%s", - safe_str(chan->conn->base_.address), chan->conn->base_.port, + connection_describe(TO_CONN(chan->conn)), checked_ed_id ? " and Ed25519" : ""); if (!public_server_mode(get_options())) { @@ -2240,11 +2217,10 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan) } else { /* We can't call it authenticated till we see an AUTHENTICATE cell. */ log_info(LD_OR, - "Got some good RSA%s certificates from %s:%d. " + "Got some good RSA%s certificates on %s. " "Waiting for AUTHENTICATE.", checked_ed_id ? " and Ed25519" : "", - safe_str(chan->conn->base_.address), - chan->conn->base_.port); + connection_describe(TO_CONN(chan->conn))); /* XXXX check more stuff? */ } @@ -2293,9 +2269,9 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan) #define ERR(s) \ do { \ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \ - "Received a bad AUTH_CHALLENGE cell from %s:%d: %s", \ - safe_str(chan->conn->base_.address), \ - chan->conn->base_.port, (s)); \ + "Received a bad AUTH_CHALLENGE cell on %s: %s", \ + connection_describe(TO_CONN(chan->conn)), \ + (s)); \ connection_or_close_for_error(chan->conn, 0); \ goto done; \ } while (0) @@ -2340,10 +2316,9 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan) if (use_type >= 0) { log_info(LD_OR, - "Got an AUTH_CHALLENGE cell from %s:%d: Sending " + "Got an AUTH_CHALLENGE cell on %s: Sending " "authentication type %d", - safe_str(chan->conn->base_.address), - chan->conn->base_.port, + connection_describe(TO_CONN(chan->conn)), use_type); if (connection_or_send_authenticate_cell(chan->conn, use_type) < 0) { @@ -2354,10 +2329,9 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan) } } else { log_info(LD_OR, - "Got an AUTH_CHALLENGE cell from %s:%d, but we don't " + "Got an AUTH_CHALLENGE cell on %s, but we don't " "know any of its authentication types. Not authenticating.", - safe_str(chan->conn->base_.address), - chan->conn->base_.port); + connection_describe(TO_CONN(chan->conn))); } if (connection_or_send_netinfo(chan->conn) < 0) { @@ -2397,9 +2371,9 @@ channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan) #define ERR(s) \ do { \ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \ - "Received a bad AUTHENTICATE cell from %s:%d: %s", \ - safe_str(chan->conn->base_.address), \ - chan->conn->base_.port, (s)); \ + "Received a bad AUTHENTICATE cell on %s: %s", \ + connection_describe(TO_CONN(chan->conn)), \ + (s)); \ connection_or_close_for_error(chan->conn, 0); \ var_cell_free(expected_cell); \ return; \ @@ -2560,9 +2534,9 @@ channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan) crypto_pk_free(identity_rcvd); log_debug(LD_HANDSHAKE, - "Calling connection_or_init_conn_from_address for %s " + "Calling connection_or_init_conn_from_address on %s " " from %s, with%s ed25519 id.", - safe_str(chan->conn->base_.address), + connection_describe(TO_CONN(chan->conn)), __func__, ed_identity_received ? "" : "out"); @@ -2575,10 +2549,9 @@ channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan) 0); log_debug(LD_HANDSHAKE, - "Got an AUTHENTICATE cell from %s:%d, type %d: Looks good.", - safe_str(chan->conn->base_.address), - chan->conn->base_.port, - authtype); + "Got an AUTHENTICATE cell on %s, type %d: Looks good.", + connection_describe(TO_CONN(chan->conn)), + authtype); } var_cell_free(expected_cell); diff --git a/src/core/or/channeltls.h b/src/core/or/channeltls.h index f04ce0fa9c..e7010a51fc 100644 --- a/src/core/or/channeltls.h +++ b/src/core/or/channeltls.h @@ -19,6 +19,8 @@ struct curve25519_public_key_t; #define BASE_CHAN_TO_TLS(c) (channel_tls_from_base((c))) #define TLS_CHAN_TO_BASE(c) (channel_tls_to_base((c))) +#define CONST_BASE_CHAN_TO_TLS(c) (channel_tls_from_base_const((c))) +#define CONST_TLS_CHAN_TO_BASE(c) (channel_tls_to_base_const((c))) #define TLS_CHAN_MAGIC 0x8a192427U @@ -44,6 +46,8 @@ channel_t * channel_tls_handle_incoming(or_connection_t *orconn); channel_t * channel_tls_to_base(channel_tls_t *tlschan); channel_tls_t * channel_tls_from_base(channel_t *chan); +const channel_t * channel_tls_to_base_const(const channel_tls_t *tlschan); +const channel_tls_t * channel_tls_from_base_const(const channel_t *chan); /* Things for connection_or.c to call back into */ void channel_tls_handle_cell(cell_t *cell, or_connection_t *conn); diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c index fd56ca1c65..76e9ccf0a5 100644 --- a/src/core/or/circuitbuild.c +++ b/src/core/or/circuitbuild.c @@ -632,7 +632,7 @@ circuit_n_chan_done(channel_t *chan, int status, int close_origin_circuits) tor_assert(chan); log_debug(LD_CIRC,"chan to %s, status=%d", - channel_get_canonical_remote_descr(chan), status); + channel_describe_peer(chan), status); pending_circs = smartlist_new(); circuit_get_all_pending_on_channel(pending_circs, chan); @@ -731,6 +731,8 @@ circuit_deliver_create_cell,(circuit_t *circ, goto error; } + tor_assert_nonfatal_once(circ->n_chan->is_canonical); + memset(&cell, 0, sizeof(cell_t)); r = relayed ? create_cell_format_relayed(&cell, create_cell) : create_cell_format(&cell, create_cell); diff --git a/src/core/or/circuitlist.c b/src/core/or/circuitlist.c index 2455aa8779..c0c28c9e2d 100644 --- a/src/core/or/circuitlist.c +++ b/src/core/or/circuitlist.c @@ -619,7 +619,7 @@ circuit_count_pending_on_channel(channel_t *chan) cnt = smartlist_len(sl); smartlist_free(sl); log_debug(LD_CIRC,"or_conn to %s, %d pending circs", - channel_get_canonical_remote_descr(chan), + channel_describe_peer(chan), cnt); return cnt; } @@ -2437,7 +2437,6 @@ single_conn_free_bytes(connection_t *conn) if (conn->outbuf) { result += buf_allocation(conn->outbuf); buf_clear(conn->outbuf); - conn->outbuf_flushlen = 0; } if (conn->type == CONN_TYPE_DIR) { dir_connection_t *dir_conn = TO_DIR_CONN(conn); diff --git a/src/core/or/circuituse.c b/src/core/or/circuituse.c index d2bdf77d8d..df23c63cff 100644 --- a/src/core/or/circuituse.c +++ b/src/core/or/circuituse.c @@ -819,7 +819,7 @@ circuit_expire_building(void) log_info(LD_CIRC, "Abandoning circ %u %s:%u (state %d,%d:%s, purpose %d, " "len %d)", TO_ORIGIN_CIRCUIT(victim)->global_identifier, - channel_get_canonical_remote_descr(victim->n_chan), + channel_describe_peer(victim->n_chan), (unsigned)victim->n_circ_id, TO_ORIGIN_CIRCUIT(victim)->has_opened, victim->state, circuit_state_to_string(victim->state), @@ -1651,11 +1651,12 @@ static void circuit_testing_opened(origin_circuit_t *circ) { if (have_performed_bandwidth_test || - !router_all_orports_seem_reachable(get_options())) { + !router_orport_seems_reachable(get_options(), AF_INET)) { /* either we've already done everything we want with testing circuits, - * or this testing circuit became open due to a fluke, e.g. we picked - * a last hop where we already had the connection open due to an - * outgoing local circuit. */ + * OR this IPv4 testing circuit became open due to a fluke, e.g. we picked + * a last hop where we already had the connection open due to a + * outgoing local circuit, OR this is an IPv6 self-test circuit, not + * a bandwidth test circuit. */ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN); } else if (circuit_enough_testing_circs()) { router_perform_bandwidth_test(NUM_PARALLEL_TESTING_CIRCS, time(NULL)); @@ -1857,7 +1858,7 @@ circuit_build_failed(origin_circuit_t *circ) "from the first hop (%s). I'm going to try to rotate to a " "better connection.", TO_CIRCUIT(circ)->n_circ_id, circ->global_identifier, - channel_get_canonical_remote_descr(n_chan)); + channel_describe_peer(n_chan)); n_chan->is_bad_for_new_circs = 1; } else { log_info(LD_OR, diff --git a/src/core/or/command.c b/src/core/or/command.c index 8a1d2066cc..9226309ff7 100644 --- a/src/core/or/command.c +++ b/src/core/or/command.c @@ -252,7 +252,7 @@ command_process_create_cell(cell_t *cell, channel_t *chan) log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Received a create cell (type %d) from %s with zero circID; " " ignoring.", (int)cell->command, - channel_get_actual_remote_descr(chan)); + channel_describe_peer(chan)); return; } @@ -295,7 +295,7 @@ command_process_create_cell(cell_t *cell, channel_t *chan) "Received create cell (type %d) from %s, but we're connected " "to it as a client. " "Sending back a destroy.", - (int)cell->command, channel_get_canonical_remote_descr(chan)); + (int)cell->command, channel_describe_peer(chan)); channel_send_destroy(cell->circ_id, chan, END_CIRC_REASON_TORPROTOCOL); return; @@ -475,7 +475,7 @@ command_process_relay_cell(cell_t *cell, channel_t *chan) log_debug(LD_OR, "unknown circuit %u on connection from %s. Dropping.", (unsigned)cell->circ_id, - channel_get_canonical_remote_descr(chan)); + channel_describe_peer(chan)); return; } @@ -536,7 +536,7 @@ command_process_relay_cell(cell_t *cell, channel_t *chan) control_event_circ_bandwidth_used_for_circ(TO_ORIGIN_CIRCUIT(circ)); } else if (circ->n_chan) { log_warn(LD_OR, " upstream=%s", - channel_get_actual_remote_descr(circ->n_chan)); + channel_describe_peer(circ->n_chan)); } circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); return; @@ -547,7 +547,7 @@ command_process_relay_cell(cell_t *cell, channel_t *chan) "Received too many RELAY_EARLY cells on circ %u from %s." " Closing circuit.", (unsigned)cell->circ_id, - safe_str(channel_get_canonical_remote_descr(chan))); + safe_str(channel_describe_peer(chan))); circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); return; } @@ -618,7 +618,7 @@ command_process_destroy_cell(cell_t *cell, channel_t *chan) if (!circ) { log_info(LD_OR,"unknown circuit %u on connection from %s. Dropping.", (unsigned)cell->circ_id, - channel_get_canonical_remote_descr(chan)); + channel_describe_peer(chan)); return; } log_debug(LD_OR,"Received for circID %u.",(unsigned)cell->circ_id); diff --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c index 45d2a9664a..25337f0720 100644 --- a/src/core/or/connection_edge.c +++ b/src/core/or/connection_edge.c @@ -166,8 +166,12 @@ static int connection_exit_connect_dir(edge_connection_t *exitconn); static int consider_plaintext_ports(entry_connection_t *conn, uint16_t port); static int connection_ap_supports_optimistic_data(const entry_connection_t *); -/** Convert a connection_t* to an edge_connection_t*; assert if the cast is - * invalid. */ +/** + * Cast a `connection_t *` to an `edge_connection_t *`. + * + * Exit with an assertion failure if the input is not an + * `edge_connection_t`. + **/ edge_connection_t * TO_EDGE_CONN(connection_t *c) { @@ -176,6 +180,24 @@ TO_EDGE_CONN(connection_t *c) return DOWNCAST(edge_connection_t, c); } +/** + * Cast a `const connection_t *` to a `const edge_connection_t *`. + * + * Exit with an assertion failure if the input is not an + * `edge_connection_t`. + **/ +const edge_connection_t * +CONST_TO_EDGE_CONN(const connection_t *c) +{ + return TO_EDGE_CONN((connection_t *)c); +} + +/** + * Cast a `connection_t *` to an `entry_connection_t *`. + * + * Exit with an assertion failure if the input is not an + * `entry_connection_t`. + **/ entry_connection_t * TO_ENTRY_CONN(connection_t *c) { @@ -183,6 +205,24 @@ TO_ENTRY_CONN(connection_t *c) return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_.base_); } +/** + * Cast a `const connection_t *` to a `const entry_connection_t *`. + * + * Exit with an assertion failure if the input is not an + * `entry_connection_t`. + **/ +const entry_connection_t * +CONST_TO_ENTRY_CONN(const connection_t *c) +{ + return TO_ENTRY_CONN((connection_t*) c); +} + +/** + * Cast an `edge_connection_t *` to an `entry_connection_t *`. + * + * Exit with an assertion failure if the input is not an + * `entry_connection_t`. + **/ entry_connection_t * EDGE_TO_ENTRY_CONN(edge_connection_t *c) { @@ -190,6 +230,18 @@ EDGE_TO_ENTRY_CONN(edge_connection_t *c) return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_); } +/** + * Cast a `const edge_connection_t *` to a `const entry_connection_t *`. + * + * Exit with an assertion failure if the input is not an + * `entry_connection_t`. + **/ +const entry_connection_t * +CONST_EDGE_TO_ENTRY_CONN(const edge_connection_t *c) +{ + return EDGE_TO_ENTRY_CONN((edge_connection_t*)c); +} + /** An AP stream has failed/finished. If it hasn't already sent back * a socks reply, send one now (based on endreason). Also set * has_sent_end to 1, and mark the conn. @@ -424,9 +476,7 @@ warn_if_hs_unreachable(const edge_connection_t *conn, uint8_t reason) char *m; if ((m = rate_limit_log(&warn_limit, approx_time()))) { log_warn(LD_EDGE, "Onion service connection to %s failed (%s)", - (conn->base_.socket_family == AF_UNIX) ? - safe_str(conn->base_.address) : - safe_str(fmt_addrport(&conn->base_.addr, conn->base_.port)), + connection_describe_peer(TO_CONN(conn)), stream_end_reason_to_string(reason)); tor_free(m); } @@ -922,9 +972,8 @@ connection_edge_finished_connecting(edge_connection_t *edge_conn) conn = TO_CONN(edge_conn); tor_assert(conn->state == EXIT_CONN_STATE_CONNECTING); - log_info(LD_EXIT,"Exit connection to %s:%u (%s) established.", - escaped_safe_str(conn->address), conn->port, - safe_str(fmt_and_decorate_addr(&conn->addr))); + log_info(LD_EXIT,"%s established.", + connection_describe(conn)); rep_hist_note_exit_stream_opened(conn->port); @@ -1504,6 +1553,16 @@ circuit_discard_optional_exit_enclaves(extend_info_t *info) } SMARTLIST_FOREACH_END(conn); } +/** Set the connection state to CONTROLLER_WAIT and send an control port event. + */ +void +connection_entry_set_controller_wait(entry_connection_t *conn) +{ + CONNECTION_AP_EXPECT_NONPENDING(conn); + ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_CONTROLLER_WAIT; + control_event_stream_status(conn, STREAM_EVENT_CONTROLLER_WAIT, 0); +} + /** The AP connection <b>conn</b> has just failed while attaching or * sending a BEGIN or resolving on <b>circ</b>, but another circuit * might work. Detach the circuit, and either reattach it, launch a @@ -1535,8 +1594,7 @@ connection_ap_detach_retriable(entry_connection_t *conn, circuit_detach_stream(TO_CIRCUIT(circ),ENTRY_TO_EDGE_CONN(conn)); connection_ap_mark_as_pending_circuit(conn); } else { - CONNECTION_AP_EXPECT_NONPENDING(conn); - ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_CONTROLLER_WAIT; + connection_entry_set_controller_wait(conn); circuit_detach_stream(TO_CIRCUIT(circ),ENTRY_TO_EDGE_CONN(conn)); } return 0; @@ -1689,8 +1747,7 @@ connection_ap_rewrite_and_attach_if_allowed,(entry_connection_t *conn, const or_options_t *options = get_options(); if (options->LeaveStreamsUnattached) { - CONNECTION_AP_EXPECT_NONPENDING(conn); - ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_CONTROLLER_WAIT; + connection_entry_set_controller_wait(conn); return 0; } return connection_ap_handshake_rewrite_and_attach(conn, circ, cpath); @@ -3840,8 +3897,8 @@ handle_hs_exit_conn(circuit_t *circ, edge_connection_t *conn) return -1; } if (ret < 0) { - log_info(LD_REND, "Didn't find rendezvous service (addr%s, port %d)", - fmt_addr(&TO_CONN(conn)->addr), TO_CONN(conn)->port); + log_info(LD_REND, "Didn't find rendezvous service at %s", + connection_describe_peer(TO_CONN(conn))); /* Send back reason DONE because we want to make hidden service port * scanning harder thus instead of returning that the exit policy * didn't match, which makes it obvious that the port is closed, @@ -3976,7 +4033,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) * proxies. */ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Attempt by %s to open a stream %s. Closing.", - safe_str(channel_get_canonical_remote_descr(or_circ->p_chan)), + safe_str(channel_describe_peer(or_circ->p_chan)), client_chan ? "on first hop of circuit" : "from unknown relay"); relay_send_end_cell_from_edge(rh.stream_id, circ, @@ -3999,10 +4056,13 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) * caller might want to know whether the remote IP address has changed, * and we might already have corrected base_.addr[ess] for the relay's * canonical IP address. */ - if (or_circ && or_circ->p_chan) - address = tor_strdup(channel_get_actual_remote_address(or_circ->p_chan)); - else + tor_addr_t chan_addr; + if (or_circ && or_circ->p_chan && + channel_get_addr_if_possible(or_circ->p_chan, &chan_addr)) { + address = tor_addr_to_str_dup(&chan_addr); + } else { address = tor_strdup("127.0.0.1"); + } port = 1; /* XXXX This value is never actually used anywhere, and there * isn't "really" a connection here. But we * need to set it to something nonzero. */ @@ -4192,8 +4252,8 @@ connection_exit_connect(edge_connection_t *edge_conn) &why_failed_exit_policy)) { if (BUG(!why_failed_exit_policy)) why_failed_exit_policy = ""; - log_info(LD_EXIT,"%s:%d failed exit policy%s. Closing.", - escaped_safe_str_client(conn->address), conn->port, + log_info(LD_EXIT,"%s failed exit policy%s. Closing.", + connection_describe(conn), why_failed_exit_policy); connection_edge_end(edge_conn, END_STREAM_REASON_EXITPOLICY); circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn); diff --git a/src/core/or/connection_edge.h b/src/core/or/connection_edge.h index 8c06af5664..c9433adade 100644 --- a/src/core/or/connection_edge.h +++ b/src/core/or/connection_edge.h @@ -20,6 +20,10 @@ edge_connection_t *TO_EDGE_CONN(connection_t *); entry_connection_t *TO_ENTRY_CONN(connection_t *); entry_connection_t *EDGE_TO_ENTRY_CONN(edge_connection_t *); +const edge_connection_t *CONST_TO_EDGE_CONN(const connection_t *); +const entry_connection_t *CONST_TO_ENTRY_CONN(const connection_t *); +const entry_connection_t *CONST_EDGE_TO_ENTRY_CONN(const edge_connection_t *); + #define EXIT_CONN_STATE_MIN_ 1 /** State for an exit connection: waiting for response from DNS farm. */ #define EXIT_CONN_STATE_RESOLVING 1 @@ -94,6 +98,8 @@ int connection_edge_flushed_some(edge_connection_t *conn); int connection_edge_finished_flushing(edge_connection_t *conn); int connection_edge_finished_connecting(edge_connection_t *conn); +void connection_entry_set_controller_wait(entry_connection_t *conn); + void connection_ap_about_to_close(entry_connection_t *edge_conn); void connection_exit_about_to_close(edge_connection_t *edge_conn); diff --git a/src/core/or/connection_or.c b/src/core/or/connection_or.c index 079fa3dfcb..0795521be0 100644 --- a/src/core/or/connection_or.c +++ b/src/core/or/connection_or.c @@ -99,8 +99,11 @@ static void connection_or_check_canonicity(or_connection_t *conn, /**************************************************************/ -/** Convert a connection_t* to an or_connection_t*; assert if the cast is - * invalid. */ +/** + * Cast a `connection_t *` to an `or_connection_t *`. + * + * Exit with an assertion failure if the input is not an `or_connnection_t`. + **/ or_connection_t * TO_OR_CONN(connection_t *c) { @@ -108,6 +111,17 @@ TO_OR_CONN(connection_t *c) return DOWNCAST(or_connection_t, c); } +/** + * Cast a `const connection_t *` to a `const or_connection_t *`. + * + * Exit with an assertion failure if the input is not an `or_connnection_t`. + **/ +const or_connection_t * +CONST_TO_OR_CONN(const connection_t *c) +{ + return TO_OR_CONN((connection_t *)c); +} + /** Clear clear conn->identity_digest and update other data * structures as appropriate.*/ void @@ -151,9 +165,9 @@ connection_or_set_identity_digest(or_connection_t *conn, if (conn->chan) chan = TLS_CHAN_TO_BASE(conn->chan); - log_info(LD_HANDSHAKE, "Set identity digest for %p (%s): %s %s.", + log_info(LD_HANDSHAKE, "Set identity digest for %s at %p: %s %s.", + connection_describe(TO_CONN(conn)), conn, - escaped_safe_str(conn->base_.address), hex_str(rsa_digest, DIGEST_LEN), ed25519_fmt(ed_id)); log_info(LD_HANDSHAKE, " (Previously: %s %s)", @@ -575,11 +589,9 @@ connection_or_process_inbuf(or_connection_t *conn) * 100% true. */ if (buf_datalen(conn->base_.inbuf) > MAX_OR_INBUF_WHEN_NONOPEN) { log_fn(LOG_PROTOCOL_WARN, LD_NET, "Accumulated too much data (%d bytes) " - "on nonopen OR connection %s %s:%u in state %s; closing.", + "on non-open %s; closing.", (int)buf_datalen(conn->base_.inbuf), - connection_or_nonopen_was_started_here(conn) ? "to" : "from", - conn->base_.address, conn->base_.port, - conn_state_to_string(conn->base_.type, conn->base_.state)); + connection_describe(TO_CONN(conn))); connection_or_close_for_error(conn, 0); ret = -1; } @@ -691,8 +703,8 @@ connection_or_finished_connecting(or_connection_t *or_conn) conn = TO_CONN(or_conn); tor_assert(conn->state == OR_CONN_STATE_CONNECTING); - log_debug(LD_HANDSHAKE,"OR connect() to router at %s:%u finished.", - conn->address,conn->port); + log_debug(LD_HANDSHAKE,"connect finished for %s", + connection_describe(conn)); if (proxy_type != PROXY_NONE) { /* start proxy handshake */ @@ -881,7 +893,9 @@ connection_or_init_conn_from_address(or_connection_t *conn, conn->base_.port = port; tor_addr_copy(&conn->base_.addr, addr); - tor_addr_copy(&conn->real_addr, addr); + if (! conn->base_.address) { + conn->base_.address = tor_strdup(fmt_addr(addr)); + } connection_or_check_canonicity(conn, started_here); } @@ -893,9 +907,10 @@ connection_or_init_conn_from_address(or_connection_t *conn, static void connection_or_check_canonicity(or_connection_t *conn, int started_here) { + (void) started_here; + const char *id_digest = conn->identity_digest; const ed25519_public_key_t *ed_id = NULL; - const tor_addr_t *addr = &conn->real_addr; if (conn->chan) ed_id = & TLS_CHAN_TO_BASE(conn->chan)->ed25519_identity; @@ -924,34 +939,17 @@ connection_or_check_canonicity(or_connection_t *conn, int started_here) } else { node_ap = &node_ipv6_ap; } - if (!started_here) { - /* Override the addr/port, so our log messages will make sense. - * This is dangerous, since if we ever try looking up a conn by - * its actual addr/port, we won't remember. Careful! */ - /* XXXX arma: this is stupid, and it's the reason we need real_addr - * to track is_canonical properly. What requires it? */ - /* XXXX <arma> i believe the reason we did this, originally, is because - * we wanted to log what OR a connection was to, and if we logged the - * right IP address and port 56244, that wouldn't be as helpful. now we - * log the "right" port too, so we know if it's moria1 or moria2. - */ - /* See #33898 for a ticket that resolves this technical debt. */ - tor_addr_copy(&conn->base_.addr, &node_ap->addr); - conn->base_.port = node_ap->port; - } + /* Remember the canonical addr/port so our log messages will make + sense. */ + tor_addr_port_copy(&conn->canonical_orport, node_ap); tor_free(conn->nickname); conn->nickname = tor_strdup(node_get_nickname(r)); - tor_free(conn->base_.address); - conn->base_.address = tor_addr_to_str_dup(&node_ap->addr); } else { tor_free(conn->nickname); conn->nickname = tor_malloc(HEX_DIGEST_LEN+2); conn->nickname[0] = '$'; base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1, conn->identity_digest, DIGEST_LEN); - - tor_free(conn->base_.address); - conn->base_.address = tor_addr_to_str_dup(addr); } /* @@ -1010,9 +1008,10 @@ connection_or_single_set_badness_(time_t now, or_conn->base_.timestamp_created + TIME_BEFORE_OR_CONN_IS_TOO_OLD < now) { log_info(LD_OR, - "Marking OR conn to %s:%d as too old for new circuits " + "Marking %s as too old for new circuits " "(fd "TOR_SOCKET_T_FORMAT", %d secs old).", - or_conn->base_.address, or_conn->base_.port, or_conn->base_.s, + connection_describe(TO_CONN(or_conn)), + or_conn->base_.s, (int)(now - or_conn->base_.timestamp_created)); connection_or_mark_bad_for_new_circs(or_conn); } @@ -1077,10 +1076,11 @@ connection_or_group_set_badness_(smartlist_t *group, int force) /* We have at least one open canonical connection to this router, * and this one is open but not canonical. Mark it bad. */ log_info(LD_OR, - "Marking OR conn to %s:%d as unsuitable for new circuits: " + "Marking %s unsuitable for new circuits: " "(fd "TOR_SOCKET_T_FORMAT", %d secs old). It is not " "canonical, and we have another connection to that OR that is.", - or_conn->base_.address, or_conn->base_.port, or_conn->base_.s, + connection_describe(TO_CONN(or_conn)), + or_conn->base_.s, (int)(now - or_conn->base_.timestamp_created)); connection_or_mark_bad_for_new_circs(or_conn); continue; @@ -1121,22 +1121,24 @@ connection_or_group_set_badness_(smartlist_t *group, int force) /* This isn't the best conn, _and_ the best conn is better than it */ if (best->is_canonical) { log_info(LD_OR, - "Marking OR conn to %s:%d as unsuitable for new circuits: " + "Marking %s as unsuitable for new circuits: " "(fd "TOR_SOCKET_T_FORMAT", %d secs old). " "We have a better canonical one " "(fd "TOR_SOCKET_T_FORMAT"; %d secs old).", - or_conn->base_.address, or_conn->base_.port, or_conn->base_.s, + connection_describe(TO_CONN(or_conn)), + or_conn->base_.s, (int)(now - or_conn->base_.timestamp_created), best->base_.s, (int)(now - best->base_.timestamp_created)); connection_or_mark_bad_for_new_circs(or_conn); - } else if (!tor_addr_compare(&or_conn->real_addr, - &best->real_addr, CMP_EXACT)) { + } else if (tor_addr_eq(&TO_CONN(or_conn)->addr, + &TO_CONN(best)->addr)) { log_info(LD_OR, - "Marking OR conn to %s:%d as unsuitable for new circuits: " + "Marking %s unsuitable for new circuits: " "(fd "TOR_SOCKET_T_FORMAT", %d secs old). We have a better " "one with the " "same address (fd "TOR_SOCKET_T_FORMAT"; %d secs old).", - or_conn->base_.address, or_conn->base_.port, or_conn->base_.s, + connection_describe(TO_CONN(or_conn)), + or_conn->base_.s, (int)(now - or_conn->base_.timestamp_created), best->base_.s, (int)(now - best->base_.timestamp_created)); connection_or_mark_bad_for_new_circs(or_conn); @@ -1259,7 +1261,7 @@ static or_connect_failure_entry_t * or_connect_failure_new(const or_connection_t *or_conn) { or_connect_failure_entry_t *ocf = tor_malloc_zero(sizeof(*ocf)); - or_connect_failure_init(or_conn->identity_digest, &or_conn->real_addr, + or_connect_failure_init(or_conn->identity_digest, &TO_CONN(or_conn)->addr, TO_CONN(or_conn)->port, ocf); return ocf; } @@ -1464,10 +1466,9 @@ connection_or_connect, (const tor_addr_t *_addr, uint16_t port, * that is we haven't had a failure earlier. This is to avoid to try to * constantly connect to relays that we think are not reachable. */ if (!should_connect_to_relay(conn)) { - log_info(LD_GENERAL, "Can't connect to identity %s at %s:%u because we " + log_info(LD_GENERAL, "Can't connect to %s because we " "failed earlier. Refusing.", - hex_str(id_digest, DIGEST_LEN), fmt_addr(&TO_CONN(conn)->addr), - TO_CONN(conn)->port); + connection_describe_peer(TO_CONN(conn))); connection_free_(TO_CONN(conn)); return NULL; } @@ -1507,7 +1508,7 @@ connection_or_connect, (const tor_addr_t *_addr, uint16_t port, "transport proxy supporting '%s'. This can happen if you " "haven't provided a ClientTransportPlugin line, or if " "your pluggable transport proxy stopped running.", - fmt_addrport(&TO_CONN(conn)->addr, TO_CONN(conn)->port), + connection_describe_peer(TO_CONN(conn)), transport_name, transport_name); control_event_bootstrap_prob_or( @@ -1516,9 +1517,9 @@ connection_or_connect, (const tor_addr_t *_addr, uint16_t port, conn); } else { - log_warn(LD_GENERAL, "Tried to connect to '%s' through a proxy, but " + log_warn(LD_GENERAL, "Tried to connect to %s through a proxy, but " "the proxy address could not be found.", - fmt_addrport(&TO_CONN(conn)->addr, TO_CONN(conn)->port)); + connection_describe_peer(TO_CONN(conn))); } connection_free_(TO_CONN(conn)); @@ -1638,8 +1639,8 @@ connection_tls_start_handshake,(or_connection_t *conn, int receiving)) log_warn(LD_BUG,"tor_tls_new failed. Closing."); return -1; } - tor_tls_set_logged_address(conn->tls, // XXX client and relay? - escaped_safe_str(conn->base_.address)); + tor_tls_set_logged_address(conn->tls, + connection_describe_peer(TO_CONN(conn))); connection_start_reading(TO_CONN(conn)); log_debug(LD_HANDSHAKE,"starting TLS handshake on fd "TOR_SOCKET_T_FORMAT, @@ -1786,18 +1787,15 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn, crypto_pk_t *identity_rcvd=NULL; const or_options_t *options = get_options(); int severity = server_mode(options) ? LOG_PROTOCOL_WARN : LOG_WARN; - const char *safe_address = - started_here ? conn->base_.address : - safe_str_client(conn->base_.address); const char *conn_type = started_here ? "outgoing" : "incoming"; int has_cert = 0; check_no_tls_errors(); has_cert = tor_tls_peer_has_cert(conn->tls); if (started_here && !has_cert) { - log_info(LD_HANDSHAKE,"Tried connecting to router at %s:%d, but it didn't " + log_info(LD_HANDSHAKE,"Tried connecting to router at %s, but it didn't " "send a cert! Closing.", - safe_address, conn->base_.port); + connection_describe_peer(TO_CONN(conn))); return -1; } else if (!has_cert) { log_debug(LD_HANDSHAKE,"Got incoming connection with no certificate. " @@ -1809,9 +1807,9 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn, int v = tor_tls_verify(started_here?severity:LOG_INFO, conn->tls, &identity_rcvd); if (started_here && v<0) { - log_fn(severity,LD_HANDSHAKE,"Tried connecting to router at %s:%d: It" + log_fn(severity,LD_HANDSHAKE,"Tried connecting to router at %s: It" " has a cert but it's invalid. Closing.", - safe_address, conn->base_.port); + connection_describe_peer(TO_CONN(conn))); return -1; } else if (v<0) { log_info(LD_HANDSHAKE,"Incoming connection gave us an invalid cert " @@ -1819,7 +1817,8 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn, } else { log_debug(LD_HANDSHAKE, "The certificate seems to be valid on %s connection " - "with %s:%d", conn_type, safe_address, conn->base_.port); + "with %s", conn_type, + connection_describe_peer(TO_CONN(conn))); } check_no_tls_errors(); } @@ -1891,9 +1890,9 @@ connection_or_client_learned_peer_id(or_connection_t *conn, const int expected_ed_key = ! ed25519_public_key_is_zero(&chan->ed25519_identity); - log_info(LD_HANDSHAKE, "learned peer id for %p (%s): %s, %s", + log_info(LD_HANDSHAKE, "learned peer id for %s at %p: %s, %s", + connection_describe(TO_CONN(conn)), conn, - safe_str_client(conn->base_.address), hex_str((const char*)rsa_peer_id, DIGEST_LEN), ed25519_fmt(ed_peer_id)); @@ -1907,9 +1906,9 @@ connection_or_client_learned_peer_id(or_connection_t *conn, conn->nickname[0] = '$'; base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1, conn->identity_digest, DIGEST_LEN); - log_info(LD_HANDSHAKE, "Connected to router %s at %s:%d without knowing " - "its key. Hoping for the best.", - conn->nickname, conn->base_.address, conn->base_.port); + log_info(LD_HANDSHAKE, "Connected to router at %s without knowing " + "its key. Hoping for the best.", + connection_describe_peer(TO_CONN(conn))); /* if it's a bridge and we didn't know its identity fingerprint, now * we do -- remember it for future attempts. */ learned_router_identity(&conn->base_.addr, conn->base_.port, @@ -1983,9 +1982,9 @@ connection_or_client_learned_peer_id(or_connection_t *conn, } log_fn(severity, LD_HANDSHAKE, - "Tried connecting to router at %s:%d, but RSA + ed25519 identity " + "Tried connecting to router at %s, but RSA + ed25519 identity " "keys were not as expected: wanted %s + %s but got %s + %s.%s", - conn->base_.address, conn->base_.port, + connection_describe_peer(TO_CONN(conn)), expected_rsa, expected_ed, seen_rsa, seen_ed, extra_log); /* Tell the new guard API about the channel failure */ @@ -2012,9 +2011,14 @@ connection_or_client_learned_peer_id(or_connection_t *conn, /* If we learned an identity for this connection, then we might have * just discovered it to be canonical. */ connection_or_check_canonicity(conn, conn->handshake_state->started_here); + if (conn->tls) + tor_tls_set_logged_address(conn->tls, + connection_describe_peer(TO_CONN(conn))); } if (authdir_mode_tests_reachability(options)) { + // We don't want to use canonical_orport here -- we want the address + // that we really used. dirserv_orconn_tls_done(&conn->base_.addr, conn->base_.port, (const char*)rsa_peer_id, ed_peer_id); } @@ -2057,11 +2061,10 @@ connection_tls_finish_handshake(or_connection_t *conn) tor_assert(!started_here); - log_debug(LD_HANDSHAKE,"%s tls handshake on %p with %s done, using " + log_debug(LD_HANDSHAKE,"%s tls handshake on %s done, using " "ciphersuite %s. verifying.", started_here?"outgoing":"incoming", - conn, - safe_str_client(conn->base_.address), + connection_describe_peer(TO_CONN(conn)), tor_tls_get_ciphersuite_name(conn->tls)); if (connection_or_check_valid_tls_handshake(conn, started_here, @@ -2493,11 +2496,9 @@ connection_or_send_netinfo,(or_connection_t *conn)) netinfo_cell_set_timestamp(netinfo_cell, (uint32_t)now); /* Their address. */ - const tor_addr_t *remote_tor_addr = - !tor_addr_is_null(&conn->real_addr) ? &conn->real_addr : &conn->base_.addr; - /* We use &conn->real_addr below, unless it hasn't yet been set. If it - * hasn't yet been set, we know that base_.addr hasn't been tampered with - * yet either. */ + const tor_addr_t *remote_tor_addr = &TO_CONN(conn)->addr; + /* We can safely use TO_CONN(conn)->addr here, since we no longer replace + * it with a canonical address. */ netinfo_addr_t *their_addr = netinfo_addr_from_tor_addr(remote_tor_addr); netinfo_cell_set_other_addr(netinfo_cell, their_addr); diff --git a/src/core/or/connection_or.h b/src/core/or/connection_or.h index e9ace56ab4..fe81b5c5e1 100644 --- a/src/core/or/connection_or.h +++ b/src/core/or/connection_or.h @@ -16,6 +16,7 @@ struct ed25519_public_key_t; struct ed25519_keypair_t; or_connection_t *TO_OR_CONN(connection_t *); +const or_connection_t *CONST_TO_OR_CONN(const connection_t *); #include "core/or/orconn_event.h" diff --git a/src/core/or/connection_st.h b/src/core/or/connection_st.h index 508328f75c..082420c4bc 100644 --- a/src/core/or/connection_st.h +++ b/src/core/or/connection_st.h @@ -69,6 +69,9 @@ struct connection_t { /** True if connection_handle_write is currently running on this connection. */ unsigned int in_connection_handle_write:1; + /** If true, then we treat this connection as remote for the purpose of + * rate-limiting, no matter what its address is. */ + unsigned int always_rate_limit_as_remote:1; /* For linked connections: */ @@ -98,8 +101,6 @@ struct connection_t { struct buf_t *inbuf; /**< Buffer holding data read over this connection. */ struct buf_t *outbuf; /**< Buffer holding data to write over this * connection. */ - size_t outbuf_flushlen; /**< How much data should we try to flush from the - * outbuf? */ time_t timestamp_last_read_allowed; /**< When was the last time libevent said * we could read? */ time_t timestamp_last_write_allowed; /**< When was the last time libevent @@ -137,15 +138,11 @@ struct connection_t { * any more! * * The misuses of this field include: - * * Setting it to the canonical address of a relay on an OR connection. * * Setting it on linked connections, possibly. * * Updating it based on the Forwarded-For header-- Forwarded-For is - * set by a proxy, but not a local trusted troxy. + * set by a proxy, but not a local trusted proxy. **/ - tor_addr_t addr; /**< IP that socket "s" is directly connected to; - * may be the IP address for a proxy or pluggable transport, - * see "address" for the address of the final destination. - */ + tor_addr_t addr; uint16_t port; /**< If non-zero, port that socket "s" is directly connected * to; may be the port for a proxy or pluggable transport, * see "address" for the port at the final destination. */ @@ -165,7 +162,6 @@ struct connection_t { * * * An address we're trying to resolve (as an exit). * * A unix address we're trying to bind to (as a listener). - * * A canonical address for an OR connection. **/ char *address; /** Another connection that's connected to this one in lieu of a socket. */ diff --git a/src/core/or/dos.c b/src/core/or/dos.c index 5f99280030..41bf303ffe 100644 --- a/src/core/or/dos.c +++ b/src/core/or/dos.c @@ -584,7 +584,7 @@ dos_geoip_entry_about_to_free(const clientmap_entry_t *geoip_ent) SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) { if (conn->type == CONN_TYPE_OR) { or_connection_t *or_conn = TO_OR_CONN(conn); - if (!tor_addr_compare(&geoip_ent->addr, &or_conn->real_addr, + if (!tor_addr_compare(&geoip_ent->addr, &TO_CONN(or_conn)->addr, CMP_EXACT)) { or_conn->tracked_for_dos_mitigation = 0; } @@ -696,12 +696,12 @@ dos_new_client_conn(or_connection_t *or_conn, const char *transport_name) * reason to do so is because network reentry is possible where a client * connection comes from an Exit node. Even when we'll fix reentry, this is * a robust defense to keep in place. */ - if (nodelist_probably_contains_address(&or_conn->real_addr)) { + if (nodelist_probably_contains_address(&TO_CONN(or_conn)->addr)) { goto end; } /* We are only interested in client connection from the geoip cache. */ - entry = geoip_lookup_client(&or_conn->real_addr, transport_name, + entry = geoip_lookup_client(&TO_CONN(or_conn)->addr, transport_name, GEOIP_CLIENT_CONNECT); if (BUG(entry == NULL)) { /* Should never happen because we note down the address in the geoip @@ -712,7 +712,7 @@ dos_new_client_conn(or_connection_t *or_conn, const char *transport_name) entry->dos_stats.concurrent_count++; or_conn->tracked_for_dos_mitigation = 1; log_debug(LD_DOS, "Client address %s has now %u concurrent connections.", - fmt_addr(&or_conn->real_addr), + fmt_addr(&TO_CONN(or_conn)->addr), entry->dos_stats.concurrent_count); end: @@ -735,7 +735,7 @@ dos_close_client_conn(const or_connection_t *or_conn) } /* We are only interested in client connection from the geoip cache. */ - entry = geoip_lookup_client(&or_conn->real_addr, NULL, + entry = geoip_lookup_client(&TO_CONN(or_conn)->addr, NULL, GEOIP_CLIENT_CONNECT); if (entry == NULL) { /* This can happen because we can close a connection before the channel @@ -753,7 +753,7 @@ dos_close_client_conn(const or_connection_t *or_conn) entry->dos_stats.concurrent_count--; log_debug(LD_DOS, "Client address %s has lost a connection. Concurrent " "connections are now at %u", - fmt_addr(&or_conn->real_addr), + fmt_addr(&TO_CONN(or_conn)->addr), entry->dos_stats.concurrent_count); end: diff --git a/src/core/or/extendinfo.c b/src/core/or/extendinfo.c index bcdb57d5a0..22e5b664bb 100644 --- a/src/core/or/extendinfo.c +++ b/src/core/or/extendinfo.c @@ -19,6 +19,9 @@ #include "core/or/policies.h" #include "feature/nodelist/describe.h" #include "feature/nodelist/nodelist.h" +#include "feature/relay/router.h" +#include "feature/relay/routermode.h" +#include "lib/crypt_ops/crypto_rand.h" #include "core/or/extend_info_st.h" #include "feature/nodelist/node_st.h" @@ -99,7 +102,7 @@ extend_info_from_node(const node_t *node, int for_direct_connect) /* Choose a preferred address first, but fall back to an allowed address. */ if (for_direct_connect) - fascist_firewall_choose_address_node(node, FIREWALL_OR_CONNECTION, 0, &ap); + reachable_addr_choose_from_node(node, FIREWALL_OR_CONNECTION, 0, &ap); else { node_get_prim_orport(node, &ap); } @@ -274,16 +277,38 @@ extend_info_get_orport(const extend_info_t *ei, int family) const tor_addr_port_t * extend_info_pick_orport(const extend_info_t *ei) { - // XXXX S55 -- for now, we just pick the first. We'll work on - // XXXX more choices as we move forward. IF_BUG_ONCE(!ei) { return NULL; } + const or_options_t *options = get_options(); + if (!server_mode(options)) { + // If we aren't a server, just pick the first address we built into + // this extendinfo. + return &ei->orports[0]; + } + + const bool ipv6_ok = router_can_extend_over_ipv6(options); + + // Use 'usable' to collect the usable orports, then pick one. + const tor_addr_port_t *usable[EXTEND_INFO_MAX_ADDRS]; + int n_usable = 0; + for (int i = 0; i < EXTEND_INFO_MAX_ADDRS; ++i) { + const tor_addr_port_t *a = &ei->orports[i]; + const int family = tor_addr_family(&a->addr); + if (family == AF_INET || (ipv6_ok && family == AF_INET6)) { + usable[n_usable++] = a; + } + } - if (tor_addr_is_unspec(&ei->orports[0].addr)) { + if (n_usable == 0) { + // Need to bail out early, since nothing will work. return NULL; } - return &ei->orports[0]; + + crypto_fast_rng_t *rng = get_thread_fast_rng(); + const int idx = crypto_fast_rng_get_uint(rng, n_usable); + + return usable[idx]; } /** diff --git a/src/core/or/or_connection_st.h b/src/core/or/or_connection_st.h index 2507f90803..8e012a6b85 100644 --- a/src/core/or/or_connection_st.h +++ b/src/core/or/or_connection_st.h @@ -50,17 +50,18 @@ struct or_connection_t { channel_tls_t *chan; /** - * The actual address (as modified by any proxies) that this connection - * came from or went to. (See connection_t.addr for caveats.) + * The "canonical" address and port for this relay's ORPort, if this is + * a known relay. * - * TECHNICAL DEBT: + * An ORPort is "canonical" in this sense only if it is the same ORPort + * that is listed for this identity in the consensus we have. * - * This field shouldn't really exist. We need it because our code - * overwrites conenction_t.addr with the "canonical address" of the OR we - * are talking to, taken from the descriptor of the authenticated OR. - * That's a bad choice. + * This field may be set on outbound connections for _any_ relay, and on + * inbound connections after authentication. If we don't know the relay's + * identity, or if we don't have the relay's identity in our consensus, we + * leave this address as UNSPEC. **/ - tor_addr_t real_addr; + tor_addr_port_t canonical_orport; /** Should this connection be used for extending circuits to the server * matching the <b>identity_digest</b> field? Set to true if we're pretty diff --git a/src/core/or/policies.c b/src/core/or/policies.c index 020eb0a152..0dc440cc96 100644 --- a/src/core/or/policies.c +++ b/src/core/or/policies.c @@ -311,7 +311,7 @@ parse_reachable_addresses(void) "ReachableAddresses, ReachableORAddresses, or " "ReachableDirAddresses reject all IPv4 addresses. " "Tor will not connect using IPv4."); - } else if (fascist_firewall_use_ipv6(options) + } else if (reachable_addr_use_ipv6(options) && (policy_is_reject_star(reachable_or_addr_policy, AF_INET6, 0) || policy_is_reject_star(reachable_dir_addr_policy, AF_INET6, 0))) { log_warn(LD_CONFIG, "You have configured tor to use or prefer IPv6 " @@ -399,12 +399,12 @@ addr_policy_permits_tor_addr(const tor_addr_t *addr, uint16_t port, * - if ClientUseIPv4 is 0, or * if pref_only and pref_ipv6 are both true; * - return false for all IPv6 addresses: - * - if fascist_firewall_use_ipv6() is 0, or + * - if reachable_addr_use_ipv6() is 0, or * - if pref_only is true and pref_ipv6 is false. * * Return false if addr is NULL or tor_addr_is_null(), or if port is 0. */ STATIC int -fascist_firewall_allows_address(const tor_addr_t *addr, +reachable_addr_allows(const tor_addr_t *addr, uint16_t port, smartlist_t *firewall_policy, int pref_only, int pref_ipv6) @@ -427,7 +427,7 @@ fascist_firewall_allows_address(const tor_addr_t *addr, /* Clients and Servers won't use IPv6 unless it's enabled (and in most * cases, IPv6 must also be preferred before it will be used). */ if (tor_addr_family(addr) == AF_INET6 && - (!fascist_firewall_use_ipv6(options) || (pref_only && !pref_ipv6))) { + (!reachable_addr_use_ipv6(options) || (pref_only && !pref_ipv6))) { return 0; } @@ -443,7 +443,7 @@ fascist_firewall_allows_address(const tor_addr_t *addr, * port: it supports bridge client per-node IPv6 preferences. */ int -fascist_firewall_use_ipv6(const or_options_t *options) +reachable_addr_use_ipv6(const or_options_t *options) { /* Clients use IPv6 if it's set, or they use bridges, or they don't use * IPv4, or they prefer it. @@ -458,7 +458,7 @@ fascist_firewall_use_ipv6(const or_options_t *options) * If we're unsure, return -1, otherwise, return 1 for IPv6 and 0 for IPv4. */ static int -fascist_firewall_prefer_ipv6_impl(const or_options_t *options) +reachable_addr_prefer_ipv6_impl(const or_options_t *options) { /* Cheap implementation of config options ClientUseIPv4 & ClientUseIPv6 -- @@ -466,7 +466,7 @@ fascist_firewall_prefer_ipv6_impl(const or_options_t *options) If IPv4 is disabled, use IPv6. */ - if (server_mode(options) || !fascist_firewall_use_ipv6(options)) { + if (server_mode(options) || !reachable_addr_use_ipv6(options)) { return 0; } @@ -482,9 +482,9 @@ fascist_firewall_prefer_ipv6_impl(const or_options_t *options) * per-node IPv6 preferences. */ int -fascist_firewall_prefer_ipv6_orport(const or_options_t *options) +reachable_addr_prefer_ipv6_orport(const or_options_t *options) { - int pref_ipv6 = fascist_firewall_prefer_ipv6_impl(options); + int pref_ipv6 = reachable_addr_prefer_ipv6_impl(options); if (pref_ipv6 >= 0) { return pref_ipv6; @@ -504,9 +504,9 @@ fascist_firewall_prefer_ipv6_orport(const or_options_t *options) * preferences. There's no reason to use it instead of this function.) */ int -fascist_firewall_prefer_ipv6_dirport(const or_options_t *options) +reachable_addr_prefer_ipv6_dirport(const or_options_t *options) { - int pref_ipv6 = fascist_firewall_prefer_ipv6_impl(options); + int pref_ipv6 = reachable_addr_prefer_ipv6_impl(options); if (pref_ipv6 >= 0) { return pref_ipv6; @@ -528,16 +528,16 @@ fascist_firewall_prefer_ipv6_dirport(const or_options_t *options) * If pref_only is false, ignore pref_ipv6, and return true if addr is allowed. */ int -fascist_firewall_allows_address_addr(const tor_addr_t *addr, uint16_t port, +reachable_addr_allows_addr(const tor_addr_t *addr, uint16_t port, firewall_connection_t fw_connection, int pref_only, int pref_ipv6) { if (fw_connection == FIREWALL_OR_CONNECTION) { - return fascist_firewall_allows_address(addr, port, + return reachable_addr_allows(addr, port, reachable_or_addr_policy, pref_only, pref_ipv6); } else if (fw_connection == FIREWALL_DIR_CONNECTION) { - return fascist_firewall_allows_address(addr, port, + return reachable_addr_allows(addr, port, reachable_dir_addr_policy, pref_only, pref_ipv6); } else { @@ -550,15 +550,15 @@ fascist_firewall_allows_address_addr(const tor_addr_t *addr, uint16_t port, /** Return true iff we think our firewall will let us make a connection to * addr:port (ap). Uses ReachableORAddresses or ReachableDirAddresses based on * fw_connection. - * pref_only and pref_ipv6 work as in fascist_firewall_allows_address_addr(). + * pref_only and pref_ipv6 work as in reachable_addr_allows_addr(). */ static int -fascist_firewall_allows_address_ap(const tor_addr_port_t *ap, +reachable_addr_allows_ap(const tor_addr_port_t *ap, firewall_connection_t fw_connection, int pref_only, int pref_ipv6) { tor_assert(ap); - return fascist_firewall_allows_address_addr(&ap->addr, ap->port, + return reachable_addr_allows_addr(&ap->addr, ap->port, fw_connection, pref_only, pref_ipv6); } @@ -567,17 +567,17 @@ fascist_firewall_allows_address_ap(const tor_addr_port_t *ap, * ipv4h_addr/ipv6_addr. Uses ipv4_orport/ipv6_orport/ReachableORAddresses or * ipv4_dirport/ipv6_dirport/ReachableDirAddresses based on IPv4/IPv6 and * <b>fw_connection</b>. - * pref_only and pref_ipv6 work as in fascist_firewall_allows_address_addr(). + * pref_only and pref_ipv6 work as in reachable_addr_allows_addr(). */ static int -fascist_firewall_allows_base(const tor_addr_t *ipv4_addr, uint16_t ipv4_orport, +reachable_addr_allows_base(const tor_addr_t *ipv4_addr, uint16_t ipv4_orport, uint16_t ipv4_dirport, const tor_addr_t *ipv6_addr, uint16_t ipv6_orport, uint16_t ipv6_dirport, firewall_connection_t fw_connection, int pref_only, int pref_ipv6) { - if (fascist_firewall_allows_address_addr(ipv4_addr, + if (reachable_addr_allows_addr(ipv4_addr, (fw_connection == FIREWALL_OR_CONNECTION ? ipv4_orport : ipv4_dirport), @@ -586,7 +586,7 @@ fascist_firewall_allows_base(const tor_addr_t *ipv4_addr, uint16_t ipv4_orport, return 1; } - if (fascist_firewall_allows_address_addr(ipv6_addr, + if (reachable_addr_allows_addr(ipv6_addr, (fw_connection == FIREWALL_OR_CONNECTION ? ipv6_orport : ipv6_dirport), @@ -598,9 +598,9 @@ fascist_firewall_allows_base(const tor_addr_t *ipv4_addr, uint16_t ipv4_orport, return 0; } -/** Like fascist_firewall_allows_base(), but takes ri. */ +/** Like reachable_addr_allows_base(), but takes ri. */ static int -fascist_firewall_allows_ri_impl(const routerinfo_t *ri, +reachable_addr_allows_ri_impl(const routerinfo_t *ri, firewall_connection_t fw_connection, int pref_only, int pref_ipv6) { @@ -609,15 +609,15 @@ fascist_firewall_allows_ri_impl(const routerinfo_t *ri, } /* Assume IPv4 and IPv6 DirPorts are the same */ - return fascist_firewall_allows_base(&ri->ipv4_addr, ri->ipv4_orport, + return reachable_addr_allows_base(&ri->ipv4_addr, ri->ipv4_orport, ri->ipv4_dirport, &ri->ipv6_addr, ri->ipv6_orport, ri->ipv4_dirport, fw_connection, pref_only, pref_ipv6); } -/** Like fascist_firewall_allows_rs, but takes pref_ipv6. */ +/** Like reachable_addr_allows_rs, but takes pref_ipv6. */ static int -fascist_firewall_allows_rs_impl(const routerstatus_t *rs, +reachable_addr_allows_rs_impl(const routerstatus_t *rs, firewall_connection_t fw_connection, int pref_only, int pref_ipv6) { @@ -626,20 +626,20 @@ fascist_firewall_allows_rs_impl(const routerstatus_t *rs, } /* Assume IPv4 and IPv6 DirPorts are the same */ - return fascist_firewall_allows_base(&rs->ipv4_addr, rs->ipv4_orport, + return reachable_addr_allows_base(&rs->ipv4_addr, rs->ipv4_orport, rs->ipv4_dirport, &rs->ipv6_addr, rs->ipv6_orport, rs->ipv4_dirport, fw_connection, pref_only, pref_ipv6); } -/** Like fascist_firewall_allows_base(), but takes rs. +/** Like reachable_addr_allows_base(), but takes rs. * When rs is a fake_status from a dir_server_t, it can have a reachable * address, even when the corresponding node does not. * nodes can be missing addresses when there's no consensus (IPv4 and IPv6), * or when there is a microdescriptor consensus, but no microdescriptors * (microdescriptors have IPv6, the microdesc consensus does not). */ int -fascist_firewall_allows_rs(const routerstatus_t *rs, +reachable_addr_allows_rs(const routerstatus_t *rs, firewall_connection_t fw_connection, int pref_only) { if (!rs) { @@ -650,20 +650,20 @@ fascist_firewall_allows_rs(const routerstatus_t *rs, * generic IPv6 preference instead. */ const or_options_t *options = get_options(); int pref_ipv6 = (fw_connection == FIREWALL_OR_CONNECTION - ? fascist_firewall_prefer_ipv6_orport(options) - : fascist_firewall_prefer_ipv6_dirport(options)); + ? reachable_addr_prefer_ipv6_orport(options) + : reachable_addr_prefer_ipv6_dirport(options)); - return fascist_firewall_allows_rs_impl(rs, fw_connection, pref_only, + return reachable_addr_allows_rs_impl(rs, fw_connection, pref_only, pref_ipv6); } /** Return true iff we think our firewall will let us make a connection to * ipv6_addr:ipv6_orport based on ReachableORAddresses. * If <b>fw_connection</b> is FIREWALL_DIR_CONNECTION, returns 0. - * pref_only and pref_ipv6 work as in fascist_firewall_allows_address_addr(). + * pref_only and pref_ipv6 work as in reachable_addr_allows_addr(). */ static int -fascist_firewall_allows_md_impl(const microdesc_t *md, +reachable_addr_allows_md_impl(const microdesc_t *md, firewall_connection_t fw_connection, int pref_only, int pref_ipv6) { @@ -677,15 +677,15 @@ fascist_firewall_allows_md_impl(const microdesc_t *md, } /* Also can't check IPv4, doesn't have that either */ - return fascist_firewall_allows_address_addr(&md->ipv6_addr, md->ipv6_orport, + return reachable_addr_allows_addr(&md->ipv6_addr, md->ipv6_orport, fw_connection, pref_only, pref_ipv6); } -/** Like fascist_firewall_allows_base(), but takes node, and looks up pref_ipv6 +/** Like reachable_addr_allows_base(), but takes node, and looks up pref_ipv6 * from node_ipv6_or/dir_preferred(). */ int -fascist_firewall_allows_node(const node_t *node, +reachable_addr_allows_node(const node_t *node, firewall_connection_t fw_connection, int pref_only) { @@ -701,15 +701,15 @@ fascist_firewall_allows_node(const node_t *node, /* Sometimes, the rs is missing the IPv6 address info, and we need to go * all the way to the md */ - if (node->ri && fascist_firewall_allows_ri_impl(node->ri, fw_connection, + if (node->ri && reachable_addr_allows_ri_impl(node->ri, fw_connection, pref_only, pref_ipv6)) { return 1; - } else if (node->rs && fascist_firewall_allows_rs_impl(node->rs, + } else if (node->rs && reachable_addr_allows_rs_impl(node->rs, fw_connection, pref_only, pref_ipv6)) { return 1; - } else if (node->md && fascist_firewall_allows_md_impl(node->md, + } else if (node->md && reachable_addr_allows_md_impl(node->md, fw_connection, pref_only, pref_ipv6)) { @@ -721,9 +721,9 @@ fascist_firewall_allows_node(const node_t *node, } } -/** Like fascist_firewall_allows_rs(), but takes ds. */ +/** Like reachable_addr_allows_rs(), but takes ds. */ int -fascist_firewall_allows_dir_server(const dir_server_t *ds, +reachable_addr_allows_dir_server(const dir_server_t *ds, firewall_connection_t fw_connection, int pref_only) { @@ -734,8 +734,8 @@ fascist_firewall_allows_dir_server(const dir_server_t *ds, /* A dir_server_t always has a fake_status. As long as it has the same * addresses/ports in both fake_status and dir_server_t, this works fine. * (See #17867.) - * fascist_firewall_allows_rs only checks the addresses in fake_status. */ - return fascist_firewall_allows_rs(&ds->fake_status, fw_connection, + * reachable_addr_allows_rs only checks the addresses in fake_status. */ + return reachable_addr_allows_rs(&ds->fake_status, fw_connection, pref_only); } @@ -743,10 +743,10 @@ fascist_firewall_allows_dir_server(const dir_server_t *ds, * choose one based on want_a and return it. * Otherwise, return whichever is allowed. * Otherwise, return NULL. - * pref_only and pref_ipv6 work as in fascist_firewall_allows_address_addr(). + * pref_only and pref_ipv6 work as in reachable_addr_allows_addr(). */ static const tor_addr_port_t * -fascist_firewall_choose_address_impl(const tor_addr_port_t *a, +reachable_addr_choose_impl(const tor_addr_port_t *a, const tor_addr_port_t *b, int want_a, firewall_connection_t fw_connection, @@ -755,12 +755,12 @@ fascist_firewall_choose_address_impl(const tor_addr_port_t *a, const tor_addr_port_t *use_a = NULL; const tor_addr_port_t *use_b = NULL; - if (fascist_firewall_allows_address_ap(a, fw_connection, pref_only, + if (reachable_addr_allows_ap(a, fw_connection, pref_only, pref_ipv6)) { use_a = a; } - if (fascist_firewall_allows_address_ap(b, fw_connection, pref_only, + if (reachable_addr_allows_ap(b, fw_connection, pref_only, pref_ipv6)) { use_b = b; } @@ -784,13 +784,13 @@ fascist_firewall_choose_address_impl(const tor_addr_port_t *a, * - Otherwise, return whichever is preferred. * Otherwise, return NULL. */ STATIC const tor_addr_port_t * -fascist_firewall_choose_address(const tor_addr_port_t *a, +reachable_addr_choose(const tor_addr_port_t *a, const tor_addr_port_t *b, int want_a, firewall_connection_t fw_connection, int pref_only, int pref_ipv6) { - const tor_addr_port_t *pref = fascist_firewall_choose_address_impl( + const tor_addr_port_t *pref = reachable_addr_choose_impl( a, b, want_a, fw_connection, 1, pref_ipv6); @@ -802,7 +802,7 @@ fascist_firewall_choose_address(const tor_addr_port_t *a, } else { /* If there's no preferred address, and we can return addresses that are * not preferred, use an address that's allowed */ - return fascist_firewall_choose_address_impl(a, b, want_a, fw_connection, + return reachable_addr_choose_impl(a, b, want_a, fw_connection, 0, pref_ipv6); } } @@ -817,7 +817,7 @@ fascist_firewall_choose_address(const tor_addr_port_t *a, * If both addresses could be chosen (they are both preferred or both allowed) * choose IPv6 if pref_ipv6 is true, otherwise choose IPv4. */ static void -fascist_firewall_choose_address_base(const tor_addr_t *ipv4_addr, +reachable_addr_choose_base(const tor_addr_t *ipv4_addr, uint16_t ipv4_orport, uint16_t ipv4_dirport, const tor_addr_t *ipv6_addr, @@ -849,7 +849,7 @@ fascist_firewall_choose_address_base(const tor_addr_t *ipv4_addr, ? ipv6_orport : ipv6_dirport); - result = fascist_firewall_choose_address(&ipv4_ap, &ipv6_ap, + result = reachable_addr_choose(&ipv4_ap, &ipv6_ap, want_ipv4, fw_connection, pref_only, pref_ipv6); @@ -860,13 +860,13 @@ fascist_firewall_choose_address_base(const tor_addr_t *ipv4_addr, } } -/** Like fascist_firewall_choose_address_base(), but takes <b>rs</b>. +/** Like reachable_addr_choose_base(), but takes <b>rs</b>. * Consults the corresponding node, then falls back to rs if node is NULL. * This should only happen when there's no valid consensus, and rs doesn't * correspond to a bridge client's bridge. */ void -fascist_firewall_choose_address_rs(const routerstatus_t *rs, +reachable_addr_choose_from_rs(const routerstatus_t *rs, firewall_connection_t fw_connection, int pref_only, tor_addr_port_t* ap) { @@ -883,15 +883,15 @@ fascist_firewall_choose_address_rs(const routerstatus_t *rs, const node_t *node = node_get_by_id(rs->identity_digest); if (node) { - fascist_firewall_choose_address_node(node, fw_connection, pref_only, ap); + reachable_addr_choose_from_node(node, fw_connection, pref_only, ap); } else { /* There's no node-specific IPv6 preference, so use the generic IPv6 * preference instead. */ int pref_ipv6 = (fw_connection == FIREWALL_OR_CONNECTION - ? fascist_firewall_prefer_ipv6_orport(options) - : fascist_firewall_prefer_ipv6_dirport(options)); + ? reachable_addr_prefer_ipv6_orport(options) + : reachable_addr_prefer_ipv6_dirport(options)); - fascist_firewall_choose_address_base(&rs->ipv4_addr, rs->ipv4_orport, + reachable_addr_choose_base(&rs->ipv4_addr, rs->ipv4_orport, rs->ipv4_dirport, &rs->ipv6_addr, rs->ipv6_orport, rs->ipv4_dirport, fw_connection, pref_only, pref_ipv6, @@ -899,13 +899,13 @@ fascist_firewall_choose_address_rs(const routerstatus_t *rs, } } -/** Like fascist_firewall_choose_address_base(), but takes in a smartlist +/** Like reachable_addr_choose_base(), but takes in a smartlist * <b>lspecs</b> consisting of one or more link specifiers. We assume * fw_connection is FIREWALL_OR_CONNECTION as link specifiers cannot * contain DirPorts. */ void -fascist_firewall_choose_address_ls(const smartlist_t *lspecs, +reachable_addr_choose_from_ls(const smartlist_t *lspecs, int pref_only, tor_addr_port_t* ap) { int have_v4 = 0, have_v6 = 0; @@ -967,20 +967,20 @@ fascist_firewall_choose_address_ls(const smartlist_t *lspecs, /* Here, don't check for DirPorts as link specifiers are only used for * ORPorts. */ const or_options_t *options = get_options(); - int pref_ipv6 = fascist_firewall_prefer_ipv6_orport(options); + int pref_ipv6 = reachable_addr_prefer_ipv6_orport(options); /* Assume that the DirPorts are zero as link specifiers only use ORPorts. */ - fascist_firewall_choose_address_base(&addr_v4, port_v4, 0, + reachable_addr_choose_base(&addr_v4, port_v4, 0, &addr_v6, port_v6, 0, FIREWALL_OR_CONNECTION, pref_only, pref_ipv6, ap); } -/** Like fascist_firewall_choose_address_base(), but takes <b>node</b>, and +/** Like reachable_addr_choose_base(), but takes <b>node</b>, and * looks up the node's IPv6 preference rather than taking an argument * for pref_ipv6. */ void -fascist_firewall_choose_address_node(const node_t *node, +reachable_addr_choose_from_node(const node_t *node, firewall_connection_t fw_connection, int pref_only, tor_addr_port_t *ap) { @@ -1010,16 +1010,16 @@ fascist_firewall_choose_address_node(const node_t *node, node_get_pref_ipv6_dirport(node, &ipv6_dir_ap); /* Assume the IPv6 OR and Dir addresses are the same. */ - fascist_firewall_choose_address_base(&ipv4_or_ap.addr, ipv4_or_ap.port, + reachable_addr_choose_base(&ipv4_or_ap.addr, ipv4_or_ap.port, ipv4_dir_ap.port, &ipv6_or_ap.addr, ipv6_or_ap.port, ipv6_dir_ap.port, fw_connection, pref_only, pref_ipv6_node, ap); } -/** Like fascist_firewall_choose_address_rs(), but takes <b>ds</b>. */ +/** Like reachable_addr_choose_from_rs(), but takes <b>ds</b>. */ void -fascist_firewall_choose_address_dir_server(const dir_server_t *ds, +reachable_addr_choose_from_dir_server(const dir_server_t *ds, firewall_connection_t fw_connection, int pref_only, tor_addr_port_t *ap) @@ -1036,9 +1036,9 @@ fascist_firewall_choose_address_dir_server(const dir_server_t *ds, /* A dir_server_t always has a fake_status. As long as it has the same * addresses/ports in both fake_status and dir_server_t, this works fine. * (See #17867.) - * This function relies on fascist_firewall_choose_address_rs looking up the + * This function relies on reachable_addr_choose_from_rs looking up the * node if it can, because that will get the latest info for the relay. */ - fascist_firewall_choose_address_rs(&ds->fake_status, fw_connection, + reachable_addr_choose_from_rs(&ds->fake_status, fw_connection, pref_only, ap); } diff --git a/src/core/or/policies.h b/src/core/or/policies.h index 1ac6f87dcf..c8502a5516 100644 --- a/src/core/or/policies.h +++ b/src/core/or/policies.h @@ -69,34 +69,34 @@ typedef struct short_policy_t { int firewall_is_fascist_or(void); int firewall_is_fascist_dir(void); -int fascist_firewall_use_ipv6(const or_options_t *options); -int fascist_firewall_prefer_ipv6_orport(const or_options_t *options); -int fascist_firewall_prefer_ipv6_dirport(const or_options_t *options); +int reachable_addr_use_ipv6(const or_options_t *options); +int reachable_addr_prefer_ipv6_orport(const or_options_t *options); +int reachable_addr_prefer_ipv6_dirport(const or_options_t *options); -int fascist_firewall_allows_address_addr(const tor_addr_t *addr, +int reachable_addr_allows_addr(const tor_addr_t *addr, uint16_t port, firewall_connection_t fw_connection, int pref_only, int pref_ipv6); -int fascist_firewall_allows_rs(const routerstatus_t *rs, +int reachable_addr_allows_rs(const routerstatus_t *rs, firewall_connection_t fw_connection, int pref_only); -int fascist_firewall_allows_node(const node_t *node, +int reachable_addr_allows_node(const node_t *node, firewall_connection_t fw_connection, int pref_only); -int fascist_firewall_allows_dir_server(const dir_server_t *ds, +int reachable_addr_allows_dir_server(const dir_server_t *ds, firewall_connection_t fw_connection, int pref_only); -void fascist_firewall_choose_address_rs(const routerstatus_t *rs, +void reachable_addr_choose_from_rs(const routerstatus_t *rs, firewall_connection_t fw_connection, int pref_only, tor_addr_port_t* ap); -void fascist_firewall_choose_address_ls(const smartlist_t *lspecs, +void reachable_addr_choose_from_ls(const smartlist_t *lspecs, int pref_only, tor_addr_port_t* ap); -void fascist_firewall_choose_address_node(const node_t *node, +void reachable_addr_choose_from_node(const node_t *node, firewall_connection_t fw_connection, int pref_only, tor_addr_port_t* ap); -void fascist_firewall_choose_address_dir_server(const dir_server_t *ds, +void reachable_addr_choose_from_dir_server(const dir_server_t *ds, firewall_connection_t fw_connection, int pref_only, tor_addr_port_t* ap); @@ -173,11 +173,11 @@ addr_policy_result_t compare_tor_addr_to_short_policy( #ifdef POLICIES_PRIVATE STATIC void append_exit_policy_string(smartlist_t **policy, const char *more); -STATIC int fascist_firewall_allows_address(const tor_addr_t *addr, +STATIC int reachable_addr_allows(const tor_addr_t *addr, uint16_t port, smartlist_t *firewall_policy, int pref_only, int pref_ipv6); -STATIC const tor_addr_port_t * fascist_firewall_choose_address( +STATIC const tor_addr_port_t * reachable_addr_choose( const tor_addr_port_t *a, const tor_addr_port_t *b, int want_a, diff --git a/src/core/or/port_cfg_st.h b/src/core/or/port_cfg_st.h index 064e679d78..f8ff6f8cc8 100644 --- a/src/core/or/port_cfg_st.h +++ b/src/core/or/port_cfg_st.h @@ -26,6 +26,8 @@ struct port_cfg_t { unsigned is_group_writable : 1; unsigned is_world_writable : 1; unsigned relax_dirmode_check : 1; + unsigned explicit_addr : 1; /** Indicate if address was explicitly set or + * we are using the default address. */ entry_port_cfg_t entry_cfg; diff --git a/src/core/or/protover.c b/src/core/or/protover.c index 1ac264925c..26fcefe8ac 100644 --- a/src/core/or/protover.c +++ b/src/core/or/protover.c @@ -250,7 +250,8 @@ parse_single_entry(const char *s, const char *end_of_entry) } s = comma; - while (*s == ',' && s < end_of_entry) + // Skip the comma separator between ranges. Don't ignore a trailing comma. + if (s < (end_of_entry - 1)) ++s; } @@ -298,11 +299,12 @@ parse_protocol_list(const char *s) } /** - * Return true if the unparsed protover in <b>s</b> would contain a protocol - * name longer than MAX_PROTOCOL_NAME_LENGTH, and false otherwise. + * Return true if the unparsed protover list in <b>s</b> contains a + * parsing error, such as extra commas, a bad number, or an over-long + * name. */ bool -protover_contains_long_protocol_names(const char *s) +protover_list_is_invalid(const char *s) { smartlist_t *list = parse_protocol_list(s); if (!list) diff --git a/src/core/or/protover.h b/src/core/or/protover.h index 2950147d1b..24008f46b9 100644 --- a/src/core/or/protover.h +++ b/src/core/or/protover.h @@ -69,7 +69,7 @@ typedef enum protocol_type_t { PRT_FLOWCTRL = 11, } protocol_type_t; -bool protover_contains_long_protocol_names(const char *s); +bool protover_list_is_invalid(const char *s); int protover_all_supported(const char *s, char **missing); int protover_is_supported_here(protocol_type_t pr, uint32_t ver); const char *protover_get_supported_protocols(void); diff --git a/src/core/or/protover_rust.c b/src/core/or/protover_rust.c index f44746b6da..99f3aa7f69 100644 --- a/src/core/or/protover_rust.c +++ b/src/core/or/protover_rust.c @@ -25,7 +25,7 @@ int protover_contains_long_protocol_names_(const char *s); * name longer than MAX_PROTOCOL_NAME_LENGTH, and false otherwise. */ bool -protover_contains_long_protocol_names(const char *s) +protover_list_is_invalid(const char *s) { return protover_contains_long_protocol_names_(s) != 0; } diff --git a/src/core/or/scheduler.c b/src/core/or/scheduler.c index 072d78128b..18f11487d9 100644 --- a/src/core/or/scheduler.c +++ b/src/core/or/scheduler.c @@ -713,7 +713,7 @@ scheduler_bug_occurred(const channel_t *chan) if (chan != NULL) { const size_t outbuf_len = - buf_datalen(TO_CONN(BASE_CHAN_TO_TLS((channel_t *) chan)->conn)->outbuf); + buf_datalen(TO_CONN(CONST_BASE_CHAN_TO_TLS(chan)->conn)->outbuf); tor_snprintf(buf, sizeof(buf), "Channel %" PRIu64 " in state %s and scheduler state %s." " Num cells on cmux: %d. Connection outbuf len: %lu.", diff --git a/src/core/or/scheduler_kist.c b/src/core/or/scheduler_kist.c index 5c1922847e..8c6a7bd1d1 100644 --- a/src/core/or/scheduler_kist.c +++ b/src/core/or/scheduler_kist.c @@ -203,7 +203,7 @@ update_socket_info_impl, (socket_table_ent_t *ent)) tor_assert(ent); tor_assert(ent->chan); const tor_socket_t sock = - TO_CONN(BASE_CHAN_TO_TLS((channel_t *) ent->chan)->conn)->s; + TO_CONN(CONST_BASE_CHAN_TO_TLS(ent->chan)->conn)->s; struct tcp_info tcp; socklen_t tcp_info_len = sizeof(tcp); diff --git a/src/core/or/sendme.c b/src/core/or/sendme.c index 788f56088c..8ea9ef15d2 100644 --- a/src/core/or/sendme.c +++ b/src/core/or/sendme.c @@ -394,7 +394,7 @@ sendme_connection_edge_consider_sending(edge_connection_t *conn) while (conn->deliver_window <= (STREAMWINDOW_START - STREAMWINDOW_INCREMENT)) { log_debug(log_domain, "Outbuf %" TOR_PRIuSZ ", queuing stream SENDME.", - TO_CONN(conn)->outbuf_flushlen); + buf_datalen(TO_CONN(conn)->outbuf)); conn->deliver_window += STREAMWINDOW_INCREMENT; if (connection_edge_send_command(conn, RELAY_COMMAND_SENDME, NULL, 0) < 0) { diff --git a/src/feature/client/bridges.c b/src/feature/client/bridges.c index 6892c4a25f..cc17e8fa67 100644 --- a/src/feature/client/bridges.c +++ b/src/feature/client/bridges.c @@ -654,7 +654,7 @@ launch_direct_bridge_descriptor_fetch(bridge_info_t *bridge) /* Until we get a descriptor for the bridge, we only know one address for * it. */ - if (!fascist_firewall_allows_address_addr(&bridge->addr, bridge->port, + if (!reachable_addr_allows_addr(&bridge->addr, bridge->port, FIREWALL_OR_CONNECTION, 0, 0)) { log_notice(LD_CONFIG, "Tried to fetch a descriptor directly from a " "bridge, but that bridge is not reachable through our " @@ -746,7 +746,7 @@ fetch_bridge_descriptors(const or_options_t *options, time_t now) !options->UpdateBridgesFromAuthority, !num_bridge_auths); if (ask_bridge_directly && - !fascist_firewall_allows_address_addr(&bridge->addr, bridge->port, + !reachable_addr_allows_addr(&bridge->addr, bridge->port, FIREWALL_OR_CONNECTION, 0, 0)) { log_notice(LD_DIR, "Bridge at '%s' isn't reachable by our " @@ -832,7 +832,7 @@ rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node) !tor_addr_is_null(&node->ri->ipv6_addr)); } else { /* Mark which address to use based on user preference */ - node->ipv6_preferred = (fascist_firewall_prefer_ipv6_orport(options) && + node->ipv6_preferred = (reachable_addr_prefer_ipv6_orport(options) && !tor_addr_is_null(&node->ri->ipv6_addr)); } @@ -889,7 +889,7 @@ rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node) !tor_addr_is_null(&node->rs->ipv6_addr)); } else { /* Mark which address to use based on user preference */ - node->ipv6_preferred = (fascist_firewall_prefer_ipv6_orport(options) && + node->ipv6_preferred = (reachable_addr_prefer_ipv6_orport(options) && !tor_addr_is_null(&node->rs->ipv6_addr)); } diff --git a/src/feature/client/entrynodes.c b/src/feature/client/entrynodes.c index 9b20684bf7..c51958acec 100644 --- a/src/feature/client/entrynodes.c +++ b/src/feature/client/entrynodes.c @@ -1466,7 +1466,7 @@ node_passes_guard_filter(const or_options_t *options, !routerset_contains_node(options->EntryNodes, node)) return 0; - if (!fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION, 0)) + if (!reachable_addr_allows_node(node, FIREWALL_OR_CONNECTION, 0)) return 0; if (node_is_a_configured_bridge(node)) @@ -1492,7 +1492,7 @@ bridge_passes_guard_filter(const or_options_t *options, /* Ignore entrynodes */ const tor_addr_port_t *addrport = bridge_get_addr_port(bridge); - if (!fascist_firewall_allows_address_addr(&addrport->addr, + if (!reachable_addr_allows_addr(&addrport->addr, addrport->port, FIREWALL_OR_CONNECTION, 0, 0)) diff --git a/src/feature/client/transports.c b/src/feature/client/transports.c index 2bdc0ae151..2eb05d6a67 100644 --- a/src/feature/client/transports.c +++ b/src/feature/client/transports.c @@ -1643,17 +1643,26 @@ pt_get_extra_info_descriptor_string(void) SMARTLIST_FOREACH_BEGIN(mp->transports, const transport_t *, t) { char *transport_args = NULL; + const char *addrport = NULL; /* If the transport proxy returned "0.0.0.0" as its address, and * we know our external IP address, use it. Otherwise, use the * returned address. */ - const char *addrport = NULL; - uint32_t external_ip_address = 0; - if (tor_addr_is_null(&t->addr) && - router_pick_published_address(get_options(), - &external_ip_address, 0) >= 0) { + if (tor_addr_is_null(&t->addr)) { tor_addr_t addr; - tor_addr_from_ipv4h(&addr, external_ip_address); + /* Attempt to find the IPv4 and then attempt to find the IPv6 if we + * can't find it. */ + bool found = relay_find_addr_to_publish(get_options(), AF_INET, + RELAY_FIND_ADDR_NO_FLAG, + &addr); + if (!found) { + found = relay_find_addr_to_publish(get_options(), AF_INET6, + RELAY_FIND_ADDR_NO_FLAG, &addr); + } + if (!found) { + log_err(LD_PT, "Unable to find address for transport %s", t->name); + continue; + } addrport = fmt_addrport(&addr, t->port); } else { addrport = fmt_addrport(&t->addr, t->port); diff --git a/src/feature/control/control.c b/src/feature/control/control.c index ee1026359d..ef707319a6 100644 --- a/src/feature/control/control.c +++ b/src/feature/control/control.c @@ -61,8 +61,12 @@ #include <sys/stat.h> #endif -/** Convert a connection_t* to an control_connection_t*; assert if the cast is - * invalid. */ +/** + * Cast a `connection_t *` to a `control_connection_t *`. + * + * Exit with an assertion failure if the input is not a + * `control_connection_t`. + **/ control_connection_t * TO_CONTROL_CONN(connection_t *c) { @@ -70,6 +74,18 @@ TO_CONTROL_CONN(connection_t *c) return DOWNCAST(control_connection_t, c); } +/** + * Cast a `const connection_t *` to a `const control_connection_t *`. + * + * Exit with an assertion failure if the input is not a + * `control_connection_t`. + **/ +const control_connection_t * +CONST_TO_CONTROL_CONN(const connection_t *c) +{ + return TO_CONTROL_CONN((connection_t*)c); +} + /** Create and add a new controller connection on <b>sock</b>. If * <b>CC_LOCAL_FD_IS_OWNER</b> is set in <b>flags</b>, this Tor process should * exit when the connection closes. If <b>CC_LOCAL_FD_IS_AUTHENTICATED</b> diff --git a/src/feature/control/control.h b/src/feature/control/control.h index 7e72b2736b..f884286ec7 100644 --- a/src/feature/control/control.h +++ b/src/feature/control/control.h @@ -13,6 +13,7 @@ #define TOR_CONTROL_H control_connection_t *TO_CONTROL_CONN(connection_t *); +const control_connection_t *CONST_TO_CONTROL_CONN(const connection_t *); #define CONTROL_CONN_STATE_MIN_ 1 /** State for a control connection: Authenticated and accepting v1 commands. */ diff --git a/src/feature/control/control_bootstrap.c b/src/feature/control/control_bootstrap.c index fee7612ba2..d4f2adde81 100644 --- a/src/feature/control/control_bootstrap.c +++ b/src/feature/control/control_bootstrap.c @@ -274,7 +274,7 @@ control_event_bootstrap_problem(const char *warn, const char *reason, const char *recommendation = "ignore"; int severity; char *or_id = NULL, *hostaddr = NULL; - or_connection_t *or_conn = NULL; + const or_connection_t *or_conn = NULL; /* bootstrap_percent must not be in "undefined" state here. */ tor_assert(status >= 0); @@ -301,7 +301,7 @@ control_event_bootstrap_problem(const char *warn, const char *reason, if (conn && conn->type == CONN_TYPE_OR) { /* XXX TO_OR_CONN can't deal with const */ - or_conn = TO_OR_CONN((connection_t *)conn); + or_conn = CONST_TO_OR_CONN(conn); or_id = tor_strdup(hex_str(or_conn->identity_digest, DIGEST_LEN)); } else { or_id = tor_strdup("?"); diff --git a/src/feature/control/control_cmd.c b/src/feature/control/control_cmd.c index a8926c0b79..5b75c24692 100644 --- a/src/feature/control/control_cmd.c +++ b/src/feature/control/control_cmd.c @@ -25,7 +25,6 @@ #include "feature/client/addressmap.h" #include "feature/client/dnsserv.h" #include "feature/client/entrynodes.h" -#include "feature/control/control_events.h" #include "feature/control/control.h" #include "feature/control/control_auth.h" #include "feature/control/control_cmd.h" @@ -982,8 +981,7 @@ handle_control_attachstream(control_connection_t *conn, edge_conn->end_reason = 0; if (tmpcirc) circuit_detach_stream(tmpcirc, edge_conn); - CONNECTION_AP_EXPECT_NONPENDING(ap_conn); - TO_CONN(edge_conn)->state = AP_CONN_STATE_CONTROLLER_WAIT; + connection_entry_set_controller_wait(ap_conn); } if (circ && (circ->base_.state != CIRCUIT_STATE_OPEN)) { diff --git a/src/feature/control/control_events.c b/src/feature/control/control_events.c index 8e69c772f6..2970745ca0 100644 --- a/src/feature/control/control_events.c +++ b/src/feature/control/control_events.c @@ -818,6 +818,7 @@ control_event_stream_status(entry_connection_t *conn, stream_status_event_t tp, case STREAM_EVENT_NEW_RESOLVE: status = "NEWRESOLVE"; break; case STREAM_EVENT_FAILED_RETRIABLE: status = "DETACHED"; break; case STREAM_EVENT_REMAP: status = "REMAP"; break; + case STREAM_EVENT_CONTROLLER_WAIT: status = "CONTROLLER_WAIT"; break; default: log_warn(LD_BUG, "Unrecognized status code %d", (int)tp); return 0; diff --git a/src/feature/control/control_events.h b/src/feature/control/control_events.h index 0c8448e0f8..6e3cfef4e9 100644 --- a/src/feature/control/control_events.h +++ b/src/feature/control/control_events.h @@ -36,7 +36,8 @@ typedef enum stream_status_event_t { STREAM_EVENT_NEW = 5, STREAM_EVENT_NEW_RESOLVE = 6, STREAM_EVENT_FAILED_RETRIABLE = 7, - STREAM_EVENT_REMAP = 8 + STREAM_EVENT_REMAP = 8, + STREAM_EVENT_CONTROLLER_WAIT = 9 } stream_status_event_t; /** Used to indicate the type of a buildtime event */ @@ -226,6 +227,8 @@ void control_event_hs_descriptor_content(const char *onion_address, void cbt_control_event_buildtimeout_set(const circuit_build_times_t *cbt, buildtimeout_set_event_t type); +int control_event_enter_controller_wait(void); + void control_events_free_all(void); #ifdef CONTROL_MODULE_PRIVATE diff --git a/src/feature/control/control_getinfo.c b/src/feature/control/control_getinfo.c index daf71f04c9..461b8eeb94 100644 --- a/src/feature/control/control_getinfo.c +++ b/src/feature/control/control_getinfo.c @@ -131,13 +131,23 @@ getinfo_helper_misc(control_connection_t *conn, const char *question, smartlist_free(signal_names); } else if (!strcmp(question, "features/names")) { *answer = tor_strdup("VERBOSE_NAMES EXTENDED_EVENTS"); - } else if (!strcmp(question, "address")) { - uint32_t addr; - if (router_pick_published_address(get_options(), &addr, 0) < 0) { + } else if (!strcmp(question, "address") || !strcmp(question, "address/v4")) { + tor_addr_t addr; + if (!relay_find_addr_to_publish(get_options(), AF_INET, + RELAY_FIND_ADDR_CACHE_ONLY, &addr)) { *errmsg = "Address unknown"; return -1; } - *answer = tor_dup_ip(addr); + *answer = tor_addr_to_str_dup(&addr); + tor_assert_nonfatal(*answer); + } else if (!strcmp(question, "address/v6")) { + tor_addr_t addr; + if (!relay_find_addr_to_publish(get_options(), AF_INET6, + RELAY_FIND_ADDR_CACHE_ONLY, &addr)) { + *errmsg = "Address unknown"; + return -1; + } + *answer = tor_addr_to_str_dup(&addr); tor_assert_nonfatal(*answer); } else if (!strcmp(question, "traffic/read")) { tor_asprintf(answer, "%"PRIu64, (get_bytes_read())); @@ -1662,6 +1672,10 @@ static const getinfo_item_t getinfo_items[] = { DOC("status/version/recommended", "List of currently recommended versions."), DOC("status/version/current", "Status of the current version."), ITEM("address", misc, "IP address of this Tor host, if we can guess it."), + ITEM("address/v4", misc, + "IPv4 address of this Tor host, if we can guess it."), + ITEM("address/v6", misc, + "IPv6 address of this Tor host, if we can guess it."), ITEM("traffic/read", misc,"Bytes read since the process was started."), ITEM("traffic/written", misc, "Bytes written since the process was started."), diff --git a/src/feature/dirauth/dirvote.c b/src/feature/dirauth/dirvote.c index c067c9b85e..8676df76ab 100644 --- a/src/feature/dirauth/dirvote.c +++ b/src/feature/dirauth/dirvote.c @@ -3848,11 +3848,10 @@ dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method) smartlist_add_asprintf(chunks, "onion-key\n%s", key); if (ri->onion_curve25519_pkey) { - char kbuf[128]; - base64_encode(kbuf, sizeof(kbuf), - (const char*)ri->onion_curve25519_pkey->public_key, - CURVE25519_PUBKEY_LEN, BASE64_ENCODE_MULTILINE); - smartlist_add_asprintf(chunks, "ntor-onion-key %s", kbuf); + char kbuf[CURVE25519_BASE64_PADDED_LEN + 1]; + bool add_padding = (consensus_method < MIN_METHOD_FOR_UNPADDED_NTOR_KEY); + curve25519_public_to_base64(kbuf, ri->onion_curve25519_pkey, add_padding); + smartlist_add_asprintf(chunks, "ntor-onion-key %s\n", kbuf); } if (family) { @@ -3963,6 +3962,8 @@ static const struct consensus_method_range_t { {MIN_SUPPORTED_CONSENSUS_METHOD, MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS - 1}, {MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS, + MIN_METHOD_FOR_UNPADDED_NTOR_KEY - 1}, + {MIN_METHOD_FOR_UNPADDED_NTOR_KEY, MAX_SUPPORTED_CONSENSUS_METHOD}, {-1, -1} }; @@ -4566,7 +4567,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, /* If it has a protover list and contains a protocol name greater than * MAX_PROTOCOL_NAME_LENGTH, skip it. */ if (ri->protocol_list && - protover_contains_long_protocol_names(ri->protocol_list)) { + protover_list_is_invalid(ri->protocol_list)) { continue; } if (ri->cache_info.published_on >= cutoff) { @@ -4724,8 +4725,8 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, voter->sigs = smartlist_new(); voter->address = hostname; tor_addr_copy(&voter->ipv4_addr, &addr); - voter->ipv4_dirport = router_get_advertised_dir_port(options, 0); - voter->ipv4_orport = router_get_advertised_or_port(options); + voter->ipv4_dirport = routerconf_find_dir_port(options, 0); + voter->ipv4_orport = routerconf_find_or_port(options, AF_INET); voter->contact = tor_strdup(contact); if (options->V3AuthUseLegacyKey) { authority_cert_t *c = get_my_v3_legacy_cert(); diff --git a/src/feature/dirauth/dirvote.h b/src/feature/dirauth/dirvote.h index 1b1c9f2cc7..9cc87489b4 100644 --- a/src/feature/dirauth/dirvote.h +++ b/src/feature/dirauth/dirvote.h @@ -53,7 +53,7 @@ #define MIN_SUPPORTED_CONSENSUS_METHOD 28 /** The highest consensus method that we currently support. */ -#define MAX_SUPPORTED_CONSENSUS_METHOD 29 +#define MAX_SUPPORTED_CONSENSUS_METHOD 30 /** * Lowest consensus method where microdescriptor lines are put in canonical @@ -61,6 +61,10 @@ **/ #define MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS 29 +/** Lowest consensus method where an unpadded base64 onion-key-ntor is allowed + * See #7869 */ +#define MIN_METHOD_FOR_UNPADDED_NTOR_KEY 30 + /** Default bandwidth to clip unmeasured bandwidths to using method >= * MIN_METHOD_TO_CLIP_UNMEASURED_BW. (This is not a consensus method; do not * get confused with the above macros.) */ diff --git a/src/feature/dircache/dircache.c b/src/feature/dircache/dircache.c index 691c100974..efcae41084 100644 --- a/src/feature/dircache/dircache.c +++ b/src/feature/dircache/dircache.c @@ -1614,7 +1614,8 @@ directory_handle_command_post,(dir_connection_t *conn, const char *headers, if (!public_server_mode(options)) { log_info(LD_DIR, "Rejected dir post request from %s " - "since we're not a public relay.", conn->base_.address); + "since we're not a public relay.", + connection_describe_peer(TO_CONN(conn))); write_short_http_response(conn, 503, "Not acting as a public relay"); goto done; } @@ -1630,7 +1631,8 @@ directory_handle_command_post,(dir_connection_t *conn, const char *headers, !strcmpstart(url,"/tor/rendezvous2/publish")) { if (rend_cache_store_v2_desc_as_dir(body) < 0) { log_warn(LD_REND, "Rejected v2 rend descriptor (body size %d) from %s.", - (int)body_len, conn->base_.address); + (int)body_len, + connection_describe_peer(TO_CONN(conn))); write_short_http_response(conn, 400, "Invalid v2 service descriptor rejected"); } else { @@ -1686,7 +1688,8 @@ directory_handle_command_post,(dir_connection_t *conn, const char *headers, log_info(LD_DIRSERV, "Rejected router descriptor or extra-info from %s " "(\"%s\").", - conn->base_.address, msg); + connection_describe_peer(TO_CONN(conn)), + msg); write_short_http_response(conn, 400, msg); } goto done; @@ -1701,7 +1704,8 @@ directory_handle_command_post,(dir_connection_t *conn, const char *headers, } else { tor_assert(msg); log_warn(LD_DIRSERV, "Rejected vote from %s (\"%s\").", - conn->base_.address, msg); + connection_describe_peer(TO_CONN(conn)), + msg); write_short_http_response(conn, status, msg); } goto done; @@ -1714,7 +1718,8 @@ directory_handle_command_post,(dir_connection_t *conn, const char *headers, write_short_http_response(conn, 200, msg?msg:"Signatures stored"); } else { log_warn(LD_DIR, "Unable to store signatures posted by %s: %s", - conn->base_.address, msg?msg:"???"); + connection_describe_peer(TO_CONN(conn)), + msg?msg:"???"); write_short_http_response(conn, 400, msg?msg:"Unable to store signatures"); } @@ -1775,8 +1780,8 @@ directory_handle_command(dir_connection_t *conn) &body, &body_len, MAX_DIR_UL_SIZE, 0)) { case -1: /* overflow */ log_warn(LD_DIRSERV, - "Request too large from address '%s' to DirPort. Closing.", - safe_str(conn->base_.address)); + "Request too large from %s to DirPort. Closing.", + connection_describe_peer(TO_CONN(conn))); return -1; case 0: log_debug(LD_DIRSERV,"command not all here yet."); diff --git a/src/feature/dirclient/dirclient.c b/src/feature/dirclient/dirclient.c index 249618f081..f088ef8283 100644 --- a/src/feature/dirclient/dirclient.c +++ b/src/feature/dirclient/dirclient.c @@ -284,10 +284,10 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose, } if (purpose_needs_anonymity(dir_purpose, router_purpose, NULL)) { indirection = DIRIND_ANONYMOUS; - } else if (!fascist_firewall_allows_dir_server(ds, + } else if (!reachable_addr_allows_dir_server(ds, FIREWALL_DIR_CONNECTION, 0)) { - if (fascist_firewall_allows_dir_server(ds, FIREWALL_OR_CONNECTION, 0)) + if (reachable_addr_allows_dir_server(ds, FIREWALL_OR_CONNECTION, 0)) indirection = DIRIND_ONEHOP; else indirection = DIRIND_ANONYMOUS; @@ -487,7 +487,7 @@ directory_get_from_dirserver,( tor_addr_port_t or_ap; directory_request_t *req = directory_request_new(dir_purpose); /* we are willing to use a non-preferred address if we need to */ - fascist_firewall_choose_address_node(node, FIREWALL_OR_CONNECTION, 0, + reachable_addr_choose_from_node(node, FIREWALL_OR_CONNECTION, 0, &or_ap); directory_request_set_or_addr_port(req, &or_ap); directory_request_set_directory_id_digest(req, @@ -666,7 +666,7 @@ directory_choose_address_routerstatus(const routerstatus_t *status, * Use the preferred address and port if they are reachable, otherwise, * use the alternate address and port (if any). */ - fascist_firewall_choose_address_rs(status, FIREWALL_OR_CONNECTION, 0, + reachable_addr_choose_from_rs(status, FIREWALL_OR_CONNECTION, 0, use_or_ap); have_or = tor_addr_port_is_valid_ap(use_or_ap, 0); } @@ -677,7 +677,7 @@ directory_choose_address_routerstatus(const routerstatus_t *status, indirection == DIRIND_ANON_DIRPORT || (indirection == DIRIND_ONEHOP && !dirclient_must_use_begindir(options))) { - fascist_firewall_choose_address_rs(status, FIREWALL_DIR_CONNECTION, 0, + reachable_addr_choose_from_rs(status, FIREWALL_DIR_CONNECTION, 0, use_dir_ap); have_dir = tor_addr_port_is_valid_ap(use_dir_ap, 0); } @@ -686,12 +686,14 @@ directory_choose_address_routerstatus(const routerstatus_t *status, * connect to it. */ if (!have_or && !have_dir) { static int logged_backtrace = 0; + char *ipv6_str = tor_addr_to_str_dup(&status->ipv6_addr); log_info(LD_BUG, "Rejected all OR and Dir addresses from %s when " "launching an outgoing directory connection to: IPv4 %s OR %d " "Dir %d IPv6 %s OR %d Dir %d", routerstatus_describe(status), fmt_addr(&status->ipv4_addr), status->ipv4_orport, - status->ipv4_dirport, fmt_addr(&status->ipv6_addr), - status->ipv6_orport, status->ipv4_dirport); + status->ipv4_dirport, ipv6_str, status->ipv6_orport, + status->ipv4_dirport); + tor_free(ipv6_str); if (!logged_backtrace) { log_backtrace(LOG_INFO, LD_BUG, "Addresses came from"); logged_backtrace = 1; @@ -740,8 +742,8 @@ connection_dir_client_request_failed(dir_connection_t *conn) if (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC || conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) { log_info(LD_DIR, "Giving up on serverdesc/extrainfo fetch from " - "directory server at '%s'; retrying", - conn->base_.address); + "directory server at %s; retrying", + connection_describe_peer(TO_CONN(conn))); if (conn->router_purpose == ROUTER_PURPOSE_BRIDGE) connection_dir_bridge_routerdesc_failed(conn); connection_dir_download_routerdesc_failed(conn); @@ -750,18 +752,19 @@ connection_dir_client_request_failed(dir_connection_t *conn) networkstatus_consensus_download_failed(0, conn->requested_resource); } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) { log_info(LD_DIR, "Giving up on certificate fetch from directory server " - "at '%s'; retrying", - conn->base_.address); + "at %s; retrying", + connection_describe_peer(TO_CONN(conn))); connection_dir_download_cert_failed(conn, 0); } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) { - log_info(LD_DIR, "Giving up downloading detached signatures from '%s'", - conn->base_.address); + log_info(LD_DIR, "Giving up downloading detached signatures from %s", + connection_describe_peer(TO_CONN(conn))); } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) { - log_info(LD_DIR, "Giving up downloading votes from '%s'", - conn->base_.address); + log_info(LD_DIR, "Giving up downloading votes from %s", + connection_describe_peer(TO_CONN(conn))); } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC) { log_info(LD_DIR, "Giving up on downloading microdescriptors from " - "directory server at '%s'; will retry", conn->base_.address); + "directory server at %s; will retry", + connection_describe_peer(TO_CONN(conn))); connection_dir_download_routerdesc_failed(conn); } } @@ -918,7 +921,7 @@ directory_command_should_use_begindir(const or_options_t *options, } if (indirection == DIRIND_ONEHOP) { /* We're firewalled and want a direct OR connection */ - if (!fascist_firewall_allows_address_addr(or_addr, or_port, + if (!reachable_addr_allows_addr(or_addr, or_port, FIREWALL_OR_CONNECTION, 0, 0)) { *reason = "ORPort not reachable"; return 0; @@ -1754,10 +1757,10 @@ directory_send_command(dir_connection_t *conn, smartlist_free(headers); log_debug(LD_DIR, - "Sent request to directory server '%s:%d': " + "Sent request to directory server %s " "(purpose: %d, request size: %"TOR_PRIuSZ", " "payload size: %"TOR_PRIuSZ")", - conn->base_.address, conn->base_.port, + connection_describe_peer(TO_CONN(conn)), conn->base_.purpose, (total_request_len), (payload ? payload_len : 0)); @@ -1893,9 +1896,10 @@ dir_client_decompress_response_body(char **bodyp, size_t *bodylenp, } tor_log(severity, LD_HTTP, - "HTTP body from server '%s:%d' was labeled as %s, " + "HTTP body from %s was labeled as %s, " "%s it seems to be %s.%s", - conn->base_.address, conn->base_.port, description1, + connection_describe(TO_CONN(conn)), + description1, guessed != compression?"but":"and", description2, (compression>0 && guessed>0 && want_to_try_both)? @@ -1941,11 +1945,11 @@ dir_client_decompress_response_body(char **bodyp, size_t *bodylenp, * we didn't manage to uncompress it, then warn and bail. */ if (!plausible && !new_body) { log_fn(LOG_PROTOCOL_WARN, LD_HTTP, - "Unable to decompress HTTP body (tried %s%s%s, server '%s:%d').", + "Unable to decompress HTTP body (tried %s%s%s, on %s).", description1, tried_both?" and ":"", tried_both?description2:"", - conn->base_.address, conn->base_.port); + connection_describe(TO_CONN(conn))); rv = -1; goto done; } @@ -2052,8 +2056,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn) allow_partial)) { case -1: /* overflow */ log_warn(LD_PROTOCOL, - "'fetch' response too large (server '%s:%d'). Closing.", - conn->base_.address, conn->base_.port); + "'fetch' response too large (%s). Closing.", + connection_describe(TO_CONN(conn))); return -1; case 0: log_info(LD_HTTP, @@ -2064,22 +2068,22 @@ connection_dir_client_reached_eof(dir_connection_t *conn) if (parse_http_response(headers, &status_code, &date_header, &compression, &reason) < 0) { - log_warn(LD_HTTP,"Unparseable headers (server '%s:%d'). Closing.", - conn->base_.address, conn->base_.port); - + log_warn(LD_HTTP,"Unparseable headers (%s). Closing.", + connection_describe(TO_CONN(conn))); rv = -1; goto done; } if (!reason) reason = tor_strdup("[no reason given]"); tor_log(LOG_DEBUG, LD_DIR, - "Received response from directory server '%s:%d': %d %s " + "Received response on %s: %d %s " "(purpose: %d, response size: %"TOR_PRIuSZ #ifdef MEASUREMENTS_21206 ", data cells received: %d, data cells sent: %d" #endif ", compression: %d)", - conn->base_.address, conn->base_.port, status_code, + connection_describe(TO_CONN(conn)), + status_code, escaped(reason), conn->base_.purpose, (received_bytes), #ifdef MEASUREMENTS_21206 @@ -2104,7 +2108,13 @@ connection_dir_client_reached_eof(dir_connection_t *conn) if (conn->dirconn_direct) { char *guess = http_get_header(headers, X_ADDRESS_HEADER); if (guess) { - router_new_address_suggestion(guess, conn); + tor_addr_t addr; + if (tor_addr_parse(&addr, guess) < 0) { + log_debug(LD_DIR, "Malformed X-Your-Address-Is header %s. Ignoring.", + escaped(guess)); + } else { + relay_address_new_suggestion(&addr, &TO_CONN(conn)->addr, NULL); + } tor_free(guess); } } @@ -2133,9 +2143,9 @@ connection_dir_client_reached_eof(dir_connection_t *conn) dir_server_t *ds; const char *id_digest = conn->identity_digest; log_info(LD_DIR,"Received http status code %d (%s) from server " - "'%s:%d'. I'll try again soon.", - status_code, escaped(reason), conn->base_.address, - conn->base_.port); + "%s. I'll try again soon.", + status_code, escaped(reason), + connection_describe_peer(TO_CONN(conn))); time_t now = approx_time(); if ((rs = router_get_mutable_consensus_status_by_id(id_digest))) rs->last_dir_503_at = now; @@ -2240,9 +2250,9 @@ handle_response_fetch_consensus(dir_connection_t *conn, int severity = (status_code == 304) ? LOG_INFO : LOG_WARN; tor_log(severity, LD_DIR, "Received http status code %d (%s) from server " - "'%s:%d' while fetching consensus directory.", - status_code, escaped(reason), conn->base_.address, - conn->base_.port); + "%s while fetching consensus directory.", + status_code, escaped(reason), + connection_describe_peer(TO_CONN(conn))); networkstatus_consensus_download_failed(status_code, flavname); return -1; } @@ -2277,21 +2287,21 @@ handle_response_fetch_consensus(dir_connection_t *conn, tor_munmap_file(mapped_consensus); if (new_consensus == NULL) { log_warn(LD_DIR, "Could not apply consensus diff received from server " - "'%s:%d'", conn->base_.address, conn->base_.port); + "%s", connection_describe_peer(TO_CONN(conn))); // XXXX If this happens too many times, we should maybe not use // XXXX this directory for diffs any more? networkstatus_consensus_download_failed(0, flavname); return -1; } log_info(LD_DIR, "Applied consensus diff (size %d) from server " - "'%s:%d', resulting in a new consensus document (size %d).", - (int)body_len, conn->base_.address, conn->base_.port, + "%s, resulting in a new consensus document (size %d).", + (int)body_len, connection_describe_peer(TO_CONN(conn)), (int)strlen(new_consensus)); consensus = new_consensus; sourcename = "generated based on a diff"; } else { log_info(LD_DIR,"Received consensus directory (body size %d) from server " - "'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port); + "%s", (int)body_len, connection_describe_peer(TO_CONN(conn))); consensus = body; sourcename = "downloaded"; } @@ -2302,8 +2312,9 @@ handle_response_fetch_consensus(dir_connection_t *conn, conn->identity_digest))<0) { log_fn(r<-1?LOG_WARN:LOG_INFO, LD_DIR, "Unable to load %s consensus directory %s from " - "server '%s:%d'. I'll try again soon.", - flavname, sourcename, conn->base_.address, conn->base_.port); + "server %s. I'll try again soon.", + flavname, sourcename, + connection_describe_peer(TO_CONN(conn))); networkstatus_consensus_download_failed(0, flavname); tor_free(new_consensus); return -1; @@ -2344,15 +2355,16 @@ handle_response_fetch_certificate(dir_connection_t *conn, if (status_code != 200) { log_warn(LD_DIR, "Received http status code %d (%s) from server " - "'%s:%d' while fetching \"/tor/keys/%s\".", - status_code, escaped(reason), conn->base_.address, - conn->base_.port, conn->requested_resource); + "%s while fetching \"/tor/keys/%s\".", + status_code, escaped(reason), + connection_describe_peer(TO_CONN(conn)), + conn->requested_resource); connection_dir_download_cert_failed(conn, status_code); return -1; } log_info(LD_DIR,"Received authority certificates (body size %d) from " - "server '%s:%d'", - (int)body_len, conn->base_.address, conn->base_.port); + "server %s", + (int)body_len, connection_describe_peer(TO_CONN(conn))); /* * Tell trusted_dirs_load_certs_from_string() whether it was by fp @@ -2403,14 +2415,15 @@ handle_response_fetch_status_vote(dir_connection_t *conn, const char *msg; int st; - log_info(LD_DIR,"Got votes (body size %d) from server %s:%d", - (int)body_len, conn->base_.address, conn->base_.port); + log_info(LD_DIR,"Got votes (body size %d) from server %s", + (int)body_len, connection_describe_peer(TO_CONN(conn))); if (status_code != 200) { log_warn(LD_DIR, "Received http status code %d (%s) from server " - "'%s:%d' while fetching \"/tor/status-vote/next/%s.z\".", - status_code, escaped(reason), conn->base_.address, - conn->base_.port, conn->requested_resource); + "%s while fetching \"/tor/status-vote/next/%s.z\".", + status_code, escaped(reason), + connection_describe_peer(TO_CONN(conn)), + conn->requested_resource); return -1; } dirvote_add_vote(body, 0, &msg, &st); @@ -2438,19 +2451,21 @@ handle_response_fetch_detached_signatures(dir_connection_t *conn, const size_t body_len = args->body_len; const char *msg = NULL; - log_info(LD_DIR,"Got detached signatures (body size %d) from server %s:%d", - (int)body_len, conn->base_.address, conn->base_.port); + log_info(LD_DIR,"Got detached signatures (body size %d) from server %s", + (int)body_len, + connection_describe_peer(TO_CONN(conn))); if (status_code != 200) { log_warn(LD_DIR, - "Received http status code %d (%s) from server '%s:%d' while fetching " + "Received http status code %d (%s) from server %s while fetching " "\"/tor/status-vote/next/consensus-signatures.z\".", - status_code, escaped(reason), conn->base_.address, - conn->base_.port); + status_code, escaped(reason), + connection_describe_peer(TO_CONN(conn))); return -1; } if (dirvote_add_signatures(body, conn->base_.address, &msg)<0) { - log_warn(LD_DIR, "Problem adding detached signatures from %s:%d: %s", - conn->base_.address, conn->base_.port, msg?msg:"???"); + log_warn(LD_DIR, "Problem adding detached signatures from %s: %s", + connection_describe_peer(TO_CONN(conn)), + msg?msg:"???"); } return 0; @@ -2476,9 +2491,9 @@ handle_response_fetch_desc(dir_connection_t *conn, int n_asked_for = 0; int descriptor_digests = conn->requested_resource && !strcmpstart(conn->requested_resource,"d/"); - log_info(LD_DIR,"Received %s (body size %d) from server '%s:%d'", + log_info(LD_DIR,"Received %s (body size %d) from server %s", was_ei ? "extra server info" : "server info", - (int)body_len, conn->base_.address, conn->base_.port); + (int)body_len, connection_describe_peer(TO_CONN(conn))); if (conn->requested_resource && (!strcmpstart(conn->requested_resource,"d/") || !strcmpstart(conn->requested_resource,"fp/"))) { @@ -2494,10 +2509,11 @@ handle_response_fetch_desc(dir_connection_t *conn, /* 404 means that it didn't have them; no big deal. * Older (pre-0.1.1.8) servers said 400 Servers unavailable instead. */ log_fn(dir_okay ? LOG_INFO : LOG_WARN, LD_DIR, - "Received http status code %d (%s) from server '%s:%d' " + "Received http status code %d (%s) from server %s " "while fetching \"/tor/server/%s\". I'll try again soon.", - status_code, escaped(reason), conn->base_.address, - conn->base_.port, conn->requested_resource); + status_code, escaped(reason), + connection_describe_peer(TO_CONN(conn)), + conn->requested_resource); if (!which) { connection_dir_download_routerdesc_failed(conn); } else { @@ -2537,10 +2553,10 @@ handle_response_fetch_desc(dir_connection_t *conn, } } if (which) { /* mark remaining ones as failed */ - log_info(LD_DIR, "Received %d/%d %s requested from %s:%d", + log_info(LD_DIR, "Received %d/%d %s requested from %s", n_asked_for-smartlist_len(which), n_asked_for, was_ei ? "extra-info documents" : "router descriptors", - conn->base_.address, (int)conn->base_.port); + connection_describe_peer(TO_CONN(conn))); if (smartlist_len(which)) { dir_routerdesc_download_failed(which, status_code, conn->router_purpose, @@ -2571,9 +2587,9 @@ handle_response_fetch_microdesc(dir_connection_t *conn, smartlist_t *which = NULL; log_info(LD_DIR,"Received answer to microdescriptor request (status %d, " - "body size %d) from server '%s:%d'", - status_code, (int)body_len, conn->base_.address, - conn->base_.port); + "body size %d) from server %s", + status_code, (int)body_len, + connection_describe_peer(TO_CONN(conn))); tor_assert(conn->requested_resource && !strcmpstart(conn->requested_resource, "d/")); tor_assert_nonfatal(!fast_mem_is_zero(conn->identity_digest, DIGEST_LEN)); @@ -2583,10 +2599,11 @@ handle_response_fetch_microdesc(dir_connection_t *conn, DSR_DIGEST256|DSR_BASE64); if (status_code != 200) { log_info(LD_DIR, "Received status code %d (%s) from server " - "'%s:%d' while fetching \"/tor/micro/%s\". I'll try again " + "%s while fetching \"/tor/micro/%s\". I'll try again " "soon.", - status_code, escaped(reason), conn->base_.address, - (int)conn->base_.port, conn->requested_resource); + status_code, escaped(reason), + connection_describe_peer(TO_CONN(conn)), + conn->requested_resource); dir_microdesc_download_failed(which, status_code, conn->identity_digest); SMARTLIST_FOREACH(which, char *, cp, tor_free(cp)); smartlist_free(which); @@ -2661,8 +2678,8 @@ handle_response_upload_dir(dir_connection_t *conn, break; case 400: log_warn(LD_GENERAL,"http status 400 (%s) response from " - "dirserver '%s:%d'. Please correct.", - escaped(reason), conn->base_.address, conn->base_.port); + "dirserver %s. Please correct.", + escaped(reason), connection_describe_peer(TO_CONN(conn))); control_event_server_status(LOG_WARN, "BAD_SERVER_DESCRIPTOR DIRAUTH=%s:%d REASON=\"%s\"", conn->base_.address, conn->base_.port, escaped(reason)); @@ -2670,10 +2687,10 @@ handle_response_upload_dir(dir_connection_t *conn, default: log_warn(LD_GENERAL, "HTTP status %d (%s) was unexpected while uploading " - "descriptor to server '%s:%d'. Possibly the server is " + "descriptor to server %s'. Possibly the server is " "misconfigured?", - status_code, escaped(reason), conn->base_.address, - conn->base_.port); + status_code, escaped(reason), + connection_describe_peer(TO_CONN(conn))); break; } /* return 0 in all cases, since we don't want to mark any @@ -2696,21 +2713,21 @@ handle_response_upload_vote(dir_connection_t *conn, switch (status_code) { case 200: { - log_notice(LD_DIR,"Uploaded a vote to dirserver %s:%d", - conn->base_.address, conn->base_.port); + log_notice(LD_DIR,"Uploaded a vote to dirserver %s", + connection_describe_peer(TO_CONN(conn))); } break; case 400: log_warn(LD_DIR,"http status 400 (%s) response after uploading " - "vote to dirserver '%s:%d'. Please correct.", - escaped(reason), conn->base_.address, conn->base_.port); + "vote to dirserver %s. Please correct.", + escaped(reason), connection_describe_peer(TO_CONN(conn))); break; default: log_warn(LD_GENERAL, "HTTP status %d (%s) was unexpected while uploading " - "vote to server '%s:%d'.", - status_code, escaped(reason), conn->base_.address, - conn->base_.port); + "vote to server %s.", + status_code, escaped(reason), + connection_describe_peer(TO_CONN(conn))); break; } /* return 0 in all cases, since we don't want to mark any @@ -2732,21 +2749,21 @@ handle_response_upload_signatures(dir_connection_t *conn, switch (status_code) { case 200: { - log_notice(LD_DIR,"Uploaded signature(s) to dirserver %s:%d", - conn->base_.address, conn->base_.port); + log_notice(LD_DIR,"Uploaded signature(s) to dirserver %s", + connection_describe_peer(TO_CONN(conn))); } break; case 400: log_warn(LD_DIR,"http status 400 (%s) response after uploading " - "signatures to dirserver '%s:%d'. Please correct.", - escaped(reason), conn->base_.address, conn->base_.port); + "signatures to dirserver %s. Please correct.", + escaped(reason), connection_describe_peer(TO_CONN(conn))); break; default: log_warn(LD_GENERAL, "HTTP status %d (%s) was unexpected while uploading " - "signatures to server '%s:%d'.", - status_code, escaped(reason), conn->base_.address, - conn->base_.port); + "signatures to server %s.", + status_code, escaped(reason), + connection_describe_peer(TO_CONN(conn))); break; } /* return 0 in all cases, since we don't want to mark any @@ -2861,10 +2878,10 @@ handle_response_fetch_renddesc_v2(dir_connection_t *conn, default: log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: " "http status %d (%s) response unexpected while " - "fetching v2 hidden service descriptor (server '%s:%d'). " + "fetching v2 hidden service descriptor (server %s). " "Retrying at another directory.", - status_code, escaped(reason), conn->base_.address, - conn->base_.port); + status_code, escaped(reason), + connection_describe_peer(TO_CONN(conn))); SEND_HS_DESC_FAILED_EVENT("UNEXPECTED"); SEND_HS_DESC_FAILED_CONTENT(); break; @@ -2908,15 +2925,15 @@ handle_response_upload_renddesc_v2(dir_connection_t *conn, break; case 400: log_warn(LD_REND,"http status 400 (%s) response from dirserver " - "'%s:%d'. Malformed rendezvous descriptor?", - escaped(reason), conn->base_.address, conn->base_.port); + "%s. Malformed rendezvous descriptor?", + escaped(reason), connection_describe_peer(TO_CONN(conn))); SEND_HS_DESC_UPLOAD_FAILED_EVENT("UPLOAD_REJECTED"); break; default: log_warn(LD_REND,"http status %d (%s) response unexpected (server " - "'%s:%d').", - status_code, escaped(reason), conn->base_.address, - conn->base_.port); + "%s).", + status_code, escaped(reason), + connection_describe_peer(TO_CONN(conn))); SEND_HS_DESC_UPLOAD_FAILED_EVENT("UNEXPECTED"); break; } @@ -2954,17 +2971,17 @@ handle_response_upload_hsdesc(dir_connection_t *conn, log_fn(LOG_PROTOCOL_WARN, LD_REND, "Uploading hidden service descriptor: http " "status 400 (%s) response from dirserver " - "'%s:%d'. Malformed hidden service descriptor?", - escaped(reason), conn->base_.address, conn->base_.port); + "%s. Malformed hidden service descriptor?", + escaped(reason), connection_describe_peer(TO_CONN(conn))); hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest, "UPLOAD_REJECTED"); break; default: log_warn(LD_REND, "Uploading hidden service descriptor: http " "status %d (%s) response unexpected (server " - "'%s:%d').", - status_code, escaped(reason), conn->base_.address, - conn->base_.port); + "%s').", + status_code, escaped(reason), + connection_describe_peer(TO_CONN(conn))); hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest, "UNEXPECTED"); break; @@ -3116,7 +3133,7 @@ connection_dir_close_consensus_fetches(dir_connection_t *except_this_one, if (d == except_this_one) continue; log_info(LD_DIR, "Closing consensus fetch (to %s) since one " - "has just arrived.", TO_CONN(d)->address); + "has just arrived.", connection_describe_peer(TO_CONN(d))); connection_mark_for_close(TO_CONN(d)); } SMARTLIST_FOREACH_END(d); smartlist_free(conns_to_close); diff --git a/src/feature/dirclient/dirclient_modes.c b/src/feature/dirclient/dirclient_modes.c index 31a3f8af58..62cdad6c36 100644 --- a/src/feature/dirclient/dirclient_modes.c +++ b/src/feature/dirclient/dirclient_modes.c @@ -40,15 +40,19 @@ int dirclient_fetches_from_authorities(const or_options_t *options) { const routerinfo_t *me; - uint32_t addr; int refuseunknown; if (options->FetchDirInfoEarly) return 1; if (options->BridgeRelay == 1) return 0; - if (server_mode(options) && - router_pick_published_address(options, &addr, 1) < 0) - return 1; /* we don't know our IP address; ask an authority. */ + /* We don't know our IP address; ask an authority. IPv4 is still mandatory + * to have thus if we don't have it, we ought to learn it from an authority + * through the NETINFO cell or the HTTP header it sends us back. + * + * Note that at the moment, relay do a direct connection so no NETINFO cell + * for now. */ + if (server_mode(options) && !relay_has_address_set(AF_INET)) + return 1; refuseunknown = ! router_my_exit_policy_is_reject_star() && should_refuse_unknown_exits(options); if (!dir_server_mode(options) && !refuseunknown) diff --git a/src/feature/dircommon/directory.c b/src/feature/dircommon/directory.c index b177fe5201..b276ac3441 100644 --- a/src/feature/dircommon/directory.c +++ b/src/feature/dircommon/directory.c @@ -79,8 +79,12 @@ * connection_finished_connecting() in connection.c */ -/** Convert a connection_t* to a dir_connection_t*; assert if the cast is - * invalid. */ +/** + * Cast a `connection_t *` to a `dir_connection_t *`. + * + * Exit with an assertion failure if the input is not a + * `dir_connection_t`. + **/ dir_connection_t * TO_DIR_CONN(connection_t *c) { @@ -88,6 +92,18 @@ TO_DIR_CONN(connection_t *c) return DOWNCAST(dir_connection_t, c); } +/** + * Cast a `const connection_t *` to a `const dir_connection_t *`. + * + * Exit with an assertion failure if the input is not a + * `dir_connection_t`. + **/ +const dir_connection_t * +CONST_TO_DIR_CONN(const connection_t *c) +{ + return TO_DIR_CONN((connection_t *)c); +} + /** Return false if the directory purpose <b>dir_purpose</b> * does not require an anonymous (three-hop) connection. * @@ -217,7 +233,7 @@ connection_dir_is_anonymous(const dir_connection_t *dir_conn) return false; } - edge_conn = TO_EDGE_CONN((connection_t *) linked_conn); + edge_conn = CONST_TO_EDGE_CONN(linked_conn); circ = edge_conn->on_circuit; /* Can't be a circuit we initiated and without a circuit, no channel. */ @@ -455,9 +471,9 @@ connection_dir_process_inbuf(dir_connection_t *conn) if (connection_get_inbuf_len(TO_CONN(conn)) > max_size) { log_warn(LD_HTTP, - "Too much data received from directory connection (%s): " + "Too much data received from %s: " "denial of service attempt, or you need to upgrade?", - conn->base_.address); + connection_describe(TO_CONN(conn))); connection_mark_for_close(TO_CONN(conn)); return -1; } @@ -540,8 +556,8 @@ connection_dir_finished_connecting(dir_connection_t *conn) tor_assert(conn->base_.type == CONN_TYPE_DIR); tor_assert(conn->base_.state == DIR_CONN_STATE_CONNECTING); - log_debug(LD_HTTP,"Dir connection to router %s:%u established.", - conn->base_.address,conn->base_.port); + log_debug(LD_HTTP,"Dir connection to %s established.", + connection_describe_peer(TO_CONN(conn))); /* start flushing conn */ conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING; diff --git a/src/feature/dircommon/directory.h b/src/feature/dircommon/directory.h index 0f26cdeff9..0aa2ff53ef 100644 --- a/src/feature/dircommon/directory.h +++ b/src/feature/dircommon/directory.h @@ -13,6 +13,7 @@ #define TOR_DIRECTORY_H dir_connection_t *TO_DIR_CONN(connection_t *c); +const dir_connection_t *CONST_TO_DIR_CONN(const connection_t *c); #define DIR_CONN_STATE_MIN_ 1 /** State for connection to directory server: waiting for connect(). */ diff --git a/src/feature/dirparse/ns_parse.c b/src/feature/dirparse/ns_parse.c index d4bcdae973..927870c4aa 100644 --- a/src/feature/dirparse/ns_parse.c +++ b/src/feature/dirparse/ns_parse.c @@ -13,6 +13,7 @@ #include "core/or/or.h" #include "app/config/config.h" +#include "core/or/protover.h" #include "core/or/versions.h" #include "feature/client/entrynodes.h" #include "feature/dirauth/dirvote.h" @@ -466,6 +467,10 @@ routerstatus_parse_entry_from_string(memarea_t *area, } } + // If the protover line is malformed, reject this routerstatus. + if (protocols && protover_list_is_invalid(protocols)) { + goto err; + } summarize_protover_flags(&rs->pv, protocols, version); } @@ -1063,6 +1068,19 @@ extract_shared_random_srvs(networkstatus_t *ns, smartlist_t *tokens) } } +/** Allocate a copy of a protover line, if present. If present but malformed, + * set *error to true. */ +static char * +dup_protocols_string(smartlist_t *tokens, bool *error, directory_keyword kw) +{ + directory_token_t *tok = find_opt_by_keyword(tokens, kw); + if (!tok) + return NULL; + if (protover_list_is_invalid(tok->args[0])) + *error = true; + return tor_strdup(tok->args[0]); +} + /** Parse a v3 networkstatus vote, opinion, or consensus (depending on * ns_type), from <b>s</b>, and return the result. Return NULL on failure. */ networkstatus_t * @@ -1184,14 +1202,18 @@ networkstatus_parse_vote_from_string(const char *s, } } - if ((tok = find_opt_by_keyword(tokens, K_RECOMMENDED_CLIENT_PROTOCOLS))) - ns->recommended_client_protocols = tor_strdup(tok->args[0]); - if ((tok = find_opt_by_keyword(tokens, K_RECOMMENDED_RELAY_PROTOCOLS))) - ns->recommended_relay_protocols = tor_strdup(tok->args[0]); - if ((tok = find_opt_by_keyword(tokens, K_REQUIRED_CLIENT_PROTOCOLS))) - ns->required_client_protocols = tor_strdup(tok->args[0]); - if ((tok = find_opt_by_keyword(tokens, K_REQUIRED_RELAY_PROTOCOLS))) - ns->required_relay_protocols = tor_strdup(tok->args[0]); + // Reject the vote if any of the protocols lines are malformed. + bool unparseable = false; + ns->recommended_client_protocols = dup_protocols_string(tokens, &unparseable, + K_RECOMMENDED_CLIENT_PROTOCOLS); + ns->recommended_relay_protocols = dup_protocols_string(tokens, &unparseable, + K_RECOMMENDED_RELAY_PROTOCOLS); + ns->required_client_protocols = dup_protocols_string(tokens, &unparseable, + K_REQUIRED_CLIENT_PROTOCOLS); + ns->required_relay_protocols = dup_protocols_string(tokens, &unparseable, + K_REQUIRED_RELAY_PROTOCOLS); + if (unparseable) + goto err; tok = find_by_keyword(tokens, K_VALID_AFTER); if (parse_iso_time(tok->args[0], &ns->valid_after)) @@ -1453,6 +1475,7 @@ networkstatus_parse_vote_from_string(const char *s, smartlist_add(ns->routerstatus_list, rs); } else { vote_routerstatus_free(rs); + goto err; // Malformed routerstatus, reject this vote. } } else { routerstatus_t *rs; @@ -1463,6 +1486,8 @@ networkstatus_parse_vote_from_string(const char *s, flav))) { /* Use exponential-backoff scheduling when downloading microdescs */ smartlist_add(ns->routerstatus_list, rs); + } else { + goto err; // Malformed routerstatus, reject this vote. } } } diff --git a/src/feature/hs/hs_client.c b/src/feature/hs/hs_client.c index 09f0657fa8..cde3560ebf 100644 --- a/src/feature/hs/hs_client.c +++ b/src/feature/hs/hs_client.c @@ -779,10 +779,16 @@ client_rendezvous_circ_has_opened(origin_circuit_t *circ) * the v3 rendezvous protocol */ if (rp_ei) { const node_t *rp_node = node_get_by_id(rp_ei->identity_digest); - if (rp_node) { - if (BUG(!node_supports_v3_rendezvous_point(rp_node))) { - return; - } + if (rp_node && !node_supports_v3_rendezvous_point(rp_node)) { + /* Even tho we checked that this node supported v3 when we created the + rendezvous circuit, there is a chance that we might think it does + not support v3 anymore. This might happen if we got a new consensus + in the meanwhile, where the relay is still listed but its listed + descriptor digest has changed and hence we can't access its 'ri' or + 'md'. */ + log_info(LD_REND, "Rendezvous node %s did not support v3 after circuit " + "has opened.", safe_str_client(extend_info_describe(rp_ei))); + return; } } @@ -1554,9 +1560,9 @@ client_dir_fetch_unexpected(dir_connection_t *dir_conn, const char *reason, log_warn(LD_REND, "Fetching v3 hidden service descriptor failed: " "http status %d (%s) response unexpected from HSDir " - "server '%s:%d'. Retrying at another directory.", - status_code, escaped(reason), TO_CONN(dir_conn)->address, - TO_CONN(dir_conn)->port); + "server %s'. Retrying at another directory.", + status_code, escaped(reason), + connection_describe_peer(TO_CONN(dir_conn))); /* Fire control port FAILED event. */ hs_control_desc_event_failed(dir_conn->hs_ident, dir_conn->identity_digest, "UNEXPECTED"); diff --git a/src/feature/hs/hs_common.c b/src/feature/hs/hs_common.c index 706b42529f..cbcb672140 100644 --- a/src/feature/hs/hs_common.c +++ b/src/feature/hs/hs_common.c @@ -1744,7 +1744,7 @@ hs_get_extend_info_from_lspecs(const smartlist_t *lspecs, switch (link_specifier_get_ls_type(ls)) { case LS_IPV4: /* Skip if we already seen a v4. If direct_conn is true, we skip this - * block because fascist_firewall_choose_address_ls() will set ap. If + * block because reachable_addr_choose_from_ls() will set ap. If * direct_conn is false, set ap to the first IPv4 address and port in * the link specifiers.*/ if (have_v4 || direct_conn) continue; @@ -1776,7 +1776,7 @@ hs_get_extend_info_from_lspecs(const smartlist_t *lspecs, /* Choose a preferred address first, but fall back to an allowed address. */ if (direct_conn) - fascist_firewall_choose_address_ls(lspecs, 0, &ap); + reachable_addr_choose_from_ls(lspecs, 0, &ap); /* Legacy ID is mandatory, and we require an IP address. */ if (!tor_addr_port_is_valid_ap(&ap, 0)) { diff --git a/src/feature/hs/hs_descriptor.c b/src/feature/hs/hs_descriptor.c index 50a46fb40f..30a36030d1 100644 --- a/src/feature/hs/hs_descriptor.c +++ b/src/feature/hs/hs_descriptor.c @@ -55,6 +55,7 @@ /* For unit tests.*/ #define HS_DESCRIPTOR_PRIVATE +#include <stdbool.h> #include "core/or/or.h" #include "app/config/config.h" #include "trunnel/ed25519_cert.h" /* Trunnel interface. */ @@ -404,7 +405,7 @@ encode_enc_key(const hs_desc_intro_point_t *ip) tor_assert(ip); /* Base64 encode the encryption key for the "enc-key" field. */ - curve25519_public_to_base64(key_b64, &ip->enc_key); + curve25519_public_to_base64(key_b64, &ip->enc_key, true); if (tor_cert_encode_ed22519(ip->enc_key_cert, &encoded_cert) < 0) { goto done; } @@ -430,7 +431,7 @@ encode_onion_key(const hs_desc_intro_point_t *ip) tor_assert(ip); /* Base64 encode the encryption key for the "onion-key" field. */ - curve25519_public_to_base64(key_b64, &ip->onion_key); + curve25519_public_to_base64(key_b64, &ip->onion_key, true); tor_asprintf(&encoded, "%s ntor %s", str_ip_onion_key, key_b64); return encoded; @@ -813,7 +814,7 @@ get_outer_encrypted_layer_plaintext(const hs_descriptor_t *desc, tor_assert(!fast_mem_is_zero((char *) ephemeral_pubkey->public_key, CURVE25519_PUBKEY_LEN)); - curve25519_public_to_base64(ephemeral_key_base64, ephemeral_pubkey); + curve25519_public_to_base64(ephemeral_key_base64, ephemeral_pubkey, true); smartlist_add_asprintf(lines, "%s %s\n", str_desc_auth_key, ephemeral_key_base64); diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c index b56b7f4368..3e264b4686 100644 --- a/src/feature/hs/hs_service.c +++ b/src/feature/hs/hs_service.c @@ -990,7 +990,7 @@ write_address_to_file(const hs_service_t *service, const char *fname_) tor_asprintf(&addr_buf, "%s.%s\n", service->onion_address, address_tld); /* Notice here that we use the given "fname_". */ fname = hs_path_from_filename(service->config.directory_path, fname_); - if (write_str_to_file(fname, addr_buf, 0) < 0) { + if (write_str_to_file_if_not_equal(fname, addr_buf)) { log_warn(LD_REND, "Could not write onion address to hostname file %s", escaped(fname)); goto end; diff --git a/src/feature/nodelist/authcert.c b/src/feature/nodelist/authcert.c index 26713d7149..c5b31be9e3 100644 --- a/src/feature/nodelist/authcert.c +++ b/src/feature/nodelist/authcert.c @@ -808,7 +808,7 @@ authority_certs_fetch_resource_impl(const char *resource, /* clients always make OR connections to bridges */ tor_addr_port_t or_ap; /* we are willing to use a non-preferred address if we need to */ - fascist_firewall_choose_address_node(node, FIREWALL_OR_CONNECTION, 0, + reachable_addr_choose_from_node(node, FIREWALL_OR_CONNECTION, 0, &or_ap); req = directory_request_new(DIR_PURPOSE_FETCH_CERTIFICATE); diff --git a/src/feature/nodelist/node_select.c b/src/feature/nodelist/node_select.c index a7c02f64d8..ecb70aef14 100644 --- a/src/feature/nodelist/node_select.c +++ b/src/feature/nodelist/node_select.c @@ -141,7 +141,7 @@ router_pick_dirserver_generic(smartlist_t *sourcelist, #define RETRY_ALTERNATE_IP_VERSION(retry_label) \ STMT_BEGIN \ if (result == NULL && try_ip_pref && options->ClientUseIPv4 \ - && fascist_firewall_use_ipv6(options) && !server_mode(options) \ + && reachable_addr_use_ipv6(options) && !server_mode(options) \ && !n_busy) { \ n_excluded = 0; \ n_busy = 0; \ @@ -212,8 +212,8 @@ router_picked_poor_directory_log(const routerstatus_t *rs) log_debug(LD_DIR, "Wanted to make an outgoing directory connection, but " "we couldn't find a directory that fit our criteria. " "Perhaps we will succeed next time with less strict criteria."); - } else if (!fascist_firewall_allows_rs(rs, FIREWALL_OR_CONNECTION, 1) - && !fascist_firewall_allows_rs(rs, FIREWALL_DIR_CONNECTION, 1) + } else if (!reachable_addr_allows_rs(rs, FIREWALL_OR_CONNECTION, 1) + && !reachable_addr_allows_rs(rs, FIREWALL_DIR_CONNECTION, 1) ) { /* This is rare, and might be interesting to users trying to diagnose * connection issues on dual-stack machines. */ @@ -374,12 +374,12 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags, * we try routers that only have one address both times.) */ if (!fascistfirewall || skip_or_fw || - fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION, + reachable_addr_allows_node(node, FIREWALL_OR_CONNECTION, try_ip_pref)) smartlist_add(is_trusted ? trusted_tunnel : is_overloaded ? overloaded_tunnel : tunnel, (void*)node); else if (!must_have_or && (skip_dir_fw || - fascist_firewall_allows_node(node, FIREWALL_DIR_CONNECTION, + reachable_addr_allows_node(node, FIREWALL_DIR_CONNECTION, try_ip_pref))) smartlist_add(is_trusted ? trusted_direct : is_overloaded ? overloaded_direct : direct, (void*)node); @@ -1162,11 +1162,11 @@ router_pick_trusteddirserver_impl(const smartlist_t *sourcelist, * we try routers that only have one address both times.) */ if (!fascistfirewall || skip_or_fw || - fascist_firewall_allows_dir_server(d, FIREWALL_OR_CONNECTION, + reachable_addr_allows_dir_server(d, FIREWALL_OR_CONNECTION, try_ip_pref)) smartlist_add(is_overloaded ? overloaded_tunnel : tunnel, (void*)d); else if (!must_have_or && (skip_dir_fw || - fascist_firewall_allows_dir_server(d, FIREWALL_DIR_CONNECTION, + reachable_addr_allows_dir_server(d, FIREWALL_DIR_CONNECTION, try_ip_pref))) smartlist_add(is_overloaded ? overloaded_direct : direct, (void*)d); } diff --git a/src/feature/nodelist/nodelist.c b/src/feature/nodelist/nodelist.c index c2e2f53038..7edc1fc51c 100644 --- a/src/feature/nodelist/nodelist.c +++ b/src/feature/nodelist/nodelist.c @@ -666,7 +666,7 @@ nodelist_set_consensus(const networkstatus_t *ns) node->is_bad_exit = rs->is_bad_exit; node->is_hs_dir = rs->is_hs_dir; node->ipv6_preferred = 0; - if (fascist_firewall_prefer_ipv6_orport(options) && + if (reachable_addr_prefer_ipv6_orport(options) && (tor_addr_is_null(&rs->ipv6_addr) == 0 || (node->md && tor_addr_is_null(&node->md->ipv6_addr) == 0))) node->ipv6_preferred = 1; @@ -1704,7 +1704,7 @@ node_has_ipv6_dirport(const node_t *node) * ii) the router has no IPv4 OR address. * * If you don't have a node, consider looking it up. - * If there is no node, use fascist_firewall_prefer_ipv6_orport(). + * If there is no node, use reachable_addr_prefer_ipv6_orport(). */ int node_ipv6_or_preferred(const node_t *node) @@ -1714,10 +1714,10 @@ node_ipv6_or_preferred(const node_t *node) node_assert_ok(node); /* XX/teor - node->ipv6_preferred is set from - * fascist_firewall_prefer_ipv6_orport() each time the consensus is loaded. + * reachable_addr_prefer_ipv6_orport() each time the consensus is loaded. */ node_get_prim_orport(node, &ipv4_addr); - if (!fascist_firewall_use_ipv6(options)) { + if (!reachable_addr_use_ipv6(options)) { return 0; } else if (node->ipv6_preferred || !tor_addr_port_is_valid_ap(&ipv4_addr, 0)) { @@ -1812,7 +1812,7 @@ node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out) * or * ii) our preference is for IPv6 Dir addresses. * - * If there is no node, use fascist_firewall_prefer_ipv6_dirport(). + * If there is no node, use reachable_addr_prefer_ipv6_dirport(). */ int node_ipv6_dir_preferred(const node_t *node) @@ -1821,15 +1821,15 @@ node_ipv6_dir_preferred(const node_t *node) tor_addr_port_t ipv4_addr; node_assert_ok(node); - /* node->ipv6_preferred is set from fascist_firewall_prefer_ipv6_orport(), + /* node->ipv6_preferred is set from reachable_addr_prefer_ipv6_orport(), * so we can't use it to determine DirPort IPv6 preference. * This means that bridge clients will use IPv4 DirPorts by default. */ node_get_prim_dirport(node, &ipv4_addr); - if (!fascist_firewall_use_ipv6(options)) { + if (!reachable_addr_use_ipv6(options)) { return 0; } else if (!tor_addr_port_is_valid_ap(&ipv4_addr, 0) - || fascist_firewall_prefer_ipv6_dirport(get_options())) { + || reachable_addr_prefer_ipv6_dirport(get_options())) { return node_has_ipv6_dirport(node); } return 0; @@ -1988,6 +1988,12 @@ node_set_country(node_t *node) else if (node->ri) ipv4_addr = &node->ri->ipv4_addr; + /* IPv4 is mandatory for a relay so this should not happen unless we are + * attempting to set the country code on a node without a descriptor. */ + if (BUG(!ipv4_addr)) { + node->country = -1; + return; + } node->country = geoip_get_country_by_addr(ipv4_addr); } diff --git a/src/feature/nodelist/routerlist.c b/src/feature/nodelist/routerlist.c index 72824f2dd2..9def90d8d5 100644 --- a/src/feature/nodelist/routerlist.c +++ b/src/feature/nodelist/routerlist.c @@ -539,7 +539,7 @@ routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2) * - <b>CRN_DIRECT_CONN</b>: is suitable for direct connections. Checks * for the relevant descriptors. Checks the address * against ReachableAddresses, ClientUseIPv4 0, and - * fascist_firewall_use_ipv6() == 0); + * reachable_addr_use_ipv6() == 0); * - <b>CRN_PREF_ADDR</b>: if we are connecting directly to the node, it has * an address that is preferred by the * ClientPreferIPv6ORPort setting; @@ -594,7 +594,7 @@ router_can_choose_node(const node_t *node, int flags) return false; /* Choose a node with an OR address that matches the firewall rules */ if (direct_conn && check_reach && - !fascist_firewall_allows_node(node, + !reachable_addr_allows_node(node, FIREWALL_OR_CONNECTION, pref_addr)) return false; diff --git a/src/feature/relay/circuitbuild_relay.c b/src/feature/relay/circuitbuild_relay.c index 881cbd51be..ad20e143be 100644 --- a/src/feature/relay/circuitbuild_relay.c +++ b/src/feature/relay/circuitbuild_relay.c @@ -501,7 +501,7 @@ circuit_extend(struct cell_t *cell, struct circuit_t *circ) circ->n_chan = n_chan; log_debug(LD_CIRC, "n_chan is %s.", - channel_get_canonical_remote_descr(n_chan)); + channel_describe_peer(n_chan)); if (circuit_deliver_create_cell(circ, &ec.create_cell, 1) < 0) return -1; diff --git a/src/feature/relay/ext_orport.c b/src/feature/relay/ext_orport.c index cff5f42cc7..2cf30262f5 100644 --- a/src/feature/relay/ext_orport.c +++ b/src/feature/relay/ext_orport.c @@ -494,6 +494,10 @@ connection_ext_or_handle_cmd_useraddr(connection_t *conn, } conn->address = tor_addr_to_str_dup(&addr); + /* Now that we know the address, we don't have to manually override rate + * limiting. */ + conn->always_rate_limit_as_remote = 0; + return 0; } diff --git a/src/feature/relay/relay_config.c b/src/feature/relay/relay_config.c index 7cb7f2ccfd..d3f904d286 100644 --- a/src/feature/relay/relay_config.c +++ b/src/feature/relay/relay_config.c @@ -133,12 +133,133 @@ port_warn_nonlocal_ext_orports(const smartlist_t *ports, const char *portname) } SMARTLIST_FOREACH_END(port); } +/** + * Return a static buffer describing the port number in @a port, which may + * CFG_AUTO_PORT. + **/ +static const char * +describe_portnum(int port) +{ + static char buf[16]; + if (port == CFG_AUTO_PORT) { + return "auto"; + } else { + tor_snprintf(buf, sizeof(buf), "%d", port); + return buf; + } +} + +/** Return a static buffer containing the human readable logging string that + * describes the given port object. */ +static const char * +describe_relay_port(const port_cfg_t *port) +{ + IF_BUG_ONCE(!port) { + return "<null port>"; + } + + static char buf[256]; + const char *type, *addr; + + switch (port->type) { + case CONN_TYPE_OR_LISTENER: + type = "OR"; + break; + case CONN_TYPE_DIR_LISTENER: + type = "Dir"; + break; + case CONN_TYPE_EXT_OR_LISTENER: + type = "ExtOR"; + break; + default: + type = ""; + break; + } + + if (port->explicit_addr) { + addr = fmt_and_decorate_addr(&port->addr); + } else { + addr = ""; + } + + tor_snprintf(buf, sizeof(buf), "%sPort %s%s%s", + type, addr, (strlen(addr) > 0) ? ":" : "", + describe_portnum(port->port)); + return buf; +} + +/** Attempt to find duplicate ORPort that would be superseded by another and + * remove them from the given ports list. This is possible if we have for + * instance: + * + * ORPort 9050 + * ORPort [4242::1]:9050 + * + * First one binds to both v4 and v6 address but second one is specific to an + * address superseding the global bind one. + * + * The following is O(n^2) but it is done at bootstrap or config reload and + * the list is not very long usually. */ +STATIC void +remove_duplicate_orports(smartlist_t *ports) +{ + /* First we'll decide what to remove, then we'll remove it. */ + bool *removing = tor_calloc(smartlist_len(ports), sizeof(bool)); + + for (int i = 0; i < smartlist_len(ports); ++i) { + const port_cfg_t *current = smartlist_get(ports, i); + if (removing[i]) { + continue; + } + + /* Skip non ORPorts. */ + if (current->type != CONN_TYPE_OR_LISTENER) { + continue; + } + + for (int j = 0; j < smartlist_len(ports); ++j) { + const port_cfg_t *next = smartlist_get(ports, j); + + /* Avoid comparing the same object. */ + if (current == next) { + continue; + } + if (removing[j]) { + continue; + } + /* Same address family and same port number, we have a match. */ + if (!current->explicit_addr && next->explicit_addr && + tor_addr_family(¤t->addr) == tor_addr_family(&next->addr) && + current->port == next->port) { + /* Remove current because next is explicitly set. */ + removing[i] = true; + char *next_str = tor_strdup(describe_relay_port(next)); + log_warn(LD_CONFIG, "Configuration port %s superseded by %s", + describe_relay_port(current), next_str); + tor_free(next_str); + } + } + } + + /* Iterate over array in reverse order to keep indices valid. */ + for (int i = smartlist_len(ports)-1; i >= 0; --i) { + tor_assert(i < smartlist_len(ports)); + if (removing[i]) { + port_cfg_t *current = smartlist_get(ports, i); + smartlist_del_keeporder(ports, i); + port_cfg_free(current); + } + } + + tor_free(removing); +} + /** Given a list of <b>port_cfg_t</b> in <b>ports</b>, check them for internal * consistency and warn as appropriate. On Unix-based OSes, set * *<b>n_low_ports_out</b> 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, +check_and_prune_server_ports(smartlist_t *ports, const or_options_t *options, int *n_low_ports_out) { @@ -159,6 +280,9 @@ check_server_ports(const smartlist_t *ports, int n_low_port = 0; int r = 0; + /* Remove possible duplicate ORPorts before inspecting the list. */ + remove_duplicate_orports(ports); + SMARTLIST_FOREACH_BEGIN(ports, const port_cfg_t *, port) { if (port->type == CONN_TYPE_DIR_LISTENER) { if (! port->server_cfg.no_advertise) @@ -271,6 +395,14 @@ port_parse_ports_relay(or_options_t *options, goto err; } if (port_parse_config(ports, + options->ORPort_lines, + "OR", CONN_TYPE_OR_LISTENER, + "[::]", 0, + CL_PORT_SERVER_OPTIONS) < 0) { + *msg = tor_strdup("Invalid ORPort configuration"); + goto err; + } + if (port_parse_config(ports, options->ExtORPort_lines, "ExtOR", CONN_TYPE_EXT_OR_LISTENER, "127.0.0.1", 0, @@ -287,7 +419,7 @@ port_parse_ports_relay(or_options_t *options, goto err; } - if (check_server_ports(ports, options, &n_low_ports) < 0) { + if (check_and_prune_server_ports(ports, options, &n_low_ports) < 0) { *msg = tor_strdup("Misconfigured server ports"); goto err; } diff --git a/src/feature/relay/relay_config.h b/src/feature/relay/relay_config.h index c70c322d88..671399ac0a 100644 --- a/src/feature/relay/relay_config.h +++ b/src/feature/relay/relay_config.h @@ -84,6 +84,7 @@ int options_act_relay_dir(const struct or_options_t *old_options); #ifdef RELAY_CONFIG_PRIVATE +STATIC void remove_duplicate_orports(struct smartlist_t *ports); STATIC int check_bridge_distribution_setting(const char *bd); STATIC int have_enough_mem_for_dircache(const struct or_options_t *options, size_t total_mem, char **msg); diff --git a/src/feature/relay/relay_find_addr.c b/src/feature/relay/relay_find_addr.c index 16d0a4733b..43b958d563 100644 --- a/src/feature/relay/relay_find_addr.c +++ b/src/feature/relay/relay_find_addr.c @@ -20,29 +20,12 @@ #include "feature/relay/router.h" #include "feature/relay/routermode.h" -/** The most recently guessed value of our IP address, based on directory - * headers. */ -static tor_addr_t last_guessed_ip = TOR_ADDR_NULL; - -/** We failed to resolve our address locally, but we'd like to build - * a descriptor and publish / test reachability. If we have a guess - * about our address based on directory headers, answer it and return - * 0; else return -1. */ -static int -router_guess_address_from_dir_headers(uint32_t *guess) -{ - if (!tor_addr_is_null(&last_guessed_ip)) { - *guess = tor_addr_to_ipv4h(&last_guessed_ip); - return 0; - } - return -1; -} - /** Consider the address suggestion suggested_addr as a possible one to use as * our address. * - * This is called when a valid NETINFO cell is recevied containing a candidate - * for our address. + * This is called when a valid NETINFO cell is received containing a candidate + * for our address or when a directory sends us back the X-Your-Address-Is + * header. * * The suggested address is ignored if it does NOT come from a trusted source. * At the moment, we only look a trusted directory authorities. @@ -51,6 +34,9 @@ router_guess_address_from_dir_headers(uint32_t *guess) * given peer_addr which is the address from the endpoint that sent the * NETINFO cell. * + * The identity_digest is NULL if this is an address suggested by a directory + * since this is a plaintext connection. + * * The suggested address is set in our suggested address cache if everything * passes. */ void @@ -62,7 +48,6 @@ relay_address_new_suggestion(const tor_addr_t *suggested_addr, tor_assert(suggested_addr); tor_assert(peer_addr); - tor_assert(identity_digest); /* Non server should just ignore this suggestion. Clients don't need to * learn their address let alone cache it. */ @@ -73,7 +58,7 @@ relay_address_new_suggestion(const tor_addr_t *suggested_addr, /* Is the peer a trusted source? Ignore anything coming from non trusted * source. In this case, we only look at trusted directory authorities. */ if (!router_addr_is_trusted_dir(peer_addr) || - !router_digest_is_trusted_dir(identity_digest)) { + (identity_digest && !router_digest_is_trusted_dir(identity_digest))) { return; } @@ -95,110 +80,74 @@ relay_address_new_suggestion(const tor_addr_t *suggested_addr, resolved_addr_set_suggested(suggested_addr); } -/** A directory server <b>d_conn</b> told us our IP address is - * <b>suggestion</b>. - * If this address is different from the one we think we are now, and - * if our computer doesn't actually know its IP address, then switch. */ -void -router_new_address_suggestion(const char *suggestion, - const dir_connection_t *d_conn) +/** Find our address to be published in our descriptor. Three places are + * looked at: + * + * 1. Resolved cache. Populated by find_my_address() during the relay + * periodic event that attempts to learn if our address has changed. + * + * 2. If flags is set with RELAY_FIND_ADDR_CACHE_ONLY, only the resolved + * and suggested cache are looked at. No address discovery will be done. + * + * 3. Finally, if all fails, use the suggested address cache which is + * populated by the NETINFO cell content or HTTP header from a + * directory. + * + * Return true on success and addr_out contains the address to use for the + * given family. On failure to find the address, false is returned and + * addr_out is set to an AF_UNSPEC address. */ +MOCK_IMPL(bool, +relay_find_addr_to_publish, (const or_options_t *options, int family, + int flags, tor_addr_t *addr_out)) { - tor_addr_t addr, my_addr, last_resolved_addr; - const or_options_t *options = get_options(); - - /* first, learn what the IP address actually is */ - if (tor_addr_parse(&addr, suggestion) == -1) { - log_debug(LD_DIR, "Malformed X-Your-Address-Is header %s. Ignoring.", - escaped(suggestion)); - return; - } + tor_assert(options); + tor_assert(addr_out); - log_debug(LD_DIR, "Got X-Your-Address-Is: %s.", suggestion); + tor_addr_make_unspec(addr_out); - if (!server_mode(options)) { - tor_addr_copy(&last_guessed_ip, &addr); - return; + /* If an IPv6 is requested, check if IPv6 address discovery is disabled on + * this instance. If so, we return a failure. It is done here so we don't + * query the suggested cache that might be populated with an IPv6. */ + if (family == AF_INET6 && options->AddressDisableIPv6) { + return false; } - /* XXXX ipv6 */ - resolved_addr_get_last(AF_INET, &last_resolved_addr); - if (!tor_addr_is_null(&last_resolved_addr)) { - /* Lets use this one. */ - tor_addr_copy(&last_guessed_ip, &last_resolved_addr); - return; + /* First, check our resolved address cache. It should contain the address + * we've discovered from the periodic relay event. */ + resolved_addr_get_last(family, addr_out); + if (!tor_addr_is_null(addr_out)) { + goto found; } - /* Attempt to find our address. */ - if (find_my_address(options, AF_INET, LOG_INFO, &my_addr, NULL, NULL)) { - /* We're all set -- we already know our address. Great. */ - tor_addr_copy(&last_guessed_ip, &my_addr); /* store it in case we - need it later */ - return; + /* Second, attempt to find our address. The following can do a DNS resolve + * thus only do it when the no cache only flag is flipped. */ + if (!(flags & RELAY_FIND_ADDR_CACHE_ONLY)) { + if (find_my_address(options, family, LOG_INFO, addr_out, NULL, NULL)) { + goto found; + } } - /* Consider the suggestion from the directory. */ - if (tor_addr_is_internal(&addr, 0)) { - /* Don't believe anybody who says our IP is, say, 127.0.0.1. */ - return; - } - if (tor_addr_eq(&d_conn->base_.addr, &addr)) { - /* Don't believe anybody who says our IP is their IP. */ - log_debug(LD_DIR, "A directory server told us our IP address is %s, " - "but they are just reporting their own IP address. Ignoring.", - suggestion); - return; + /* Third, consider address from our suggestion cache. */ + resolved_addr_get_suggested(family, addr_out); + if (!tor_addr_is_null(addr_out)) { + goto found; } - /* Okay. We can't resolve our own address, and X-Your-Address-Is is giving - * us an answer different from what we had the last time we managed to - * resolve it. */ - if (!tor_addr_eq(&last_guessed_ip, &addr)) { - control_event_server_status(LOG_NOTICE, - "EXTERNAL_ADDRESS ADDRESS=%s METHOD=DIRSERV", - suggestion); - log_addr_has_changed(LOG_NOTICE, &last_guessed_ip, &addr, - d_conn->base_.address); - ip_address_changed(0); - tor_addr_copy(&last_guessed_ip, &addr); /* router_rebuild_descriptor() - will fetch it */ - } + /* No publishable address was found. */ + return false; + + found: + return true; } -/** Make a current best guess at our address, either because - * it's configured in torrc, or because we've learned it from - * dirserver headers. Place the answer in *<b>addr</b> and return - * 0 on success, else return -1 if we have no guess. +/** Return true iff this relay has an address set for the given family. * - * If <b>cache_only</b> is true, just return any cached answers, and - * don't try to get any new answers. - */ -MOCK_IMPL(int, -router_pick_published_address, (const or_options_t *options, uint32_t *addr, - int cache_only)) + * This only checks the caches so it will not trigger a full discovery of the + * address. */ +bool +relay_has_address_set(int family) { - tor_addr_t last_resolved_addr; - - /* First, check the cached output from find_my_address(). */ - resolved_addr_get_last(AF_INET, &last_resolved_addr); - if (!tor_addr_is_null(&last_resolved_addr)) { - *addr = tor_addr_to_ipv4h(&last_resolved_addr); - return 0; - } - - /* Second, consider doing a resolve attempt right here. */ - if (!cache_only) { - tor_addr_t my_addr; - if (find_my_address(options, AF_INET, LOG_INFO, &my_addr, NULL, NULL)) { - log_info(LD_CONFIG,"Success: chose address '%s'.", fmt_addr(&my_addr)); - *addr = tor_addr_to_ipv4h(&my_addr); - return 0; - } - } - - /* Third, check the cached output from router_new_address_suggestion(). */ - if (router_guess_address_from_dir_headers(addr) >= 0) - return 0; - - /* We have no useful cached answers. Return failure. */ - return -1; + tor_addr_t addr; + return relay_find_addr_to_publish(get_options(), family, + RELAY_FIND_ADDR_CACHE_ONLY, &addr); } diff --git a/src/feature/relay/relay_find_addr.h b/src/feature/relay/relay_find_addr.h index 6f298e6c79..3d30946b05 100644 --- a/src/feature/relay/relay_find_addr.h +++ b/src/feature/relay/relay_find_addr.h @@ -9,16 +9,21 @@ #ifndef TOR_RELAY_FIND_ADDR_H #define TOR_RELAY_FIND_ADDR_H -MOCK_DECL(int, router_pick_published_address, - (const or_options_t *options, uint32_t *addr, int cache_only)); - -void router_new_address_suggestion(const char *suggestion, - const dir_connection_t *d_conn); +typedef enum { + RELAY_FIND_ADDR_NO_FLAG = (1U << 0), + RELAY_FIND_ADDR_CACHE_ONLY = (1U << 1), +} relay_find_addr_flags_t; void relay_address_new_suggestion(const tor_addr_t *suggested_addr, const tor_addr_t *peer_addr, const char *identity_digest); +MOCK_DECL(bool, relay_find_addr_to_publish, + (const or_options_t *options, int family, int flags, + tor_addr_t *addr_out)); + +bool relay_has_address_set(int family); + #ifdef RELAY_FIND_ADDR_PRIVATE #endif /* RELAY_FIND_ADDR_PRIVATE */ diff --git a/src/feature/relay/relay_periodic.c b/src/feature/relay/relay_periodic.c index cc346bc3fc..ac54064901 100644 --- a/src/feature/relay/relay_periodic.c +++ b/src/feature/relay/relay_periodic.c @@ -12,6 +12,8 @@ #include "orconfig.h" #include "core/or/or.h" +#include "app/config/resolve_addr.h" + #include "core/mainloop/periodic.h" #include "core/mainloop/cpuworker.h" // XXXX use a pubsub event. #include "core/mainloop/mainloop.h" @@ -152,6 +154,9 @@ check_for_reachability_bw_callback(time_t now, const or_options_t *options) { /* XXXX This whole thing was stuck in the middle of what is now * XXXX check_descriptor_callback. I'm not sure it's right. */ + /** How often should we consider launching reachability tests in our first + * TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT seconds? */ +#define EARLY_CHECK_REACHABILITY_INTERVAL (60) /* also, check religiously for reachability, if it's within the first * 20 minutes of our uptime. */ @@ -162,7 +167,7 @@ check_for_reachability_bw_callback(time_t now, const or_options_t *options) router_do_reachability_checks(1, dirport_reachability_count==0); if (++dirport_reachability_count > 5) dirport_reachability_count = 0; - return 1; + return EARLY_CHECK_REACHABILITY_INTERVAL; } else { /* If we haven't checked for 12 hours and our bandwidth estimate is * low, do another bandwidth test. This is especially important for @@ -218,14 +223,31 @@ reachability_warnings_callback(time_t now, const or_options_t *options) tor_asprintf(&where6, "[%s]:%d", address6, me->ipv6_orport); const char *opt_and = (!v4_ok && !v6_ok) ? "and" : ""; - log_warn(LD_CONFIG, - "Your server has not managed to confirm reachability for " - "its ORPort(s) at %s%s%s. Relays do not publish descriptors " - "until their ORPort and DirPort are reachable. Please check " - "your firewalls, ports, address, /etc/hosts file, etc.", - where4?where4:"", - opt_and, - where6?where6:""); + /* IPv4 reachability test worked but not the IPv6. We will _not_ + * publish the descriptor if our IPv6 was configured. We will if it + * was auto discovered. */ + if (v4_ok && !v6_ok && !resolved_addr_is_configured(AF_INET6)) { + static ratelim_t rlim = RATELIM_INIT(3600); + log_fn_ratelim(&rlim, LOG_NOTICE, LD_CONFIG, + "Auto-discovered IPv6 address %s has not been found " + "reachable. However, IPv4 address is reachable. " + "Publishing server descriptor without IPv6 address.", + where6 ? where6 : ""); + /* Indicate we want to publish even if reachability test failed. */ + mark_my_descriptor_if_omit_ipv6_changes("IPv4 is reachable. " + "IPv6 is not but was " + "auto-discovered", true); + } else { + log_warn(LD_CONFIG, + "Your server has not managed to confirm reachability for " + "its ORPort(s) at %s%s%s. Relays do not publish " + "descriptors until their ORPort and DirPort are " + "reachable. Please check your firewalls, ports, address, " + "/etc/hosts file, etc.", + where4?where4:"", + opt_and, + where6?where6:""); + } tor_free(where4); tor_free(where6); if (!v4_ok) { diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c index 4f4ba8559b..675b977ade 100644 --- a/src/feature/relay/router.c +++ b/src/feature/relay/router.c @@ -38,6 +38,7 @@ #include "feature/relay/dns.h" #include "feature/relay/relay_config.h" #include "feature/relay/relay_find_addr.h" +#include "feature/relay/relay_periodic.h" #include "feature/relay/router.h" #include "feature/relay/routerkeys.h" #include "feature/relay/routermode.h" @@ -834,7 +835,7 @@ router_initialize_tls_context(void) STATIC int router_write_fingerprint(int hashed, int ed25519_identity) { - char *keydir = NULL, *cp = NULL; + char *keydir = NULL; const char *fname = hashed ? "hashed-fingerprint" : (ed25519_identity ? "fingerprint-ed25519" : "fingerprint"); @@ -869,15 +870,11 @@ router_write_fingerprint(int hashed, int ed25519_identity) tor_asprintf(&fingerprint_line, "%s %s\n", options->Nickname, fingerprint); /* Check whether we need to write the (hashed-)fingerprint file. */ - - cp = read_file_to_str(keydir, RFTS_IGNORE_MISSING, NULL); - if (!cp || strcmp(cp, fingerprint_line)) { - if (write_str_to_file(keydir, fingerprint_line, 0)) { - log_err(LD_FS, "Error writing %s%s line to file", - hashed ? "hashed " : "", - ed25519_identity ? "ed25519 identity" : "fingerprint"); - goto done; - } + if (write_str_to_file_if_not_equal(keydir, fingerprint_line)) { + log_err(LD_FS, "Error writing %s%s line to file", + hashed ? "hashed " : "", + ed25519_identity ? "ed25519 identity" : "fingerprint"); + goto done; } log_notice(LD_GENERAL, "Your Tor %s identity key %s fingerprint is '%s %s'", @@ -887,7 +884,6 @@ router_write_fingerprint(int hashed, int ed25519_identity) result = 0; done: - tor_free(cp); tor_free(keydir); tor_free(fingerprint_line); return result; @@ -1150,10 +1146,10 @@ init_keys(void) ds = router_get_trusteddirserver_by_digest(digest); if (!ds) { tor_addr_port_t ipv6_orport; - router_get_advertised_ipv6_or_ap(options, &ipv6_orport); + routerconf_find_ipv6_or_ap(options, &ipv6_orport); ds = trusted_dir_server_new(options->Nickname, NULL, - router_get_advertised_dir_port(options, 0), - router_get_advertised_or_port(options), + routerconf_find_dir_port(options, 0), + routerconf_find_or_port(options,AF_INET), &ipv6_orport, digest, v3_digest, @@ -1305,10 +1301,10 @@ decide_to_advertise_dir_impl(const or_options_t *options, return 1; if (net_is_disabled()) return 0; - if (dir_port && !router_get_advertised_dir_port(options, dir_port)) + if (dir_port && !routerconf_find_dir_port(options, dir_port)) return 0; if (supports_tunnelled_dir_requests && - !router_get_advertised_or_port(options)) + !routerconf_find_or_port(options, AF_INET)) return 0; /* Part two: consider config options that could make us choose to @@ -1389,7 +1385,7 @@ decide_if_publishable_server(void) return 0; if (authdir_mode(options)) return 1; - if (!router_get_advertised_or_port(options)) + if (!routerconf_find_or_port(options, AF_INET)) return 0; if (!router_orport_seems_reachable(options, AF_INET)) { // We have an ipv4 orport, and it doesn't seem reachable. @@ -1458,22 +1454,14 @@ router_get_active_listener_port_by_type_af(int listener_type, return 0; } -/** Return the port that we should advertise as our ORPort; this is either - * the one configured in the ORPort option, or the one we actually bound to - * if ORPort is "auto". Returns 0 if no port is found. */ +/** Return the port that we should advertise as our ORPort in a given address + * family; this is either the one configured in the ORPort option, or the one + * we actually bound to if ORPort is "auto". Returns 0 if no port is found. */ uint16_t -router_get_advertised_or_port(const or_options_t *options) +routerconf_find_or_port(const or_options_t *options, + sa_family_t family) { - return router_get_advertised_or_port_by_af(options, AF_INET); -} - -/** As router_get_advertised_or_port(), but allows an address family argument. - */ -uint16_t -router_get_advertised_or_port_by_af(const or_options_t *options, - sa_family_t family) -{ - int port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER, + int port = portconf_get_first_advertised_port(CONN_TYPE_OR_LISTENER, family); (void)options; @@ -1486,11 +1474,11 @@ router_get_advertised_or_port_by_af(const or_options_t *options, return port; } -/** As router_get_advertised_or_port(), but returns the IPv6 address and +/** As routerconf_find_or_port(), but returns the IPv6 address and * port in ipv6_ap_out, which must not be NULL. Returns a null address and * zero port, if no ORPort is found. */ void -router_get_advertised_ipv6_or_ap(const or_options_t *options, +routerconf_find_ipv6_or_ap(const or_options_t *options, tor_addr_port_t *ipv6_ap_out) { /* Bug in calling function, we can't return a sensible result, and it @@ -1501,11 +1489,10 @@ router_get_advertised_ipv6_or_ap(const or_options_t *options, tor_addr_make_null(&ipv6_ap_out->addr, AF_INET6); ipv6_ap_out->port = 0; - const tor_addr_t *addr = get_first_advertised_addr_by_type_af( + const tor_addr_t *addr = portconf_get_first_advertised_addr( CONN_TYPE_OR_LISTENER, AF_INET6); - const uint16_t port = router_get_advertised_or_port_by_af( - options, + const uint16_t port = routerconf_find_or_port(options, AF_INET6); if (!addr || port == 0) { @@ -1532,11 +1519,18 @@ router_get_advertised_ipv6_or_ap(const or_options_t *options, /** Returns true if this router has an advertised IPv6 ORPort. */ bool -router_has_advertised_ipv6_orport(const or_options_t *options) +routerconf_has_ipv6_orport(const or_options_t *options) { - tor_addr_port_t ipv6_ap; - router_get_advertised_ipv6_or_ap(options, &ipv6_ap); - return tor_addr_port_is_valid_ap(&ipv6_ap, 0); + /* What we want here is to learn if we have configured an IPv6 ORPort. + * Remember, ORPort can listen on [::] and thus consider internal by + * router_get_advertised_ipv6_or_ap() since we do _not_ want to advertise + * such address. */ + const tor_addr_t *addr = + portconf_get_first_advertised_addr(CONN_TYPE_OR_LISTENER, AF_INET6); + const uint16_t port = + routerconf_find_or_port(options, AF_INET6); + + return tor_addr_port_is_valid(addr, port, 1); } /** Returns true if this router can extend over IPv6. @@ -1560,7 +1554,7 @@ router_can_extend_over_ipv6,(const or_options_t *options)) { /* We might add some extra checks here, such as ExtendAllowIPv6Addresses * from ticket 33818. */ - return router_has_advertised_ipv6_orport(options); + return routerconf_has_ipv6_orport(options); } /** Return the port that we should advertise as our DirPort; @@ -1569,9 +1563,9 @@ router_can_extend_over_ipv6,(const or_options_t *options)) * the one configured in the DirPort option, * or the one we actually bound to if DirPort is "auto". */ uint16_t -router_get_advertised_dir_port(const or_options_t *options, uint16_t dirport) +routerconf_find_dir_port(const or_options_t *options, uint16_t dirport) { - int dirport_configured = get_primary_dir_port(); + int dirport_configured = portconf_get_primary_dir_port(); (void)options; if (!dirport_configured) @@ -1757,16 +1751,6 @@ router_get_my_routerinfo_with_err,(int *err)) return NULL; } - if (!desc_clean_since) { - int rebuild_err = router_rebuild_descriptor(0); - if (rebuild_err < 0) { - if (err) - *err = rebuild_err; - - return NULL; - } - } - if (!desc_routerinfo) { if (err) *err = TOR_ROUTERINFO_ERROR_DESC_REBUILDING; @@ -1822,54 +1806,55 @@ router_get_descriptor_gen_reason(void) * 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, +router_check_descriptor_address_port_consistency(const tor_addr_t *addr, int listener_type) { + int family, port_cfg; + + tor_assert(addr); 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. + family = tor_addr_family(addr); + /* The first advertised Port may be the magic constant CFG_AUTO_PORT. */ + port_cfg = portconf_get_first_advertised_port(listener_type, family); + if (port_cfg != 0 && + !port_exists_by_type_addr_port(listener_type, addr, port_cfg, 1)) { + const tor_addr_t *port_addr = + portconf_get_first_advertised_addr(listener_type, family); + /* If we're building a descriptor with no advertised address, + * something is terribly wrong. */ + tor_assert(port_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_to_str(desc_addr_str, addr, TOR_ADDR_BUF_LEN, 0); + + const char *listener_str = (listener_type == CONN_TYPE_OR_LISTENER ? + "OR" : "Dir"); + const char *af_str = fmt_af_family(family); + log_warn(LD_CONFIG, "The %s %sPort address %s does not match the " + "descriptor address %s. If you have a static public IPv4 " + "address, use 'Address <%s>' and 'OutboundBindAddress " + "<%s>'. If you are behind a NAT, use two %sPort lines: " + "'%sPort <PublicPort> NoListen' and '%sPort <InternalPort> " + "NoAdvertise'.", + af_str, listener_str, port_addr_str, desc_addr_str, af_str, + af_str, listener_str, listener_str, listener_str); + } +} + +/** Tor relays only have one IPv4 or/and one IPv6 address in the descriptor, + * which is derived from the Address torrc option, or guessed using various + * methods in relay_find_addr_to_publish(). + * + * Warn the operator if there is no ORPort associated with the given address + * in 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 @@ -1878,20 +1863,22 @@ router_check_descriptor_address_port_consistency(uint32_t ipv4h_desc_addr, * 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). - */ + * the Address (using NoListen if needed). */ static void -router_check_descriptor_address_consistency(uint32_t ipv4h_desc_addr) +router_check_descriptor_address_consistency(const tor_addr_t *addr) { - router_check_descriptor_address_port_consistency(ipv4h_desc_addr, + router_check_descriptor_address_port_consistency(addr, CONN_TYPE_OR_LISTENER); - router_check_descriptor_address_port_consistency(ipv4h_desc_addr, + router_check_descriptor_address_port_consistency(addr, CONN_TYPE_DIR_LISTENER); } @@ -2033,33 +2020,56 @@ MOCK_IMPL(STATIC int, router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out)) { routerinfo_t *ri = NULL; - uint32_t addr; + tor_addr_t ipv4_addr, ipv6_addr; char platform[256]; int hibernating = we_are_hibernating(); const or_options_t *options = get_options(); int result = TOR_ROUTERINFO_ERROR_INTERNAL_BUG; + uint16_t ipv6_orport = 0; if (BUG(!ri_out)) { result = TOR_ROUTERINFO_ERROR_INTERNAL_BUG; goto err; } - if (router_pick_published_address(options, &addr, 0) < 0) { + /* Find our resolved address both IPv4 and IPv6. In case the address is not + * found, the object is set to an UNSPEC address. */ + bool have_v4 = relay_find_addr_to_publish(options, AF_INET, + RELAY_FIND_ADDR_NO_FLAG, + &ipv4_addr); + bool have_v6 = relay_find_addr_to_publish(options, AF_INET6, + RELAY_FIND_ADDR_NO_FLAG, + &ipv6_addr); + + /* Tor requires a relay to have an IPv4 so bail if we can't find it. */ + if (!have_v4) { log_warn(LD_CONFIG, "Don't know my address while generating descriptor"); result = TOR_ROUTERINFO_ERROR_NO_EXT_ADDR; goto err; } - /* 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); + router_check_descriptor_address_consistency(&ipv4_addr); + router_check_descriptor_address_consistency(&ipv6_addr); ri = tor_malloc_zero(sizeof(routerinfo_t)); ri->cache_info.routerlist_index = -1; ri->nickname = tor_strdup(options->Nickname); - tor_addr_from_ipv4h(&ri->ipv4_addr, addr); - ri->ipv4_orport = router_get_advertised_or_port(options); - ri->ipv4_dirport = router_get_advertised_dir_port(options, 0); + + /* IPv4. */ + tor_addr_copy(&ri->ipv4_addr, &ipv4_addr); + ri->ipv4_orport = routerconf_find_or_port(options, AF_INET); + ri->ipv4_dirport = routerconf_find_dir_port(options, 0); + + /* IPv6. Do not publish an IPv6 if we don't have an ORPort that can be used + * with the address. This is possible for instance if the ORPort is + * IPv4Only. */ + ipv6_orport = routerconf_find_or_port(options, AF_INET6); + if (have_v6 && ipv6_orport != 0) { + tor_addr_copy(&ri->ipv6_addr, &ipv6_addr); + ri->ipv6_orport = ipv6_orport; + } + ri->supports_tunnelled_dir_requests = directory_permits_begindir_requests(options); ri->cache_info.published_on = time(NULL); @@ -2071,13 +2081,6 @@ router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out)) tor_memdup(&get_current_curve25519_keypair()->pubkey, sizeof(curve25519_public_key_t)); - /* For now, at most one IPv6 or-address is being advertised. */ - tor_addr_port_t ipv6_orport; - router_get_advertised_ipv6_or_ap(options, &ipv6_orport); - /* If there is no valid IPv6 ORPort, the address and port are null. */ - tor_addr_copy(&ri->ipv6_addr, &ipv6_orport.addr); - ri->ipv6_orport = ipv6_orport.port; - ri->identity_pkey = crypto_pk_dup_key(get_server_identity_key()); if (BUG(crypto_pk_get_digest(ri->identity_pkey, ri->cache_info.identity_digest) < 0)) { @@ -2389,21 +2392,10 @@ router_rebuild_descriptor(int force) int err = 0; routerinfo_t *ri; extrainfo_t *ei; - uint32_t addr; - const or_options_t *options = get_options(); if (desc_clean_since && !force) return 0; - if (router_pick_published_address(options, &addr, 0) < 0 || - router_get_advertised_or_port(options) == 0) { - /* Stop trying to rebuild our descriptor every second. We'll - * learn that it's time to try again when ip_address_changed() - * marks it dirty. */ - desc_clean_since = time(NULL); - return TOR_ROUTERINFO_ERROR_DESC_REBUILDING; - } - log_info(LD_OR, "Rebuilding relay descriptor%s", force ? " (forced)" : ""); err = router_build_fresh_descriptor(&ri, &ei); @@ -2445,6 +2437,34 @@ router_new_consensus_params(const networkstatus_t *ns) publish_even_when_ipv6_orport_unreachable = ar || ar6; } +/** Indicate if the IPv6 address should be omitted from the descriptor when + * publishing it. This can happen if the IPv4 is reachable but the + * auto-discovered IPv6 is not. We still publish the descriptor. + * + * Only relays should look at this and only for their descriptor. + * + * XXX: The real harder fix is to never put in the routerinfo_t a non + * reachable address and instead use the last resolved address cache to do + * reachability test or anything that has to do with what address tor thinks + * it has. */ +static bool omit_ipv6_on_publish = false; + +/** Mark our descriptor out of data iff the IPv6 omit status flag is flipped + * it changes from its previous value. + * + * This is used when our IPv6 port is found reachable or not. */ +void +mark_my_descriptor_if_omit_ipv6_changes(const char *reason, bool omit_ipv6) +{ + bool previous = omit_ipv6_on_publish; + omit_ipv6_on_publish = omit_ipv6; + + /* Only mark it dirty if the IPv6 omit flag was flipped. */ + if (previous != omit_ipv6) { + mark_my_descriptor_dirty(reason); + } +} + /** If our router descriptor ever goes this long without being regenerated * because something changed, we force an immediate regenerate-and-upload. */ #define FORCE_REGENERATE_DESCRIPTOR_INTERVAL (18*60*60) @@ -2503,11 +2523,13 @@ mark_my_descriptor_dirty(const char *reason) if (BUG(reason == NULL)) { reason = "marked descriptor dirty for unspecified reason"; } - if (server_mode(options) && options->PublishServerDescriptor_) + if (server_mode(options) && options->PublishServerDescriptor_) { log_info(LD_OR, "Decided to publish new relay descriptor: %s", reason); + } desc_clean_since = 0; if (!desc_dirty_reason) desc_dirty_reason = reason; + reschedule_descriptor_update_check(); } /** How frequently will we republish our descriptor because of large (factor @@ -2590,51 +2612,59 @@ log_addr_has_changed(int severity, addrbuf_cur, source); } -/** Check whether our own address as defined by the Address configuration - * has changed. This is for routers that get their address from a service - * like dyndns. If our address has changed, mark our descriptor dirty. */ +/** Check whether our own address has changed versus the one we have in our + * current descriptor. + * + * If our address has changed, call ip_address_changed() which takes + * appropriate actions. */ void check_descriptor_ipaddress_changed(time_t now) { - uint32_t prev, cur; - tor_addr_t addr; - const or_options_t *options = get_options(); - const char *method = NULL; - char *hostname = NULL; const routerinfo_t *my_ri = router_get_my_routerinfo(); + resolved_addr_method_t method = RESOLVED_ADDR_NONE; + char *hostname = NULL; + int families[2] = { AF_INET, AF_INET6 }; + bool has_changed = false; (void) now; - if (my_ri == NULL) /* make sure routerinfo exists */ - return; - - /* XXXX ipv6 */ - prev = tor_addr_to_ipv4h(&my_ri->ipv4_addr); - if (!find_my_address(options, AF_INET, LOG_INFO, &addr, &method, - &hostname)) { - log_info(LD_CONFIG,"options->Address didn't resolve into an IP."); + /* We can't learn our descriptor address without one. */ + if (my_ri == NULL) { return; } - cur = tor_addr_to_ipv4h(&addr); - if (prev != cur) { - char *source; - tor_addr_t tmp_prev, tmp_cur; + for (size_t i = 0; i < ARRAY_LENGTH(families); i++) { + tor_addr_t current; + const tor_addr_t *previous; + int family = families[i]; - tor_addr_from_ipv4h(&tmp_prev, prev); - tor_addr_from_ipv4h(&tmp_cur, cur); - - tor_asprintf(&source, "METHOD=%s%s%s", method, - hostname ? " HOSTNAME=" : "", - hostname ? hostname : ""); + /* Get the descriptor address from the family we are looking up. */ + previous = &my_ri->ipv4_addr; + if (family == AF_INET6) { + previous = &my_ri->ipv6_addr; + } - log_addr_has_changed(LOG_NOTICE, &tmp_prev, &tmp_cur, source); - tor_free(source); + /* Ignore returned value because we want to notice not only an address + * change but also if an address is lost (current == UNSPEC). */ + find_my_address(get_options(), family, LOG_INFO, ¤t, &method, + &hostname); + + if (!tor_addr_eq(previous, ¤t)) { + char *source; + tor_asprintf(&source, "METHOD=%s%s%s", + resolved_addr_method_to_str(method), + hostname ? " HOSTNAME=" : "", + hostname ? hostname : ""); + log_addr_has_changed(LOG_NOTICE, previous, ¤t, source); + tor_free(source); + has_changed = true; + } + tor_free(hostname); + } + if (has_changed) { ip_address_changed(0); } - - tor_free(hostname); } /** Set <b>platform</b> (max length <b>len</b>) to a NUL-terminated short @@ -2840,7 +2870,7 @@ router_dump_router_to_string(routerinfo_t *router, } } - if (router->ipv6_orport && + if (!omit_ipv6_on_publish && router->ipv6_orport && tor_addr_family(&router->ipv6_addr) == AF_INET6) { char addr[TOR_ADDR_BUF_LEN]; const char *a; @@ -2929,11 +2959,9 @@ router_dump_router_to_string(routerinfo_t *router, } if (router->onion_curve25519_pkey) { - char kbuf[128]; - base64_encode(kbuf, sizeof(kbuf), - (const char *)router->onion_curve25519_pkey->public_key, - CURVE25519_PUBKEY_LEN, BASE64_ENCODE_MULTILINE); - smartlist_add_asprintf(chunks, "ntor-onion-key %s", kbuf); + char kbuf[CURVE25519_BASE64_PADDED_LEN + 1]; + curve25519_public_to_base64(kbuf, router->onion_curve25519_pkey, false); + smartlist_add_asprintf(chunks, "ntor-onion-key %s\n", kbuf); } else { /* Authorities will start rejecting relays without ntor keys in 0.2.9 */ log_err(LD_BUG, "A relay must have an ntor onion key"); diff --git a/src/feature/relay/router.h b/src/feature/relay/router.h index fab109be7c..89b4a479a4 100644 --- a/src/feature/relay/router.h +++ b/src/feature/relay/router.h @@ -65,14 +65,13 @@ int init_keys_client(void); uint16_t router_get_active_listener_port_by_type_af(int listener_type, sa_family_t family); -uint16_t router_get_advertised_or_port(const or_options_t *options); -void router_get_advertised_ipv6_or_ap(const or_options_t *options, +void routerconf_find_ipv6_or_ap(const or_options_t *options, tor_addr_port_t *ipv6_ap_out); -bool router_has_advertised_ipv6_orport(const or_options_t *options); +bool routerconf_has_ipv6_orport(const or_options_t *options); MOCK_DECL(bool, router_can_extend_over_ipv6,(const or_options_t *options)); -uint16_t router_get_advertised_or_port_by_af(const or_options_t *options, - sa_family_t family); -uint16_t router_get_advertised_dir_port(const or_options_t *options, +uint16_t routerconf_find_or_port(const or_options_t *options, + sa_family_t family); +uint16_t routerconf_find_dir_port(const or_options_t *options, uint16_t dirport); int router_should_advertise_dirport(const or_options_t *options, @@ -85,6 +84,8 @@ void router_new_consensus_params(const networkstatus_t *); void router_upload_dir_desc_to_dirservers(int force); void mark_my_descriptor_dirty_if_too_old(time_t now); void mark_my_descriptor_dirty(const char *reason); +void mark_my_descriptor_if_omit_ipv6_changes(const char *reason, + bool omit_ipv6); void check_descriptor_bandwidth_changed(time_t now); void check_descriptor_ipaddress_changed(time_t now); int router_has_bandwidth_to_be_dirserver(const or_options_t *options); diff --git a/src/feature/relay/routerkeys.c b/src/feature/relay/routerkeys.c index d3de83cb86..744a73d936 100644 --- a/src/feature/relay/routerkeys.c +++ b/src/feature/relay/routerkeys.c @@ -519,19 +519,33 @@ print_cert_expiration(const char *expiration, /** * Log when a certificate, <b>cert</b>, with some <b>description</b> and - * stored in a file named <b>fname</b>, is going to expire. + * stored in a file named <b>fname</b>, is going to expire. Formats the expire + * time according to <b>time_format</b>. */ static void log_ed_cert_expiration(const tor_cert_t *cert, const char *description, - const char *fname) { - char expiration[ISO_TIME_LEN+1]; - + const char *fname, + key_expiration_format_t time_format) { if (BUG(!cert)) { /* If the specified key hasn't been loaded */ log_warn(LD_OR, "No %s key loaded; can't get certificate expiration.", description); } else { - format_local_iso_time(expiration, cert->valid_until); + char expiration[ISO_TIME_LEN+1]; + switch (time_format) { + case KEY_EXPIRATION_FORMAT_ISO8601: + format_local_iso_time(expiration, cert->valid_until); + break; + + case KEY_EXPIRATION_FORMAT_TIMESTAMP: + tor_snprintf(expiration, sizeof(expiration), "%"PRId64, + (int64_t) cert->valid_until); + break; + + default: + log_err(LD_BUG, "Unknown time format value: %d.", time_format); + return; + } log_notice(LD_OR, "The %s certificate stored in %s is valid until %s.", description, fname, expiration); print_cert_expiration(expiration, description); @@ -567,7 +581,8 @@ log_master_signing_key_cert_expiration(const or_options_t *options) /* If we do have a signing key, log the expiration time. */ if (signing_key) { - log_ed_cert_expiration(signing_key, "signing", fn); + key_expiration_format_t time_format = options->key_expiration_format; + log_ed_cert_expiration(signing_key, "signing", fn, time_format); } else { log_warn(LD_OR, "Could not load signing key certificate from %s, so " \ "we couldn't learn anything about certificate expiration.", fn); diff --git a/src/feature/relay/selftest.c b/src/feature/relay/selftest.c index d24748b297..87ba29c130 100644 --- a/src/feature/relay/selftest.c +++ b/src/feature/relay/selftest.c @@ -57,11 +57,24 @@ static bool can_reach_or_port_ipv6 = false; /** Whether we can reach our DirPort from the outside. */ static bool can_reach_dir_port = false; +/** Has informed_testing_reachable logged a message about testing our IPv4 + * ORPort? */ +static bool have_informed_testing_or_port_ipv4 = false; +/** Has informed_testing_reachable logged a message about testing our IPv6 + * ORPort? */ +static bool have_informed_testing_or_port_ipv6 = false; +/** Has informed_testing_reachable logged a message about testing our + * DirPort? */ +static bool have_informed_testing_dir_port = false; + /** Forget what we have learned about our reachability status. */ void router_reset_reachability(void) { can_reach_or_port_ipv4 = can_reach_or_port_ipv6 = can_reach_dir_port = false; + have_informed_testing_or_port_ipv4 = + have_informed_testing_or_port_ipv6 = + have_informed_testing_dir_port = false; } /** Return 1 if we won't do reachability checks, because: @@ -260,12 +273,9 @@ router_do_orport_reachability_checks(const routerinfo_t *me, log_info(LD_CIRC, "Testing %s of my %s ORPort: %s.", !orport_reachable ? "reachability" : "bandwidth", family_name, fmt_addrport_ap(ap)); - if (!orport_reachable) { - /* This is only a 'reachability test' if we don't already think that - * the port is reachable. If we _do_ think it's reachable, then - * it counts as a 'bandwidth test'. */ - inform_testing_reachability(&ap->addr, ap->port, false); - } + + inform_testing_reachability(&ap->addr, ap->port, false); + circuit_launch_by_extend_info(CIRCUIT_PURPOSE_TESTING, ei, CIRCLAUNCH_NEED_CAPACITY| CIRCLAUNCH_IS_INTERNAL| @@ -349,10 +359,13 @@ router_do_reachability_checks(int test_or, int test_dir) } /** Log a message informing the user that we are testing a port for - * reachability. + * reachability, if we have not already logged such a message. * * If @a is_dirport is true, then the port is a DirPort; otherwise it is an - * ORPort. */ + * ORPort. + * + * Calls to router_reset_reachability() will reset our view of whether we have + * logged this message for a given port. */ static void inform_testing_reachability(const tor_addr_t *addr, uint16_t port, @@ -361,6 +374,21 @@ inform_testing_reachability(const tor_addr_t *addr, if (!router_get_my_routerinfo()) return; + bool *have_informed_ptr; + if (is_dirport) { + have_informed_ptr = &have_informed_testing_dir_port; + } else if (tor_addr_family(addr) == AF_INET) { + have_informed_ptr = &have_informed_testing_or_port_ipv4; + } else { + have_informed_ptr = &have_informed_testing_or_port_ipv6; + } + + if (*have_informed_ptr) { + /* We already told the user that we're testing this port; no need to + * do it again. */ + return; + } + char addr_buf[TOR_ADDRPORT_BUF_LEN]; strlcpy(addr_buf, fmt_addrport(addr, port), sizeof(addr_buf)); @@ -377,6 +405,8 @@ inform_testing_reachability(const tor_addr_t *addr, "messages indicating success)", afname, port_type, addr_buf, TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT/60); + + *have_informed_ptr = true; } /** @@ -398,6 +428,7 @@ router_orport_found_reachable(int family) { const routerinfo_t *me = router_get_my_routerinfo(); const or_options_t *options = get_options(); + const char *reachable_reason = "ORPort found reachable"; bool *can_reach_ptr; if (family == AF_INET) { can_reach_ptr = &can_reach_or_port_ipv4; @@ -422,7 +453,13 @@ router_orport_found_reachable(int family) ready_to_publish(options) ? " Publishing server descriptor." : ""); - mark_my_descriptor_dirty("ORPort found reachable"); + /* Make sure our descriptor is marked to publish the IPv6 if it is now + * reachable. This can change at runtime. */ + if (family == AF_INET6) { + mark_my_descriptor_if_omit_ipv6_changes(reachable_reason, false); + } else { + mark_my_descriptor_dirty(reachable_reason); + } /* This is a significant enough change to upload immediately, * at least in a test network */ if (options->TestingTorNetwork == 1) { diff --git a/src/feature/rend/rendcache.c b/src/feature/rend/rendcache.c index 0890a81d8f..53fec7532f 100644 --- a/src/feature/rend/rendcache.c +++ b/src/feature/rend/rendcache.c @@ -340,8 +340,9 @@ rend_cache_failure_purge(void) /** Lookup the rend failure cache using a relay identity digest in * <b>identity</b> which has DIGEST_LEN bytes and service ID <b>service_id</b> - * which is a null-terminated string. If found, the intro failure is set in - * <b>intro_entry</b> else it stays untouched. Return 1 iff found else 0. */ + * which is a null-terminated string. If @a intro_entry is provided, then it + * is set to the entry on success, and to NULL on failure. + * Return 1 iff found else 0. */ STATIC int cache_failure_intro_lookup(const uint8_t *identity, const char *service_id, rend_cache_failure_intro_t **intro_entry) diff --git a/src/feature/rend/rendclient.c b/src/feature/rend/rendclient.c index e171562d17..8d3ed1ad03 100644 --- a/src/feature/rend/rendclient.c +++ b/src/feature/rend/rendclient.c @@ -268,8 +268,8 @@ rend_client_send_introduction(origin_circuit_t *introcirc, > MAX_NICKNAME_LEN)) { goto perm_err; } - strncpy(tmp, rendcirc->build_state->chosen_exit->nickname, - (MAX_NICKNAME_LEN+1)); /* nul pads */ + strlcpy(tmp, rendcirc->build_state->chosen_exit->nickname, + sizeof(tmp)); memcpy(tmp+MAX_NICKNAME_LEN+1, rendcirc->rend_data->rend_cookie, REND_COOKIE_LEN); dh_offset = MAX_NICKNAME_LEN+1+REND_COOKIE_LEN; diff --git a/src/feature/rend/rendservice.c b/src/feature/rend/rendservice.c index 1ac88d0eb7..68dd8f4f4a 100644 --- a/src/feature/rend/rendservice.c +++ b/src/feature/rend/rendservice.c @@ -1554,7 +1554,7 @@ rend_service_load_keys(rend_service_t *s) fname = rend_service_path(s, hostname_fname); tor_snprintf(buf, sizeof(buf),"%s.onion\n", s->service_id); - if (write_str_to_file(fname,buf,0)<0) { + if (write_str_to_file_if_not_equal(fname, buf)) { log_warn(LD_CONFIG, "Could not write onion address to hostname file."); goto err; } @@ -1849,13 +1849,13 @@ rend_service_use_direct_connection(const or_options_t* options, const extend_info_t* ei) { /* We'll connect directly all reachable addresses, whether preferred or not. - * The prefer_ipv6 argument to fascist_firewall_allows_address_addr is + * The prefer_ipv6 argument to reachable_addr_allows_addr is * ignored, because pref_only is 0. */ const tor_addr_port_t *ap = extend_info_get_orport(ei, AF_INET); if (!ap) return 0; return (rend_service_allow_non_anonymous_connection(options) && - fascist_firewall_allows_address_addr(&ap->addr, ap->port, + reachable_addr_allows_addr(&ap->addr, ap->port, FIREWALL_OR_CONNECTION, 0, 0)); } @@ -1867,7 +1867,7 @@ rend_service_use_direct_connection_node(const or_options_t* options, /* We'll connect directly all reachable addresses, whether preferred or not. */ return (rend_service_allow_non_anonymous_connection(options) && - fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION, 0)); + reachable_addr_allows_node(node, FIREWALL_OR_CONNECTION, 0)); } /****** diff --git a/src/feature/stats/bw_array_st.h b/src/feature/stats/bw_array_st.h new file mode 100644 index 0000000000..2d05ff0f77 --- /dev/null +++ b/src/feature/stats/bw_array_st.h @@ -0,0 +1,57 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file bw_array_st.h + * @brief Declaration for bw_array_t structure and related constants + **/ + +#ifndef TOR_FEATURE_STATS_BW_ARRAY_ST_H +#define TOR_FEATURE_STATS_BW_ARRAY_ST_H + +/** For how many seconds do we keep track of individual per-second bandwidth + * totals? */ +#define NUM_SECS_ROLLING_MEASURE 10 +/** How large are the intervals for which we track and report bandwidth use? */ +#define NUM_SECS_BW_SUM_INTERVAL (24*60*60) +/** How far in the past do we remember and publish bandwidth use? */ +#define NUM_SECS_BW_SUM_IS_VALID (5*24*60*60) +/** How many bandwidth usage intervals do we remember? (derived) */ +#define NUM_TOTALS (NUM_SECS_BW_SUM_IS_VALID/NUM_SECS_BW_SUM_INTERVAL) + +/** Structure to track bandwidth use, and remember the maxima for a given + * time period. + */ +struct bw_array_t { + /** Observation array: Total number of bytes transferred in each of the last + * NUM_SECS_ROLLING_MEASURE seconds. This is used as a circular array. */ + uint64_t obs[NUM_SECS_ROLLING_MEASURE]; + int cur_obs_idx; /**< Current position in obs. */ + time_t cur_obs_time; /**< Time represented in obs[cur_obs_idx] */ + uint64_t total_obs; /**< Total for all members of obs except + * obs[cur_obs_idx] */ + uint64_t max_total; /**< Largest value that total_obs has taken on in the + * current period. */ + uint64_t total_in_period; /**< Total bytes transferred in the current + * period. */ + + /** When does the next period begin? */ + time_t next_period; + /** Where in 'maxima' should the maximum bandwidth usage for the current + * period be stored? */ + int next_max_idx; + /** How many values in maxima/totals have been set ever? */ + int num_maxes_set; + /** Circular array of the maximum + * bandwidth-per-NUM_SECS_ROLLING_MEASURE usage for the last + * NUM_TOTALS periods */ + uint64_t maxima[NUM_TOTALS]; + /** Circular array of the total bandwidth usage for the last NUM_TOTALS + * periods */ + uint64_t totals[NUM_TOTALS]; +}; + +#endif /* !defined(TOR_FEATURE_STATS_BW_ARRAY_ST_H) */ diff --git a/src/feature/stats/bwhist.c b/src/feature/stats/bwhist.c index e74a2881f5..7cbc5f60a6 100644 --- a/src/feature/stats/bwhist.c +++ b/src/feature/stats/bwhist.c @@ -23,51 +23,10 @@ #include "app/config/statefile.h" #include "feature/relay/routermode.h" +#include "feature/stats/bw_array_st.h" #include "app/config/or_state_st.h" #include "app/config/or_options_st.h" -/** For how many seconds do we keep track of individual per-second bandwidth - * totals? */ -#define NUM_SECS_ROLLING_MEASURE 10 -/** How large are the intervals for which we track and report bandwidth use? */ -#define NUM_SECS_BW_SUM_INTERVAL (24*60*60) -/** How far in the past do we remember and publish bandwidth use? */ -#define NUM_SECS_BW_SUM_IS_VALID (5*24*60*60) -/** How many bandwidth usage intervals do we remember? (derived) */ -#define NUM_TOTALS (NUM_SECS_BW_SUM_IS_VALID/NUM_SECS_BW_SUM_INTERVAL) - -/** Structure to track bandwidth use, and remember the maxima for a given - * time period. - */ -struct bw_array_t { - /** Observation array: Total number of bytes transferred in each of the last - * NUM_SECS_ROLLING_MEASURE seconds. This is used as a circular array. */ - uint64_t obs[NUM_SECS_ROLLING_MEASURE]; - int cur_obs_idx; /**< Current position in obs. */ - time_t cur_obs_time; /**< Time represented in obs[cur_obs_idx] */ - uint64_t total_obs; /**< Total for all members of obs except - * obs[cur_obs_idx] */ - uint64_t max_total; /**< Largest value that total_obs has taken on in the - * current period. */ - uint64_t total_in_period; /**< Total bytes transferred in the current - * period. */ - - /** When does the next period begin? */ - time_t next_period; - /** Where in 'maxima' should the maximum bandwidth usage for the current - * period be stored? */ - int next_max_idx; - /** How many values in maxima/totals have been set ever? */ - int num_maxes_set; - /** Circular array of the maximum - * bandwidth-per-NUM_SECS_ROLLING_MEASURE usage for the last - * NUM_TOTALS periods */ - uint64_t maxima[NUM_TOTALS]; - /** Circular array of the total bandwidth usage for the last NUM_TOTALS - * periods */ - uint64_t totals[NUM_TOTALS]; -}; - /** Shift the current period of b forward by one. */ STATIC void commit_max(bw_array_t *b) @@ -115,7 +74,7 @@ advance_obs(bw_array_t *b) /** Add <b>n</b> bytes to the number of bytes in <b>b</b> for second * <b>when</b>. */ -static inline void +STATIC void add_obs(bw_array_t *b, time_t when, uint64_t n) { if (when < b->cur_obs_time) @@ -136,7 +95,7 @@ add_obs(bw_array_t *b, time_t when, uint64_t n) } /** Allocate, initialize, and return a new bw_array. */ -static bw_array_t * +STATIC bw_array_t * bw_array_new(void) { bw_array_t *b; @@ -148,11 +107,8 @@ bw_array_new(void) return b; } -#define bw_array_free(val) \ - FREE_AND_NULL(bw_array_t, bw_array_free_, (val)) - /** Free storage held by bandwidth array <b>b</b>. */ -static void +STATIC void bw_array_free_(bw_array_t *b) { if (!b) { @@ -291,7 +247,7 @@ bwhist_bandwidth_assess,(void)) * * It returns the number of bytes written. */ -static size_t +STATIC size_t bwhist_fill_bandwidth_history(char *buf, size_t len, const bw_array_t *b) { char *cp = buf; diff --git a/src/feature/stats/bwhist.h b/src/feature/stats/bwhist.h index d556f5a026..f88b951447 100644 --- a/src/feature/stats/bwhist.h +++ b/src/feature/stats/bwhist.h @@ -31,6 +31,13 @@ typedef struct bw_array_t bw_array_t; STATIC uint64_t find_largest_max(bw_array_t *b); STATIC void commit_max(bw_array_t *b); STATIC void advance_obs(bw_array_t *b); +STATIC bw_array_t *bw_array_new(void); +STATIC void add_obs(bw_array_t *b, time_t when, uint64_t n); +#define bw_array_free(val) \ + FREE_AND_NULL(bw_array_t, bw_array_free_, (val)) +STATIC void bw_array_free_(bw_array_t *b); +STATIC size_t bwhist_fill_bandwidth_history(char *buf, size_t len, + const bw_array_t *b); #endif /* defined(REPHIST_PRIVATE) */ #ifdef TOR_UNIT_TESTS diff --git a/src/feature/stats/include.am b/src/feature/stats/include.am index bc13882f4b..5be519936f 100644 --- a/src/feature/stats/include.am +++ b/src/feature/stats/include.am @@ -9,6 +9,7 @@ LIBTOR_APP_A_SOURCES += \ # ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ + src/feature/stats/bw_array_st.h \ src/feature/stats/bwhist.h \ src/feature/stats/connstats.h \ src/feature/stats/geoip_stats.h \ diff --git a/src/lib/buf/buffers.c b/src/lib/buf/buffers.c index 95b384bf06..23fc1e23a6 100644 --- a/src/lib/buf/buffers.c +++ b/src/lib/buf/buffers.c @@ -685,17 +685,22 @@ buf_move_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen) } /** Moves all data from <b>buf_in</b> to <b>buf_out</b>, without copying. + * Return the number of bytes that were moved. */ -void +size_t buf_move_all(buf_t *buf_out, buf_t *buf_in) { tor_assert(buf_out); if (!buf_in) - return; + return 0; + if (buf_datalen(buf_in) == 0) + return 0; if (BUG(buf_out->datalen > BUF_MAX_LEN || buf_in->datalen > BUF_MAX_LEN)) - return; + return 0; if (BUG(buf_out->datalen > BUF_MAX_LEN - buf_in->datalen)) - return; + return 0; + + size_t n_bytes_moved = buf_in->datalen; if (buf_out->head == NULL) { buf_out->head = buf_in->head; @@ -708,6 +713,8 @@ buf_move_all(buf_t *buf_out, buf_t *buf_in) buf_out->datalen += buf_in->datalen; buf_in->head = buf_in->tail = NULL; buf_in->datalen = 0; + + return n_bytes_moved; } /** Internal structure: represents a position in a buffer. */ diff --git a/src/lib/buf/buffers.h b/src/lib/buf/buffers.h index d8a77feb72..1361a02eba 100644 --- a/src/lib/buf/buffers.h +++ b/src/lib/buf/buffers.h @@ -46,7 +46,7 @@ void buf_add_printf(buf_t *buf, const char *format, ...) void buf_add_vprintf(buf_t *buf, const char *format, va_list args) CHECK_PRINTF(2, 0); int buf_move_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen); -void buf_move_all(buf_t *buf_out, buf_t *buf_in); +size_t buf_move_all(buf_t *buf_out, buf_t *buf_in); void buf_peek(const buf_t *buf, char *string, size_t string_len); void buf_drain(buf_t *buf, size_t n); int buf_get_bytes(buf_t *buf, char *string, size_t string_len); diff --git a/src/lib/crypt_ops/crypto_curve25519.h b/src/lib/crypt_ops/crypto_curve25519.h index 154a0b94bc..f1e5d1265d 100644 --- a/src/lib/crypt_ops/crypto_curve25519.h +++ b/src/lib/crypt_ops/crypto_curve25519.h @@ -9,6 +9,7 @@ #ifndef TOR_CRYPTO_CURVE25519_H #define TOR_CRYPTO_CURVE25519_H +#include <stdbool.h> #include "lib/testsupport/testsupport.h" #include "lib/cc/torint.h" #include "lib/crypt_ops/crypto_digest.h" @@ -77,7 +78,8 @@ STATIC int curve25519_basepoint_impl(uint8_t *output, const uint8_t *secret); int curve25519_public_from_base64(curve25519_public_key_t *pkey, const char *input); void curve25519_public_to_base64(char *output, - const curve25519_public_key_t *pkey); + const curve25519_public_key_t *pkey, + bool pad); void curve25519_set_impl_params(int use_ed); void curve25519_init(void); diff --git a/src/lib/crypt_ops/crypto_format.c b/src/lib/crypt_ops/crypto_format.c index 92b8b9372e..4483b7d2f5 100644 --- a/src/lib/crypt_ops/crypto_format.c +++ b/src/lib/crypt_ops/crypto_format.c @@ -131,9 +131,10 @@ crypto_read_tagged_contents_from_file(const char *fname, return r; } -/** Encode <b>pkey</b> as a base64-encoded string, including trailing "=" - * characters, in the buffer <b>output</b>, which must have at least - * CURVE25519_BASE64_PADDED_LEN+1 bytes available. +/** Encode <b>pkey</b> as a base64-encoded string in the buffer <b>output</b>. + * If <b>pad</b> is false do not include trailing "=" characters, otherwise + * include them. <b>output</b> must have at least + * CURVE25519_BASE64_PADDED_LEN+1 bytes available, even if <b>pad</b> is false. * Can not fail. * * Careful! CURVE25519_BASE64_PADDED_LEN is one byte longer than @@ -141,17 +142,25 @@ crypto_read_tagged_contents_from_file(const char *fname, */ void curve25519_public_to_base64(char *output, - const curve25519_public_key_t *pkey) + const curve25519_public_key_t *pkey, bool pad) { - char buf[128]; - int n = base64_encode(buf, sizeof(buf), - (const char*)pkey->public_key, - CURVE25519_PUBKEY_LEN, 0); + int n, expected_len; + if (pad) { + n = base64_encode(output, CURVE25519_BASE64_PADDED_LEN+1, + (const char*)pkey->public_key, + CURVE25519_PUBKEY_LEN, 0); + expected_len = CURVE25519_BASE64_PADDED_LEN; + } else { + n = base64_encode_nopad(output, CURVE25519_BASE64_PADDED_LEN+1, + (const uint8_t*)pkey->public_key, + CURVE25519_PUBKEY_LEN); + expected_len = CURVE25519_BASE64_LEN; + } + /* These asserts should always succeed, unless there is a bug in * base64_encode(). */ - tor_assert(n == CURVE25519_BASE64_PADDED_LEN); - tor_assert(buf[CURVE25519_BASE64_PADDED_LEN] == '\0'); - memcpy(output, buf, CURVE25519_BASE64_PADDED_LEN+1); + tor_assert(n == expected_len); + tor_assert(output[expected_len] == '\0'); } /** Try to decode a base64-encoded curve25519 public key from <b>input</b> @@ -162,11 +171,11 @@ curve25519_public_from_base64(curve25519_public_key_t *pkey, const char *input) { size_t len = strlen(input); - if (len == CURVE25519_BASE64_PADDED_LEN - 1) { + if (len == CURVE25519_BASE64_LEN) { /* not padded */ return digest256_from_base64((char*)pkey->public_key, input); } else if (len == CURVE25519_BASE64_PADDED_LEN) { - char buf[128]; + char buf[CURVE25519_BASE64_PADDED_LEN+1]; if (base64_decode(buf, sizeof(buf), input, len) != CURVE25519_PUBKEY_LEN) return -1; memcpy(pkey->public_key, buf, CURVE25519_PUBKEY_LEN); diff --git a/src/lib/crypt_ops/crypto_util.c b/src/lib/crypt_ops/crypto_util.c index 60e81af165..7ebb860d09 100644 --- a/src/lib/crypt_ops/crypto_util.c +++ b/src/lib/crypt_ops/crypto_util.c @@ -107,3 +107,17 @@ memwipe(void *mem, uint8_t byte, size_t sz) **/ memset(mem, byte, sz); } + +/** + * Securely all memory in <b>str</b>, then free it. + * + * As tor_free(), tolerates null pointers. + **/ +void +tor_str_wipe_and_free_(char *str) +{ + if (!str) + return; + memwipe(str, 0, strlen(str)); + tor_free_(str); +} diff --git a/src/lib/crypt_ops/crypto_util.h b/src/lib/crypt_ops/crypto_util.h index 4c08180f92..36ee230176 100644 --- a/src/lib/crypt_ops/crypto_util.h +++ b/src/lib/crypt_ops/crypto_util.h @@ -14,8 +14,18 @@ #define TOR_CRYPTO_UTIL_H #include "lib/cc/torint.h" +#include "lib/malloc/malloc.h" /** OpenSSL-based utility functions. */ void memwipe(void *mem, uint8_t byte, size_t sz); +void tor_str_wipe_and_free_(char *str); +/** + * Securely all memory in <b>str</b>, then free it. + * + * As tor_free(), tolerates null pointers, and sets <b>str</b> to NULL. + **/ +#define tor_str_wipe_and_free(str) \ + FREE_AND_NULL(char, tor_str_wipe_and_free_, (str)) + #endif /* !defined(TOR_CRYPTO_UTIL_H) */ diff --git a/src/lib/defs/x25519_sizes.h b/src/lib/defs/x25519_sizes.h index acb08c5e6a..e650f5a350 100644 --- a/src/lib/defs/x25519_sizes.h +++ b/src/lib/defs/x25519_sizes.h @@ -36,6 +36,9 @@ /** Length of a Curve25519 key when encoded in base 64, with padding. */ #define CURVE25519_BASE64_PADDED_LEN 44 +/** Length of a Curve25519 key when encoded in base 64, without padding. */ +#define CURVE25519_BASE64_LEN 43 + /** Length of a Ed25519 key when encoded in base 64, without padding. */ #define ED25519_BASE64_LEN 43 /** Length of a Ed25519 signature when encoded in base 64, without padding. */ diff --git a/src/lib/fdio/fdio.c b/src/lib/fdio/fdio.c index df4196aacd..56e3818f5c 100644 --- a/src/lib/fdio/fdio.c +++ b/src/lib/fdio/fdio.c @@ -48,7 +48,7 @@ off_t tor_fd_getpos(int fd) { #ifdef _WIN32 - return (off_t) _lseek(fd, 0, SEEK_CUR); + return (off_t) _lseeki64(fd, 0, SEEK_CUR); #else return (off_t) lseek(fd, 0, SEEK_CUR); #endif @@ -61,7 +61,7 @@ int tor_fd_seekend(int fd) { #ifdef _WIN32 - return _lseek(fd, 0, SEEK_END) < 0 ? -1 : 0; + return _lseeki64(fd, 0, SEEK_END) < 0 ? -1 : 0; #else off_t rc = lseek(fd, 0, SEEK_END) < 0 ? -1 : 0; #ifdef ESPIPE @@ -80,7 +80,7 @@ int tor_fd_setpos(int fd, off_t pos) { #ifdef _WIN32 - return _lseek(fd, pos, SEEK_SET) < 0 ? -1 : 0; + return _lseeki64(fd, pos, SEEK_SET) < 0 ? -1 : 0; #else return lseek(fd, pos, SEEK_SET) < 0 ? -1 : 0; #endif diff --git a/src/lib/fs/files.c b/src/lib/fs/files.c index b4a432701f..aff78db718 100644 --- a/src/lib/fs/files.c +++ b/src/lib/fs/files.c @@ -734,6 +734,26 @@ read_file_to_str, (const char *filename, int flags, struct stat *stat_out)) return string; } +/** Attempt to read a file <b>fname</b>. If the file's contents is + * equal to the string <b>str</b>, return 0. Otherwise, attempt to + * overwrite the file with the contents of <b>str</b> and return + * the value of write_str_to_file(). + */ +int +write_str_to_file_if_not_equal(const char *fname, const char *str) +{ + char *fstr = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL); + int rv; + + if (!fstr || strcmp(str, fstr)) { + rv = write_str_to_file(fname, str, 0); + } else { + rv = 0; + } + tor_free(fstr); + return rv; +} + #if !defined(HAVE_GETDELIM) || defined(TOR_UNIT_TESTS) #include "ext/getdelim.c" #endif diff --git a/src/lib/fs/files.h b/src/lib/fs/files.h index 6eeba85e89..f0178e2b5b 100644 --- a/src/lib/fs/files.h +++ b/src/lib/fs/files.h @@ -93,6 +93,8 @@ int append_bytes_to_file(const char *fname, const char *str, size_t len, int write_bytes_to_new_file(const char *fname, const char *str, size_t len, int bin); +int write_str_to_file_if_not_equal(const char *fname, const char *str); + /** Flag for read_file_to_str: open the file in binary mode. */ #define RFTS_BIN 1 /** Flag for read_file_to_str: it's okay if the file doesn't exist. */ diff --git a/src/lib/net/address.c b/src/lib/net/address.c index cf4af423a7..5a32533610 100644 --- a/src/lib/net/address.c +++ b/src/lib/net/address.c @@ -2114,6 +2114,18 @@ tor_addr_port_eq(const tor_addr_port_t *a, return tor_addr_eq(&a->addr, &b->addr) && a->port == b->port; } +/** + * Copy a tor_addr_port_t from @a source to @a dest. + **/ +void +tor_addr_port_copy(tor_addr_port_t *dest, + const tor_addr_port_t *source) +{ + tor_assert(dest); + tor_assert(source); + memcpy(dest, source, sizeof(tor_addr_port_t)); +} + /** Return true if <b>string</b> represents a valid IPv4 adddress in * 'a.b.c.d' form. */ diff --git a/src/lib/net/address.h b/src/lib/net/address.h index e19b446e8d..bc8ec7744f 100644 --- a/src/lib/net/address.h +++ b/src/lib/net/address.h @@ -394,6 +394,7 @@ get_interface_address_list(int severity, int include_internal) tor_addr_port_t *tor_addr_port_new(const tor_addr_t *addr, uint16_t port); int tor_addr_port_eq(const tor_addr_port_t *a, const tor_addr_port_t *b); +void tor_addr_port_copy(tor_addr_port_t *dest, const tor_addr_port_t *source); int string_is_valid_dest(const char *string); int string_is_valid_nonrfc_hostname(const char *string); diff --git a/src/lib/net/buffers_net.c b/src/lib/net/buffers_net.c index 4dbf491e1a..4a0eb3bf16 100644 --- a/src/lib/net/buffers_net.c +++ b/src/lib/net/buffers_net.c @@ -137,13 +137,12 @@ buf_read_from_fd(buf_t *buf, int fd, size_t at_most, } /** Helper for buf_flush_to_socket(): try to write <b>sz</b> bytes from chunk - * <b>chunk</b> of buffer <b>buf</b> onto file descriptor <b>fd</b>. On - * success, deduct the bytes written from *<b>buf_flushlen</b>. Return the - * number of bytes written on success, 0 on blocking, -1 on failure. + * <b>chunk</b> of buffer <b>buf</b> onto file descriptor <b>fd</b>. Return + * the number of bytes written on success, 0 on blocking, -1 on failure. */ static inline int flush_chunk(tor_socket_t fd, buf_t *buf, chunk_t *chunk, size_t sz, - size_t *buf_flushlen, bool is_socket) + bool is_socket) { ssize_t write_result; @@ -168,7 +167,6 @@ flush_chunk(tor_socket_t fd, buf_t *buf, chunk_t *chunk, size_t sz, log_debug(LD_NET,"write() would block, returning."); return 0; } else { - *buf_flushlen -= write_result; buf_drain(buf, write_result); tor_assert(write_result <= BUF_MAX_LEN); return (int)write_result; @@ -176,27 +174,22 @@ flush_chunk(tor_socket_t fd, buf_t *buf, chunk_t *chunk, size_t sz, } /** Write data from <b>buf</b> to the file descriptor <b>fd</b>. Write at most - * <b>sz</b> bytes, decrement *<b>buf_flushlen</b> by - * the number of bytes actually written, and remove the written bytes + * <b>sz</b> bytes, and remove the written bytes * from the buffer. Return the number of bytes written on success, * -1 on failure. Return 0 if write() would block. */ static int buf_flush_to_fd(buf_t *buf, int fd, size_t sz, - size_t *buf_flushlen, bool is_socket) + bool is_socket) { /* XXXX It's stupid to overload the return values for these functions: * "error status" and "number of bytes flushed" are not mutually exclusive. */ int r; size_t flushed = 0; - tor_assert(buf_flushlen); tor_assert(SOCKET_OK(fd)); - if (BUG(*buf_flushlen > buf->datalen)) { - *buf_flushlen = buf->datalen; - } - if (BUG(sz > *buf_flushlen)) { - sz = *buf_flushlen; + if (BUG(sz > buf->datalen)) { + sz = buf->datalen; } check(); @@ -208,7 +201,7 @@ buf_flush_to_fd(buf_t *buf, int fd, size_t sz, else flushlen0 = buf->head->datalen; - r = flush_chunk(fd, buf, buf->head, flushlen0, buf_flushlen, is_socket); + r = flush_chunk(fd, buf, buf->head, flushlen0, is_socket); check(); if (r < 0) return r; @@ -228,10 +221,9 @@ buf_flush_to_fd(buf_t *buf, int fd, size_t sz, * -1 on failure. Return 0 if write() would block. */ int -buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz, - size_t *buf_flushlen) +buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz) { - return buf_flush_to_fd(buf, s, sz, buf_flushlen, true); + return buf_flush_to_fd(buf, s, sz, true); } /** Read from socket <b>s</b>, writing onto end of <b>buf</b>. Read at most @@ -254,10 +246,9 @@ buf_read_from_socket(buf_t *buf, tor_socket_t s, size_t at_most, * -1 on failure. Return 0 if write() would block. */ int -buf_flush_to_pipe(buf_t *buf, int fd, size_t sz, - size_t *buf_flushlen) +buf_flush_to_pipe(buf_t *buf, int fd, size_t sz) { - return buf_flush_to_fd(buf, fd, sz, buf_flushlen, false); + return buf_flush_to_fd(buf, fd, sz, false); } /** Read from pipe <b>fd</b>, writing onto end of <b>buf</b>. Read at most diff --git a/src/lib/net/buffers_net.h b/src/lib/net/buffers_net.h index a45c23a273..556575c3dc 100644 --- a/src/lib/net/buffers_net.h +++ b/src/lib/net/buffers_net.h @@ -21,14 +21,12 @@ int buf_read_from_socket(struct buf_t *buf, tor_socket_t s, size_t at_most, int *reached_eof, int *socket_error); -int buf_flush_to_socket(struct buf_t *buf, tor_socket_t s, size_t sz, - size_t *buf_flushlen); +int buf_flush_to_socket(struct buf_t *buf, tor_socket_t s, size_t sz); int buf_read_from_pipe(struct buf_t *buf, int fd, size_t at_most, int *reached_eof, int *socket_error); -int buf_flush_to_pipe(struct buf_t *buf, int fd, size_t sz, - size_t *buf_flushlen); +int buf_flush_to_pipe(struct buf_t *buf, int fd, size_t sz); #endif /* !defined(TOR_BUFFERS_NET_H) */ diff --git a/src/lib/osinfo/include.am b/src/lib/osinfo/include.am index 84bd7feb00..df8c98500c 100644 --- a/src/lib/osinfo/include.am +++ b/src/lib/osinfo/include.am @@ -7,7 +7,8 @@ endif # ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_osinfo_a_SOURCES = \ - src/lib/osinfo/uname.c + src/lib/osinfo/uname.c \ + src/lib/osinfo/libc.c src_lib_libtor_osinfo_testing_a_SOURCES = \ $(src_lib_libtor_osinfo_a_SOURCES) @@ -16,4 +17,5 @@ src_lib_libtor_osinfo_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) # ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ - src/lib/osinfo/uname.h + src/lib/osinfo/uname.h \ + src/lib/osinfo/libc.h diff --git a/src/lib/osinfo/libc.c b/src/lib/osinfo/libc.c new file mode 100644 index 0000000000..32cbad0fa2 --- /dev/null +++ b/src/lib/osinfo/libc.c @@ -0,0 +1,66 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file libc.c + * @brief Functions to get the name and version of the system libc. + **/ + +#include "orconfig.h" +#include "lib/osinfo/libc.h" +#include <stdlib.h> + +#ifdef HAVE_GNU_LIBC_VERSION_H +#include <gnu/libc-version.h> +#endif + +#ifdef HAVE_GNU_LIBC_VERSION_H +#ifdef HAVE_GNU_GET_LIBC_VERSION +#define CHECK_LIBC_VERSION +#endif +#endif + +#define STR_IMPL(x) #x +#define STR(x) STR_IMPL(x) + +/** Return the name of the compile time libc. Returns NULL if we + * cannot identify the libc. */ +const char * +tor_libc_get_name(void) +{ +#ifdef __GLIBC__ + return "Glibc"; +#else /* !defined(__GLIBC__) */ + return NULL; +#endif /* defined(__GLIBC__) */ +} + +/** Return a string representation of the version of the currently running + * version of Glibc. */ +const char * +tor_libc_get_version_str(void) +{ +#ifdef CHECK_LIBC_VERSION + const char *version = gnu_get_libc_version(); + if (version == NULL) + return "N/A"; + return version; +#else /* !defined(CHECK_LIBC_VERSION) */ + return "N/A"; +#endif /* defined(CHECK_LIBC_VERSION) */ +} + +/** Return a string representation of the version of Glibc that was used at + * compilation time. */ +const char * +tor_libc_get_header_version_str(void) +{ +#ifdef __GLIBC__ + return STR(__GLIBC__) "." STR(__GLIBC_MINOR__); +#else + return "N/A"; +#endif /* defined(__GLIBC__) */ +} diff --git a/src/lib/osinfo/libc.h b/src/lib/osinfo/libc.h new file mode 100644 index 0000000000..f4303f8c9c --- /dev/null +++ b/src/lib/osinfo/libc.h @@ -0,0 +1,19 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file libc.h + * @brief Header for lib/osinfo/libc.c + **/ + +#ifndef TOR_LIB_OSINFO_LIBC_H +#define TOR_LIB_OSINFO_LIBC_H + +const char *tor_libc_get_name(void); +const char *tor_libc_get_version_str(void); +const char *tor_libc_get_header_version_str(void); + +#endif /* !defined(TOR_LIB_OSINFO_LIBC_H) */ diff --git a/src/lib/process/process_unix.c b/src/lib/process/process_unix.c index 2b47e1874d..82b2630a5d 100644 --- a/src/lib/process/process_unix.c +++ b/src/lib/process/process_unix.c @@ -418,7 +418,7 @@ process_unix_write(process_t *process, buf_t *buffer) /* We have data to write and the kernel have told us to write it. */ return buf_flush_to_pipe(buffer, process_get_unix_process(process)->stdin_handle.fd, - max_to_write, &buffer_flush_len); + max_to_write); } /** Read data from the given process's standard output and put it into diff --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c index 81240bcfdb..8d467c516e 100644 --- a/src/lib/sandbox/sandbox.c +++ b/src/lib/sandbox/sandbox.c @@ -137,6 +137,10 @@ static sandbox_cfg_t *filter_dynamic = NULL; * the high bits of the value might get masked out improperly. */ #define SCMP_CMP_MASKED(a,b,c) \ SCMP_CMP4((a), SCMP_CMP_MASKED_EQ, ~(scmp_datum_t)(b), (c)) +/* For negative constants, the rule to add depends on the glibc version. */ +#define SCMP_CMP_NEG(a,op,b) (libc_negative_constant_needs_cast() ? \ + (SCMP_CMP((a), (op), (unsigned int)(b))) : \ + (SCMP_CMP_STR((a), (op), (b)))) /** Variable used for storing all syscall numbers that will be allowed with the * stage 1 general Tor sandbox. @@ -287,6 +291,12 @@ static int filter_nopar_gen[] = { SCMP_SYS(poll) }; +/* opendir is not a syscall but it will use either open or openat. We do not + * want the decision to allow open/openat to be the callers reponsability, so + * we create a phony syscall number for opendir and sb_opendir will choose the + * correct syscall. */ +#define PHONY_OPENDIR_SYSCALL -2 + /* These macros help avoid the error where the number of filters we add on a * single rule don't match the arg_cnt param. */ #define seccomp_rule_add_0(ctx,act,call) \ @@ -440,31 +450,59 @@ sb_mmap2(scmp_filter_ctx ctx, sandbox_cfg_t *filter) #endif #endif -/* Return true if we think we're running with a libc that always uses - * openat on linux. */ +/* Return true the libc version is greater or equal than + * <b>major</b>.<b>minor</b>. Returns false otherwise. */ static int -libc_uses_openat_for_everything(void) +is_libc_at_least(int major, int minor) { #ifdef CHECK_LIBC_VERSION const char *version = gnu_get_libc_version(); if (version == NULL) return 0; - int major = -1; - int minor = -1; + int libc_major = -1; + int libc_minor = -1; - tor_sscanf(version, "%d.%d", &major, &minor); - if (major >= 3) + tor_sscanf(version, "%d.%d", &libc_major, &libc_minor); + if (libc_major > major) return 1; - else if (major == 2 && minor >= 26) + else if (libc_major == major && libc_minor >= minor) return 1; else return 0; #else /* !defined(CHECK_LIBC_VERSION) */ + (void)major; + (void)minor; return 0; #endif /* defined(CHECK_LIBC_VERSION) */ } +/* Return true if we think we're running with a libc that uses openat for the + * open function on linux. */ +static int +libc_uses_openat_for_open(void) +{ + return is_libc_at_least(2, 26); +} + +/* Return true if we think we're running with a libc that uses openat for the + * opendir function on linux. */ +static int +libc_uses_openat_for_opendir(void) +{ + // libc 2.27 and above or between 2.15 (inclusive) and 2.22 (exclusive) + return is_libc_at_least(2, 27) || + (is_libc_at_least(2, 15) && !is_libc_at_least(2, 22)); +} + +/* Return true if we think we're running with a libc that needs to cast + * negative arguments like AT_FDCWD for seccomp rules. */ +static int +libc_negative_constant_needs_cast(void) +{ + return is_libc_at_least(2, 27); +} + /** Allow a single file to be opened. If <b>use_openat</b> is true, * we're using a libc that remaps all the opens into openats. */ static int @@ -472,7 +510,7 @@ allow_file_open(scmp_filter_ctx ctx, int use_openat, const char *file) { if (use_openat) { return seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), - SCMP_CMP(0, SCMP_CMP_EQ, (unsigned int)AT_FDCWD), + SCMP_CMP_NEG(0, SCMP_CMP_EQ, AT_FDCWD), SCMP_CMP_STR(1, SCMP_CMP_EQ, file)); } else { return seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), @@ -490,7 +528,7 @@ sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter) int rc; sandbox_cfg_t *elem = NULL; - int use_openat = libc_uses_openat_for_everything(); + int use_openat = libc_uses_openat_for_open(); // for each dynamic parameter filters for (elem = filter; elem != NULL; elem = elem->next) { @@ -608,7 +646,7 @@ sb_openat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) if (param != NULL && param->prot == 1 && param->syscall == SCMP_SYS(openat)) { rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), - SCMP_CMP(0, SCMP_CMP_EQ, AT_FDCWD), + SCMP_CMP_NEG(0, SCMP_CMP_EQ, AT_FDCWD), SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value), SCMP_CMP(2, SCMP_CMP_EQ, O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY| O_CLOEXEC)); @@ -623,6 +661,30 @@ sb_openat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } +static int +sb_opendir(scmp_filter_ctx ctx, sandbox_cfg_t *filter) +{ + int rc; + sandbox_cfg_t *elem = NULL; + + // for each dynamic parameter filters + for (elem = filter; elem != NULL; elem = elem->next) { + smp_param_t *param = elem->param; + + if (param != NULL && param->prot == 1 && param->syscall + == PHONY_OPENDIR_SYSCALL) { + rc = allow_file_open(ctx, libc_uses_openat_for_opendir(), param->value); + if (rc != 0) { + log_err(LD_BUG,"(Sandbox) failed to add openat syscall, received " + "libseccomp error %d", rc); + return rc; + } + } + } + + return 0; +} + /** * Function responsible for setting up the socket syscall for * the seccomp filter sandbox. @@ -1137,6 +1199,7 @@ static sandbox_filter_func_t filter_func[] = { sb_chmod, sb_open, sb_openat, + sb_opendir, sb_rename, #ifdef __NR_fcntl64 sb_fcntl64, @@ -1456,6 +1519,19 @@ sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file) return 0; } +int +sandbox_cfg_allow_opendir_dirname(sandbox_cfg_t **cfg, char *dir) +{ + sandbox_cfg_t *elem = NULL; + + elem = new_element(PHONY_OPENDIR_SYSCALL, dir); + + elem->next = *cfg; + *cfg = elem; + + return 0; +} + /** * Function responsible for going through the parameter syscall filters and * call each function pointer in the list. @@ -1784,6 +1860,13 @@ sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file) } int +sandbox_cfg_allow_opendir_dirname(sandbox_cfg_t **cfg, char *dir) +{ + (void)cfg; (void)dir; + return 0; +} + +int sandbox_cfg_allow_stat_filename(sandbox_cfg_t **cfg, char *file) { (void)cfg; (void)file; diff --git a/src/lib/sandbox/sandbox.h b/src/lib/sandbox/sandbox.h index b50df48255..a2b3227b90 100644 --- a/src/lib/sandbox/sandbox.h +++ b/src/lib/sandbox/sandbox.h @@ -136,6 +136,13 @@ int sandbox_cfg_allow_rename(sandbox_cfg_t **cfg, char *file1, char *file2); int sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file); /** + * Function used to add a opendir allowed filename to a supplied configuration. + * The (char*) specifies the path to the allowed dir; we steal the pointer to + * that dir. + */ +int sandbox_cfg_allow_opendir_dirname(sandbox_cfg_t **cfg, char *dir); + +/** * Function used to add a stat/stat64 allowed filename to a configuration. * The (char*) specifies the path to the allowed file; that pointer is stolen. */ diff --git a/src/lib/tls/buffers_tls.c b/src/lib/tls/buffers_tls.c index 1b99467d2b..de0e9cb4ef 100644 --- a/src/lib/tls/buffers_tls.c +++ b/src/lib/tls/buffers_tls.c @@ -106,8 +106,7 @@ buf_read_from_tls(buf_t *buf, tor_tls_t *tls, size_t at_most) * written on success, and a TOR_TLS error code on failure or blocking. */ static inline int -flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk, - size_t sz, size_t *buf_flushlen) +flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk, size_t sz) { int r; size_t forced; @@ -126,13 +125,9 @@ flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk, r = tor_tls_write(tls, data, sz); if (r < 0) return r; - if (*buf_flushlen > (size_t)r) - *buf_flushlen -= r; - else - *buf_flushlen = 0; buf_drain(buf, r); - log_debug(LD_NET,"flushed %d bytes, %d ready to flush, %d remain.", - r,(int)*buf_flushlen,(int)buf->datalen); + log_debug(LD_NET,"flushed %d bytes, %d remain.", + r,(int)buf->datalen); return r; } @@ -140,18 +135,13 @@ flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk, * more than <b>flushlen</b> bytes. */ int -buf_flush_to_tls(buf_t *buf, tor_tls_t *tls, size_t flushlen, - size_t *buf_flushlen) +buf_flush_to_tls(buf_t *buf, tor_tls_t *tls, size_t flushlen) { int r; size_t flushed = 0; ssize_t sz; - tor_assert(buf_flushlen); - IF_BUG_ONCE(*buf_flushlen > buf->datalen) { - *buf_flushlen = buf->datalen; - } - IF_BUG_ONCE(flushlen > *buf_flushlen) { - flushlen = *buf_flushlen; + IF_BUG_ONCE(flushlen > buf->datalen) { + flushlen = buf->datalen; } sz = (ssize_t) flushlen; @@ -170,7 +160,7 @@ buf_flush_to_tls(buf_t *buf, tor_tls_t *tls, size_t flushlen, flushlen0 = 0; } - r = flush_chunk_tls(tls, buf, buf->head, flushlen0, buf_flushlen); + r = flush_chunk_tls(tls, buf, buf->head, flushlen0); if (r < 0) return r; flushed += r; diff --git a/src/lib/tls/buffers_tls.h b/src/lib/tls/buffers_tls.h index 587426801d..ed391cefbd 100644 --- a/src/lib/tls/buffers_tls.h +++ b/src/lib/tls/buffers_tls.h @@ -18,6 +18,6 @@ struct tor_tls_t; int buf_read_from_tls(struct buf_t *buf, struct tor_tls_t *tls, size_t at_most); int buf_flush_to_tls(struct buf_t *buf, struct tor_tls_t *tls, - size_t sz, size_t *buf_flushlen); + size_t sz); #endif /* !defined(TOR_BUFFERS_TLS_H) */ diff --git a/src/rust/protover/protover.rs b/src/rust/protover/protover.rs index 076cd5301e..550732734c 100644 --- a/src/rust/protover/protover.rs +++ b/src/rust/protover/protover.rs @@ -253,6 +253,11 @@ impl FromStr for ProtoEntry { /// Otherwise, the `Err` value of this `Result` is a `ProtoverError`. fn from_str(protocol_entry: &str) -> Result<ProtoEntry, ProtoverError> { let mut proto_entry: ProtoEntry = ProtoEntry::default(); + + if protocol_entry.is_empty() { + return Ok(proto_entry); + } + let entries = protocol_entry.split(' '); for entry in entries { @@ -501,6 +506,10 @@ impl UnvalidatedProtoEntry { ) -> Result<Vec<(&'a str, &'a str)>, ProtoverError> { let mut protovers: Vec<(&str, &str)> = Vec::new(); + if protocol_string.is_empty() { + return Ok(protovers); + } + for subproto in protocol_string.split(' ') { let mut parts = subproto.splitn(2, '='); @@ -859,7 +868,8 @@ mod test { #[test] fn test_protoentry_from_str_empty() { - assert_protoentry_is_unparseable!(""); + assert_protoentry_is_parseable!(""); + assert!(UnvalidatedProtoEntry::from_str("").is_ok()); } #[test] @@ -883,11 +893,6 @@ mod test { } #[test] - fn test_protoentry_from_str_() { - assert_protoentry_is_unparseable!(""); - } - - #[test] fn test_protoentry_all_supported_single_protocol_single_version() { let protocol: UnvalidatedProtoEntry = "Cons=1".parse().unwrap(); let unsupported: Option<UnvalidatedProtoEntry> = protocol.all_supported(); diff --git a/src/rust/protover/tests/protover.rs b/src/rust/protover/tests/protover.rs index 942fe3c6ab..c97810a6f2 100644 --- a/src/rust/protover/tests/protover.rs +++ b/src/rust/protover/tests/protover.rs @@ -70,18 +70,6 @@ fn protocol_all_supported_with_one_value() { } #[test] -#[should_panic] -fn parse_protocol_unvalidated_with_empty() { - let _: UnvalidatedProtoEntry = "".parse().unwrap(); -} - -#[test] -#[should_panic] -fn parse_protocol_validated_with_empty() { - let _: UnvalidatedProtoEntry = "".parse().unwrap(); -} - -#[test] fn protocol_all_supported_with_three_values() { let protocols: UnvalidatedProtoEntry = "LinkAuth=1 Microdesc=1-2 Relay=2".parse().unwrap(); let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported(); @@ -156,7 +144,6 @@ fn parse_protocol_with_unexpected_characters() { } #[test] -#[should_panic] fn protover_compute_vote_returns_empty_for_empty_string() { let protocols: &[UnvalidatedProtoEntry] = &["".parse().unwrap()]; let listed = ProtoverVote::compute(protocols, &1); diff --git a/src/test/conf_examples/crypto_accel/expected_log_nss b/src/test/conf_examples/crypto_accel/expected_log_nss index c0fe7b003c..bcbfa2cf6b 100644 --- a/src/test/conf_examples/crypto_accel/expected_log_nss +++ b/src/test/conf_examples/crypto_accel/expected_log_nss @@ -1 +1 @@ -Tor 0.* running on .* with Libevent .*, NSS .*, Zlib .*, Liblzma .*, and Libzstd .* +Tor 0.* running on .* with Libevent .*, NSS .*, Zlib .*, Liblzma .*, Libzstd .* and .* .* as libc diff --git a/src/test/conf_examples/crypto_accel_req/expected_log_nss b/src/test/conf_examples/crypto_accel_req/expected_log_nss index c0fe7b003c..bcbfa2cf6b 100644 --- a/src/test/conf_examples/crypto_accel_req/expected_log_nss +++ b/src/test/conf_examples/crypto_accel_req/expected_log_nss @@ -1 +1 @@ -Tor 0.* running on .* with Libevent .*, NSS .*, Zlib .*, Liblzma .*, and Libzstd .* +Tor 0.* running on .* with Libevent .*, NSS .*, Zlib .*, Liblzma .*, Libzstd .* and .* .* as libc diff --git a/src/test/conf_examples/lzma_zstd_1/expected_log b/src/test/conf_examples/lzma_zstd_1/expected_log index a5531ca21e..f143b23102 100644 --- a/src/test/conf_examples/lzma_zstd_1/expected_log +++ b/src/test/conf_examples/lzma_zstd_1/expected_log @@ -1 +1 @@ -Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma N/A, and Libzstd N/A +Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma N/A, Libzstd N/A and .* .* as libc diff --git a/src/test/conf_examples/lzma_zstd_1/expected_log_lzma b/src/test/conf_examples/lzma_zstd_1/expected_log_lzma index 2947e5991b..abb4731abc 100644 --- a/src/test/conf_examples/lzma_zstd_1/expected_log_lzma +++ b/src/test/conf_examples/lzma_zstd_1/expected_log_lzma @@ -1 +1 @@ -Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma .*, and Libzstd N/A +Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma .*, Libzstd N/A and .* .* as libc diff --git a/src/test/conf_examples/lzma_zstd_1/expected_log_lzma_zstd b/src/test/conf_examples/lzma_zstd_1/expected_log_lzma_zstd index e76e4357f8..b4e45772dd 100644 --- a/src/test/conf_examples/lzma_zstd_1/expected_log_lzma_zstd +++ b/src/test/conf_examples/lzma_zstd_1/expected_log_lzma_zstd @@ -1 +1 @@ -Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma .*, and Libzstd .*
\ No newline at end of file +Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma .*, Libzstd .* and .* .* as libc
\ No newline at end of file diff --git a/src/test/conf_examples/lzma_zstd_1/expected_log_zstd b/src/test/conf_examples/lzma_zstd_1/expected_log_zstd index c8b174423b..994b46974b 100644 --- a/src/test/conf_examples/lzma_zstd_1/expected_log_zstd +++ b/src/test/conf_examples/lzma_zstd_1/expected_log_zstd @@ -1 +1 @@ -Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma N/A, and Libzstd .*
\ No newline at end of file +Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma N/A, Libzstd .* and .* .* as libc
\ No newline at end of file diff --git a/src/test/conf_examples/nss_1/expected_log b/src/test/conf_examples/nss_1/expected_log index 32e8cfc2f8..38f1febda5 100644 --- a/src/test/conf_examples/nss_1/expected_log +++ b/src/test/conf_examples/nss_1/expected_log @@ -1 +1 @@ -Tor 0.* running on .* with Libevent .*, OpenSSL .*, Zlib .*, Liblzma .*, and Libzstd .* +Tor 0.* running on .* with Libevent .*, OpenSSL .*, Zlib .*, Liblzma .*, Libzstd .* and .* .* as libc diff --git a/src/test/conf_examples/nss_1/expected_log_nss b/src/test/conf_examples/nss_1/expected_log_nss index c0fe7b003c..bcbfa2cf6b 100644 --- a/src/test/conf_examples/nss_1/expected_log_nss +++ b/src/test/conf_examples/nss_1/expected_log_nss @@ -1 +1 @@ -Tor 0.* running on .* with Libevent .*, NSS .*, Zlib .*, Liblzma .*, and Libzstd .* +Tor 0.* running on .* with Libevent .*, NSS .*, Zlib .*, Liblzma .*, Libzstd .* and .* .* as libc diff --git a/src/test/test_buffers.c b/src/test/test_buffers.c index cc79426c1e..fbaa628fd7 100644 --- a/src/test/test_buffers.c +++ b/src/test/test_buffers.c @@ -303,6 +303,69 @@ test_buffer_pullup(void *arg) } static void +test_buffers_move_all(void *arg) +{ + (void)arg; + buf_t *input = buf_new(); + buf_t *output = buf_new(); + char *s = NULL; + + /* Move from empty buffer to nonempty buffer. (This is a regression test for + * #40076) */ + buf_add(output, "abc", 3); + buf_assert_ok(input); + buf_assert_ok(output); + buf_move_all(output, input); + buf_assert_ok(input); + buf_assert_ok(output); + tt_int_op(buf_datalen(output), OP_EQ, 3); + s = buf_extract(output, NULL); + tt_str_op(s, OP_EQ, "abc"); + buf_free(output); + buf_free(input); + tor_free(s); + + /* Move from empty to empty. */ + output = buf_new(); + input = buf_new(); + buf_move_all(output, input); + buf_assert_ok(input); + buf_assert_ok(output); + tt_int_op(buf_datalen(output), OP_EQ, 0); + buf_free(output); + buf_free(input); + + /* Move from nonempty to empty. */ + output = buf_new(); + input = buf_new(); + buf_add(input, "longstanding bugs", 17); + buf_move_all(output, input); + buf_assert_ok(input); + buf_assert_ok(output); + s = buf_extract(output, NULL); + tt_str_op(s, OP_EQ, "longstanding bugs"); + buf_free(output); + buf_free(input); + tor_free(s); + + /* Move from nonempty to nonempty. */ + output = buf_new(); + input = buf_new(); + buf_add(output, "the start of", 12); + buf_add(input, " a string", 9); + buf_move_all(output, input); + buf_assert_ok(input); + buf_assert_ok(output); + s = buf_extract(output, NULL); + tt_str_op(s, OP_EQ, "the start of a string"); + + done: + buf_free(output); + buf_free(input); + tor_free(s); +} + +static void test_buffer_copy(void *arg) { buf_t *buf=NULL, *buf2=NULL; @@ -799,6 +862,7 @@ struct testcase_t buffer_tests[] = { { "basic", test_buffers_basic, TT_FORK, NULL, NULL }, { "copy", test_buffer_copy, TT_FORK, NULL, NULL }, { "pullup", test_buffer_pullup, TT_FORK, NULL, NULL }, + { "move_all", test_buffers_move_all, 0, NULL, NULL }, { "startswith", test_buffer_peek_startswith, 0, NULL, NULL }, { "allocation_tracking", test_buffer_allocation_tracking, TT_FORK, NULL, NULL }, diff --git a/src/test/test_channel.c b/src/test/test_channel.c index 2b723b4a8d..042eb27d9d 100644 --- a/src/test/test_channel.c +++ b/src/test/test_channel.c @@ -50,7 +50,6 @@ static int dump_statistics_mock_matches = 0; static int test_close_called = 0; static int test_chan_should_be_canonical = 0; static int test_chan_should_match_target = 0; -static int test_chan_canonical_should_be_reliable = 0; static int test_chan_listener_close_fn_called = 0; static int test_chan_listener_fn_called = 0; @@ -163,16 +162,23 @@ chan_test_finish_close(channel_t *ch) } static const char * -chan_test_get_remote_descr(channel_t *ch, int flags) +chan_test_describe_peer(const channel_t *ch) { tt_assert(ch); - tt_int_op(flags & ~(GRD_FLAG_ORIGINAL | GRD_FLAG_ADDR_ONLY), OP_EQ, 0); done: return "Fake channel for unit tests; no real endpoint"; } static int +chan_test_get_remote_addr(const channel_t *ch, tor_addr_t *out) +{ + (void)ch; + tor_addr_from_ipv4h(out, 0x7f000001); + return 1; +} + +static int chan_test_num_cells_writeable(channel_t *ch) { tt_assert(ch); @@ -268,7 +274,8 @@ new_fake_channel(void) chan->close = chan_test_close; chan->num_cells_writeable = chan_test_num_cells_writeable; - chan->get_remote_descr = chan_test_get_remote_descr; + chan->describe_peer = chan_test_describe_peer; + chan->get_remote_addr = chan_test_get_remote_addr; chan->write_packed_cell = chan_test_write_packed_cell; chan->write_var_cell = chan_test_write_var_cell; chan->state = CHANNEL_STATE_OPEN; @@ -343,14 +350,10 @@ scheduler_release_channel_mock(channel_t *ch) } static int -test_chan_is_canonical(channel_t *chan, int req) +test_chan_is_canonical(channel_t *chan) { tor_assert(chan); - if (req && test_chan_canonical_should_be_reliable) { - return 1; - } - if (test_chan_should_be_canonical) { return 1; } @@ -1366,6 +1369,9 @@ test_channel_for_extend(void *arg) /* Make it older than chan1. */ chan2->timestamp_created = chan1->timestamp_created - 1; + /* Say it's all canonical. */ + test_chan_should_be_canonical = 1; + /* Set channel identities and add it to the channel map. The last one to be * added is made the first one in the list so the lookup will always return * that one first. */ @@ -1469,8 +1475,8 @@ test_channel_for_extend(void *arg) chan2->is_bad_for_new_circs = 0; /* Non canonical channels. */ + test_chan_should_be_canonical = 0; test_chan_should_match_target = 0; - test_chan_canonical_should_be_reliable = 1; ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr, &msg, &launch); tt_assert(!ret_chan); @@ -1546,11 +1552,11 @@ test_channel_listener(void *arg) #define TEST_SETUP_MATCHES_ADDR(orcon, addr, src, rv) STMT_BEGIN \ rv = tor_inet_pton(addr.family, src, &addr.addr); \ tt_int_op(rv, OP_EQ, 1); \ - orcon->real_addr = addr; \ + orcon->base_.addr = addr; \ STMT_END; #define TEST_MATCHES_ADDR(chan, addr4, addr6, rv, exp) STMT_BEGIN \ - rv = channel_matches_target_addr_for_extend(chan, addr4, addr6); \ + rv = channel_matches_target_addr_for_extend(chan, addr4, addr6); \ tt_int_op(rv, OP_EQ, exp); \ STMT_END; diff --git a/src/test/test_channeltls.c b/src/test/test_channeltls.c index f682c57acf..0227779e8b 100644 --- a/src/test/test_channeltls.c +++ b/src/test/test_channeltls.c @@ -293,7 +293,7 @@ tlschan_connection_or_connect_mock(const tor_addr_t *addr, result->base_.port = port; memcpy(result->identity_digest, digest, DIGEST_LEN); result->chan = tlschan; - memcpy(&(result->real_addr), addr, sizeof(tor_addr_t)); + memcpy(&result->base_.addr, addr, sizeof(tor_addr_t)); result->tls = (tor_tls_t *)((void *)(&fake_tortls)); done: diff --git a/src/test/test_circuitbuild.c b/src/test/test_circuitbuild.c index 66751bc5aa..74824a1bc1 100644 --- a/src/test/test_circuitbuild.c +++ b/src/test/test_circuitbuild.c @@ -1286,7 +1286,7 @@ test_circuit_extend(void *arg) MOCK(server_mode, mock_server_mode); /* Mock a debug function, but otherwise ignore it */ - MOCK(channel_get_canonical_remote_descr, + MOCK(channel_describe_peer, mock_channel_get_canonical_remote_descr); setup_full_capture_of_logs(LOG_INFO); @@ -1479,7 +1479,7 @@ test_circuit_extend(void *arg) UNMOCK(server_mode); server = 0; - UNMOCK(channel_get_canonical_remote_descr); + UNMOCK(channel_describe_peer); UNMOCK(extend_cell_parse); memset(&mock_extend_cell_parse_cell_out, 0, diff --git a/src/test/test_config.c b/src/test/test_config.c index cb88b95761..48a7091ef6 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -1244,8 +1244,7 @@ get_interface_address6_failure(int severity, sa_family_t family, #define VALIDATE_FOUND_ADDRESS(ret, method, hostname) \ do { \ tt_int_op(retval, OP_EQ, ret); \ - if (method == NULL) tt_assert(!method_used); \ - else tt_str_op(method_used, OP_EQ, method); \ + tt_int_op(method, OP_EQ, method_used); \ if (hostname == NULL) tt_assert(!hostname_out); \ else tt_str_op(hostname_out, OP_EQ, hostname); \ if (ret == true) { \ @@ -1260,6 +1259,7 @@ get_interface_address6_failure(int severity, sa_family_t family, do { \ config_free_lines(options->Address); \ config_free_lines(options->ORPort_lines); \ + options->AddressDisableIPv6 = 0; \ options->ORPort_set = 0; \ tor_free(options->DirAuthorities); \ tor_free(hostname_out); \ @@ -1273,7 +1273,7 @@ test_config_find_my_address_mixed(void *arg) { or_options_t *options; tor_addr_t resolved_addr, test_addr; - const char *method_used; + resolved_addr_method_t method_used; char *hostname_out = NULL; bool retval; @@ -1290,14 +1290,10 @@ test_config_find_my_address_mixed(void *arg) "2a01:4f8:fff0:4f:266:37ff:fe2c:5d19"); tor_addr_parse(&test_addr, "2a01:4f8:fff0:4f:266:37ff:fe2c:5d19"); - /* IPv4 address not guessed since one Address statement exists. */ - retval = find_my_address(options, AF_INET, LOG_NOTICE, &resolved_addr, - &method_used, &hostname_out); - VALIDATE_FOUND_ADDRESS(false, NULL, NULL); /* IPv6 address should be found and considered configured. */ retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr, &method_used, &hostname_out); - VALIDATE_FOUND_ADDRESS(true, "CONFIGURED", NULL); + VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED, NULL); CLEANUP_FOUND_ADDRESS; @@ -1312,13 +1308,13 @@ test_config_find_my_address_mixed(void *arg) /* IPv4 address should be found and considered configured. */ retval = find_my_address(options, AF_INET, LOG_NOTICE, &resolved_addr, &method_used, &hostname_out); - VALIDATE_FOUND_ADDRESS(true, "CONFIGURED", NULL); + VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED, NULL); /* IPv6 address should be found and considered configured. */ tor_addr_parse(&test_addr, "2a01:4f8:fff0:4f:266:37ff:fe2c:5d19"); retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr, &method_used, &hostname_out); - VALIDATE_FOUND_ADDRESS(true, "CONFIGURED", NULL); + VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED, NULL); CLEANUP_FOUND_ADDRESS; @@ -1335,14 +1331,16 @@ test_config_find_my_address_mixed(void *arg) tor_addr_parse(&test_addr, "1.1.1.1"); retval = find_my_address(options, AF_INET, LOG_NOTICE, &resolved_addr, &method_used, &hostname_out); - VALIDATE_FOUND_ADDRESS(true, "RESOLVED", "www.torproject.org.v4"); + VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_RESOLVED, + "www.torproject.org.v4"); tor_free(hostname_out); /* IPv6 address should be found and considered resolved. */ tor_addr_parse(&test_addr, "0101::0101"); retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr, &method_used, &hostname_out); - VALIDATE_FOUND_ADDRESS(true, "RESOLVED", "www.torproject.org.v6"); + VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_RESOLVED, + "www.torproject.org.v6"); CLEANUP_FOUND_ADDRESS; UNMOCK(tor_addr_lookup); @@ -1360,13 +1358,14 @@ test_config_find_my_address_mixed(void *arg) tor_addr_parse(&test_addr, "1.1.1.1"); retval = find_my_address(options, AF_INET, LOG_NOTICE, &resolved_addr, &method_used, &hostname_out); - VALIDATE_FOUND_ADDRESS(true, "CONFIGURED", NULL); + VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED, NULL); /* IPv6 address should be found and considered resolved. */ tor_addr_parse(&test_addr, "0101::0101"); retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr, &method_used, &hostname_out); - VALIDATE_FOUND_ADDRESS(true, "RESOLVED", "www.torproject.org.v6"); + VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_RESOLVED, + "www.torproject.org.v6"); CLEANUP_FOUND_ADDRESS; UNMOCK(tor_addr_lookup); @@ -1384,14 +1383,15 @@ test_config_find_my_address_mixed(void *arg) tor_addr_parse(&test_addr, "1.1.1.1"); retval = find_my_address(options, AF_INET, LOG_NOTICE, &resolved_addr, &method_used, &hostname_out); - VALIDATE_FOUND_ADDRESS(true, "RESOLVED", "www.torproject.org.v4"); + VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_RESOLVED, + "www.torproject.org.v4"); tor_free(hostname_out); /* IPv6 address should be found and considered resolved. */ tor_addr_parse(&test_addr, "0101::0101"); retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr, &method_used, &hostname_out); - VALIDATE_FOUND_ADDRESS(true, "CONFIGURED", NULL); + VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED, NULL); CLEANUP_FOUND_ADDRESS; UNMOCK(tor_addr_lookup); @@ -1442,7 +1442,7 @@ test_config_find_my_address(void *arg) { or_options_t *options; tor_addr_t resolved_addr, test_addr; - const char *method_used; + resolved_addr_method_t method_used; char *hostname_out = NULL; bool retval; int prev_n_hostname_01010101; @@ -1460,6 +1460,24 @@ test_config_find_my_address(void *arg) options_init(options); /* + * Case 0: + * AddressDisableIPv6 is set. + * + * Only run this if we are in the IPv6 test. + */ + if (p->family == AF_INET6) { + options->AddressDisableIPv6 = 1; + /* Set a valid IPv6. However, the discovery should still fail. */ + config_line_append(&options->Address, "Address", p->public_ip); + tor_addr_parse(&test_addr, p->public_ip); + + retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr, + &method_used, &hostname_out); + VALIDATE_FOUND_ADDRESS(false, RESOLVED_ADDR_NONE, NULL); + CLEANUP_FOUND_ADDRESS; + } + + /* * Case 1: * 1. Address is a valid address. * @@ -1471,7 +1489,7 @@ test_config_find_my_address(void *arg) retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr, &method_used, &hostname_out); - VALIDATE_FOUND_ADDRESS(true, "CONFIGURED", NULL); + VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED, NULL); CLEANUP_FOUND_ADDRESS; /* @@ -1488,7 +1506,7 @@ test_config_find_my_address(void *arg) &method_used, &hostname_out); tt_int_op(n_hostname_01010101, OP_EQ, ++prev_n_hostname_01010101); - VALIDATE_FOUND_ADDRESS(true, "RESOLVED", "www.torproject.org"); + VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_RESOLVED, "www.torproject.org"); CLEANUP_FOUND_ADDRESS; UNMOCK(tor_addr_lookup); @@ -1508,7 +1526,7 @@ test_config_find_my_address(void *arg) "public IP addresses."); teardown_capture_of_logs(); - VALIDATE_FOUND_ADDRESS(false, NULL, NULL); + VALIDATE_FOUND_ADDRESS(false, RESOLVED_ADDR_NONE, NULL); CLEANUP_FOUND_ADDRESS; /* @@ -1522,7 +1540,7 @@ test_config_find_my_address(void *arg) retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr, &method_used, &hostname_out); - VALIDATE_FOUND_ADDRESS(true, "CONFIGURED", NULL); + VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED, NULL); CLEANUP_FOUND_ADDRESS; /* @@ -1539,53 +1557,10 @@ test_config_find_my_address(void *arg) expect_log_msg_containing("Found 2 Address statement of address family"); teardown_capture_of_logs(); - VALIDATE_FOUND_ADDRESS(false, NULL, NULL); - CLEANUP_FOUND_ADDRESS; - - /* - * Case 6: Another address family is configured. Expected to fail. - */ - if (p->family == AF_INET) { - config_line_append(&options->Address, "Address", "4242::4242"); - } else { - config_line_append(&options->Address, "Address", "1.1.1.1"); - } - - setup_full_capture_of_logs(LOG_NOTICE); - - retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr, - &method_used, &hostname_out); - - expect_log_msg_containing("No Address option found for family"); - teardown_capture_of_logs(); - - VALIDATE_FOUND_ADDRESS(false, NULL, NULL); + VALIDATE_FOUND_ADDRESS(false, RESOLVED_ADDR_NONE, NULL); CLEANUP_FOUND_ADDRESS; /* - * Case 7: Address is a non resolvable hostname. Expected to fail. - */ - MOCK(tor_addr_lookup, tor_addr_lookup_failure); - - config_line_append(&options->Address, "Address", "www.torproject.org"); - prev_n_hostname_failure = n_hostname_failure; - - setup_full_capture_of_logs(LOG_NOTICE); - - retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr, - &method_used, &hostname_out); - - expect_log_msg_containing("Could not resolve local Address " - "'www.torproject.org'. Failing."); - teardown_capture_of_logs(); - - tt_int_op(n_hostname_failure, OP_EQ, ++prev_n_hostname_failure); - VALIDATE_FOUND_ADDRESS(false, NULL, NULL); - CLEANUP_FOUND_ADDRESS; - - UNMOCK(tor_addr_lookup); - - /* * Case 8: * 1. Address is NULL * 2. Interface address is a valid address. @@ -1603,7 +1578,7 @@ test_config_find_my_address(void *arg) &method_used, &hostname_out); tt_int_op(n_get_interface_address6, OP_EQ, ++prev_n_get_interface_address6); - VALIDATE_FOUND_ADDRESS(true, "INTERFACE", NULL); + VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_INTERFACE, NULL); CLEANUP_FOUND_ADDRESS; UNMOCK(get_interface_address6); @@ -1636,7 +1611,7 @@ test_config_find_my_address(void *arg) ++prev_n_hostname_01010101); tt_int_op(n_gethostname_replacement, OP_EQ, ++prev_n_gethostname_replacement); - VALIDATE_FOUND_ADDRESS(true, "GETHOSTNAME", "onionrouter!"); + VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_GETHOSTNAME, "onionrouter!"); CLEANUP_FOUND_ADDRESS; UNMOCK(get_interface_address6); @@ -1670,7 +1645,7 @@ test_config_find_my_address(void *arg) ++prev_n_hostname_localhost); tt_int_op(n_gethostname_localhost, OP_EQ, ++prev_n_gethostname_localhost); - VALIDATE_FOUND_ADDRESS(false, NULL, NULL); + VALIDATE_FOUND_ADDRESS(false, RESOLVED_ADDR_NONE, NULL); CLEANUP_FOUND_ADDRESS; UNMOCK(get_interface_address6); @@ -1700,7 +1675,7 @@ test_config_find_my_address(void *arg) ++prev_n_get_interface_address6_failure); tt_int_op(n_gethostname_failure, OP_EQ, ++prev_n_gethostname_failure); - VALIDATE_FOUND_ADDRESS(false, NULL, NULL); + VALIDATE_FOUND_ADDRESS(false, RESOLVED_ADDR_NONE, NULL); CLEANUP_FOUND_ADDRESS; UNMOCK(get_interface_address6); @@ -1733,7 +1708,7 @@ test_config_find_my_address(void *arg) ++prev_n_gethostname_replacement); tt_int_op(n_hostname_failure, OP_EQ, ++prev_n_hostname_failure); - VALIDATE_FOUND_ADDRESS(false, NULL, NULL); + VALIDATE_FOUND_ADDRESS(false, RESOLVED_ADDR_NONE, NULL); CLEANUP_FOUND_ADDRESS; /* @@ -1764,7 +1739,7 @@ test_config_find_my_address(void *arg) retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr, &method_used, &hostname_out); - VALIDATE_FOUND_ADDRESS(true, "CONFIGURED_ORPORT", NULL); + VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED_ORPORT, NULL); CLEANUP_FOUND_ADDRESS; /* @@ -1802,7 +1777,7 @@ test_config_find_my_address(void *arg) &method_used, &hostname_out); tt_int_op(n_get_interface_address6, OP_EQ, ++prev_n_get_interface_address6); - VALIDATE_FOUND_ADDRESS(true, "INTERFACE", NULL); + VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_INTERFACE, NULL); CLEANUP_FOUND_ADDRESS; UNMOCK(get_interface_address6); @@ -3889,16 +3864,17 @@ test_config_default_dir_servers(void *arg) or_options_free(opts); } -static int mock_router_pick_published_address_result = 0; +static bool mock_relay_find_addr_to_publish_result = true; -static int -mock_router_pick_published_address(const or_options_t *options, - uint32_t *addr, int cache_only) +static bool +mock_relay_find_addr_to_publish(const or_options_t *options, int family, + int flags, tor_addr_t *addr_out) { - (void)options; - (void)addr; - (void)cache_only; - return mock_router_pick_published_address_result; + (void) options; + (void) family; + (void) flags; + (void) addr_out; + return mock_relay_find_addr_to_publish_result; } static int mock_router_my_exit_policy_is_reject_star_result = 0; @@ -3934,11 +3910,11 @@ test_config_directory_fetch(void *arg) or_options_t *options = options_new(); routerinfo_t routerinfo; memset(&routerinfo, 0, sizeof(routerinfo)); - mock_router_pick_published_address_result = -1; + mock_relay_find_addr_to_publish_result = false; mock_router_my_exit_policy_is_reject_star_result = 1; mock_advertised_server_mode_result = 0; mock_router_get_my_routerinfo_result = NULL; - MOCK(router_pick_published_address, mock_router_pick_published_address); + MOCK(relay_find_addr_to_publish, mock_relay_find_addr_to_publish); MOCK(router_my_exit_policy_is_reject_star, mock_router_my_exit_policy_is_reject_star); MOCK(advertised_server_mode, mock_advertised_server_mode); @@ -3994,14 +3970,14 @@ test_config_directory_fetch(void *arg) options = options_new(); options->ORPort_set = 1; - mock_router_pick_published_address_result = -1; + mock_relay_find_addr_to_publish_result = false; tt_assert(server_mode(options) == 1); tt_assert(public_server_mode(options) == 1); tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 1); tt_int_op(networkstatus_consensus_can_use_multiple_directories(options), OP_EQ, 0); - mock_router_pick_published_address_result = 0; + mock_relay_find_addr_to_publish_result = true; tt_assert(server_mode(options) == 1); tt_assert(public_server_mode(options) == 1); tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 0); @@ -4015,7 +3991,7 @@ test_config_directory_fetch(void *arg) options = options_new(); options->ORPort_set = 1; options->ExitRelay = 1; - mock_router_pick_published_address_result = 0; + mock_relay_find_addr_to_publish_result = true; mock_router_my_exit_policy_is_reject_star_result = 0; mock_advertised_server_mode_result = 1; mock_router_get_my_routerinfo_result = &routerinfo; @@ -4030,7 +4006,7 @@ test_config_directory_fetch(void *arg) OP_EQ, 0); options->RefuseUnknownExits = 0; - mock_router_pick_published_address_result = 0; + mock_relay_find_addr_to_publish_result = true; tt_assert(server_mode(options) == 1); tt_assert(public_server_mode(options) == 1); tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 0); @@ -4047,7 +4023,7 @@ test_config_directory_fetch(void *arg) options->DirPort_set = 1; options->ORPort_set = 1; options->DirCache = 1; - mock_router_pick_published_address_result = 0; + mock_relay_find_addr_to_publish_result = true; mock_router_my_exit_policy_is_reject_star_result = 1; mock_advertised_server_mode_result = 1; @@ -4098,7 +4074,7 @@ test_config_directory_fetch(void *arg) done: or_options_free(options); - UNMOCK(router_pick_published_address); + UNMOCK(relay_find_addr_to_publish); UNMOCK(router_get_my_routerinfo); UNMOCK(advertised_server_mode); UNMOCK(router_my_exit_policy_is_reject_star); @@ -5189,6 +5165,44 @@ test_config_parse_port_config__ports__server_options(void *data) 0, CL_PORT_SERVER_OPTIONS); tt_int_op(ret, OP_EQ, -1); + /* Default address is IPv4 but pass IPv6Only flag. Should be ignored. */ + config_free_lines(config_port_invalid); config_port_invalid = NULL; + SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf)); + smartlist_clear(slout); + config_port_invalid = mock_config_line("ORPort", "9050 IPv6Only"); + ret = port_parse_config(slout, config_port_invalid, "ORPort", 0, + "127.0.0.1", 0, CL_PORT_SERVER_OPTIONS); + tt_int_op(ret, OP_EQ, 0); + + /* Default address is IPv6 but pass IPv4Only flag. Should be ignored. */ + config_free_lines(config_port_invalid); config_port_invalid = NULL; + SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf)); + smartlist_clear(slout); + config_port_invalid = mock_config_line("ORPort", "9050 IPv4Only"); + ret = port_parse_config(slout, config_port_invalid, "ORPort", 0, + "[::]", 0, CL_PORT_SERVER_OPTIONS); + tt_int_op(ret, OP_EQ, 0); + + /* Explicit address is IPv6 but pass IPv4Only flag. Should error. */ + config_free_lines(config_port_invalid); config_port_invalid = NULL; + SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf)); + smartlist_clear(slout); + config_port_invalid = mock_config_line("ORPort", + "[4242::4242]:9050 IPv4Only"); + ret = port_parse_config(slout, config_port_invalid, "ORPort", 0, + "[::]", 0, CL_PORT_SERVER_OPTIONS); + tt_int_op(ret, OP_EQ, -1); + + /* Explicit address is IPv4 but pass IPv6Only flag. Should error. */ + config_free_lines(config_port_invalid); config_port_invalid = NULL; + SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf)); + smartlist_clear(slout); + config_port_invalid = mock_config_line("ORPort", + "1.2.3.4:9050 IPv6Only"); + ret = port_parse_config(slout, config_port_invalid, "ORPort", 0, + "127.0.0.1", 0, CL_PORT_SERVER_OPTIONS); + tt_int_op(ret, OP_EQ, -1); + done: if (slout) SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf)); @@ -5208,17 +5222,17 @@ test_config_get_first_advertised(void *data) const tor_addr_t *addr; // no ports are configured? We get NULL. - port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER, + port = portconf_get_first_advertised_port(CONN_TYPE_OR_LISTENER, AF_INET); tt_int_op(port, OP_EQ, 0); - addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER, + addr = portconf_get_first_advertised_addr(CONN_TYPE_OR_LISTENER, AF_INET); tt_ptr_op(addr, OP_EQ, NULL); - port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER, + port = portconf_get_first_advertised_port(CONN_TYPE_OR_LISTENER, AF_INET6); tt_int_op(port, OP_EQ, 0); - addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER, + addr = portconf_get_first_advertised_addr(CONN_TYPE_OR_LISTENER, AF_INET6); tt_ptr_op(addr, OP_EQ, NULL); @@ -5232,27 +5246,27 @@ test_config_get_first_advertised(void *data) tt_assert(r == 0); // UNSPEC gets us nothing. - port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER, + port = portconf_get_first_advertised_port(CONN_TYPE_OR_LISTENER, AF_UNSPEC); tt_int_op(port, OP_EQ, 0); - addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER, + addr = portconf_get_first_advertised_addr(CONN_TYPE_OR_LISTENER, AF_UNSPEC); tt_ptr_op(addr, OP_EQ, NULL); // Try AF_INET. - port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER, + port = portconf_get_first_advertised_port(CONN_TYPE_OR_LISTENER, AF_INET); tt_int_op(port, OP_EQ, 9911); - addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER, + addr = portconf_get_first_advertised_addr(CONN_TYPE_OR_LISTENER, AF_INET); tt_ptr_op(addr, OP_NE, NULL); tt_str_op(fmt_addrport(addr,port), OP_EQ, "5.6.7.8:9911"); // Try AF_INET6 - port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER, + port = portconf_get_first_advertised_port(CONN_TYPE_OR_LISTENER, AF_INET6); tt_int_op(port, OP_EQ, 8080); - addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER, + addr = portconf_get_first_advertised_addr(CONN_TYPE_OR_LISTENER, AF_INET6); tt_ptr_op(addr, OP_NE, NULL); tt_str_op(fmt_addrport(addr,port), OP_EQ, "[1234::5678]:8080"); @@ -6822,6 +6836,39 @@ test_config_getinfo_config_names(void *arg) tor_free(answer); } +static void +test_config_duplicate_orports(void *arg) +{ + (void)arg; + + config_line_t *config_port = NULL; + smartlist_t *ports = smartlist_new(); + + // Pretend that the user has specified an implicit 0.0.0.0:9050, an implicit + // [::]:9050, and an explicit on [::1]:9050. + config_line_append(&config_port, "ORPort", "9050"); // two implicit entries. + config_line_append(&config_port, "ORPort", "[::1]:9050"); + + // Parse IPv4, then IPv6. + port_parse_config(ports, config_port, "OR", CONN_TYPE_OR_LISTENER, "0.0.0.0", + 0, CL_PORT_SERVER_OPTIONS); + port_parse_config(ports, config_port, "OR", CONN_TYPE_OR_LISTENER, "[::]", + 0, CL_PORT_SERVER_OPTIONS); + + // There should be three ports at this point. + tt_int_op(smartlist_len(ports), OP_EQ, 3); + + remove_duplicate_orports(ports); + + // The explicit IPv6 port should have replaced the implicit IPv6 port. + tt_int_op(smartlist_len(ports), OP_EQ, 2); + + done: + SMARTLIST_FOREACH(ports,port_cfg_t *,pf,port_cfg_free(pf)); + smartlist_free(ports); + config_free_lines(config_port); +} + #ifndef COCCI #define CONFIG_TEST(name, flags) \ { #name, test_config_ ## name, flags, NULL, NULL } @@ -6889,5 +6936,6 @@ struct testcase_t config_tests[] = { CONFIG_TEST(extended_fmt, 0), CONFIG_TEST(kvline_parse, 0), CONFIG_TEST(getinfo_config_names, 0), + CONFIG_TEST(duplicate_orports, 0), END_OF_TESTCASES }; diff --git a/src/test/test_connection.c b/src/test/test_connection.c index 7ced49a166..954aeb82e3 100644 --- a/src/test/test_connection.c +++ b/src/test/test_connection.c @@ -10,6 +10,7 @@ #include "core/or/or.h" #include "test/test.h" +#include "app/config/config.h" #include "app/config/or_options_st.h" #include "core/mainloop/connection.h" #include "core/or/connection_edge.h" @@ -910,7 +911,8 @@ test_failed_orconn_tracker(void *arg) /* Prepare the OR connection that will be used in this test */ or_connection_t or_conn; - tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.real_addr, "18.0.0.1")); + tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.canonical_orport.addr, + "18.0.0.1")); tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.base_.addr, "18.0.0.1")); or_conn.base_.port = 1; memset(or_conn.identity_digest, 'c', sizeof(or_conn.identity_digest)); @@ -961,6 +963,114 @@ test_failed_orconn_tracker(void *arg) ; } +static void +test_conn_describe(void *arg) +{ + (void)arg; + or_options_t *options = get_options_mutable(); + options->SafeLogging_ = SAFELOG_SCRUB_ALL; + + // Let's start with a listener connection since they're simple. + connection_t *conn = connection_new(CONN_TYPE_OR_LISTENER, AF_INET); + tor_addr_parse(&conn->addr, "44.22.11.11"); + conn->port = 80; + tt_str_op(connection_describe(conn), OP_EQ, + "OR listener connection (ready) on 44.22.11.11:80"); + // If the address is unspec, we should still work. + tor_addr_make_unspec(&conn->addr); + tt_str_op(connection_describe(conn), OP_EQ, + "OR listener connection (ready) on <unset>:80"); + // Try making the address null. + tor_addr_make_null(&conn->addr, AF_INET); + tt_str_op(connection_describe(conn), OP_EQ, + "OR listener connection (ready) on 0.0.0.0:80"); + // What if the address is uninitialized? (This can happen if we log about the + // connection before we set the address.) + memset(&conn->addr, 0, sizeof(conn->addr)); + tt_str_op(connection_describe(conn), OP_EQ, + "OR listener connection (ready) on <unset>:80"); + connection_free_minimal(conn); + + // Try a unix socket. + conn = connection_new(CONN_TYPE_CONTROL_LISTENER, AF_UNIX); + conn->address = tor_strdup("/a/path/that/could/exist"); + tt_str_op(connection_describe(conn), OP_EQ, + "Control listener connection (ready) on /a/path/that/could/exist"); + connection_free_minimal(conn); + + // Try an IPv6 address. + conn = connection_new(CONN_TYPE_AP_LISTENER, AF_INET6); + tor_addr_parse(&conn->addr, "ff00::3"); + conn->port = 9050; + tt_str_op(connection_describe(conn), OP_EQ, + "Socks listener connection (ready) on [ff00::3]:9050"); + connection_free_minimal(conn); + + // Now let's mess with exit connections. They have some special issues. + options->SafeLogging_ = SAFELOG_SCRUB_NONE; + conn = connection_new(CONN_TYPE_EXIT, AF_INET); + // If address and state are unset, we should say SOMETHING. + tt_str_op(connection_describe(conn), OP_EQ, + "Exit connection (uninitialized) to <unset> (DNS lookup pending)"); + // Now suppose that the address is set but we haven't resolved the hostname. + conn->port = 443; + conn->address = tor_strdup("www.torproject.org"); + conn->state = EXIT_CONN_STATE_RESOLVING; + tt_str_op(connection_describe(conn), OP_EQ, + "Exit connection (waiting for dest info) to " + "www.torproject.org:443 (DNS lookup pending)"); + // Now give it a hostname! + tor_addr_parse(&conn->addr, "192.168.8.8"); + conn->state = EXIT_CONN_STATE_OPEN; + tt_str_op(connection_describe(conn), OP_EQ, + "Exit connection (open) to 192.168.8.8:443"); + // But what if safelogging is on? + options->SafeLogging_ = SAFELOG_SCRUB_RELAY; + tt_str_op(connection_describe(conn), OP_EQ, + "Exit connection (open) to [scrubbed]"); + connection_free_minimal(conn); + + // Now at last we look at OR addresses, which are complicated. + conn = connection_new(CONN_TYPE_OR, AF_INET6); + conn->state = OR_CONN_STATE_OPEN; + conn->port = 8080; + tor_addr_parse(&conn->addr, "[ffff:3333:1111::2]"); + // This should get scrubbed, since the lack of a set ID means we might be + // talking to a client. + tt_str_op(connection_describe(conn), OP_EQ, + "OR connection (open) with [scrubbed]"); + // But now suppose we aren't safelogging? We'll get the address then. + options->SafeLogging_ = SAFELOG_SCRUB_NONE; + tt_str_op(connection_describe(conn), OP_EQ, + "OR connection (open) with [ffff:3333:1111::2]:8080"); + // Suppose we have an ID, so we know it isn't a client. + TO_OR_CONN(conn)->identity_digest[3] = 7; + options->SafeLogging_ = SAFELOG_SCRUB_RELAY; // back to safelogging. + tt_str_op(connection_describe(conn), OP_EQ, + "OR connection (open) with [ffff:3333:1111::2]:8080 " + "ID=0000000700000000000000000000000000000000"); + // Add a 'canonical address' that is the same as the one we have. + tor_addr_parse(&TO_OR_CONN(conn)->canonical_orport.addr, + "[ffff:3333:1111::2]"); + TO_OR_CONN(conn)->canonical_orport.port = 8080; + tt_str_op(connection_describe(conn), OP_EQ, + "OR connection (open) with [ffff:3333:1111::2]:8080 " + "ID=0000000700000000000000000000000000000000"); + // Add a different 'canonical address' + tor_addr_parse(&TO_OR_CONN(conn)->canonical_orport.addr, + "[ffff:3333:1111::8]"); + tt_str_op(connection_describe(conn), OP_EQ, + "OR connection (open) with [ffff:3333:1111::2]:8080 " + "ID=0000000700000000000000000000000000000000 " + "canonical_addr=[ffff:3333:1111::8]:8080"); + + // Clear identity_digest so that free_minimal won't complain. + memset(TO_OR_CONN(conn)->identity_digest, 0, DIGEST_LEN); + + done: + connection_free_minimal(conn); +} + #ifndef COCCI #define CONNECTION_TESTCASE(name, fork, setup) \ { #name, test_conn_##name, fork, &setup, NULL } @@ -995,5 +1105,6 @@ struct testcase_t connection_tests[] = { //CONNECTION_TESTCASE(func_suffix, TT_FORK, setup_func_pair), { "failed_orconn_tracker", test_failed_orconn_tracker, TT_FORK, NULL, NULL }, + { "describe", test_conn_describe, TT_FORK, NULL, NULL }, END_OF_TESTCASES }; diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c index 0d75a212e9..ffd6a25bd5 100644 --- a/src/test/test_crypto.c +++ b/src/test/test_crypto.c @@ -2107,21 +2107,21 @@ test_crypto_curve25519_encode(void *arg) { curve25519_secret_key_t seckey; curve25519_public_key_t key1, key2, key3; - char buf[64]; + char buf[64], buf_nopad[64]; (void)arg; curve25519_secret_key_generate(&seckey, 0); curve25519_public_key_generate(&key1, &seckey); - curve25519_public_to_base64(buf, &key1); + curve25519_public_to_base64(buf, &key1, true); tt_int_op(CURVE25519_BASE64_PADDED_LEN, OP_EQ, strlen(buf)); tt_int_op(0, OP_EQ, curve25519_public_from_base64(&key2, buf)); tt_mem_op(key1.public_key,OP_EQ, key2.public_key, CURVE25519_PUBKEY_LEN); - buf[CURVE25519_BASE64_PADDED_LEN - 1] = '\0'; - tt_int_op(CURVE25519_BASE64_PADDED_LEN-1, OP_EQ, strlen(buf)); - tt_int_op(0, OP_EQ, curve25519_public_from_base64(&key3, buf)); + curve25519_public_to_base64(buf_nopad, &key1, false); + tt_int_op(CURVE25519_BASE64_LEN, OP_EQ, strlen(buf_nopad)); + tt_int_op(0, OP_EQ, curve25519_public_from_base64(&key3, buf_nopad)); tt_mem_op(key1.public_key,OP_EQ, key3.public_key, CURVE25519_PUBKEY_LEN); /* Now try bogus parses. */ diff --git a/src/test/test_dir.c b/src/test/test_dir.c index 12221f6ad4..ab0315aa2d 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -397,18 +397,14 @@ get_new_ntor_onion_key_line(const curve25519_public_key_t *ntor_onion_pubkey) { char *line = NULL; char cert_buf[256]; - int rv = 0; tor_assert(ntor_onion_pubkey); - rv = base64_encode(cert_buf, sizeof(cert_buf), - (const char*)ntor_onion_pubkey->public_key, 32, - BASE64_ENCODE_MULTILINE); - tor_assert(rv > 0); + curve25519_public_to_base64(cert_buf, ntor_onion_pubkey, false); tor_assert(strlen(cert_buf) > 0); tor_asprintf(&line, - "ntor-onion-key %s", + "ntor-onion-key %s\n", cert_buf); tor_assert(line); diff --git a/src/test/test_dos.c b/src/test/test_dos.c index 7378efd426..850bbef59b 100644 --- a/src/test/test_dos.c +++ b/src/test/test_dos.c @@ -66,9 +66,9 @@ test_dos_conn_creation(void *arg) /* Initialize test data */ or_connection_t or_conn; time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */ - tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.real_addr, + tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&TO_CONN(&or_conn)->addr, "18.0.0.1")); - tor_addr_t *addr = &or_conn.real_addr; + tor_addr_t *addr = &TO_CONN(&or_conn)->addr; /* Get DoS subsystem limits */ dos_init(); @@ -139,9 +139,9 @@ test_dos_circuit_creation(void *arg) /* Initialize test data */ or_connection_t or_conn; time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */ - tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.real_addr, + tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&TO_CONN(&or_conn)->addr, "18.0.0.1")); - tor_addr_t *addr = &or_conn.real_addr; + tor_addr_t *addr = &TO_CONN(&or_conn)->addr; /* Get DoS subsystem limits */ dos_init(); @@ -202,9 +202,9 @@ test_dos_bucket_refill(void *arg) channel_init(chan); chan->is_client = 1; or_connection_t or_conn; - tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.real_addr, + tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&TO_CONN(&or_conn)->addr, "18.0.0.1")); - tor_addr_t *addr = &or_conn.real_addr; + tor_addr_t *addr = &TO_CONN(&or_conn)->addr; /* Initialize DoS subsystem and get relevant limits */ dos_init(); @@ -443,10 +443,10 @@ test_known_relay(void *arg) /* Setup an OR conn so we can pass it to the DoS subsystem. */ or_connection_t or_conn; - tor_addr_parse(&or_conn.real_addr, "42.42.42.42"); + tor_addr_parse(&TO_CONN(&or_conn)->addr, "42.42.42.42"); rs = tor_malloc_zero(sizeof(*rs)); - tor_addr_copy(&rs->ipv4_addr, &or_conn.real_addr); + tor_addr_copy(&rs->ipv4_addr, &TO_CONN(&or_conn)->addr); crypto_rand(rs->identity_digest, sizeof(rs->identity_digest)); smartlist_add(dummy_ns->routerstatus_list, rs); @@ -457,7 +457,8 @@ test_known_relay(void *arg) /* We have now a node in our list so we'll make sure we don't count it as a * client connection. */ - geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &or_conn.real_addr, NULL, 0); + geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &TO_CONN(&or_conn)->addr, + NULL, 0); /* Suppose we have 5 connections in rapid succession, the counter should * always be 0 because we should ignore this. */ dos_new_client_conn(&or_conn, NULL); @@ -465,18 +466,21 @@ test_known_relay(void *arg) dos_new_client_conn(&or_conn, NULL); dos_new_client_conn(&or_conn, NULL); dos_new_client_conn(&or_conn, NULL); - entry = geoip_lookup_client(&or_conn.real_addr, NULL, GEOIP_CLIENT_CONNECT); + entry = geoip_lookup_client(&TO_CONN(&or_conn)->addr, NULL, + GEOIP_CLIENT_CONNECT); tt_assert(entry); /* We should have a count of 0. */ tt_uint_op(entry->dos_stats.concurrent_count, OP_EQ, 0); /* To make sure that his is working properly, make a unknown client * connection and see if we do get it. */ - tor_addr_parse(&or_conn.real_addr, "42.42.42.43"); - geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &or_conn.real_addr, NULL, 0); + tor_addr_parse(&TO_CONN(&or_conn)->addr, "42.42.42.43"); + geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &TO_CONN(&or_conn)->addr, + NULL, 0); dos_new_client_conn(&or_conn, NULL); dos_new_client_conn(&or_conn, NULL); - entry = geoip_lookup_client(&or_conn.real_addr, NULL, GEOIP_CLIENT_CONNECT); + entry = geoip_lookup_client(&TO_CONN(&or_conn)->addr, NULL, + GEOIP_CLIENT_CONNECT); tt_assert(entry); /* We should have a count of 2. */ tt_uint_op(entry->dos_stats.concurrent_count, OP_EQ, 2); diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c index 7da7ea66e4..589876db2a 100644 --- a/src/test/test_entrynodes.c +++ b/src/test/test_entrynodes.c @@ -322,7 +322,7 @@ test_node_preferred_orport(void *arg) * ClientUseIPv4 is 0 */ mocked_options->ClientUseIPv4 = 0; mocked_options->ClientUseIPv6 = 1; - node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(mocked_options); + node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(mocked_options); node_get_pref_orport(&node, &ap); tt_assert(tor_addr_eq(&ap.addr, &ipv6_addr)); tt_assert(ap.port == ipv6_port); diff --git a/src/test/test_key_expiration.sh b/src/test/test_key_expiration.sh index 2238f7aa78..1ba8179aa1 100755 --- a/src/test/test_key_expiration.sh +++ b/src/test/test_key_expiration.sh @@ -61,6 +61,11 @@ fi CASE1=$dflt CASE2=$dflt CASE3=$dflt +CASE4=$dflt +CASE5=$dflt +CASE6=$dflt +CASE7=$dflt +CASE8=$dflt if [ $# -ge 1 ]; then eval "CASE${1}"=1 @@ -125,16 +130,17 @@ if [ "$CASE1" = 1 ]; then ${TOR} ${QUIETLY} --key-expiration 2>"$FN" || true grep "No valid argument to --key-expiration found!" "$FN" >/dev/null || \ - die "Tor didn't mention supported --key-expiration argmuents" + die "Tor didn't mention supported --key-expiration arguments" echo "==== Case 1: ok" fi if [ "$CASE2" = 1 ]; then - echo "==== Case 2: Start Tor with --key-expiration 'sign' and make sure it prints an expiration." + echo "==== Case 2: Start Tor with --key-expiration 'sign' and make sure it" + echo " prints an expiration using ISO8601 date format." ${TOR} ${QUIETLY} --key-expiration sign 2>"$FN" - grep "signing-cert-expiry:" "$FN" >/dev/null || \ + grep "signing-cert-expiry: [0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\} [0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}" "$FN" >/dev/null || \ die "Tor didn't print an expiration" echo "==== Case 2: ok" @@ -160,3 +166,61 @@ if [ "$CASE3" = 1 ]; then echo "==== Case 3: ok" fi + +if [ "$CASE4" = 1 ]; then + echo "==== Case 4: Start Tor with --format iso8601 and make sure it prints an" + echo " error message due to missing --key-expiration argument." + + ${TOR} --format iso8601 > "$FN" 2>&1 || true + grep -- "--format specified without --key-expiration!" "$FN" >/dev/null || \ + die "Tor didn't print a missing --key-expiration error message" + + echo "==== Case 4: ok" +fi + +if [ "$CASE5" = 1 ]; then + echo "==== Case 5: Start Tor with --key-expiration 'sign' --format '' and" + echo " make sure it prints an error message due to missing value." + + ${TOR} --key-expiration sign --format > "$FN" 2>&1 || true + grep "Command-line option '--format' with no value. Failing." "$FN" >/dev/null || \ + die "Tor didn't print a missing format value error message" + + echo "==== Case 5: ok" +fi + +if [ "$CASE6" = 1 ]; then + echo "==== Case 6: Start Tor with --key-expiration 'sign' --format 'invalid'" + echo " and make sure it prints an error message due to invalid" + echo " value." + + ${TOR} --key-expiration sign --format invalid > "$FN" 2>&1 || true + grep "Invalid --format value" "$FN" >/dev/null || \ + die "Tor didn't print an invalid format value error message" + + echo "==== Case 6: ok" +fi + +if [ "$CASE7" = 1 ]; then + echo "==== Case 7: Start Tor with --key-expiration 'sign' --format 'iso8601'" + echo " and make sure it prints an expiration using ISO8601 date" + echo " format." + + ${TOR} ${QUIETLY} --key-expiration sign --format iso8601 2>"$FN" + grep "signing-cert-expiry: [0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\} [0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}" "$FN" >/dev/null || \ + die "Tor didn't print an expiration" + + echo "==== Case 7: ok" +fi + +if [ "$CASE8" = 1 ]; then + echo "==== Case 8: Start Tor with --key-expiration 'sign' --format 'timestamp'" + echo " and make sure it prints an expiration using timestamp date" + echo " format." + + ${TOR} ${QUIETLY} --key-expiration sign --format timestamp 2>"$FN" + grep "signing-cert-expiry: [0-9]\{5,\}" "$FN" >/dev/null || \ + die "Tor didn't print an expiration" + + echo "==== Case 8: ok" +fi diff --git a/src/test/test_parseconf.sh b/src/test/test_parseconf.sh index 4fe27d9f5d..c02b8b23c0 100755 --- a/src/test/test_parseconf.sh +++ b/src/test/test_parseconf.sh @@ -202,7 +202,7 @@ STANDARD_LIBS="libevent\\|openssl\\|zlib" # shellcheck disable=SC2018,SC2019 TOR_LIBS_ENABLED="$("$TOR_BINARY" --verify-config \ -f "$EMPTY" --defaults-torrc "$EMPTY" \ - | sed -n 's/.* Tor .* running on .* with\(.*\)\./\1/p' \ + | sed -n 's/.* Tor .* running on .* with\(.*\) and .* .* as libc\./\1/p' \ | tr 'A-Z' 'a-z' | tr ',' '\n' \ | grep -v "$STANDARD_LIBS" | grep -v "n/a" \ | sed 's/\( and\)* \(lib\)*\([a-z0-9]*\) .*/\3/' \ diff --git a/src/test/test_policy.c b/src/test/test_policy.c index 3559c0dda8..0a0548d161 100644 --- a/src/test/test_policy.c +++ b/src/test/test_policy.c @@ -1753,7 +1753,7 @@ test_policies_getinfo_helper_policies(void *arg) #define OTHER_IPV4_ADDR_STR "6.7.8.9" #define OTHER_IPV6_ADDR_STR "[afff::]" -/** Run unit tests for fascist_firewall_allows_address */ +/** Run unit tests for reachable_addr_allows */ static void test_policies_fascist_firewall_allows_address(void *arg) { @@ -1822,33 +1822,33 @@ test_policies_fascist_firewall_allows_address(void *arg) mock_options.ClientUseIPv6 = 1; mock_options.UseBridges = 0; - tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 0, 0), OP_EQ, 1); - tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 0, 0), OP_EQ, 1); - tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 0, 0), OP_EQ, 0); - tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 0, 0), OP_EQ, 0); /* Preferring IPv4 */ - tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 0), + tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 1, 0), OP_EQ, 1); - tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 0), + tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 1, 0), OP_EQ, 0); - tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 0), + tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 1, 0), OP_EQ, 0); - tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 0), + tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 1, 0), OP_EQ, 0); /* Preferring IPv6 */ - tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 1), + tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 1, 1), OP_EQ, 0); - tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 1), + tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 1, 1), OP_EQ, 1); - tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 1), + tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 1, 1), OP_EQ, 0); - tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 1), + tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 1, 1), OP_EQ, 0); /* Test the function's address matching with UseBridges on */ @@ -1857,45 +1857,45 @@ test_policies_fascist_firewall_allows_address(void *arg) mock_options.ClientUseIPv6 = 1; mock_options.UseBridges = 1; - tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 0, 0), OP_EQ, 1); - tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 0, 0), OP_EQ, 1); - tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 0, 0), OP_EQ, 0); - tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 0, 0), OP_EQ, 0); /* Preferring IPv4 */ - tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 0), + tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 1, 0), OP_EQ, 1); - tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 0), + tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 1, 0), OP_EQ, 0); - tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 0), + tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 1, 0), OP_EQ, 0); - tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 0), + tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 1, 0), OP_EQ, 0); /* Preferring IPv6 */ - tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 1), + tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 1, 1), OP_EQ, 0); - tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 1), + tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 1, 1), OP_EQ, 1); - tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 1), + tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 1, 1), OP_EQ, 0); - tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 1), + tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 1, 1), OP_EQ, 0); /* bridge clients always use IPv6, regardless of ClientUseIPv6 */ mock_options.ClientUseIPv4 = 1; mock_options.ClientUseIPv6 = 0; - tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 0, 0), OP_EQ, 1); - tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 0, 0), OP_EQ, 1); - tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 0, 0), OP_EQ, 0); - tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 0, 0), OP_EQ, 0); /* Test the function's address matching with IPv4 on */ @@ -1904,13 +1904,13 @@ test_policies_fascist_firewall_allows_address(void *arg) mock_options.ClientUseIPv6 = 0; mock_options.UseBridges = 0; - tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 0, 0), OP_EQ, 1); - tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 0, 0), OP_EQ, 0); - tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 0, 0), OP_EQ, 0); - tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 0, 0), OP_EQ, 0); /* Test the function's address matching with IPv6 on */ @@ -1919,13 +1919,13 @@ test_policies_fascist_firewall_allows_address(void *arg) mock_options.ClientUseIPv6 = 1; mock_options.UseBridges = 0; - tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 0, 0), OP_EQ, 0); - tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 0, 0), OP_EQ, 1); - tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 0, 0), OP_EQ, 0); - tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 0, 0), OP_EQ, 0); /* Test the function's address matching with ClientUseIPv4 0. @@ -1935,13 +1935,13 @@ test_policies_fascist_firewall_allows_address(void *arg) mock_options.ClientUseIPv6 = 0; mock_options.UseBridges = 0; - tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 0, 0), OP_EQ, 0); - tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 0, 0), OP_EQ, 1); - tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 0, 0), OP_EQ, 0); - tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 0, 0), OP_EQ, 0); /* Test the function's address matching for unusual inputs */ @@ -1951,27 +1951,27 @@ test_policies_fascist_firewall_allows_address(void *arg) mock_options.UseBridges = 1; /* NULL and tor_addr_is_null addresses are rejected */ - tt_int_op(fascist_firewall_allows_address(NULL, port, policy, 0, 0), OP_EQ, + tt_int_op(reachable_addr_allows(NULL, port, policy, 0, 0), OP_EQ, 0); - tt_int_op(fascist_firewall_allows_address(&n_ipv4_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&n_ipv4_addr, port, policy, 0, 0), OP_EQ, 0); - tt_int_op(fascist_firewall_allows_address(&n_ipv6_addr, port, policy, 0, 0), + tt_int_op(reachable_addr_allows(&n_ipv6_addr, port, policy, 0, 0), OP_EQ, 0); /* zero ports are rejected */ - tt_int_op(fascist_firewall_allows_address(&ipv4_addr, 0, policy, 0, 0), + tt_int_op(reachable_addr_allows(&ipv4_addr, 0, policy, 0, 0), OP_EQ, 0); - tt_int_op(fascist_firewall_allows_address(&ipv6_addr, 0, policy, 0, 0), + tt_int_op(reachable_addr_allows(&ipv6_addr, 0, policy, 0, 0), OP_EQ, 0); /* NULL and empty policies accept everything */ - tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, NULL, 0, 0), + tt_int_op(reachable_addr_allows(&ipv4_addr, port, NULL, 0, 0), OP_EQ, 1); - tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, NULL, 0, 0), + tt_int_op(reachable_addr_allows(&ipv6_addr, port, NULL, 0, 0), OP_EQ, 1); - tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, e_policy, 0, 0), + tt_int_op(reachable_addr_allows(&ipv4_addr, port, e_policy, 0, 0), OP_EQ, 1); - tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, e_policy, 0, 0), + tt_int_op(reachable_addr_allows(&ipv6_addr, port, e_policy, 0, 0), OP_EQ, 1); done: @@ -1991,7 +1991,7 @@ test_policies_fascist_firewall_allows_address(void *arg) #define TEST_IPV6_OR_PORT 61234 #define TEST_IPV6_DIR_PORT 62345 -/* Check that fascist_firewall_choose_address_rs() returns the expected +/* Check that reachable_addr_choose_from_rs() returns the expected * results. */ #define CHECK_CHOSEN_ADDR_RS(fake_rs, fw_connection, pref_only, expect_rv, \ expect_ap) \ @@ -1999,13 +1999,13 @@ test_policies_fascist_firewall_allows_address(void *arg) tor_addr_port_t chosen_rs_ap; \ tor_addr_make_null(&chosen_rs_ap.addr, AF_INET); \ chosen_rs_ap.port = 0; \ - fascist_firewall_choose_address_rs(&(fake_rs), (fw_connection), \ + reachable_addr_choose_from_rs(&(fake_rs), (fw_connection), \ (pref_only), &chosen_rs_ap); \ tt_assert(tor_addr_eq(&(expect_ap).addr, &chosen_rs_ap.addr)); \ tt_int_op((expect_ap).port, OP_EQ, chosen_rs_ap.port); \ STMT_END -/* Check that fascist_firewall_choose_address_node() returns the expected +/* Check that reachable_addr_choose_from_node() returns the expected * results. */ #define CHECK_CHOSEN_ADDR_NODE(fake_node, fw_connection, pref_only, \ expect_rv, expect_ap) \ @@ -2013,14 +2013,14 @@ test_policies_fascist_firewall_allows_address(void *arg) tor_addr_port_t chosen_node_ap; \ tor_addr_make_null(&chosen_node_ap.addr, AF_INET); \ chosen_node_ap.port = 0; \ - fascist_firewall_choose_address_node(&(fake_node),(fw_connection), \ + reachable_addr_choose_from_node(&(fake_node),(fw_connection), \ (pref_only), &chosen_node_ap); \ tt_assert(tor_addr_eq(&(expect_ap).addr, &chosen_node_ap.addr)); \ tt_int_op((expect_ap).port, OP_EQ, chosen_node_ap.port); \ STMT_END -/* Check that fascist_firewall_choose_address_rs and - * fascist_firewall_choose_address_node() both return the expected results. */ +/* Check that reachable_addr_choose_from_rs and + * reachable_addr_choose_from_node() both return the expected results. */ #define CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, fw_connection, pref_only, \ expect_rv, expect_ap) \ STMT_BEGIN \ @@ -2030,7 +2030,7 @@ test_policies_fascist_firewall_allows_address(void *arg) expect_ap); \ STMT_END -/* Check that fascist_firewall_choose_address_ls() returns the expected +/* Check that reachable_addr_choose_from_ls() returns the expected * results. */ #define CHECK_CHOSEN_ADDR_NULL_LS() \ STMT_BEGIN \ @@ -2038,7 +2038,7 @@ test_policies_fascist_firewall_allows_address(void *arg) tor_addr_make_null(&chosen_ls_ap.addr, AF_UNSPEC); \ chosen_ls_ap.port = 0; \ setup_full_capture_of_logs(LOG_WARN); \ - fascist_firewall_choose_address_ls(NULL, 1, &chosen_ls_ap); \ + reachable_addr_choose_from_ls(NULL, 1, &chosen_ls_ap); \ expect_single_log_msg("Unknown or missing link specifiers"); \ teardown_capture_of_logs(); \ STMT_END @@ -2049,7 +2049,7 @@ test_policies_fascist_firewall_allows_address(void *arg) tor_addr_make_null(&chosen_ls_ap.addr, AF_UNSPEC); \ chosen_ls_ap.port = 0; \ setup_full_capture_of_logs(LOG_WARN); \ - fascist_firewall_choose_address_ls(fake_ls, pref_only, &chosen_ls_ap); \ + reachable_addr_choose_from_ls(fake_ls, pref_only, &chosen_ls_ap); \ if (smartlist_len(fake_ls) == 0) { \ expect_single_log_msg("Link specifiers are empty"); \ } else { \ @@ -2066,7 +2066,7 @@ test_policies_fascist_firewall_allows_address(void *arg) tor_addr_make_null(&chosen_ls_ap.addr, AF_UNSPEC); \ chosen_ls_ap.port = 0; \ setup_full_capture_of_logs(LOG_WARN); \ - fascist_firewall_choose_address_ls(fake_ls, 0, &chosen_ls_ap); \ + reachable_addr_choose_from_ls(fake_ls, 0, &chosen_ls_ap); \ expect_single_log_msg("None of our link specifiers have IPv4 or IPv6"); \ teardown_capture_of_logs(); \ STMT_END @@ -2125,7 +2125,7 @@ test_policies_fascist_firewall_allows_address(void *arg) teardown_capture_of_logs(); \ STMT_END -/** Run unit tests for fascist_firewall_choose_address */ +/** Run unit tests for reachable_addr_choose */ static void test_policies_fascist_firewall_choose_address(void *arg) { @@ -2153,87 +2153,87 @@ test_policies_fascist_firewall_choose_address(void *arg) tor_addr_make_null(&n_ipv6_ap.addr, AF_INET6); n_ipv6_ap.port = 0; - /* Sanity check fascist_firewall_choose_address with IPv4 and IPv6 on */ + /* Sanity check reachable_addr_choose with IPv4 and IPv6 on */ memset(&mock_options, 0, sizeof(or_options_t)); mock_options.ClientUseIPv4 = 1; mock_options.ClientUseIPv6 = 1; mock_options.UseBridges = 0; /* Prefer IPv4 */ - tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 1, + tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 1, FIREWALL_OR_CONNECTION, 0, 0) == &ipv4_or_ap); - tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 1, + tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 1, FIREWALL_OR_CONNECTION, 1, 0) == &ipv4_or_ap); - tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 1, + tt_assert(reachable_addr_choose(&ipv4_dir_ap, &ipv6_dir_ap, 1, FIREWALL_DIR_CONNECTION, 0, 0) == &ipv4_dir_ap); - tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 1, + tt_assert(reachable_addr_choose(&ipv4_dir_ap, &ipv6_dir_ap, 1, FIREWALL_DIR_CONNECTION, 1, 0) == &ipv4_dir_ap); /* Prefer IPv6 */ - tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 0, FIREWALL_OR_CONNECTION, 0, 1) == &ipv6_or_ap); - tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 0, FIREWALL_OR_CONNECTION, 1, 1) == &ipv6_or_ap); - tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + tt_assert(reachable_addr_choose(&ipv4_dir_ap, &ipv6_dir_ap, 0, FIREWALL_DIR_CONNECTION, 0, 1) == &ipv6_dir_ap); - tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + tt_assert(reachable_addr_choose(&ipv4_dir_ap, &ipv6_dir_ap, 0, FIREWALL_DIR_CONNECTION, 1, 1) == &ipv6_dir_ap); /* Unusual inputs */ /* null preferred OR addresses */ - tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &n_ipv6_ap, 0, + tt_assert(reachable_addr_choose(&ipv4_or_ap, &n_ipv6_ap, 0, FIREWALL_OR_CONNECTION, 0, 1) == &ipv4_or_ap); - tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &ipv6_or_ap, 1, + tt_assert(reachable_addr_choose(&n_ipv4_ap, &ipv6_or_ap, 1, FIREWALL_OR_CONNECTION, 0, 0) == &ipv6_or_ap); /* null both OR addresses */ - tt_ptr_op(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 0, + tt_ptr_op(reachable_addr_choose(&n_ipv4_ap, &n_ipv6_ap, 0, FIREWALL_OR_CONNECTION, 0, 1), OP_EQ, NULL); - tt_ptr_op(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 1, + tt_ptr_op(reachable_addr_choose(&n_ipv4_ap, &n_ipv6_ap, 1, FIREWALL_OR_CONNECTION, 0, 0), OP_EQ, NULL); /* null preferred Dir addresses */ - tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &n_ipv6_ap, 0, + tt_assert(reachable_addr_choose(&ipv4_dir_ap, &n_ipv6_ap, 0, FIREWALL_DIR_CONNECTION, 0, 1) == &ipv4_dir_ap); - tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &ipv6_dir_ap, 1, + tt_assert(reachable_addr_choose(&n_ipv4_ap, &ipv6_dir_ap, 1, FIREWALL_DIR_CONNECTION, 0, 0) == &ipv6_dir_ap); /* null both Dir addresses */ - tt_ptr_op(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 0, + tt_ptr_op(reachable_addr_choose(&n_ipv4_ap, &n_ipv6_ap, 0, FIREWALL_DIR_CONNECTION, 0, 1), OP_EQ, NULL); - tt_ptr_op(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 1, + tt_ptr_op(reachable_addr_choose(&n_ipv4_ap, &n_ipv6_ap, 1, FIREWALL_DIR_CONNECTION, 0, 0), OP_EQ, NULL); /* Prefer IPv4 but want IPv6 (contradictory) */ - tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 0, FIREWALL_OR_CONNECTION, 0, 0) == &ipv4_or_ap); - tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 0, FIREWALL_OR_CONNECTION, 1, 0) == &ipv4_or_ap); /* Prefer IPv6 but want IPv4 (contradictory) */ - tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 1, + tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 1, FIREWALL_OR_CONNECTION, 0, 1) == &ipv6_or_ap); - tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 1, + tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 1, FIREWALL_OR_CONNECTION, 1, 1) == &ipv6_or_ap); @@ -2268,7 +2268,7 @@ test_policies_fascist_firewall_choose_address(void *arg) mock_options.ClientPreferIPv6ORPort = 0; mock_options.ClientPreferIPv6DirPort = 0; /* Simulate the initialisation of fake_node.ipv6_preferred */ - fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport( + fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport( &mock_options); CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1, @@ -2284,7 +2284,7 @@ test_policies_fascist_firewall_choose_address(void *arg) mock_options.ClientPreferIPv6ORPort = -1; mock_options.ClientPreferIPv6DirPort = -1; /* Simulate the initialisation of fake_node.ipv6_preferred */ - fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport( + fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport( &mock_options); CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1, @@ -2300,7 +2300,7 @@ test_policies_fascist_firewall_choose_address(void *arg) mock_options.ClientPreferIPv6ORPort = 1; mock_options.ClientPreferIPv6DirPort = 1; /* Simulate the initialisation of fake_node.ipv6_preferred */ - fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport( + fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport( &mock_options); CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1, @@ -2316,7 +2316,7 @@ test_policies_fascist_firewall_choose_address(void *arg) mock_options.ClientPreferIPv6ORPort = 0; mock_options.ClientPreferIPv6DirPort = 1; /* Simulate the initialisation of fake_node.ipv6_preferred */ - fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport( + fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport( &mock_options); CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1, @@ -2332,7 +2332,7 @@ test_policies_fascist_firewall_choose_address(void *arg) mock_options.ClientPreferIPv6ORPort = 1; mock_options.ClientPreferIPv6DirPort = 0; /* Simulate the initialisation of fake_node.ipv6_preferred */ - fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport( + fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport( &mock_options); CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1, @@ -2354,7 +2354,7 @@ test_policies_fascist_firewall_choose_address(void *arg) mock_options.ClientPreferIPv6ORPort = 0; mock_options.ClientPreferIPv6DirPort = 0; /* Simulate the initialisation of fake_node.ipv6_preferred */ - fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport( + fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport( &mock_options); CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1, @@ -2405,7 +2405,7 @@ test_policies_fascist_firewall_choose_address(void *arg) mock_options.ClientPreferIPv6ORPort = 1; mock_options.ClientPreferIPv6DirPort = 1; /* Simulate the initialisation of fake_node.ipv6_preferred */ - fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport( + fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport( &mock_options); CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1, @@ -2454,7 +2454,7 @@ test_policies_fascist_firewall_choose_address(void *arg) mock_options.ClientUseIPv4 = 1; mock_options.ClientUseIPv6 = 0; /* Simulate the initialisation of fake_node.ipv6_preferred */ - fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport( + fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport( &mock_options); CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1, @@ -2471,7 +2471,7 @@ test_policies_fascist_firewall_choose_address(void *arg) mock_options.ClientUseIPv4 = 0; mock_options.ClientUseIPv6 = 1; /* Simulate the initialisation of fake_node.ipv6_preferred */ - fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport( + fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport( &mock_options); CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1, @@ -2489,7 +2489,7 @@ test_policies_fascist_firewall_choose_address(void *arg) mock_options.ClientUseIPv4 = 0; mock_options.ClientUseIPv6 = 0; /* Simulate the initialisation of fake_node.ipv6_preferred */ - fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport( + fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport( &mock_options); CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1, @@ -2511,7 +2511,7 @@ test_policies_fascist_firewall_choose_address(void *arg) mock_options.ClientPreferIPv6DirPort = 1; /* Simulate the initialisation of fake_node.ipv6_preferred */ - fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport( + fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport( &mock_options); CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1, @@ -2683,9 +2683,9 @@ struct testcase_t policy_tests[] = { { "reject_interface_address", test_policies_reject_interface_address, 0, NULL, NULL }, { "reject_port_address", test_policies_reject_port_address, 0, NULL, NULL }, - { "fascist_firewall_allows_address", + { "reachable_addr_allows", test_policies_fascist_firewall_allows_address, 0, NULL, NULL }, - { "fascist_firewall_choose_address", + { "reachable_addr_choose", test_policies_fascist_firewall_choose_address, 0, NULL, NULL }, END_OF_TESTCASES }; diff --git a/src/test/test_protover.c b/src/test/test_protover.c index 5e74265550..4ccec73699 100644 --- a/src/test/test_protover.c +++ b/src/test/test_protover.c @@ -612,6 +612,10 @@ test_protover_vote_roundtrip(void *args) { "N-1=1,2", "N-1=1-2" }, { "-1=4294967295", NULL }, { "-1=3", "-1=3" }, + { "Foo=,", NULL }, + { "Foo=,1", NULL }, + { "Foo=1,,3", NULL }, + { "Foo=1,3,", NULL }, /* junk. */ { "!!3@*", NULL }, /* Missing equals sign */ diff --git a/src/test/test_rebind.py b/src/test/test_rebind.py index 3fc3deb68e..6b72ece911 100644 --- a/src/test/test_rebind.py +++ b/src/test/test_rebind.py @@ -116,7 +116,7 @@ tor_process = subprocess.Popen([tor_path, if tor_process == None: fail('ERROR: running tor failed') -wait_for_log('Opened Control listener on') +wait_for_log('Opened Control listener') try_connecting_to_socksport() diff --git a/src/test/test_relay.c b/src/test/test_relay.c index 060ca1b75d..545cb4ac46 100644 --- a/src/test/test_relay.c +++ b/src/test/test_relay.c @@ -17,6 +17,14 @@ #include "core/or/cell_st.h" #include "core/or/or_circuit_st.h" +#define RESOLVE_ADDR_PRIVATE +#include "feature/nodelist/dirlist.h" +#include "feature/relay/relay_find_addr.h" +#include "feature/relay/routermode.h" +#include "feature/dirclient/dir_server_st.h" + +#include "app/config/resolve_addr.h" + /* Test suite stuff */ #include "test/test.h" #include "test/fakechans.h" @@ -24,6 +32,13 @@ static void test_relay_append_cell_to_circuit_queue(void *arg); +static int +mock_server_mode_true(const or_options_t *options) +{ + (void) options; + return 1; +} + static void assert_circuit_ok_mock(const circuit_t *c) { @@ -192,10 +207,167 @@ test_relay_append_cell_to_circuit_queue(void *arg) return; } +static void +test_suggested_address(void *arg) +{ + int ret; + const char *untrusted_id = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + dir_server_t *ds = NULL; + tor_addr_t ipv4_addr, ipv6_addr, cache_addr; + tor_addr_t trusted_addr, untrusted_addr; + tor_addr_port_t trusted_ap_v6 = { .port = 443 }; + + (void) arg; + + MOCK(server_mode, mock_server_mode_true); + + /* Unstrusted relay source. */ + ret = tor_addr_parse(&untrusted_addr, "8.8.8.8"); + tt_int_op(ret, OP_EQ, AF_INET); + + /* Add gabelmoo as a trusted directory authority. */ + ret = tor_addr_parse(&trusted_addr, "[2001:638:a000:4140::ffff:189]"); + tt_int_op(ret, OP_EQ, AF_INET6); + tor_addr_copy(&trusted_ap_v6.addr, &trusted_addr); + + ds = trusted_dir_server_new("gabelmoo", "131.188.40.189", 80, 443, + &trusted_ap_v6, + "F2044413DAC2E02E3D6BCF4735A19BCA1DE97281", + "ED03BB616EB2F60BEC80151114BB25CEF515B226", + V3_DIRINFO, 1.0); + tt_assert(ds); + dir_server_add(ds); + + /* 1. Valid IPv4 from a trusted authority (gabelmoo). */ + ret = tor_addr_parse(&ipv4_addr, "1.2.3.4"); + relay_address_new_suggestion(&ipv4_addr, &ds->ipv4_addr, ds->digest); + resolved_addr_get_suggested(AF_INET, &cache_addr); + tt_assert(tor_addr_eq(&cache_addr, &ipv4_addr)); + resolve_addr_reset_suggested(AF_INET); + + /* 2. Valid IPv6 from a trusted authority (gabelmoo). */ + ret = tor_addr_parse(&ipv6_addr, "[4242::4242]"); + relay_address_new_suggestion(&ipv6_addr, &ds->ipv6_addr, ds->digest); + resolved_addr_get_suggested(AF_INET6, &cache_addr); + tt_assert(tor_addr_eq(&cache_addr, &ipv6_addr)); + resolve_addr_reset_suggested(AF_INET6); + + /* 3. Valid IPv4 but untrusted source. */ + ret = tor_addr_parse(&ipv4_addr, "1.2.3.4"); + relay_address_new_suggestion(&ipv4_addr, &untrusted_addr, untrusted_id); + resolved_addr_get_suggested(AF_INET, &cache_addr); + tt_assert(tor_addr_is_unspec(&cache_addr)); + + /* 4. Valid IPv6 but untrusted source. */ + ret = tor_addr_parse(&ipv6_addr, "[4242::4242]"); + relay_address_new_suggestion(&ipv6_addr, &untrusted_addr, untrusted_id); + resolved_addr_get_suggested(AF_INET6, &cache_addr); + tt_assert(tor_addr_is_unspec(&cache_addr)); + + /* 5. Internal IPv4 from a trusted authority (gabelmoo). */ + ret = tor_addr_parse(&ipv4_addr, "127.0.0.1"); + relay_address_new_suggestion(&ipv4_addr, &ds->ipv4_addr, ds->digest); + resolved_addr_get_suggested(AF_INET, &cache_addr); + tt_assert(tor_addr_is_unspec(&cache_addr)); + + /* 6. Internal IPv6 from a trusted authority (gabelmoo). */ + ret = tor_addr_parse(&ipv6_addr, "[::1]"); + relay_address_new_suggestion(&ipv6_addr, &ds->ipv6_addr, ds->digest); + resolved_addr_get_suggested(AF_INET6, &cache_addr); + tt_assert(tor_addr_is_unspec(&cache_addr)); + + /* 7. IPv4 from a trusted authority (gabelmoo). */ + relay_address_new_suggestion(&ds->ipv4_addr, &ds->ipv4_addr, ds->digest); + resolved_addr_get_suggested(AF_INET, &cache_addr); + tt_assert(tor_addr_is_unspec(&cache_addr)); + + /* 8. IPv6 from a trusted authority (gabelmoo). */ + relay_address_new_suggestion(&ds->ipv6_addr, &ds->ipv6_addr, ds->digest); + resolved_addr_get_suggested(AF_INET6, &cache_addr); + tt_assert(tor_addr_is_unspec(&cache_addr)); + + done: + dirlist_free_all(); + + UNMOCK(server_mode); +} + +static void +test_find_addr_to_publish(void *arg) +{ + int family; + bool ret; + tor_addr_t ipv4_addr, ipv6_addr, cache_addr; + or_options_t options; + + (void) arg; + + memset(&options, 0, sizeof(options)); + + /* Populate our resolved cache with a valid IPv4 and IPv6. */ + family = tor_addr_parse(&ipv4_addr, "1.2.3.4"); + tt_int_op(family, OP_EQ, AF_INET); + resolved_addr_set_last(&ipv4_addr, RESOLVED_ADDR_CONFIGURED, NULL); + resolved_addr_get_last(AF_INET, &cache_addr); + tt_assert(tor_addr_eq(&ipv4_addr, &cache_addr)); + + family = tor_addr_parse(&ipv6_addr, "[4242::4242]"); + tt_int_op(family, OP_EQ, AF_INET6); + resolved_addr_set_last(&ipv6_addr, RESOLVED_ADDR_CONFIGURED, NULL); + resolved_addr_get_last(AF_INET6, &cache_addr); + tt_assert(tor_addr_eq(&ipv6_addr, &cache_addr)); + + /* 1. Address located in the resolved cache. */ + ret = relay_find_addr_to_publish(&options, AF_INET, + RELAY_FIND_ADDR_CACHE_ONLY, &cache_addr); + tt_assert(ret); + tt_assert(tor_addr_eq(&ipv4_addr, &cache_addr)); + + ret = relay_find_addr_to_publish(&options, AF_INET6, + RELAY_FIND_ADDR_CACHE_ONLY, &cache_addr); + tt_assert(ret); + tt_assert(tor_addr_eq(&ipv6_addr, &cache_addr)); + resolved_addr_reset_last(AF_INET); + resolved_addr_reset_last(AF_INET6); + + /* 2. No IP in the resolve cache, go to the suggested cache. We will ignore + * the find_my_address() code path because that is extensively tested in + * another unit tests. */ + resolved_addr_set_suggested(&ipv4_addr); + ret = relay_find_addr_to_publish(&options, AF_INET, + RELAY_FIND_ADDR_CACHE_ONLY, &cache_addr); + tt_assert(ret); + tt_assert(tor_addr_eq(&ipv4_addr, &cache_addr)); + + resolved_addr_set_suggested(&ipv6_addr); + ret = relay_find_addr_to_publish(&options, AF_INET6, + RELAY_FIND_ADDR_CACHE_ONLY, &cache_addr); + tt_assert(ret); + tt_assert(tor_addr_eq(&ipv6_addr, &cache_addr)); + resolve_addr_reset_suggested(AF_INET); + resolve_addr_reset_suggested(AF_INET6); + + /* 3. No IP anywhere. */ + ret = relay_find_addr_to_publish(&options, AF_INET, + RELAY_FIND_ADDR_CACHE_ONLY, &cache_addr); + tt_assert(!ret); + ret = relay_find_addr_to_publish(&options, AF_INET6, + RELAY_FIND_ADDR_CACHE_ONLY, &cache_addr); + tt_assert(!ret); + + done: + ; +} + struct testcase_t relay_tests[] = { { "append_cell_to_circuit_queue", test_relay_append_cell_to_circuit_queue, TT_FORK, NULL, NULL }, { "close_circ_rephist", test_relay_close_circuit, TT_FORK, NULL, NULL }, + { "suggested_address", test_suggested_address, + TT_FORK, NULL, NULL }, + { "find_addr_to_publish", test_find_addr_to_publish, + TT_FORK, NULL, NULL }, + END_OF_TESTCASES }; diff --git a/src/test/test_relaycell.c b/src/test/test_relaycell.c index da9e791fb6..3a317be5fe 100644 --- a/src/test/test_relaycell.c +++ b/src/test/test_relaycell.c @@ -220,7 +220,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) int sendme_cells = (STREAMWINDOW_START-edgeconn->package_window) /STREAMWINDOW_INCREMENT; ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; - ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0; connection_edge_reached_eof(edgeconn); /* Data cell not in the half-opened list */ @@ -272,7 +271,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) /* DATA cells up to limit */ while (data_cells > 0) { ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; - ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); @@ -283,7 +281,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) data_cells--; } ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; - ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); @@ -295,7 +292,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) /* SENDME cells up to limit */ while (sendme_cells > 0) { ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; - ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); @@ -306,7 +302,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) sendme_cells--; } ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; - ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); @@ -317,7 +312,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) /* Only one END cell */ ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; - ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); @@ -327,7 +321,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) ASSERT_COUNTED_BW(); ENTRY_TO_CONN(entryconn2)->marked_for_close = 0; - ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); @@ -339,7 +332,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) edgeconn = ENTRY_TO_EDGE_CONN(entryconn3); edgeconn->base_.state = AP_CONN_STATE_OPEN; ENTRY_TO_CONN(entryconn3)->marked_for_close = 0; - ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0; /* sendme cell on open entryconn with full window */ PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234"); int ret = @@ -350,7 +342,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) /* connected cell on a after EOF */ ENTRY_TO_CONN(entryconn3)->marked_for_close = 0; - ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0; edgeconn->base_.state = AP_CONN_STATE_CONNECT_WAIT; connection_edge_reached_eof(edgeconn); PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_CONNECTED, "Data1234"); @@ -362,7 +353,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) ASSERT_COUNTED_BW(); ENTRY_TO_CONN(entryconn3)->marked_for_close = 0; - ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_CONNECTED, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); @@ -373,7 +363,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) /* DATA and SENDME after END cell */ ENTRY_TO_CONN(entryconn3)->marked_for_close = 0; - ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); @@ -383,7 +372,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) ASSERT_COUNTED_BW(); ENTRY_TO_CONN(entryconn3)->marked_for_close = 0; - ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234"); ret = connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, @@ -392,7 +380,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) ASSERT_UNCOUNTED_BW(); ENTRY_TO_CONN(entryconn3)->marked_for_close = 0; - ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); @@ -407,11 +394,9 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) edgeconn->base_.state = AP_CONN_STATE_RESOLVE_WAIT; edgeconn->on_circuit = TO_CIRCUIT(circ); ENTRY_TO_CONN(entryconn4)->marked_for_close = 0; - ENTRY_TO_CONN(entryconn4)->outbuf_flushlen = 0; connection_edge_reached_eof(edgeconn); ENTRY_TO_CONN(entryconn4)->marked_for_close = 0; - ENTRY_TO_CONN(entryconn4)->outbuf_flushlen = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_RESOLVED, "\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) @@ -422,7 +407,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) ASSERT_COUNTED_BW(); ENTRY_TO_CONN(entryconn4)->marked_for_close = 0; - ENTRY_TO_CONN(entryconn4)->outbuf_flushlen = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_RESOLVED, "\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, @@ -431,7 +415,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) /* Data not counted after resolved */ ENTRY_TO_CONN(entryconn4)->marked_for_close = 0; - ENTRY_TO_CONN(entryconn4)->outbuf_flushlen = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); @@ -442,7 +425,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id) /* End not counted after resolved */ ENTRY_TO_CONN(entryconn4)->marked_for_close = 0; - ENTRY_TO_CONN(entryconn4)->outbuf_flushlen = 0; PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234"); if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell); @@ -660,7 +642,6 @@ test_halfstream_wrap(void *arg) /* Insert an opened stream on the circ with that id */ ENTRY_TO_CONN(entryconn)->marked_for_close = 0; - ENTRY_TO_CONN(entryconn)->outbuf_flushlen = 0; edgeconn->base_.state = AP_CONN_STATE_CONNECT_WAIT; circ->p_streams = edgeconn; @@ -784,14 +765,12 @@ test_circbw_relay(void *arg) /* Sendme on valid stream: counted */ edgeconn->package_window -= STREAMWINDOW_INCREMENT; - ENTRY_TO_CONN(entryconn1)->outbuf_flushlen = 0; PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, circ->cpath); ASSERT_COUNTED_BW(); /* Sendme on valid stream with full window: not counted */ - ENTRY_TO_CONN(entryconn1)->outbuf_flushlen = 0; PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234"); edgeconn->package_window = STREAMWINDOW_START; connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn, @@ -799,7 +778,6 @@ test_circbw_relay(void *arg) ASSERT_UNCOUNTED_BW(); /* Sendme on unknown stream: not counted */ - ENTRY_TO_CONN(entryconn1)->outbuf_flushlen = 0; PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234"); connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL, circ->cpath); diff --git a/src/test/test_router.c b/src/test/test_router.c index 6980a62e5e..ddd043b941 100644 --- a/src/test/test_router.c +++ b/src/test/test_router.c @@ -507,13 +507,12 @@ test_router_get_advertised_or_port(void *arg) listener_connection_t *listener = NULL; tor_addr_port_t ipv6; - // Test one failing case of router_get_advertised_ipv6_or_ap(). - router_get_advertised_ipv6_or_ap(opts, &ipv6); + // Test one failing case of routerconf_find_ipv6_or_ap(). + routerconf_find_ipv6_or_ap(opts, &ipv6); tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::]:0"); - // And one failing case of router_get_advertised_or_port(). - tt_int_op(0, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET)); - tt_int_op(0, OP_EQ, router_get_advertised_or_port(opts)); + // And one failing case of routerconf_find_or_port(). + tt_int_op(0, OP_EQ, routerconf_find_or_port(opts, AF_INET)); // Set up a couple of configured ports. config_line_append(&opts->ORPort_lines, "ORPort", "[1234::5678]:auto"); @@ -522,13 +521,12 @@ test_router_get_advertised_or_port(void *arg) tt_assert(r == 0); // There are no listeners, so the "auto" case will turn up no results. - tt_int_op(0, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6)); - router_get_advertised_ipv6_or_ap(opts, &ipv6); + tt_int_op(0, OP_EQ, routerconf_find_or_port(opts, AF_INET6)); + routerconf_find_ipv6_or_ap(opts, &ipv6); tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::]:0"); // This will return the matching value from the configured port. - tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET)); - tt_int_op(9999, OP_EQ, router_get_advertised_or_port(opts)); + tt_int_op(9999, OP_EQ, routerconf_find_or_port(opts, AF_INET)); // Now set up a dummy listener. MOCK(get_connection_array, mock_get_connection_array); @@ -538,16 +536,15 @@ test_router_get_advertised_or_port(void *arg) smartlist_add(fake_connection_array, TO_CONN(listener)); // We should get a port this time. - tt_int_op(54321, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6)); + tt_int_op(54321, OP_EQ, routerconf_find_or_port(opts, AF_INET6)); - // Test one succeeding case of router_get_advertised_ipv6_or_ap(). - router_get_advertised_ipv6_or_ap(opts, &ipv6); + // Test one succeeding case of routerconf_find_ipv6_or_ap(). + routerconf_find_ipv6_or_ap(opts, &ipv6); tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[1234::5678]:54321"); // This will return the matching value from the configured port. - tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET)); - tt_int_op(9999, OP_EQ, router_get_advertised_or_port(opts)); + tt_int_op(9999, OP_EQ, routerconf_find_or_port(opts, AF_INET)); done: or_options_free(opts); @@ -573,28 +570,26 @@ test_router_get_advertised_or_port_localhost(void *arg) tt_assert(r == 0); // We should refuse to advertise them, since we have default dirauths. - router_get_advertised_ipv6_or_ap(opts, &ipv6); + routerconf_find_ipv6_or_ap(opts, &ipv6); tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::]:0"); // But the lower-level function should still report the correct value - tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6)); + tt_int_op(9999, OP_EQ, routerconf_find_or_port(opts, AF_INET6)); // The IPv4 checks are done in resolve_my_address(), which doesn't use // ORPorts so we can't test them here. (See #33681.) Both these lower-level // functions should still report the correct value. - tt_int_op(8888, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET)); - tt_int_op(8888, OP_EQ, router_get_advertised_or_port(opts)); + tt_int_op(8888, OP_EQ, routerconf_find_or_port(opts, AF_INET)); // Now try with a fake authority set up. config_line_append(&opts->DirAuthorities, "DirAuthority", "127.0.0.1:1066 " "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); - tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6)); - router_get_advertised_ipv6_or_ap(opts, &ipv6); + tt_int_op(9999, OP_EQ, routerconf_find_or_port(opts, AF_INET6)); + routerconf_find_ipv6_or_ap(opts, &ipv6); tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::1]:9999"); - tt_int_op(8888, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET)); - tt_int_op(8888, OP_EQ, router_get_advertised_or_port(opts)); + tt_int_op(8888, OP_EQ, routerconf_find_or_port(opts, AF_INET)); done: or_options_free(opts); diff --git a/src/test/test_routerkeys.c b/src/test/test_routerkeys.c index bafc886bc6..8d653e44a2 100644 --- a/src/test/test_routerkeys.c +++ b/src/test/test_routerkeys.c @@ -111,7 +111,6 @@ test_routerkeys_write_ed25519_identity(void *arg) set_client_identity_key(crypto_pk_dup_key(key)); load_ed_keys(options, now); - generate_ed_link_cert(options, now, 0); tt_assert(get_master_identity_key()); tt_int_op(0, OP_EQ, check_private_dir(ddir, CPD_CREATE, NULL)); diff --git a/src/test/test_stats.c b/src/test/test_stats.c index f0715c2e45..b6849b0b6d 100644 --- a/src/test/test_stats.c +++ b/src/test/test_stats.c @@ -30,6 +30,7 @@ #define CIRCUITLIST_PRIVATE #define MAINLOOP_PRIVATE #define STATEFILE_PRIVATE +#define BWHIST_PRIVATE #include "core/or/or.h" #include "lib/err/backtrace.h" @@ -42,6 +43,8 @@ #include "feature/stats/connstats.h" #include "feature/stats/rephist.h" #include "app/config/statefile.h" +#include "feature/stats/bwhist.h" +#include "feature/stats/bw_array_st.h" /** Run unit tests for some stats code. */ static void @@ -250,6 +253,246 @@ test_rephist_mtbf(void *arg) tor_free(ddir_fname); } +static void +test_commit_max(void *arg) +{ + (void) arg; + bw_array_t *b = bw_array_new(); + time_t now = b->cur_obs_time; + + commit_max(b); + tt_int_op(b->next_period, OP_EQ, now + 2*86400); + + b->total_in_period = 100; + b->max_total = 10; + commit_max(b); + tor_assert(b->total_in_period == 0); + tor_assert(b->max_total == 0); + tt_int_op(b->totals[1], OP_EQ, 100); + tt_int_op(b->maxima[1], OP_EQ, 10); + tt_int_op(b->next_period, OP_EQ, now + 3*86400); + + commit_max(b); + tt_int_op(b->next_period, OP_EQ, now + 4*86400); + + commit_max(b); + tt_int_op(b->next_period, OP_EQ, now + 5*86400); + + b->total_in_period = 100; + b->max_total = 10; + commit_max(b); + tor_assert(!b->next_max_idx); + tt_int_op(b->cur_obs_idx, OP_EQ, 0); + tt_int_op(b->totals[4], OP_EQ, 100); + tt_int_op(b->maxima[4], OP_EQ, 10); + tt_int_op(b->next_period, OP_EQ, now + 6*86400); + done: + bw_array_free(b); +} + +#define test_obs(b, idx, time, tot, max) STMT_BEGIN \ + tt_int_op(b->cur_obs_idx, OP_EQ, idx); \ + tt_int_op(b->cur_obs_time, OP_EQ, time); \ + tt_int_op(b->total_obs, OP_EQ, tot); \ + tt_int_op(b->max_total, OP_EQ, max); \ + STMT_END; + +static void +test_advance_obs(void *arg) +{ + (void) arg; + int iter, tot = 0; + bw_array_t *b = bw_array_new(); + time_t now = b->cur_obs_time; + + for (iter = 0; iter < 10; ++iter) { + b->obs[b->cur_obs_idx] += 10; + tot += 10; + advance_obs(b); + if (iter == 9) { + /* The current value under cur_obs_idx was zeroed in last iterN. */ + test_obs(b, 0, now+iter+1, tot - 10, tot); + break; + } + test_obs(b, iter+1, now+iter+1, tot, tot); + } + + b->total_in_period = 100; + b->cur_obs_time = now + NUM_SECS_BW_SUM_INTERVAL - 1; + advance_obs(b); + test_obs(b, 1, now+NUM_SECS_BW_SUM_INTERVAL, 80, 0); + tt_int_op(b->maxima[0], OP_EQ, 100); + tt_int_op(b->totals[0], OP_EQ, 100); + tt_int_op(b->num_maxes_set, OP_EQ, 1); + done: + bw_array_free(b); +} + +#define test_add_obs_(b, now, checknow, bw, tot) STMT_BEGIN \ + tot += bw; \ + add_obs(b, now, bw); \ + tt_int_op(b->cur_obs_time, OP_EQ, checknow); \ + tt_int_op(b->obs[b->cur_obs_idx], OP_EQ, bw); \ + tt_int_op(b->total_in_period, OP_EQ, tot); \ + STMT_END; + +static void +test_add_obs(void *arg) +{ + (void) arg; + bw_array_t *b = bw_array_new(); + time_t now = b->cur_obs_time; + uint64_t bw = 0, tot = 0; + /* Requests for the past should not be entertained. */ + test_add_obs_(b, now-1, now, bw, tot); + /* Test the expected functionalities for random values. */ + now += 53; + bw = 97; + test_add_obs_(b, now, now, bw, tot); + + now += 60*60; + bw = 90; + test_add_obs_(b, now, now, bw, tot); + + now += 24*60*60; + bw = 100; + tot = 0; + test_add_obs_(b, now, now, bw, tot); + done: + bw_array_free(b); +} + +static or_options_t mock_options; + +static const or_options_t * +mock_get_options(void) +{ + return &mock_options; +} + +#define MAX_HIST_VALUE_LEN 21*NUM_TOTALS + +#define set_test_case(b, max, idx, a1, a2, a3, a4, a5) STMT_BEGIN \ + b->num_maxes_set = max; \ + b->next_max_idx = idx; \ + b->totals[0] = a1; \ + b->totals[1] = a2; \ + b->totals[2] = a3; \ + b->totals[3] = a4; \ + b->totals[4] = a5; \ + STMT_END; + +#define test_fill_bw(b, buf, rv, str, checkrv) STMT_BEGIN \ + buf = tor_malloc_zero(MAX_HIST_VALUE_LEN); \ + rv = bwhist_fill_bandwidth_history(buf, MAX_HIST_VALUE_LEN, b); \ + tt_str_op(buf, OP_EQ, str); \ + tt_int_op(rv, OP_EQ, checkrv); \ + tor_free(buf); \ + STMT_END; + +static void +test_fill_bandwidth_history(void *arg) +{ + (void) arg; + bw_array_t *b = bw_array_new(); + char *buf; + size_t rv; + /* Remember bandwidth is rounded down to the nearest 1K. */ + /* Day 1. */ + set_test_case(b, 0, 0, 0, 0, 0, 0, 0); + buf = tor_malloc_zero(MAX_HIST_VALUE_LEN); + rv = bwhist_fill_bandwidth_history(buf, MAX_HIST_VALUE_LEN, b); + tt_int_op(rv, OP_EQ, 0); + tor_free(buf); + /* Day 2. */ + set_test_case(b, 1, 1, 1000, 0, 0, 0, 0); + test_fill_bw(b, buf, rv, "0", 1); + /* Day 3. */ + set_test_case(b, 2, 2, 1000, 1500, 0, 0, 0); + test_fill_bw(b, buf, rv, "0,1024", 6); + /* Day 4. */ + set_test_case(b, 3, 3, 1000, 1500, 3500, 0, 0); + test_fill_bw(b, buf, rv, "0,1024,3072", 11); + /* Day 5. */ + set_test_case(b, 4, 4, 1000, 1500, 3500, 8000, 0); + test_fill_bw(b, buf, rv, "0,1024,3072,7168", 16); + /* Day 6. */ + set_test_case(b, 5, 0, 1000, 1500, 3500, 8000, 6000); + test_fill_bw(b, buf, rv, "0,1024,3072,7168,5120", 21); + /* Day 7. */ + /* Remember oldest entry first. */ + set_test_case(b, 5, 1, 10000, 1500, 3500, 8000, 6000); + test_fill_bw(b, buf, rv, "1024,3072,7168,5120,9216", 24); + /* Mocking get_options to manipulate RelayBandwidthRate. */ + MOCK(get_options, mock_get_options); + /* Limits bandwidth to 1 KBps. */ + /* Cutoff is set to 88473600. */ + mock_options.RelayBandwidthRate = 1024; + set_test_case(b, 5, 2, 88573600, 88473600, 10000, 8000, 6000); + test_fill_bw(b, buf, rv, "9216,7168,5120,88473600,88473600", 32); + done: + UNMOCK(get_options); + bw_array_free(b); +} + +#define set_test_bw_lines(r, w, dr, dw, when) STMT_BEGIN \ + bwhist_note_bytes_read(r, when, false); \ + bwhist_note_bytes_written(w, when, false); \ + bwhist_note_dir_bytes_read(dr, when); \ + bwhist_note_dir_bytes_written(dw, when); \ + STMT_END; + +#define test_get_bw_lines(str, checkstr) STMT_BEGIN \ + str = bwhist_get_bandwidth_lines(); \ + tt_str_op(str, OP_EQ, checkstr); \ + tor_free(str); \ + STMT_END; + +static void +test_get_bandwidth_lines(void *arg) +{ + (void) arg; + char *str = NULL, *checkstr = NULL; + char t[ISO_TIME_LEN+1]; + int len = (67+MAX_HIST_VALUE_LEN)*4; + checkstr = tor_malloc_zero(len); + time_t now = time(NULL); + bwhist_init(); + + /* Day 1. */ + now += 86400; + set_test_bw_lines(5000, 5500, 3000, 3500, now - 6*60*60); + /* Day 2. */ + now += 86400; + set_test_bw_lines(50000, 55000, 30000, 35000, now - 6*60*60); + /* Day 3. */ + now += 86400; + set_test_bw_lines(25000, 27500, 15000, 17500, now - 6*60*60); + /* Day 4. */ + now += 86400; + set_test_bw_lines(90000, 76000, 60000, 45000, now - 6*60*60); + /* Day 5. */ + now += 86400; + set_test_bw_lines(500, 55000, 30000, 35000, now - 6*60*60); + set_test_bw_lines(0, 0, 0, 0, now); + format_iso_time(t, now); + tor_snprintf(checkstr, len, "write-history %s (86400 s) " + "5120,54272,26624,75776,54272\n" + "read-history %s (86400 s) " + "4096,49152,24576,89088,0\n" + "dirreq-write-history %s (86400 s) " + "3072,34816,17408,44032,34816\n" + "dirreq-read-history %s (86400 s) " + "2048,29696,14336,59392,29696\n", + t, t, t, t); + test_get_bw_lines(str, checkstr); + + done: + tor_free(str); + tor_free(checkstr); + bwhist_free_all(); +} + #define ENT(name) \ { #name, test_ ## name , 0, NULL, NULL } #define FORK(name) \ @@ -258,6 +501,11 @@ test_rephist_mtbf(void *arg) struct testcase_t stats_tests[] = { FORK(stats), ENT(rephist_mtbf), + FORK(commit_max), + FORK(advance_obs), + FORK(add_obs), + FORK(fill_bandwidth_history), + FORK(get_bandwidth_lines), END_OF_TESTCASES }; diff --git a/src/test/test_util.c b/src/test/test_util.c index 4f54d45468..230f2c7034 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -78,6 +78,8 @@ #define DISABLE_PWDB_TESTS #endif +static void set_file_mtime(const char *fname, time_t when); + #define INFINITY_DBL ((double)INFINITY) #define NAN_DBL ((double)NAN) @@ -356,6 +358,55 @@ test_util_write_chunks_to_file(void *arg) tor_free(temp_str); } +/* Test write_str_to_file_if_not_equal(). */ +static void +test_util_write_str_if_changed(void *arg) +{ + (void)arg; + char *fname = tor_strdup(get_fname("write_if_changed")); + char *s = NULL; + int rv; + const char str1[] = "The wombat lives across the seas"; + const char str2[] = "Among the far Antipodes"; /* -- Ogden Nash */ + + /* We can create files. */ + rv = write_str_to_file_if_not_equal(fname, str1); + tt_int_op(rv, OP_EQ, 0); + s = read_file_to_str(fname, 0, NULL); + tt_str_op(s, OP_EQ, str1); + tor_free(s); + + /* We can replace files. */ + rv = write_str_to_file_if_not_equal(fname, str2); + tt_int_op(rv, OP_EQ, 0); + s = read_file_to_str(fname, 0, NULL); + tt_str_op(s, OP_EQ, str2); + tor_free(s); + + /* Make sure we don't replace files when they're equal. (That's the whole + * point of the function we're testing. */ + /* First, change the mtime of the file so that we can tell whether we + * replaced it. */ + const time_t now = time(NULL); + const time_t five_sec_ago = now - 5; + set_file_mtime(fname, five_sec_ago); + rv = write_str_to_file_if_not_equal(fname, str2); + tt_int_op(rv, OP_EQ, 0); + /* Make sure that the file's mtime is unchanged... */ + struct stat st; + rv = stat(fname, &st); + tt_int_op(rv, OP_EQ, 0); + tt_i64_op(st.st_mtime, OP_EQ, five_sec_ago); + /* And make sure its contents are unchanged. */ + s = read_file_to_str(fname, 0, NULL); + tt_str_op(s, OP_EQ, str2); + tor_free(s); + + done: + tor_free(fname); + tor_free(s); +} + #ifndef COCCI #define _TFE(a, b, f) tt_int_op((a).f, OP_EQ, (b).f) /** test the minimum set of struct tm fields needed for a unique epoch value @@ -6219,6 +6270,20 @@ test_util_get_avail_disk_space(void *arg) ; } +/** Helper: Change the atime and mtime of a file. */ +static void +set_file_mtime(const char *fname, time_t when) +{ + struct utimbuf u = { when, when }; + struct stat st; + tt_int_op(0, OP_EQ, utime(fname, &u)); + tt_int_op(0, OP_EQ, stat(fname, &st)); + /* Let's hope that utime/stat give the same second as a round-trip? */ + tt_i64_op(st.st_mtime, OP_EQ, when); +done: + ; +} + static void test_util_touch_file(void *arg) { @@ -6236,11 +6301,7 @@ test_util_touch_file(void *arg) tt_i64_op(st.st_mtime, OP_GE, now - 1); const time_t five_sec_ago = now - 5; - struct utimbuf u = { five_sec_ago, five_sec_ago }; - tt_int_op(0, OP_EQ, utime(fname, &u)); - tt_int_op(0, OP_EQ, stat(fname, &st)); - /* Let's hope that utime/stat give the same second as a round-trip? */ - tt_i64_op(st.st_mtime, OP_EQ, five_sec_ago); + set_file_mtime(fname, five_sec_ago); /* Finally we can touch the file */ tt_int_op(0, OP_EQ, touch_file(fname)); @@ -6981,6 +7042,7 @@ struct testcase_t util_tests[] = { UTIL_TEST(read_file_eof_zero_bytes, 0), UTIL_TEST(read_file_endlines, 0), UTIL_TEST(write_chunks_to_file, 0), + UTIL_TEST(write_str_if_changed, 0), UTIL_TEST(mathlog, 0), UTIL_TEST(fraction, 0), UTIL_TEST(weak_random, 0), |