From fe96fe10c7279a6a52cb0f0831efc44dfcf04767 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 7 May 2018 13:58:12 +0930 Subject: [PATCH] Clean up network options. It's become clear that our network options are insufficient, with the coming addition of Tor and unix domain support. Currently: 1. We always bind to local IPv4 and IPv6 sockets, unless --port=0, --offline, or any address is specified explicitly. If they're routable, we announce. 2. --addr is used to announce, but not to control binding. After this change: 1. --port is deprecated. 2. --addr controls what we bind to and announce. 3. --bind-addr/--announce-addr can be used to control one and not the other. 4. Unless --autolisten=0, we add local IPv4 & IPv6 port 9735 (and announce if they are routable). 5. --offline still overrides listening (though announcing is still the same). This means we can bind to as many ports/interfaces as we want, and for special effects we can announce different things (eg. we're sitting behind a port forward or a proxy). What remains to implement is semi-automatic binding: we should be able to say '--addr=0.0.0.0:9999' and have the address resolve at bind time, or even '--addr=0.0.0.0:0' and have the port autoresolve too (you could determine what it was from 'lightning-cli getinfo'. Signed-off-by: Rusty Russell --- common/wireaddr.c | 11 ++++ common/wireaddr.h | 12 ++++ gossipd/gossip.c | 123 ++++++++++++++++++------------------ gossipd/gossip_wire.csv | 5 +- lightningd/gossip_control.c | 6 +- lightningd/jsonrpc.c | 27 ++++++-- lightningd/lightningd.c | 2 + lightningd/lightningd.h | 7 +- lightningd/netaddress.c | 36 +++++++---- lightningd/options.c | 98 ++++++++++++++++++++++------ tests/test_gossip.py | 4 +- tests/test_lightningd.py | 1 - tests/utils.py | 5 +- 13 files changed, 228 insertions(+), 109 deletions(-) diff --git a/common/wireaddr.c b/common/wireaddr.c index 71062ab48..1a621027e 100644 --- a/common/wireaddr.c +++ b/common/wireaddr.c @@ -42,6 +42,17 @@ void towire_wireaddr(u8 **pptr, const struct wireaddr *addr) towire_u16(pptr, addr->port); } +enum addr_listen_announce fromwire_addr_listen_announce(const u8 **cursor, + size_t *max) +{ + return fromwire_u8(cursor, max); +} + +void towire_addr_listen_announce(u8 **pptr, enum addr_listen_announce ala) +{ + towire_u8(pptr, ala); +} + char *fmt_wireaddr(const tal_t *ctx, const struct wireaddr *a) { char addrstr[INET6_ADDRSTRLEN]; diff --git a/common/wireaddr.h b/common/wireaddr.h index ade052295..32a67417a 100644 --- a/common/wireaddr.h +++ b/common/wireaddr.h @@ -37,10 +37,22 @@ struct wireaddr { u16 port; }; +/* We use wireaddr to tell gossipd both what to listen on, and what to + * announce */ +enum addr_listen_announce { + ADDR_LISTEN = (1 << 0), + ADDR_ANNOUNCE = (1 << 1), + ADDR_LISTEN_AND_ANNOUNCE = ADDR_LISTEN|ADDR_ANNOUNCE +}; + /* Inserts a single ADDR_TYPE_PADDING if addr is NULL */ void towire_wireaddr(u8 **pptr, const struct wireaddr *addr); bool fromwire_wireaddr(const u8 **cursor, size_t *max, struct wireaddr *addr); +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); char *fmt_wireaddr(const tal_t *ctx, const struct wireaddr *a); diff --git a/gossipd/gossip.c b/gossipd/gossip.c index 977a74e17..9aa33b223 100644 --- a/gossipd/gossip.c +++ b/gossipd/gossip.c @@ -128,6 +128,7 @@ struct daemon { u8 alias[33]; u8 rgb[3]; struct wireaddr *wireaddrs; + enum addr_listen_announce *listen_announce; /* To make sure our node_announcement timestamps increase */ u32 last_announce_timestamp; @@ -563,8 +564,10 @@ static u8 *create_node_announcement(const tal_t *ctx, struct daemon *daemon, sig = tal(ctx, secp256k1_ecdsa_signature); memset(sig, 0, sizeof(*sig)); } - for (i = 0; i < tal_count(daemon->wireaddrs); i++) - towire_wireaddr(&addresses, daemon->wireaddrs+i); + for (i = 0; i < tal_count(daemon->wireaddrs); i++) { + if (daemon->listen_announce[i] & ADDR_ANNOUNCE) + towire_wireaddr(&addresses, daemon->wireaddrs+i); + } announcement = towire_node_announcement(ctx, sig, features, timestamp, @@ -1552,69 +1555,63 @@ static struct io_plan *connection_in(struct io_conn *conn, struct daemon *daemon init_new_peer, daemon); } -static void setup_listeners(struct daemon *daemon, u16 portnum) +static void setup_listeners(struct daemon *daemon) { + bool had_ipv6_wildcard = false; struct sockaddr_in addr; struct sockaddr_in6 addr6; - socklen_t len; - int fd1, fd2; - - if (!portnum) { - status_info("Zero portnum, not listening for incoming"); - return; - } - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - addr.sin_port = htons(portnum); - - memset(&addr6, 0, sizeof(addr6)); - addr6.sin6_family = AF_INET6; - addr6.sin6_addr = in6addr_any; - addr6.sin6_port = htons(portnum); - - /* IPv6, since on Linux that (usually) binds to IPv4 too. */ - fd1 = make_listen_fd(AF_INET6, &addr6, sizeof(addr6), true); - if (fd1 >= 0) { - struct sockaddr_in6 in6 = {}; + int fd; - len = sizeof(in6); - if (getsockname(fd1, (void *)&in6, &len) != 0) { - status_broken("Failed get IPv6 sockname: %s", - strerror(errno)); - close_noerr(fd1); - fd1 = -1; - } else { - addr.sin_port = in6.sin6_port; - assert(portnum == ntohs(addr.sin_port)); - status_trace("Creating IPv6 listener on port %u", - portnum); - io_new_listener(daemon, fd1, connection_in, daemon); - } - } + for (size_t i = 0; i < tal_count(daemon->wireaddrs); i++) { + if (!(daemon->listen_announce[i] & ADDR_LISTEN)) + continue; - /* Just in case, aim for the same port... */ - fd2 = make_listen_fd(AF_INET, &addr, sizeof(addr), false); - if (fd2 >= 0) { - len = sizeof(addr); - if (getsockname(fd2, (void *)&addr, &len) != 0) { - status_broken("Failed get IPv4 sockname: %s", - strerror(errno)); - close_noerr(fd2); - fd2 = -1; - } else { - assert(portnum == ntohs(addr.sin_port)); - status_trace("Creating IPv4 listener on port %u", - portnum); - io_new_listener(daemon, fd2, connection_in, daemon); + switch (daemon->wireaddrs[i].type) { + case ADDR_TYPE_IPV4: + addr.sin_family = AF_INET; + addr.sin_port = htons(daemon->wireaddrs[i].port); + assert(daemon->wireaddrs[i].addrlen + == sizeof(addr.sin_addr)); + memcpy(&addr.sin_addr, + daemon->wireaddrs[i].addr, + sizeof(addr.sin_addr)); + /* We might fail if IPv6 bound to port first */ + fd = make_listen_fd(AF_INET, &addr, sizeof(addr), + !had_ipv6_wildcard); + if (fd >= 0) { + status_trace("Created IPv4 listener on port %u", + daemon->wireaddrs[i].port); + io_new_listener(daemon, fd, connection_in, + daemon); + } + continue; + case ADDR_TYPE_IPV6: + memset(&addr6, 0, sizeof(addr6)); + addr6.sin6_family = AF_INET6; + addr6.sin6_port = htons(daemon->wireaddrs[i].port); + assert(daemon->wireaddrs[i].addrlen + == sizeof(addr6.sin6_addr)); + memcpy(&addr6.sin6_addr, daemon->wireaddrs[i].addr, + sizeof(addr6.sin6_addr)); + if (memeqzero(&addr6.sin6_addr, sizeof(addr6.sin6_addr))) + had_ipv6_wildcard = true; + fd = make_listen_fd(AF_INET6, &addr6, sizeof(addr6), + true); + if (fd >= 0) { + status_trace("Created IPv6 listener on port %u", + daemon->wireaddrs[i].port); + io_new_listener(daemon, fd, connection_in, + daemon); + } + continue; + case ADDR_TYPE_PADDING: + break; } - } - - if (fd1 < 0 && fd2 < 0) + /* Shouldn't happen. */ status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Could not bind to a network address on port %u", - portnum); + "Invalid listener address type %u", + daemon->wireaddrs[i].type); + } } /* Parse an incoming gossip init message and assign config variables @@ -1630,7 +1627,8 @@ static struct io_plan *gossip_init(struct daemon_conn *master, if (!fromwire_gossipctl_init( daemon, msg, &daemon->broadcast_interval, &chain_hash, &daemon->id, &daemon->globalfeatures, - &daemon->localfeatures, &daemon->wireaddrs, daemon->rgb, + &daemon->localfeatures, &daemon->wireaddrs, + &daemon->listen_announce, daemon->rgb, daemon->alias, &update_channel_interval, &daemon->reconnect)) { master_badmsg(WIRE_GOSSIPCTL_INIT, msg); } @@ -1652,12 +1650,13 @@ static struct io_plan *gossip_activate(struct daemon_conn *master, struct daemon *daemon, const u8 *msg) { - u16 port; + bool listen; - if (!fromwire_gossipctl_activate(msg, &port)) + if (!fromwire_gossipctl_activate(msg, &listen)) master_badmsg(WIRE_GOSSIPCTL_ACTIVATE, msg); - setup_listeners(daemon, port); + if (listen) + setup_listeners(daemon); /* OK, we're ready! */ daemon_conn_send(&daemon->master, diff --git a/gossipd/gossip_wire.csv b/gossipd/gossip_wire.csv index e530c341d..870878b79 100644 --- a/gossipd/gossip_wire.csv +++ b/gossipd/gossip_wire.csv @@ -13,6 +13,7 @@ gossipctl_init,,lflen,u16 gossipctl_init,,lfeatures,lflen*u8 gossipctl_init,,num_wireaddrs,u16 gossipctl_init,,wireaddrs,num_wireaddrs*struct wireaddr +gossipctl_init,,listen_announce,num_wireaddrs*enum addr_listen_announce gossipctl_init,,rgb,3*u8 gossipctl_init,,alias,32*u8 gossipctl_init,,update_channel_interval,u32 @@ -20,8 +21,8 @@ gossipctl_init,,reconnect,bool # Activate the gossip daemon, so others can connect. gossipctl_activate,3025 -# If non-zero, port to listen on. -gossipctl_activate,,port,u16 +# Do we listen? +gossipctl_activate,,listen,bool # Gossipd->master, I am ready. gossipctl_activate_reply,3125 diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 1a19bc369..37ae6393c 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -206,7 +206,8 @@ void gossip_init(struct lightningd *ld) tmpctx, ld->config.broadcast_interval, &get_chainparams(ld)->genesis_blockhash, &ld->id, get_offered_global_features(tmpctx), - get_offered_local_features(tmpctx), ld->wireaddrs, ld->rgb, + get_offered_local_features(tmpctx), ld->wireaddrs, + ld->listen_announce, ld->rgb, ld->alias, ld->config.channel_update_interval, ld->reconnect); subd_send_msg(ld->gossip, msg); } @@ -222,8 +223,7 @@ static void gossip_activate_done(struct subd *gossip UNUSED, void gossip_activate(struct lightningd *ld) { - const u8 *msg = towire_gossipctl_activate(NULL, - ld->listen ? ld->portnum : 0); + const u8 *msg = towire_gossipctl_activate(NULL, ld->listen); subd_req(ld->gossip, ld->gossip, take(msg), -1, 0, gossip_activate_done, NULL); diff --git a/lightningd/jsonrpc.c b/lightningd/jsonrpc.c index d3f050aeb..7ed0709cf 100644 --- a/lightningd/jsonrpc.c +++ b/lightningd/jsonrpc.c @@ -149,12 +149,31 @@ static void json_getinfo(struct command *cmd, json_object_start(response, NULL); json_add_pubkey(response, "id", &cmd->ld->id); - if (cmd->ld->listen && cmd->ld->portnum) { - json_add_num(response, "port", cmd->ld->portnum); + if (cmd->ld->listen) { + bool have_listen_no_announce = false; + if (deprecated_apis) + json_add_num(response, "port", cmd->ld->portnum); + + /* These are the addresses we're announcing */ json_array_start(response, "address"); - for (size_t i = 0; i < tal_count(cmd->ld->wireaddrs); i++) - json_add_address(response, NULL, cmd->ld->wireaddrs+i); + for (size_t i = 0; i < tal_count(cmd->ld->wireaddrs); i++) { + if (cmd->ld->listen_announce[i] & ADDR_ANNOUNCE) + json_add_address(response, NULL, + cmd->ld->wireaddrs+i); + else + have_listen_no_announce = true; + } json_array_end(response); + + if (have_listen_no_announce) { + json_array_start(response, "listen-only"); + for (size_t i = 0; i < tal_count(cmd->ld->wireaddrs); i++) { + if (cmd->ld->listen_announce[i] == ADDR_LISTEN) + json_add_address(response, NULL, + cmd->ld->wireaddrs+i); + } + json_array_end(response); + } } json_add_string(response, "version", version()); json_add_num(response, "blockheight", get_block_height(cmd->ld->topology)); diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index 3da3507a8..fefc5c976 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -70,8 +70,10 @@ static struct lightningd *new_lightningd(const tal_t *ctx) list_head_init(&ld->sendpay_commands); list_head_init(&ld->close_commands); ld->wireaddrs = tal_arr(ld, struct wireaddr, 0); + ld->listen_announce = tal_arr(ld, enum addr_listen_announce, 0); ld->portnum = DEFAULT_PORT; ld->listen = true; + ld->autolisten = true; ld->reconnect = true; timers_init(&ld->timers, time_mono()); ld->topology = new_topology(ld, ld->log); diff --git a/lightningd/lightningd.h b/lightningd/lightningd.h index 2709a9ff1..e60f25e82 100644 --- a/lightningd/lightningd.h +++ b/lightningd/lightningd.h @@ -117,8 +117,13 @@ struct lightningd { /* Do we want to listen for other peers? */ bool listen; - /* Addresses to announce to the network (tal_count()) */ + /* Do we want to guess addresses to listen and announce? */ + bool autolisten; + + /* Addresses to bind/announce to the network (tal_count()) */ struct wireaddr *wireaddrs; + /* And the bitset for each, whether to listen, announce or both */ + enum addr_listen_announce *listen_announce; /* Bearer of all my secrets. */ int hsm_fd; diff --git a/lightningd/netaddress.c b/lightningd/netaddress.c index 4231a6977..987c20e66 100644 --- a/lightningd/netaddress.c +++ b/lightningd/netaddress.c @@ -228,10 +228,13 @@ static bool get_local_sockname(struct lightningd *ld, return true; } -/* Return a wireaddr without port filled in */ -static bool guess_one_address(struct lightningd *ld, - struct wireaddr *addr, u16 portnum, - enum wire_addr_type type) +/* Return 0 if not available, or whether it's listenable-only or announceable. + * If it's listenable only, will set wireaddr to all-zero address for universal + * binding. */ +static enum addr_listen_announce guess_one_address(struct lightningd *ld, + struct wireaddr *addr, + u16 portnum, + enum wire_addr_type type) { addr->type = type; addr->port = portnum; @@ -245,7 +248,7 @@ static bool guess_one_address(struct lightningd *ld, sin.sin_addr.s_addr = 0x08080808; sin.sin_family = AF_INET; if (!get_local_sockname(ld, AF_INET, &sin, sizeof(sin))) - return false; + return 0; addr->addrlen = sizeof(sin.sin_addr); memcpy(addr->addr, &sin.sin_addr, addr->addrlen); break; @@ -260,25 +263,27 @@ static bool guess_one_address(struct lightningd *ld, sin6.sin6_family = AF_INET6; memcpy(sin6.sin6_addr.s6_addr, pchGoogle, sizeof(pchGoogle)); if (!get_local_sockname(ld, AF_INET6, &sin6, sizeof(sin6))) - return false; + return 0; addr->addrlen = sizeof(sin6.sin6_addr); memcpy(addr->addr, &sin6.sin6_addr, addr->addrlen); break; } case ADDR_TYPE_PADDING: log_debug(ld->log, "Padding address, ignoring"); - return false; + return 0; } if (!IsRoutable(addr)) { log_debug(ld->log, "Address %s is not routable", type_to_string(tmpctx, struct wireaddr, addr)); - return false; + /* This corresponds to INADDR_ANY or in6addr_any */ + memset(addr->addr, 0, addr->addrlen); + return ADDR_LISTEN; } log_debug(ld->log, "Public address %s", type_to_string(tmpctx, struct wireaddr, addr)); - return true; + return ADDR_LISTEN_AND_ANNOUNCE; } void guess_addresses(struct lightningd *ld) @@ -289,10 +294,19 @@ void guess_addresses(struct lightningd *ld) /* We allocate an extra, then remove if it's not needed. */ tal_resize(&ld->wireaddrs, n+1); - if (guess_one_address(ld, &ld->wireaddrs[n], ld->portnum, ADDR_TYPE_IPV4)) { + tal_resize(&ld->listen_announce, n+1); + /* We do IPv6 first: on Linux, that binds to IPv4 too. */ + ld->listen_announce[n] = guess_one_address(ld, &ld->wireaddrs[n], + ld->portnum, ADDR_TYPE_IPV6); + if (ld->listen_announce[n] != 0) { n++; tal_resize(&ld->wireaddrs, n+1); + tal_resize(&ld->listen_announce, n+1); } - if (!guess_one_address(ld, &ld->wireaddrs[n], ld->portnum, ADDR_TYPE_IPV6)) + ld->listen_announce[n] = guess_one_address(ld, &ld->wireaddrs[n], + ld->portnum, ADDR_TYPE_IPV4); + if (ld->listen_announce[n] == 0) { tal_resize(&ld->wireaddrs, n); + tal_resize(&ld->listen_announce, n); + } } diff --git a/lightningd/options.c b/lightningd/options.c index 0ee33951a..6a907ec1f 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -102,11 +102,15 @@ static char *opt_set_u32(const char *arg, u32 *u) return NULL; } -static char *opt_set_u16(const char *arg, u16 *u) +static char *opt_set_port(const char *arg, struct lightningd *ld) { char *endp; unsigned long l; + log_broken(ld->log, "--port has been deprecated, use --autolisten=0 or --addr=:"); + if (!deprecated_apis) + return "--port is deprecated"; + assert(arg != NULL); /* This is how the manpage says to do it. Yech. */ @@ -114,9 +118,13 @@ static char *opt_set_u16(const char *arg, u16 *u) l = strtoul(arg, &endp, 0); if (*endp || !arg[0]) return tal_fmt(NULL, "'%s' is not a number", arg); - *u = l; - if (errno || *u != l) + ld->portnum = l; + if (errno || ld->portnum != l) return tal_fmt(NULL, "'%s' is out of range", arg); + + if (ld->portnum == 0) + ld->autolisten = false; + return NULL; } @@ -138,7 +146,9 @@ static char *opt_set_s32(const char *arg, s32 *u) return NULL; } -static char *opt_add_addr(const char *arg, struct lightningd *ld) +static char *opt_add_addr_withtype(const char *arg, + struct lightningd *ld, + enum addr_listen_announce ala) { size_t n = tal_count(ld->wireaddrs); char const *err_msg; @@ -146,6 +156,8 @@ static char *opt_add_addr(const char *arg, struct lightningd *ld) assert(arg != NULL); tal_resize(&ld->wireaddrs, n+1); + tal_resize(&ld->listen_announce, n+1); + ld->listen_announce[n] = ala; if (!parse_wireaddr(arg, &ld->wireaddrs[n], ld->portnum, &err_msg)) { return tal_fmt(NULL, "Unable to parse IP address '%s': %s", arg, err_msg); @@ -155,6 +167,21 @@ static char *opt_add_addr(const char *arg, struct lightningd *ld) } +static char *opt_add_addr(const char *arg, struct lightningd *ld) +{ + return opt_add_addr_withtype(arg, ld, ADDR_LISTEN_AND_ANNOUNCE); +} + +static char *opt_add_bind_addr(const char *arg, struct lightningd *ld) +{ + return opt_add_addr_withtype(arg, ld, ADDR_LISTEN); +} + +static char *opt_add_announce_addr(const char *arg, struct lightningd *ld) +{ + return opt_add_addr_withtype(arg, ld, ADDR_ANNOUNCE); +} + static char *opt_add_ipaddr(const char *arg, struct lightningd *ld) { log_broken(ld->log, "--ipaddr has been deprecated, use --addr"); @@ -177,11 +204,6 @@ static void opt_show_s32(char buf[OPT_SHOW_LEN], const s32 *u) snprintf(buf, OPT_SHOW_LEN, "%"PRIi32, *u); } -static void opt_show_u16(char buf[OPT_SHOW_LEN], const u16 *u) -{ - snprintf(buf, OPT_SHOW_LEN, "%u", *u); -} - static char *opt_set_network(const char *arg, struct lightningd *ld) { assert(arg != NULL); @@ -339,9 +361,19 @@ static void config_register_opts(struct lightningd *ld) ld, opt_hidden); opt_register_arg("--addr", opt_add_addr, NULL, ld, - "Set the IP address (v4 or v6) to listen on and announce to the network for incoming connections"); + "Set an IP address (v4 or v6) to listen on and announce to the network for incoming connections"); + opt_register_arg("--bind-addr", opt_add_bind_addr, NULL, + ld, + "Set an IP address (v4 or v6) to listen on, but not announce"); + opt_register_arg("--announce-addr", opt_add_announce_addr, NULL, + ld, + "Set an IP address (v4 or v6) to announce, but not listen on"); + opt_register_noarg("--offline", opt_set_offline, ld, "Start in offline-mode (do not automatically reconnect and do not accept incoming connections)"); + opt_register_arg("--autolisten", opt_set_bool_arg, opt_show_bool, + &ld->autolisten, + "If true, listen on default port and announce if it seems to be a public interface"); opt_register_early_arg("--network", opt_set_network, opt_show_network, ld, @@ -649,8 +681,8 @@ void register_opts(struct lightningd *ld) /* --port needs to be an early arg to force it being parsed * before --ipaddr which may depend on it */ - opt_register_early_arg("--port", opt_set_u16, opt_show_u16, &ld->portnum, - "Port to bind to (0 means don't listen)"); + opt_register_early_arg("--port", opt_set_port, NULL, ld, + opt_hidden); opt_register_arg("--bitcoin-datadir", opt_set_talstr, NULL, &ld->topology->bitcoind->datadir, "-datadir arg for bitcoin-cli"); @@ -778,11 +810,11 @@ void handle_opts(struct lightningd *ld, int argc, char *argv[]) check_config(ld); - if (ld->portnum && ld->listen && tal_count(ld->wireaddrs) == 0) + if (ld->listen && ld->autolisten) guess_addresses(ld); else log_debug(ld->log, "Not guessing addresses: %s", - (ld->portnum && ld->listen) ? "manually set" : "port set to zero"); + !ld->listen ? "--offline" : "--autolisten=0"); } /* FIXME: This is a hack! Expose somehow in ccan/opt.*/ @@ -801,6 +833,21 @@ static const char *next_name(const char *names, unsigned *len) return first_name(names + 1, len); } +static void json_add_opt_addrs(struct json_result *response, + const char *name0, + const struct wireaddr *wireaddrs, + const enum addr_listen_announce *listen_announce, + enum addr_listen_announce ala) +{ + for (size_t i = 0; i < tal_count(wireaddrs); i++) { + if (listen_announce[i] != ala) + continue; + json_add_string(response, + name0, + fmt_wireaddr(name0, wireaddrs+i)); + } +} + static void add_config(struct lightningd *ld, struct json_result *response, const struct opt_table *opt, @@ -870,16 +917,25 @@ static void add_config(struct lightningd *ld, topo->override_fee_rate[0], topo->override_fee_rate[1], topo->override_fee_rate[2]); + } else if (opt->cb_arg == (void *)opt_set_port) { + if (!deprecated_apis) + answer = tal_fmt(name0, "%u", ld->portnum); } else if (opt->cb_arg == (void *)opt_add_ipaddr) { /* Covered by opt_add_addr below */ } else if (opt->cb_arg == (void *)opt_add_addr) { - /* This is a bit weird, we can have multiple args */ - for (size_t i = 0; i < tal_count(ld->wireaddrs); i++) { - json_add_string(response, - name0, - fmt_wireaddr(name0, - ld->wireaddrs+i)); - } + json_add_opt_addrs(response, name0, + ld->wireaddrs, ld->listen_announce, + ADDR_LISTEN_AND_ANNOUNCE); + return; + } else if (opt->cb_arg == (void *)opt_add_bind_addr) { + json_add_opt_addrs(response, name0, + ld->wireaddrs, ld->listen_announce, + ADDR_LISTEN); + return; + } else if (opt->cb_arg == (void *)opt_add_announce_addr) { + json_add_opt_addrs(response, name0, + ld->wireaddrs, ld->listen_announce, + ADDR_ANNOUNCE); return; #if DEVELOPER } else if (strstarts(name, "dev-")) { diff --git a/tests/test_gossip.py b/tests/test_gossip.py index 963cc183c..e595d863d 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -16,8 +16,8 @@ def test_gossip_pruning(node_factory, bitcoind): opts = {'channel-update-interval': 5} l1, l2, l3 = node_factory.get_nodes(3, opts) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) - l2.rpc.connect(l3.info['id'], 'localhost', l3.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + l2.rpc.connect(l3.info['id'], 'localhost', l3.port) scid1 = l1.fund_channel(l2, 10**6) scid2 = l2.fund_channel(l3, 10**6) diff --git a/tests/test_lightningd.py b/tests/test_lightningd.py index 94f4b32ef..bdf4d738a 100644 --- a/tests/test_lightningd.py +++ b/tests/test_lightningd.py @@ -4288,7 +4288,6 @@ class LightningDTests(BaseLightningDTests): # See utils.py assert configs['bitcoin-datadir'] == bitcoind.bitcoin_dir assert configs['lightning-dir'] == l1.daemon.lightning_dir - assert configs['port'] == l1.port assert configs['allow-deprecated-apis'] is False assert configs['override-fee-rates'] == '15000/7500/1000' assert configs['network'] == 'regtest' diff --git a/tests/utils.py b/tests/utils.py index ce508a53a..5ddba846e 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -261,7 +261,7 @@ class LightningD(TailableProc): opts = { 'bitcoin-datadir': bitcoin_dir, 'lightning-dir': lightning_dir, - 'port': port, + 'addr': '127.0.0.1:{}'.format(port), 'allow-deprecated-apis': 'false', 'override-fee-rates': '15000/7500/1000', 'network': 'regtest', @@ -369,7 +369,8 @@ class LightningNode(object): def start(self): self.daemon.start() - self.port = self.rpc.getinfo()['port'] + # This shortcut is sufficient for our simple tests. + self.port = self.rpc.getinfo()['address'][0]['port'] def stop(self, timeout=10): """ Attempt to do a clean shutdown, but kill if it hangs