From 5a0bc83b20e0b23951417157c62a64ff8b3af00e Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 10 May 2018 08:48:24 +0930 Subject: [PATCH] Tor: don't do seed queries if we're supposed to always use proxy. Risks leakage. We could do lookup via the proxy, but that's a TODO. There's only one occurance of getaddrinfo (and no gethostbyname), so we add a flag to the callers. Note: the use of --always-use-proxy suppresses *all* DNS lookups, even those from connect commands and the command line. FIXME: An implicit setting of use_proxy_always is done in gossipd if it determines that we are announcing nothing but Tor addresses, but that does *not* suppress 'connect'. This is fixed in a later patch. Signed-off-by: Rusty Russell --- common/test/run-ip_port_parsing.c | 16 ++++++++-------- common/wireaddr.c | 13 ++++++++----- common/wireaddr.h | 9 ++++++--- gossipd/gossip.c | 9 ++++++--- lightningd/connect_control.c | 1 + lightningd/options.c | 15 ++++++++++----- lightningd/tor.c | 2 +- wallet/wallet.c | 2 +- 8 files changed, 41 insertions(+), 26 deletions(-) diff --git a/common/test/run-ip_port_parsing.c b/common/test/run-ip_port_parsing.c index d9ce6d8ad..2217774f2 100644 --- a/common/test/run-ip_port_parsing.c +++ b/common/test/run-ip_port_parsing.c @@ -85,35 +85,35 @@ int main(void) assert(!separate_address_and_port(tmpctx, "[::1]:http", &ip, &port)); // localhost hostnames for backward compat - assert(parse_wireaddr("localhost", &addr, 200, NULL)); + assert(parse_wireaddr("localhost", &addr, 200, false, NULL)); assert(addr.port == 200); // string should win the port battle - assert(parse_wireaddr("[::1]:9735", &addr, 500, NULL)); + assert(parse_wireaddr("[::1]:9735", &addr, 500, false, NULL)); assert(addr.port == 9735); ip = fmt_wireaddr(tmpctx, &addr); assert(streq(ip, "[::1]:9735")); // should use argument if we have no port in string - assert(parse_wireaddr("2001:db8:85a3::8a2e:370:7334", &addr, 9777, NULL)); + assert(parse_wireaddr("2001:db8:85a3::8a2e:370:7334", &addr, 9777, false, NULL)); assert(addr.port == 9777); ip = fmt_wireaddr(tmpctx, &addr); assert(streq(ip, "[2001:db8:85a3::8a2e:370:7334]:9777")); - assert(parse_wireaddr("[::ffff:127.0.0.1]:49150", &addr, 1, NULL)); + assert(parse_wireaddr("[::ffff:127.0.0.1]:49150", &addr, 1, false, NULL)); assert(addr.port == 49150); - assert(parse_wireaddr("4ruvswpqec5i2gogopxl4vm5bruzknbvbylov2awbo4rxiq4cimdldad.onion:49150", &addr, 1, NULL)); + assert(parse_wireaddr("4ruvswpqec5i2gogopxl4vm5bruzknbvbylov2awbo4rxiq4cimdldad.onion:49150", &addr, 1, false, NULL)); assert(addr.port == 49150); - assert(parse_wireaddr("4ruvswpqec5i2gogopxl4vm5bruzknbvbylov2awbo4rxiq4cimdldad.onion", &addr, 1, NULL)); + assert(parse_wireaddr("4ruvswpqec5i2gogopxl4vm5bruzknbvbylov2awbo4rxiq4cimdldad.onion", &addr, 1, false, NULL)); assert(addr.port == 1); - assert(parse_wireaddr("odpzvneidqdf5hdq.onion:49150", &addr, 1, NULL)); + assert(parse_wireaddr("odpzvneidqdf5hdq.onion:49150", &addr, 1, false, NULL)); assert(addr.port == 49150); - assert(parse_wireaddr("odpzvneidqdf5hdq.onion", &addr, 1, NULL)); + assert(parse_wireaddr("odpzvneidqdf5hdq.onion", &addr, 1, false, NULL)); assert(addr.port == 1); tal_free(tmpctx); return 0; diff --git a/common/wireaddr.c b/common/wireaddr.c index d3a623d8c..481fbd576 100644 --- a/common/wireaddr.c +++ b/common/wireaddr.c @@ -262,7 +262,7 @@ static bool separate_address_and_port(const tal_t *ctx, const char *arg, } bool wireaddr_from_hostname(struct wireaddr *addr, const char *hostname, - const u16 port, const char **err_msg) + const u16 port, bool dns_ok, const char **err_msg) { struct sockaddr_in6 *sa6; struct sockaddr_in *sa4; @@ -296,6 +296,8 @@ bool wireaddr_from_hostname(struct wireaddr *addr, const char *hostname, hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; hints.ai_flags = AI_ADDRCONFIG; + if (!dns_ok) + hints.ai_flags = AI_NUMERICHOST; gai_err = getaddrinfo(hostname, tal_fmt(tmpctx, "%d", port), &hints, &addrinfo); if (gai_err != 0) { @@ -320,7 +322,7 @@ bool wireaddr_from_hostname(struct wireaddr *addr, const char *hostname, } bool parse_wireaddr(const char *arg, struct wireaddr *addr, u16 defport, - const char **err_msg) + bool dns_ok, const char **err_msg) { struct in6_addr v6; struct in_addr v4; @@ -353,7 +355,7 @@ bool parse_wireaddr(const char *arg, struct wireaddr *addr, u16 defport, /* Resolve with getaddrinfo */ if (!res) - res = wireaddr_from_hostname(addr, ip, port, err_msg); + res = wireaddr_from_hostname(addr, ip, port, dns_ok, err_msg); finish: if (!res && err_msg && !*err_msg) @@ -362,7 +364,8 @@ finish: } bool parse_wireaddr_internal(const char *arg, struct wireaddr_internal *addr, - u16 port, bool wildcard_ok, const char **err_msg) + u16 port, bool wildcard_ok, bool dns_ok, + const char **err_msg) { u16 wildport; char *ip; @@ -392,7 +395,7 @@ bool parse_wireaddr_internal(const char *arg, struct wireaddr_internal *addr, } addr->itype = ADDR_INTERNAL_WIREADDR; - return parse_wireaddr(arg, &addr->u.wireaddr, port, err_msg); + return parse_wireaddr(arg, &addr->u.wireaddr, port, dns_ok, err_msg); } void wireaddr_from_sockname(struct wireaddr_internal *addr, diff --git a/common/wireaddr.h b/common/wireaddr.h index 5881803e1..a76215c36 100644 --- a/common/wireaddr.h +++ b/common/wireaddr.h @@ -67,13 +67,14 @@ enum addr_listen_announce fromwire_addr_listen_announce(const u8 **cursor, size_t *max); void towire_addr_listen_announce(u8 **pptr, enum addr_listen_announce ala); -bool parse_wireaddr(const char *arg, struct wireaddr *addr, u16 port, const char **err_msg); +bool parse_wireaddr(const char *arg, struct wireaddr *addr, u16 port, + bool dns_ok, const char **err_msg); char *fmt_wireaddr(const tal_t *ctx, const struct wireaddr *a); char *fmt_wireaddr_without_port(const tal_t *ctx, const struct wireaddr *a); bool wireaddr_from_hostname(struct wireaddr *addr, const char *hostname, - const u16 port, const char **err_msg); + const u16 port, bool dns_ok, const char **err_msg); void wireaddr_from_ipv4(struct wireaddr *addr, const struct in_addr *ip4, @@ -104,7 +105,9 @@ struct wireaddr_internal { char sockname[sizeof(((struct sockaddr_un *)0)->sun_path)]; } u; }; -bool parse_wireaddr_internal(const char *arg, struct wireaddr_internal *addr, u16 port, bool wildcard_ok, const char **err_msg); +bool parse_wireaddr_internal(const char *arg, struct wireaddr_internal *addr, + u16 port, bool wildcard_ok, bool dns_ok, + const char **err_msg); void towire_wireaddr_internal(u8 **pptr, const struct wireaddr_internal *addr); diff --git a/gossipd/gossip.c b/gossipd/gossip.c index d3056019b..c6ae03841 100644 --- a/gossipd/gossip.c +++ b/gossipd/gossip.c @@ -1930,7 +1930,8 @@ static struct io_plan *conn_tor_init(struct io_conn *conn, } static struct addrhint * -seed_resolve_addr(const tal_t *ctx, const struct pubkey *id, const u16 port) +seed_resolve_addr(const tal_t *ctx, const struct pubkey *id, const u16 port, + bool dns_ok) { struct addrhint *a; char bech32[100], *addr; @@ -1946,7 +1947,8 @@ seed_resolve_addr(const tal_t *ctx, const struct pubkey *id, const u16 port) a = tal(ctx, struct addrhint); a->addr.itype = ADDR_INTERNAL_WIREADDR; - if (!wireaddr_from_hostname(&a->addr.u.wireaddr, addr, port, NULL)) { + if (!wireaddr_from_hostname(&a->addr.u.wireaddr, addr, port, dns_ok, + NULL)) { status_trace("Could not resolve %s", addr); return tal_free(a); } else { @@ -2033,7 +2035,8 @@ static void try_reach_peer(struct daemon *daemon, const struct pubkey *id, id); if (!a) - a = seed_resolve_addr(tmpctx, id, 9735); + a = seed_resolve_addr(tmpctx, id, 9735, + !daemon->use_proxy_always); if (!a) { status_debug("No address known for %s, giving up", diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c index 9ee955b38..9d2f99a7a 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -152,6 +152,7 @@ static void json_connect(struct command *cmd, port = DEFAULT_PORT; } if (!parse_wireaddr_internal(name, &addr, port, false, + !cmd->ld->use_proxy_always, &err_msg)) { command_fail(cmd, "Host %s:%u not valid: %s", name, port, err_msg ? err_msg : "port is 0"); diff --git a/lightningd/options.c b/lightningd/options.c index 2877a7247..8f202acd5 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -159,7 +159,7 @@ static char *opt_add_addr_withtype(const char *arg, ld->proposed_listen_announce[n] = ala; if (!parse_wireaddr_internal(arg, &ld->proposed_wireaddr[n], ld->portnum, - true, &err_msg)) { + true, !ld->use_proxy_always, &err_msg)) { return tal_fmt(NULL, "Unable to parse address '%s': %s", arg, err_msg); } @@ -302,7 +302,8 @@ static char *opt_add_proxy_addr(const char *arg, struct lightningd *ld) /* We use a tal_arr here, so we can marshal it to gossipd */ ld->proxyaddr = tal_arr(ld, struct wireaddr, 1); - if (!parse_wireaddr(arg, ld->proxyaddr, 9050, NULL)) { + if (!parse_wireaddr(arg, ld->proxyaddr, 9050, !ld->use_proxy_always, + NULL)) { return tal_fmt(NULL, "Unable to parse Tor proxy address '%s'", arg); } @@ -313,7 +314,8 @@ static char *opt_add_tor_service_addr(const char *arg, struct lightningd *ld) { tal_free(ld->tor_serviceaddr); ld->tor_serviceaddr = tal(ld, struct wireaddr); - if (!parse_wireaddr(arg, ld->tor_serviceaddr, 9051, NULL)) { + if (!parse_wireaddr(arg, ld->tor_serviceaddr, 9051, + !ld->use_proxy_always, NULL)) { return tal_fmt(NULL, "Unable to parse Tor service address '%s'", arg); } @@ -432,8 +434,11 @@ static void config_register_opts(struct lightningd *ld) "Set a Tor hidden service password"); opt_register_arg("--tor-auto-listen", opt_set_bool_arg, opt_show_bool, &ld->config.tor_enable_auto_hidden_service , "Generate and use a temp auto hidden-service and show the onion address"); - opt_register_arg("--always-use-proxy", opt_set_bool_arg, opt_show_bool, - &ld->use_proxy_always, "Use the proxy always"); + + /* Early, as it suppresses DNS lookups from cmdline too. */ + opt_register_early_arg("--always-use-proxy", + opt_set_bool_arg, opt_show_bool, + &ld->use_proxy_always, "Use the proxy always"); } #if DEVELOPER diff --git a/lightningd/tor.c b/lightningd/tor.c index 903217121..cc6e16af8 100644 --- a/lightningd/tor.c +++ b/lightningd/tor.c @@ -94,7 +94,7 @@ static void make_onion(struct lightningd *ld, struct rbuf *rbuf) tal_resize(&ld->proposed_listen_announce, n + 1); parse_wireaddr_internal(tal_fmt(tmpctx, "%s.onion", line), &ld->proposed_wireaddr[n], - ld->portnum, false, NULL); + ld->portnum, false, false, NULL); ld->proposed_listen_announce[n] = ADDR_ANNOUNCE; discard_remaining_response(ld, rbuf); return; diff --git a/wallet/wallet.c b/wallet/wallet.c index cead5db5d..2ac993f84 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -510,7 +510,7 @@ static struct peer *wallet_peer_load(struct wallet *w, const u64 dbid) addrstr = sqlite3_column_text(stmt, 2); if (addrstr) { addrp = &addr; - if (!parse_wireaddr_internal((const char*)addrstr, addrp, DEFAULT_PORT, false, NULL)) { + if (!parse_wireaddr_internal((const char*)addrstr, addrp, DEFAULT_PORT, false, false, NULL)) { db_stmt_done(stmt); return NULL; }