From faec7956a96b143f8ba7192e7ff2a996469935e0 Mon Sep 17 00:00:00 2001 From: "teor (Tim Wilson-Brown)" Date: Sat, 7 May 2016 10:17:46 -0700 Subject: [PATCH 1/6] Refactor duplicate code in config.c into port_binds_ipv4/6 No behavioural change Preserves and documents behaviour when passed AF_UNSPEC. --- src/or/config.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/or/config.c b/src/or/config.c index 2e14ba69dc..7ca927744f 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -6841,6 +6841,22 @@ parse_ports(or_options_t *options, int validate_only, return retval; } +/* Does port bind to IPv4? */ +static int port_binds_ipv4(const port_cfg_t *port) +{ + return tor_addr_family(&port->addr) == AF_INET || + (tor_addr_family(&port->addr) == AF_UNSPEC + && !port->server_cfg.bind_ipv6_only); +} + +/* Does port bind to IPv6? */ +static int port_binds_ipv6(const port_cfg_t *port) +{ + return tor_addr_family(&port->addr) == AF_INET6 || + (tor_addr_family(&port->addr) == AF_UNSPEC + && !port->server_cfg.bind_ipv4_only); +} + /** Given a list of port_cfg_t in ports, check them for internal * consistency and warn as appropriate. Set *n_low_ports_out to the * number of sub-1024 ports we will be binding. */ @@ -6866,9 +6882,7 @@ check_server_ports(const smartlist_t *ports, } else if (port->type == CONN_TYPE_OR_LISTENER) { if (! port->server_cfg.no_advertise) { ++n_orport_advertised; - if (tor_addr_family(&port->addr) == AF_INET || - (tor_addr_family(&port->addr) == AF_UNSPEC && - !port->server_cfg.bind_ipv6_only)) + if (port_binds_ipv4(port)) ++n_orport_advertised_ipv4; } if (! port->server_cfg.no_listen) @@ -7002,20 +7016,20 @@ get_first_listener_addrport_string(int listener_type) } /** Return the first advertised port of type listener_type in - address_family. */ + * address_family. Returns 0 when no port is found, and when passed + * AF_UNSPEC. */ int get_first_advertised_port_by_type_af(int listener_type, int address_family) { + if (address_family == AF_UNSPEC) + return 0; if (!configured_ports) return 0; SMARTLIST_FOREACH_BEGIN(configured_ports, const port_cfg_t *, cfg) { if (cfg->type == listener_type && - !cfg->server_cfg.no_advertise && - (tor_addr_family(&cfg->addr) == address_family || - tor_addr_family(&cfg->addr) == AF_UNSPEC)) { - if (tor_addr_family(&cfg->addr) != AF_UNSPEC || - (address_family == AF_INET && !cfg->server_cfg.bind_ipv6_only) || - (address_family == AF_INET6 && !cfg->server_cfg.bind_ipv4_only)) { + !cfg->server_cfg.no_advertise) { + if ((address_family == AF_INET && port_binds_ipv4(cfg)) || + (address_family == AF_INET6 && port_binds_ipv6(cfg))) { return cfg->port; } } From c75bf388b5fc3555dd21d44b7856358f771292a4 Mon Sep 17 00:00:00 2001 From: "teor (Tim Wilson-Brown)" Date: Sat, 7 May 2016 10:18:52 -0700 Subject: [PATCH 2/6] Warn users when addresses in ports and descriptor are inconsistent This mitigates bug 13953. --- changes/bug13953 | 3 ++ src/or/config.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++ src/or/config.h | 6 ++++ src/or/router.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 173 insertions(+) create mode 100644 changes/bug13953 diff --git a/changes/bug13953 b/changes/bug13953 new file mode 100644 index 0000000000..42b013ffd8 --- /dev/null +++ b/changes/bug13953 @@ -0,0 +1,3 @@ + o Minor bugfixes (config): + - Warn users when descriptor and port addresses are inconsistent. + Mitigates bug 13953; patch by teor. diff --git a/src/or/config.c b/src/or/config.c index 7ca927744f..2fd97de20d 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -7037,6 +7037,87 @@ get_first_advertised_port_by_type_af(int listener_type, int address_family) return 0; } +/** Return the first advertised address of type listener_type in + * address_family. Returns NULL if there is no advertised address, + * and when passed AF_UNSPEC. */ +const tor_addr_t * +get_first_advertised_addr_by_type_af(int listener_type, int address_family) +{ + if (address_family == AF_UNSPEC) + return NULL; + if (!configured_ports) + return NULL; + SMARTLIST_FOREACH_BEGIN(configured_ports, const port_cfg_t *, cfg) { + if (cfg->type == listener_type && + !cfg->server_cfg.no_advertise) { + if ((address_family == AF_INET && port_binds_ipv4(cfg)) || + (address_family == AF_INET6 && port_binds_ipv6(cfg))) { + return &cfg->addr; + } + } + } SMARTLIST_FOREACH_END(cfg); + return NULL; +} + +/** Return 1 if a port exists of type listener_type on addr and + * port. If check_wildcard is true, INADDR[6]_ANY and AF_UNSPEC + * addresses match any address of the appropriate family; and port -1 matches + * any port. + * To match auto ports, pass CFG_PORT_AUTO. (Does not match on the actual + * automatically chosen listener ports.) */ +int +port_exists_by_type_addr_port(int listener_type, const tor_addr_t *addr, + int port, int check_wildcard) +{ + if (!configured_ports || !addr) + return 0; + SMARTLIST_FOREACH_BEGIN(configured_ports, const port_cfg_t *, cfg) { + if (cfg->type == listener_type) { + if (cfg->port == port || (check_wildcard && port == -1)) { + /* Exact match */ + if (tor_addr_eq(&cfg->addr, addr)) { + return 1; + } + /* Skip wildcard matches if we're not doing them */ + if (!check_wildcard) { + continue; + } + /* Wildcard matches IPv4 */ + const int cfg_v4 = port_binds_ipv4(cfg); + const int cfg_any_v4 = tor_addr_is_null(&cfg->addr) && cfg_v4; + const int addr_v4 = tor_addr_family(addr) == AF_INET || + tor_addr_family(addr) == AF_UNSPEC; + const int addr_any_v4 = tor_addr_is_null(&cfg->addr) && addr_v4; + if ((cfg_any_v4 && addr_v4) || (cfg_v4 && addr_any_v4)) { + return 1; + } + /* Wildcard matches IPv6 */ + const int cfg_v6 = port_binds_ipv6(cfg); + const int cfg_any_v6 = tor_addr_is_null(&cfg->addr) && cfg_v6; + const int addr_v6 = tor_addr_family(addr) == AF_INET6 || + tor_addr_family(addr) == AF_UNSPEC; + const int addr_any_v6 = tor_addr_is_null(&cfg->addr) && addr_v6; + if ((cfg_any_v6 && addr_v6) || (cfg_v6 && addr_any_v6)) { + return 1; + } + } + } + } SMARTLIST_FOREACH_END(cfg); + return 0; +} + +/* Like port_exists_by_type_addr_port, but accepts a host-order IPv4 address + * instead. */ +int +port_exists_by_type_addr32h_port(int listener_type, uint32_t addr_ipv4h, + int port, int check_wildcard) +{ + tor_addr_t ipv4; + tor_addr_from_ipv4h(&ipv4, addr_ipv4h); + return port_exists_by_type_addr_port(listener_type, &ipv4, port, + check_wildcard); +} + /** Adjust the value of options->DataDirectory, or fill it in if it's * absent. Return 0 on success, -1 on failure. */ static int diff --git a/src/or/config.h b/src/or/config.h index 02121cf95c..168e7d9926 100644 --- a/src/or/config.h +++ b/src/or/config.h @@ -87,6 +87,12 @@ int get_first_advertised_port_by_type_af(int listener_type, (get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER, AF_INET)) #define get_primary_dir_port() \ (get_first_advertised_port_by_type_af(CONN_TYPE_DIR_LISTENER, AF_INET)) +const tor_addr_t *get_first_advertised_addr_by_type_af(int listener_type, + int address_family); +int port_exists_by_type_addr_port(int listener_type, const tor_addr_t *addr, + int port, int check_wildcard); +int port_exists_by_type_addr32h_port(int listener_type, uint32_t addr_ipv4h, + int port, int check_wildcard); char *get_first_listener_addrport_string(int listener_type); diff --git a/src/or/router.c b/src/or/router.c index 68bcf1326e..d48bd05d98 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -1896,6 +1896,85 @@ router_pick_published_address,(const or_options_t *options, uint32_t *addr)) return 0; } +/* Tor relays only have one IPv4 address in the descriptor, which is derived + * from the Address torrc option, or guessed using various methods in + * router_pick_published_address(). + * Warn the operator if there is no ORPort on the descriptor address + * ipv4h_desc_addr. + * Warn the operator if there is no DirPort on the descriptor address. + * This catches a few common config errors: + * - operators who expect ORPorts and DirPorts to be advertised on the + * ports' listen addresses, rather than the torrc Address (or guessed + * addresses in the absence of an Address config). This includes + * operators who attempt to put their ORPort and DirPort on different + * addresses; + * - discrepancies between guessed addresses and configured listen + * addresses (when the Address option isn't set). + * If a listener is listening on all IPv4 addresses, it is assumed that it + * is listening on the configured Address, and no messages are logged. + * If an operators has specified NoAdvertise ORPorts in a NAT setting, + * no messages are logged, unless they have specified other advertised + * addresses. + * The message tells operators to configure an ORPort and DirPort that match + * the Address (using NoListen if needed). + */ +static void +router_check_descriptor_address_consistency(uint32_t ipv4h_desc_addr) +{ + + /* The first configured ORPort and DirPort, which may be CFG_AUTO_PORT. */ + int orport_v4_cfg = get_first_advertised_port_by_type_af( + CONN_TYPE_OR_LISTENER, + AF_INET); + int dirport_v4_cfg = get_first_advertised_port_by_type_af( + CONN_TYPE_DIR_LISTENER, + AF_INET); + + if (orport_v4_cfg != 0 && + !port_exists_by_type_addr32h_port(CONN_TYPE_OR_LISTENER, + ipv4h_desc_addr, orport_v4_cfg, 1)) { + const tor_addr_t *port_addr = get_first_advertised_addr_by_type_af( + CONN_TYPE_OR_LISTENER, + AF_INET); + 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); + + log_warn(LD_CONFIG, "The configured IPv4 ORPort address %s does not " + "match the address %s in the descriptor. Please configure " + "matching IPv4 addresses for the Address and ORPort options. " + "Use NoListen on the ORPort if you are behind a NAT.", + port_addr_str, desc_addr_str); + } + + if (dirport_v4_cfg != 0 && + !port_exists_by_type_addr32h_port(CONN_TYPE_DIR_LISTENER, + ipv4h_desc_addr, dirport_v4_cfg, 1)) { + const tor_addr_t *port_addr = get_first_advertised_addr_by_type_af( + CONN_TYPE_DIR_LISTENER, + AF_INET); + 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); + + log_warn(LD_CONFIG, "The configured IPv4 DirPort address %s does not " + "match the address %s in the descriptor. Please configure " + "matching IPv4 addresses for the Address and DirPort options. " + "Use NoListen on the DirPort if you are behind a NAT.", + port_addr_str, desc_addr_str); + } +} + /** Build a fresh routerinfo, signed server descriptor, and extra-info document * for this OR. Set r to the generated routerinfo, e to the generated * extra-info document. Return 0 on success, -1 on temporary error. Failure to @@ -1918,6 +1997,10 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e) return -1; } + /* Log a message if the address in the descriptor doesn't match the ORPort + * and DirPort addresses configured by the operator. */ + router_check_descriptor_address_consistency(addr); + ri = tor_malloc_zero(sizeof(routerinfo_t)); ri->cache_info.routerlist_index = -1; ri->nickname = tor_strdup(options->Nickname); From 4d2b3164ec922916d01d6772ef86b7041e7c7d78 Mon Sep 17 00:00:00 2001 From: s7r Date: Mon, 15 Aug 2016 09:50:10 +0000 Subject: [PATCH 3/6] Make log message clearer Longer and more explicit log message so we don't confuse users with behind NAT with working configurations and state that public IP addresses only should be provided with "Address", won't work with internal addresses. --- src/or/router.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/or/router.c b/src/or/router.c index d48bd05d98..c6bbafb95f 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -1947,8 +1947,13 @@ router_check_descriptor_address_consistency(uint32_t ipv4h_desc_addr) log_warn(LD_CONFIG, "The configured IPv4 ORPort address %s does not " "match the address %s in the descriptor. Please configure " - "matching IPv4 addresses for the Address and ORPort options. " - "Use NoListen on the ORPort if you are behind a NAT.", + "the matching IPv4 addresses for this Tor relay as " + "Address in the torrc configuration file if " + "you have multiple public IP addresses. If you are behind a " + "NAT and have the right ports forwarded, you can ignore this " + "warning or, to remove it, use 2 ORPort lines with options " + "NoListen (for the public IPv4 address line) and NoAdvertise " + "(for the internal NAT IPv4 address line).", port_addr_str, desc_addr_str); } @@ -1969,8 +1974,13 @@ router_check_descriptor_address_consistency(uint32_t ipv4h_desc_addr) log_warn(LD_CONFIG, "The configured IPv4 DirPort address %s does not " "match the address %s in the descriptor. Please configure " - "matching IPv4 addresses for the Address and DirPort options. " - "Use NoListen on the DirPort if you are behind a NAT.", + "the matching IPv4 addresses for this Tor relay as " + "Address in the torrc configuration file if " + "you have multiple public IP addresses. If you are behind a " + "NAT and have the right ports forwarded, you can ignore this " + "warning or, to remove it, use 2 DirPort lines with options " + "NoListen (for the public IPv4 address line) and NoAdvertise " + "(for the internal NAT IPv4 address line).", port_addr_str, desc_addr_str); } } From 427663428bf91dca0dfa2ede151cdb7eb9007408 Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 16 Aug 2016 14:05:46 +1000 Subject: [PATCH 4/6] Refactor duplicate code in router_check_descriptor_address_consistency No behaviour change --- src/or/router.c | 107 ++++++++++++++++++++---------------------------- 1 file changed, 45 insertions(+), 62 deletions(-) diff --git a/src/or/router.c b/src/or/router.c index c6bbafb95f..db800b8f76 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -1896,6 +1896,47 @@ router_pick_published_address,(const or_options_t *options, uint32_t *addr)) return 0; } +/* Like router_check_descriptor_address_consistency, but specifically for the + * ORPort or DirPort. + * listener_type is either CONN_TYPE_OR_LISTENER or CONN_TYPE_DIR_LISTENER. */ +static void +router_check_descriptor_address_port_consistency(uint32_t ipv4h_desc_addr, + int listener_type) +{ + /* The first configured Port, which 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); + 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); + + log_warn(LD_CONFIG, "The configured IPv4 %sPort address %s does not " + "match the address %s in the descriptor. Please configure " + "the matching IPv4 addresses for this Tor relay as " + "Address in the torrc configuration file if " + "you have multiple public IP addresses. If you are behind a " + "NAT and have the right ports forwarded, you can ignore this " + "warning or, to remove it, use 2 %sPort lines with options " + "NoListen (for the public IPv4 address line) and NoAdvertise " + "(for the internal NAT IPv4 address line).", + listener_type ? "OR" : "Dir", + port_addr_str, desc_addr_str, + listener_type ? "OR" : "Dir"); + } +} + /* 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(). @@ -1921,68 +1962,10 @@ router_pick_published_address,(const or_options_t *options, uint32_t *addr)) static void router_check_descriptor_address_consistency(uint32_t ipv4h_desc_addr) { - - /* The first configured ORPort and DirPort, which may be CFG_AUTO_PORT. */ - int orport_v4_cfg = get_first_advertised_port_by_type_af( - CONN_TYPE_OR_LISTENER, - AF_INET); - int dirport_v4_cfg = get_first_advertised_port_by_type_af( - CONN_TYPE_DIR_LISTENER, - AF_INET); - - if (orport_v4_cfg != 0 && - !port_exists_by_type_addr32h_port(CONN_TYPE_OR_LISTENER, - ipv4h_desc_addr, orport_v4_cfg, 1)) { - const tor_addr_t *port_addr = get_first_advertised_addr_by_type_af( - CONN_TYPE_OR_LISTENER, - AF_INET); - 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); - - log_warn(LD_CONFIG, "The configured IPv4 ORPort address %s does not " - "match the address %s in the descriptor. Please configure " - "the matching IPv4 addresses for this Tor relay as " - "Address in the torrc configuration file if " - "you have multiple public IP addresses. If you are behind a " - "NAT and have the right ports forwarded, you can ignore this " - "warning or, to remove it, use 2 ORPort lines with options " - "NoListen (for the public IPv4 address line) and NoAdvertise " - "(for the internal NAT IPv4 address line).", - port_addr_str, desc_addr_str); - } - - if (dirport_v4_cfg != 0 && - !port_exists_by_type_addr32h_port(CONN_TYPE_DIR_LISTENER, - ipv4h_desc_addr, dirport_v4_cfg, 1)) { - const tor_addr_t *port_addr = get_first_advertised_addr_by_type_af( - CONN_TYPE_DIR_LISTENER, - AF_INET); - 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); - - log_warn(LD_CONFIG, "The configured IPv4 DirPort address %s does not " - "match the address %s in the descriptor. Please configure " - "the matching IPv4 addresses for this Tor relay as " - "Address in the torrc configuration file if " - "you have multiple public IP addresses. If you are behind a " - "NAT and have the right ports forwarded, you can ignore this " - "warning or, to remove it, use 2 DirPort lines with options " - "NoListen (for the public IPv4 address line) and NoAdvertise " - "(for the internal NAT IPv4 address line).", - port_addr_str, desc_addr_str); - } + router_check_descriptor_address_port_consistency(ipv4h_desc_addr, + CONN_TYPE_OR_LISTENER); + router_check_descriptor_address_port_consistency(ipv4h_desc_addr, + CONN_TYPE_DIR_LISTENER); } /** Build a fresh routerinfo, signed server descriptor, and extra-info document From 4b4389280e397e4c79c0ceea97094d8593419d7b Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 16 Aug 2016 14:39:46 +1000 Subject: [PATCH 5/6] Check parameters to router_check_descriptor_address_port_consistency --- src/or/router.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/or/router.c b/src/or/router.c index db800b8f76..8fed36c8ff 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -1903,7 +1903,10 @@ static void router_check_descriptor_address_port_consistency(uint32_t ipv4h_desc_addr, int listener_type) { - /* The first configured Port, which may be the magic constant CFG_AUTO_PORT. + 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); @@ -1913,6 +1916,10 @@ router_check_descriptor_address_port_consistency(uint32_t ipv4h_desc_addr, 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. */ + assert(port_addr); + tor_addr_t desc_addr; char port_addr_str[TOR_ADDR_BUF_LEN]; char desc_addr_str[TOR_ADDR_BUF_LEN]; From a60ef723450672740eb2d5b0801af78704b77236 Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 16 Aug 2016 14:40:16 +1000 Subject: [PATCH 6/6] Reword the router_check_descriptor_address_port_consistency log message The new message covers static and dynamic public IPv4 addresses, and external / internal addresses in NAT setups. --- src/or/router.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/or/router.c b/src/or/router.c index 8fed36c8ff..acb5bc1fe1 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -1929,18 +1929,16 @@ router_check_descriptor_address_port_consistency(uint32_t ipv4h_desc_addr, tor_addr_from_ipv4h(&desc_addr, ipv4h_desc_addr); tor_addr_to_str(desc_addr_str, &desc_addr, TOR_ADDR_BUF_LEN, 0); - log_warn(LD_CONFIG, "The configured IPv4 %sPort address %s does not " - "match the address %s in the descriptor. Please configure " - "the matching IPv4 addresses for this Tor relay as " - "Address in the torrc configuration file if " - "you have multiple public IP addresses. If you are behind a " - "NAT and have the right ports forwarded, you can ignore this " - "warning or, to remove it, use 2 %sPort lines with options " - "NoListen (for the public IPv4 address line) and NoAdvertise " - "(for the internal NAT IPv4 address line).", - listener_type ? "OR" : "Dir", - port_addr_str, desc_addr_str, - listener_type ? "OR" : "Dir"); + 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 ' and 'OutboundBindAddress " + "'. If you are behind a NAT, use two %sPort lines: " + "'%sPort NoListen' and '%sPort " + "NoAdvertise'.", + listener_str, port_addr_str, desc_addr_str, listener_str, + listener_str, listener_str); } }