diff --git a/common/wireaddr.c b/common/wireaddr.c index 8130fee5dd98..48a1b3c37992 100644 --- a/common/wireaddr.c +++ b/common/wireaddr.c @@ -361,6 +361,11 @@ bool is_toraddr(const char *arg) return true; } +bool is_wildcardaddr(const char *arg) +{ + return streq(arg, ""); +} + /* Rules: * * - not longer than 255 @@ -374,7 +379,7 @@ bool is_dnsaddr(const char *arg) size_t i, arglen; int lastdot; - if (is_ipaddr(arg) || is_toraddr(arg)) + if (is_ipaddr(arg) || is_toraddr(arg) || is_wildcardaddr(arg)) return false; /* now that its not IP or TOR, check its a DNS name */ @@ -684,7 +689,7 @@ bool parse_wireaddr_internal(const char *arg, struct wireaddr_internal *addr, /* An empty string means IPv4 and IPv6 (which under Linux by default * means just IPv6, and IPv4 gets autobound). */ - if (wildcard_ok && streq(ip, "")) { + if (wildcard_ok && is_wildcardaddr(ip)) { addr->itype = ADDR_INTERNAL_ALLPROTO; addr->u.port = splitport; return true; diff --git a/common/wireaddr.h b/common/wireaddr.h index 8b8b79904b72..ed83194d1af5 100644 --- a/common/wireaddr.h +++ b/common/wireaddr.h @@ -162,6 +162,8 @@ bool is_ipaddr(const char *arg); bool is_toraddr(const char *arg); +bool is_wildcardaddr(const char *arg); + bool is_dnsaddr(const char *arg); bool parse_wireaddr_internal(const char *arg, struct wireaddr_internal *addr, diff --git a/connectd/connectd.c b/connectd/connectd.c index 9a56abe2fea5..8ed57ebb0b3f 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -1413,17 +1413,20 @@ static struct wireaddr_internal *setup_listeners(const tal_t *ctx, /* Override with websocket port */ addr = binding[i].u.wireaddr; addr.port = daemon->websocket_port; - handle_wireaddr_listen(daemon, &addr, false, true); - announced_some = true; + if (handle_wireaddr_listen(daemon, &addr, true, true)) + announced_some = true; /* FIXME: We don't report these bindings to * lightningd, so they don't appear in * getinfo. */ } - - /* We add the websocket port to the announcement if it - * applies to any */ - if (announced_some) { + /* We add the websocket port to the announcement if we made one + * *and* we have other announced addresses. */ + /* BOLT-websocket #7: + * - MUST NOT add a `type 6` address unless there is also at + * least one address of different type. + */ + if (announced_some && tal_count(*announcable) != 0) { wireaddr_from_websocket(&addr, daemon->websocket_port); add_announcable(announcable, &addr); } diff --git a/lightningd/options.c b/lightningd/options.c index 4e79efeb32f2..9fb1eac0ffab 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -198,7 +198,10 @@ static char *opt_add_addr_withtype(const char *arg, if (!separate_address_and_port(tmpctx, arg, &address, &port)) return tal_fmt(NULL, "Unable to parse address:port '%s'", arg); - if (is_ipaddr(address) || is_toraddr(address) || ala != ADDR_ANNOUNCE) { + if (is_ipaddr(address) + || is_toraddr(address) + || is_wildcardaddr(address) + || ala != ADDR_ANNOUNCE) { if (!parse_wireaddr_internal(arg, &wi, ld->portnum, wildcard_ok, dns_ok, false, deprecated_apis, &err_msg)) { diff --git a/tests/test_connection.py b/tests/test_connection.py index 7740bf85b967..eb62b1b9322b 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -3749,8 +3749,13 @@ def test_old_feerate(node_factory): @pytest.mark.developer("needs --dev-allow-localhost") def test_websocket(node_factory): ws_port = reserve() + port1, port2 = reserve(), reserve() + # We need a wildcard to show the websocket bug, but we need a real + # address to give us something to announce. l1, l2 = node_factory.line_graph(2, opts=[{'experimental-websocket-port': ws_port, + 'addr': [':' + str(port1), + '127.0.0.1: ' + str(port2)], 'dev-allow-localhost': None}, {'dev-allow-localhost': None}], wait_for_announce=True) @@ -3804,7 +3809,7 @@ def recv(self, maxlen): # Check node_announcement has websocket assert (only_one(l2.rpc.listnodes(l1.info['id'])['nodes'])['addresses'] - == [{'type': 'ipv4', 'address': '127.0.0.1', 'port': l1.port}, {'type': 'websocket', 'port': ws_port}]) + == [{'type': 'ipv4', 'address': '127.0.0.1', 'port': port2}, {'type': 'websocket', 'port': ws_port}]) @pytest.mark.developer("dev-disconnect required")