diff --git a/.msggen.json b/.msggen.json index 92961336c..7146f66f3 100644 --- a/.msggen.json +++ b/.msggen.json @@ -63,7 +63,8 @@ "ipv6": 2, "local socket": 0, "torv2": 3, - "torv3": 4 + "torv3": 4, + "websocket": 5 }, "GetrouteRouteStyle": { "tlv": 0 diff --git a/cln-grpc/proto/node.proto b/cln-grpc/proto/node.proto index 5c0bc1b77..3dbd9ae7a 100644 --- a/cln-grpc/proto/node.proto +++ b/cln-grpc/proto/node.proto @@ -113,6 +113,7 @@ message GetinfoBinding { // Getinfo.binding[].type enum GetinfoBindingType { LOCAL_SOCKET = 0; + WEBSOCKET = 5; IPV4 = 1; IPV6 = 2; TORV2 = 3; diff --git a/cln-rpc/src/model.rs b/cln-rpc/src/model.rs index f83b34221..220a5d81b 100644 --- a/cln-rpc/src/model.rs +++ b/cln-rpc/src/model.rs @@ -1476,6 +1476,8 @@ pub mod responses { pub enum GetinfoBindingType { #[serde(rename = "local socket")] LOCAL_SOCKET, + #[serde(rename = "websocket")] + WEBSOCKET, #[serde(rename = "ipv4")] IPV4, #[serde(rename = "ipv6")] @@ -1491,10 +1493,11 @@ pub mod responses { fn try_from(c: i32) -> Result { match c { 0 => Ok(GetinfoBindingType::LOCAL_SOCKET), - 1 => Ok(GetinfoBindingType::IPV4), - 2 => Ok(GetinfoBindingType::IPV6), - 3 => Ok(GetinfoBindingType::TORV2), - 4 => Ok(GetinfoBindingType::TORV3), + 1 => Ok(GetinfoBindingType::WEBSOCKET), + 2 => Ok(GetinfoBindingType::IPV4), + 3 => Ok(GetinfoBindingType::IPV6), + 4 => Ok(GetinfoBindingType::TORV2), + 5 => Ok(GetinfoBindingType::TORV3), o => Err(anyhow::anyhow!("Unknown variant {} for enum GetinfoBindingType", o)), } } diff --git a/common/json_stream.c b/common/json_stream.c index 144ee4950..2a6c568a8 100644 --- a/common/json_stream.c +++ b/common/json_stream.c @@ -493,35 +493,54 @@ void json_add_short_channel_id(struct json_stream *response, short_channel_id_outnum(scid)); } +static void json_add_address_fields(struct json_stream *response, + const struct wireaddr *addr, + const char *typefield) +{ + switch (addr->type) { + case ADDR_TYPE_IPV4: { + char addrstr[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, addr->addr, addrstr, INET_ADDRSTRLEN); + json_add_string(response, typefield, "ipv4"); + json_add_string(response, "address", addrstr); + json_add_num(response, "port", addr->port); + return; + } + case ADDR_TYPE_IPV6: { + char addrstr[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, addr->addr, addrstr, INET6_ADDRSTRLEN); + json_add_string(response, typefield, "ipv6"); + json_add_string(response, "address", addrstr); + json_add_num(response, "port", addr->port); + return; + } + case ADDR_TYPE_TOR_V2_REMOVED: { + json_add_string(response, typefield, "torv2"); + json_add_string(response, "address", fmt_wireaddr_without_port(tmpctx, addr)); + json_add_num(response, "port", addr->port); + return; + } + case ADDR_TYPE_TOR_V3: { + json_add_string(response, typefield, "torv3"); + json_add_string(response, "address", fmt_wireaddr_without_port(tmpctx, addr)); + json_add_num(response, "port", addr->port); + return; + } + case ADDR_TYPE_DNS: { + json_add_string(response, typefield, "dns"); + json_add_string(response, "address", fmt_wireaddr_without_port(tmpctx, addr)); + json_add_num(response, "port", addr->port); + return; + } + } + abort(); +} + void json_add_address(struct json_stream *response, const char *fieldname, const struct wireaddr *addr) { json_object_start(response, fieldname); - if (addr->type == ADDR_TYPE_IPV4) { - char addrstr[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, addr->addr, addrstr, INET_ADDRSTRLEN); - json_add_string(response, "type", "ipv4"); - json_add_string(response, "address", addrstr); - json_add_num(response, "port", addr->port); - } else if (addr->type == ADDR_TYPE_IPV6) { - char addrstr[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, addr->addr, addrstr, INET6_ADDRSTRLEN); - json_add_string(response, "type", "ipv6"); - json_add_string(response, "address", addrstr); - json_add_num(response, "port", addr->port); - } else if (addr->type == ADDR_TYPE_TOR_V2_REMOVED) { - json_add_string(response, "type", "torv2"); - json_add_string(response, "address", fmt_wireaddr_without_port(tmpctx, addr)); - json_add_num(response, "port", addr->port); - } else if (addr->type == ADDR_TYPE_TOR_V3) { - json_add_string(response, "type", "torv3"); - json_add_string(response, "address", fmt_wireaddr_without_port(tmpctx, addr)); - json_add_num(response, "port", addr->port); - } else if (addr->type == ADDR_TYPE_DNS) { - json_add_string(response, "type", "dns"); - json_add_string(response, "address", fmt_wireaddr_without_port(tmpctx, addr)); - json_add_num(response, "port", addr->port); - } + json_add_address_fields(response, addr, "type"); json_object_end(response); } @@ -538,8 +557,13 @@ void json_add_address_internal(struct json_stream *response, return; case ADDR_INTERNAL_ALLPROTO: json_object_start(response, fieldname); - json_add_string(response, "type", "any protocol"); - json_add_num(response, "port", addr->u.port); + if (addr->u.allproto.is_websocket) { + json_add_string(response, "type", "websocket"); + json_add_string(response, "subtype", "any protocol"); + } else { + json_add_string(response, "type", "any protocol"); + } + json_add_num(response, "port", addr->u.allproto.port); json_object_end(response); return; case ADDR_INTERNAL_AUTOTOR: @@ -562,7 +586,14 @@ void json_add_address_internal(struct json_stream *response, json_object_end(response); return; case ADDR_INTERNAL_WIREADDR: - json_add_address(response, fieldname, &addr->u.wireaddr); + json_object_start(response, fieldname); + if (addr->u.wireaddr.is_websocket) { + json_add_string(response, "type", "websocket"); + json_add_address_fields(response, &addr->u.wireaddr.wireaddr, "subtype"); + } else { + json_add_address_fields(response, &addr->u.wireaddr.wireaddr, "type"); + } + json_object_end(response); return; } abort(); diff --git a/common/test/run-wireaddr.c b/common/test/run-wireaddr.c index 71160f001..cb26f3a9e 100644 --- a/common/test/run-wireaddr.c +++ b/common/test/run-wireaddr.c @@ -134,25 +134,29 @@ int main(int argc, char *argv[]) /* Simple IPv4 address. */ assert(parse_wireaddr_internal(tmpctx, "127.0.0.1", DEFAULT_PORT, false, &addr) == NULL); expect->itype = ADDR_INTERNAL_WIREADDR; - assert(parse_wireaddr(tmpctx, "127.0.0.1:9735", 0, NULL, &expect->u.wireaddr) == NULL); + expect->u.wireaddr.is_websocket = false; + assert(parse_wireaddr(tmpctx, "127.0.0.1:9735", 0, NULL, &expect->u.wireaddr.wireaddr) == NULL); assert(wireaddr_internal_eq(&addr, expect)); /* IPv4 address with port. */ assert(parse_wireaddr_internal(tmpctx, "127.0.0.1:1", DEFAULT_PORT, false, &addr) == NULL); expect->itype = ADDR_INTERNAL_WIREADDR; - assert(parse_wireaddr(tmpctx, "127.0.0.1:1", 0, NULL, &expect->u.wireaddr) == NULL); + expect->u.wireaddr.is_websocket = false; + assert(parse_wireaddr(tmpctx, "127.0.0.1:1", 0, NULL, &expect->u.wireaddr.wireaddr) == NULL); assert(wireaddr_internal_eq(&addr, expect)); /* Simple IPv6 address. */ assert(parse_wireaddr_internal(tmpctx, "::1", DEFAULT_PORT, false, &addr) == NULL); expect->itype = ADDR_INTERNAL_WIREADDR; - assert(parse_wireaddr(tmpctx, "::1", DEFAULT_PORT, NULL, &expect->u.wireaddr) == NULL); + expect->u.wireaddr.is_websocket = false; + assert(parse_wireaddr(tmpctx, "::1", DEFAULT_PORT, NULL, &expect->u.wireaddr.wireaddr) == NULL); assert(wireaddr_internal_eq(&addr, expect)); /* IPv6 address with port. */ assert(parse_wireaddr_internal(tmpctx, "[::1]:1", DEFAULT_PORT, false, &addr) == NULL); expect->itype = ADDR_INTERNAL_WIREADDR; - assert(parse_wireaddr(tmpctx, "::1", 1, NULL, &expect->u.wireaddr) == NULL); + expect->u.wireaddr.is_websocket = false; + assert(parse_wireaddr(tmpctx, "::1", 1, NULL, &expect->u.wireaddr.wireaddr) == NULL); assert(wireaddr_internal_eq(&addr, expect)); /* autotor address */ diff --git a/common/wireaddr.c b/common/wireaddr.c index b82eff5d2..c9fc18aff 100644 --- a/common/wireaddr.c +++ b/common/wireaddr.c @@ -98,10 +98,12 @@ void towire_wireaddr_internal(u8 **pptr, const struct wireaddr_internal *addr) towire_u16(pptr, addr->u.torservice.port); return; case ADDR_INTERNAL_ALLPROTO: - towire_u16(pptr, addr->u.port); + towire_bool(pptr, addr->u.allproto.is_websocket); + towire_u16(pptr, addr->u.allproto.port); return; case ADDR_INTERNAL_WIREADDR: - towire_wireaddr(pptr, &addr->u.wireaddr); + towire_bool(pptr, addr->u.wireaddr.is_websocket); + towire_wireaddr(pptr, &addr->u.wireaddr.wireaddr); return; case ADDR_INTERNAL_FORPROXY: towire_u8_array(pptr, (const u8 *)addr->u.unresolved.name, @@ -125,7 +127,8 @@ bool fromwire_wireaddr_internal(const u8 **cursor, size_t *max, fromwire_fail(cursor, max); return *cursor != NULL; case ADDR_INTERNAL_ALLPROTO: - addr->u.port = fromwire_u16(cursor, max); + addr->u.allproto.is_websocket = fromwire_bool(cursor, max); + addr->u.allproto.port = fromwire_u16(cursor, max); return *cursor != NULL; case ADDR_INTERNAL_AUTOTOR: fromwire_wireaddr(cursor, max, &addr->u.torservice.address); @@ -138,7 +141,8 @@ bool fromwire_wireaddr_internal(const u8 **cursor, size_t *max, addr->u.torservice.port = fromwire_u16(cursor, max); return *cursor != NULL; case ADDR_INTERNAL_WIREADDR: - return fromwire_wireaddr(cursor, max, &addr->u.wireaddr); + addr->u.wireaddr.is_websocket = fromwire_bool(cursor, max); + return fromwire_wireaddr(cursor, max, &addr->u.wireaddr.wireaddr); case ADDR_INTERNAL_FORPROXY: fromwire_u8_array(cursor, max, (u8 *)addr->u.unresolved.name, sizeof(addr->u.unresolved.name)); @@ -220,9 +224,13 @@ char *fmt_wireaddr_internal(const tal_t *ctx, case ADDR_INTERNAL_SOCKNAME: return tal_fmt(ctx, "%s", a->u.sockname); case ADDR_INTERNAL_ALLPROTO: - return tal_fmt(ctx, ":%u", a->u.port); + return tal_fmt(ctx, "%s:%u", a->u.allproto.is_websocket ? "(ws)": "", + a->u.allproto.port); case ADDR_INTERNAL_WIREADDR: - return fmt_wireaddr(ctx, &a->u.wireaddr); + if (a->u.wireaddr.is_websocket) + return tal_fmt(ctx, "(ws)%s", + fmt_wireaddr(tmpctx, &a->u.wireaddr.wireaddr)); + return fmt_wireaddr(ctx, &a->u.wireaddr.wireaddr); case ADDR_INTERNAL_FORPROXY: return tal_fmt(ctx, "%s:%u", a->u.unresolved.name, a->u.unresolved.port); @@ -573,7 +581,8 @@ bool wireaddr_internal_eq(const struct wireaddr_internal *a, case ADDR_INTERNAL_SOCKNAME: return streq(a->u.sockname, b->u.sockname); case ADDR_INTERNAL_ALLPROTO: - return a->u.port == b->u.port; + return a->u.allproto.is_websocket == b->u.allproto.is_websocket + && a->u.allproto.port == b->u.allproto.port; case ADDR_INTERNAL_STATICTOR: if (!memeq(a->u.torservice.blob, sizeof(a->u.torservice.blob), b->u.torservice.blob, sizeof(b->u.torservice.blob))) @@ -589,7 +598,8 @@ bool wireaddr_internal_eq(const struct wireaddr_internal *a, return false; return a->u.unresolved.port == b->u.unresolved.port; case ADDR_INTERNAL_WIREADDR: - return wireaddr_eq(&a->u.wireaddr, &b->u.wireaddr); + return a->u.wireaddr.is_websocket == b->u.wireaddr.is_websocket + && wireaddr_eq(&a->u.wireaddr.wireaddr, &b->u.wireaddr.wireaddr); } abort(); } @@ -696,16 +706,18 @@ const char *parse_wireaddr_internal(const tal_t *ctx, * means just IPv6, and IPv4 gets autobound). */ if (ip && streq(ip, "")) { addr->itype = ADDR_INTERNAL_ALLPROTO; - addr->u.port = splitport; + addr->u.allproto.is_websocket = false; + addr->u.allproto.port = splitport; return NULL; } needed_dns = false; err = parse_wireaddr(ctx, arg, default_port, dns_lookup_ok ? NULL : &needed_dns, - &addr->u.wireaddr); + &addr->u.wireaddr.wireaddr); if (!err) { addr->itype = ADDR_INTERNAL_WIREADDR; + addr->u.wireaddr.is_websocket = false; return NULL; } @@ -779,7 +791,7 @@ struct addrinfo *wireaddr_internal_to_addrinfo(const tal_t *ctx, case ADDR_INTERNAL_FORPROXY: break; case ADDR_INTERNAL_WIREADDR: - return wireaddr_to_addrinfo(ctx, &wireaddr->u.wireaddr); + return wireaddr_to_addrinfo(ctx, &wireaddr->u.wireaddr.wireaddr); } abort(); } @@ -859,7 +871,7 @@ bool all_tor_addresses(const struct wireaddr_internal *wireaddr) case ADDR_INTERNAL_STATICTOR: continue; case ADDR_INTERNAL_WIREADDR: - switch (wireaddr[i].u.wireaddr.type) { + switch (wireaddr[i].u.wireaddr.wireaddr.type) { case ADDR_TYPE_IPV4: case ADDR_TYPE_IPV6: case ADDR_TYPE_DNS: diff --git a/common/wireaddr.h b/common/wireaddr.h index 1cd22bc77..7a34f70c4 100644 --- a/common/wireaddr.h +++ b/common/wireaddr.h @@ -127,9 +127,15 @@ struct wireaddr_internal { enum wireaddr_internal_type itype; union { /* ADDR_INTERNAL_WIREADDR */ - struct wireaddr wireaddr; + struct waddr { + struct wireaddr wireaddr; + bool is_websocket; + } wireaddr; /* ADDR_INTERNAL_ALLPROTO */ - u16 port; + struct allproto { + u16 port; + bool is_websocket; + } allproto; /* ADDR_INTERNAL_AUTOTOR * ADDR_INTERNAL_STATICTOR */ struct torservice { diff --git a/connectd/connectd.c b/connectd/connectd.c index 4486db0f7..585d1cdeb 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -410,12 +410,12 @@ static bool get_remote_address(struct io_conn *conn, if (s.ss_family == AF_INET6) { struct sockaddr_in6 *s6 = (void *)&s; addr->itype = ADDR_INTERNAL_WIREADDR; - wireaddr_from_ipv6(&addr->u.wireaddr, + wireaddr_from_ipv6(&addr->u.wireaddr.wireaddr, &s6->sin6_addr, ntohs(s6->sin6_port)); } else if (s.ss_family == AF_INET) { struct sockaddr_in *s4 = (void *)&s; addr->itype = ADDR_INTERNAL_WIREADDR; - wireaddr_from_ipv4(&addr->u.wireaddr, + wireaddr_from_ipv4(&addr->u.wireaddr.wireaddr, &s4->sin_addr, ntohs(s4->sin_port)); } else if (s.ss_family == AF_UNIX) { struct sockaddr_un *sun = (void *)&s; @@ -468,6 +468,7 @@ static struct io_plan *connection_in(struct io_conn *conn, { struct conn_in conn_in_arg; + conn_in_arg.addr.u.wireaddr.is_websocket = false; if (!get_remote_address(conn, &conn_in_arg.addr)) return io_close(conn); @@ -487,6 +488,7 @@ static struct io_plan *websocket_connection_in(struct io_conn *conn, int err; struct conn_in conn_in_arg; + conn_in_arg.addr.u.wireaddr.is_websocket = true; if (!get_remote_address(conn, &conn_in_arg.addr)) return io_close(conn); @@ -724,10 +726,10 @@ static struct io_plan *conn_init(struct io_conn *conn, break; case ADDR_INTERNAL_WIREADDR: /* DNS should have been resolved before */ - assert(addr->u.wireaddr.type != ADDR_TYPE_DNS); + assert(addr->u.wireaddr.wireaddr.type != ADDR_TYPE_DNS); /* If it was a Tor address, we wouldn't be here. */ - assert(!is_toraddr((char*)addr->u.wireaddr.addr)); - ai = wireaddr_to_addrinfo(tmpctx, &addr->u.wireaddr); + assert(!is_toraddr((char*)addr->u.wireaddr.wireaddr.addr)); + ai = wireaddr_to_addrinfo(tmpctx, &addr->u.wireaddr.wireaddr); break; } assert(ai); @@ -751,8 +753,8 @@ static struct io_plan *conn_proxy_init(struct io_conn *conn, port = addr->u.unresolved.port; break; case ADDR_INTERNAL_WIREADDR: - host = fmt_wireaddr_without_port(tmpctx, &addr->u.wireaddr); - port = addr->u.wireaddr.port; + host = fmt_wireaddr_without_port(tmpctx, &addr->u.wireaddr.wireaddr); + port = addr->u.wireaddr.wireaddr.port; break; case ADDR_INTERNAL_SOCKNAME: case ADDR_INTERNAL_ALLPROTO: @@ -818,7 +820,7 @@ static void try_connect_one_addr(struct connecting *connect) use_proxy = true; break; case ADDR_INTERNAL_WIREADDR: - switch (addr->u.wireaddr.type) { + switch (addr->u.wireaddr.wireaddr.type) { case ADDR_TYPE_TOR_V2_REMOVED: af = -1; break; @@ -848,9 +850,9 @@ static void try_connect_one_addr(struct connecting *connect) hints.ai_family = AF_UNSPEC; hints.ai_protocol = 0; hints.ai_flags = AI_ADDRCONFIG; - gai_err = getaddrinfo((char *)addr->u.wireaddr.addr, + gai_err = getaddrinfo((char *)addr->u.wireaddr.wireaddr.addr, tal_fmt(tmpctx, "%d", - addr->u.wireaddr.port), + addr->u.wireaddr.wireaddr.port), &hints, &ais); if (gai_err != 0) { tal_append_fmt(&connect->errors, @@ -864,16 +866,17 @@ static void try_connect_one_addr(struct connecting *connect) /* create new addrhints on-the-fly per result ... */ for (aii = ais; aii; aii = aii->ai_next) { addrhint.itype = ADDR_INTERNAL_WIREADDR; + addrhint.u.wireaddr.is_websocket = false; if (aii->ai_family == AF_INET) { sa4 = (struct sockaddr_in *) aii->ai_addr; - wireaddr_from_ipv4(&addrhint.u.wireaddr, + wireaddr_from_ipv4(&addrhint.u.wireaddr.wireaddr, &sa4->sin_addr, - addr->u.wireaddr.port); + addr->u.wireaddr.wireaddr.port); } else if (aii->ai_family == AF_INET6) { sa6 = (struct sockaddr_in6 *) aii->ai_addr; - wireaddr_from_ipv6(&addrhint.u.wireaddr, + wireaddr_from_ipv6(&addrhint.u.wireaddr.wireaddr, &sa6->sin6_addr, - addr->u.wireaddr.port); + addr->u.wireaddr.wireaddr.port); } else { /* skip unsupported ai_family */ continue; @@ -1038,15 +1041,15 @@ fail: static struct listen_fd *handle_wireaddr_listen(const tal_t *ctx, const struct wireaddr_internal *wi, bool listen_mayfail, - enum is_websocket is_websocket, char **errstr) { struct sockaddr_in addr; struct sockaddr_in6 addr6; const struct wireaddr *wireaddr; + bool is_websocket = wi->u.wireaddr.is_websocket; assert(wi->itype == ADDR_INTERNAL_WIREADDR); - wireaddr = &wi->u.wireaddr; + wireaddr = &wi->u.wireaddr.wireaddr; /* Note the use of a switch() over enum here, even though it must be * IPv4 or IPv6 here; that will catch future changes. */ @@ -1098,10 +1101,12 @@ find_local_address(const struct listen_fd **listen_fds) for (size_t i = 0; i < tal_count(listen_fds); i++) { if (listen_fds[i]->wi.itype != ADDR_INTERNAL_WIREADDR) continue; - if (listen_fds[i]->wi.u.wireaddr.type != ADDR_TYPE_IPV4 - && listen_fds[i]->wi.u.wireaddr.type != ADDR_TYPE_IPV6) + if (listen_fds[i]->wi.u.wireaddr.is_websocket) continue; - return &listen_fds[i]->wi.u.wireaddr; + if (listen_fds[i]->wi.u.wireaddr.wireaddr.type != ADDR_TYPE_IPV4 + && listen_fds[i]->wi.u.wireaddr.wireaddr.type != ADDR_TYPE_IPV6) + continue; + return &listen_fds[i]->wi.u.wireaddr.wireaddr; } return NULL; } @@ -1164,7 +1169,7 @@ setup_listeners(const tal_t *ctx, /* You can only announce wiretypes, not internal formats! */ assert(proposed_wireaddr[i].itype == ADDR_INTERNAL_WIREADDR); - add_announceable(announceable, &wa.u.wireaddr); + add_announceable(announceable, &wa.u.wireaddr.wireaddr); } /* Now look for listening addresses. */ @@ -1204,42 +1209,41 @@ setup_listeners(const tal_t *ctx, bool ipv6_ok; wa.itype = ADDR_INTERNAL_WIREADDR; - wa.u.wireaddr.port = wa.u.port; + wa.u.wireaddr.wireaddr.port = wa.u.allproto.port; + wa.u.wireaddr.is_websocket = wa.u.allproto.is_websocket; /* First, create wildcard IPv6 address. */ - wa.u.wireaddr.type = ADDR_TYPE_IPV6; - wa.u.wireaddr.addrlen = 16; - memset(wa.u.wireaddr.addr, 0, - sizeof(wa.u.wireaddr.addr)); + wa.u.wireaddr.wireaddr.type = ADDR_TYPE_IPV6; + wa.u.wireaddr.wireaddr.addrlen = 16; + memset(wa.u.wireaddr.wireaddr.addr, 0, + sizeof(wa.u.wireaddr.wireaddr.addr)); /* This may fail due to no IPv6 support. */ - lfd = handle_wireaddr_listen(ctx, &wa, false, - NORMAL_SOCKET, errstr); + lfd = handle_wireaddr_listen(ctx, &wa, false, errstr); if (lfd) { tal_arr_expand(&listen_fds, tal_steal(listen_fds, lfd)); if (announce - && public_address(daemon, &wa.u.wireaddr)) + && public_address(daemon, &wa.u.wireaddr.wireaddr)) add_announceable(announceable, - &wa.u.wireaddr); + &wa.u.wireaddr.wireaddr); } ipv6_ok = (lfd != NULL); /* Now, create wildcard IPv4 address. */ - wa.u.wireaddr.type = ADDR_TYPE_IPV4; - wa.u.wireaddr.addrlen = 4; - memset(wa.u.wireaddr.addr, 0, - sizeof(wa.u.wireaddr.addr)); + wa.u.wireaddr.wireaddr.type = ADDR_TYPE_IPV4; + wa.u.wireaddr.wireaddr.addrlen = 4; + memset(wa.u.wireaddr.wireaddr.addr, 0, + sizeof(wa.u.wireaddr.wireaddr.addr)); /* This listen *may* fail, as long as IPv6 succeeds! */ - lfd = handle_wireaddr_listen(ctx, &wa, ipv6_ok, - NORMAL_SOCKET, errstr); + lfd = handle_wireaddr_listen(ctx, &wa, ipv6_ok, errstr); if (lfd) { tal_arr_expand(&listen_fds, tal_steal(listen_fds, lfd)); if (announce - && public_address(daemon, &wa.u.wireaddr)) + && public_address(daemon, &wa.u.wireaddr.wireaddr)) add_announceable(announceable, - &wa.u.wireaddr); + &wa.u.wireaddr.wireaddr); } else if (!ipv6_ok) { /* Both failed, return now, errstr set. */ return NULL; @@ -1248,13 +1252,12 @@ setup_listeners(const tal_t *ctx, } /* This is a vanilla wireaddr as per BOLT #7 */ case ADDR_INTERNAL_WIREADDR: - lfd = handle_wireaddr_listen(ctx, &wa, false, - NORMAL_SOCKET, errstr); + lfd = handle_wireaddr_listen(ctx, &wa, false, errstr); if (!lfd) return NULL; tal_arr_expand(&listen_fds, tal_steal(listen_fds, lfd)); - if (announce && public_address(daemon, &wa.u.wireaddr)) - add_announceable(announceable, &wa.u.wireaddr); + if (announce && public_address(daemon, &wa.u.wireaddr.wireaddr)) + add_announceable(announceable, &wa.u.wireaddr.wireaddr); continue; case ADDR_INTERNAL_FORPROXY: break; @@ -1288,14 +1291,14 @@ setup_listeners(const tal_t *ctx, /* Override with websocket port */ addr = listen_fds[i]->wi; - addr.u.wireaddr.port = daemon->websocket_port; + addr.u.wireaddr.is_websocket = true; + addr.u.wireaddr.wireaddr.port = daemon->websocket_port; /* We set mayfail on all but the first websocket; * it's quite common to have multple overlapping * addresses. */ - lfd = handle_wireaddr_listen(ctx, &addr, - announced_some, - WEBSOCKET, errstr); + lfd = handle_wireaddr_listen(ctx, &addr, announced_some, + errstr); if (!lfd) continue; @@ -1610,10 +1613,11 @@ static void add_seed_addrs(struct wireaddr_internal **addrs, continue; struct wireaddr_internal a; a.itype = ADDR_INTERNAL_WIREADDR; - a.u.wireaddr = new_addrs[j]; + a.u.wireaddr.is_websocket = false; + a.u.wireaddr.wireaddr = new_addrs[j]; status_peer_debug(id, "Resolved %s to %s", hostnames[i], type_to_string(tmpctx, struct wireaddr, - &a.u.wireaddr)); + &a.u.wireaddr.wireaddr)); tal_arr_expand(addrs, a); } /* Other seeds will likely have the same information. */ @@ -1640,7 +1644,8 @@ static void add_gossip_addrs_bytypes(struct wireaddr_internal **addrs, if (((u64)1 << normal_addrs[i].type) & types) { struct wireaddr_internal addr; addr.itype = ADDR_INTERNAL_WIREADDR; - addr.u.wireaddr = normal_addrs[i]; + addr.u.wireaddr.is_websocket = false; + addr.u.wireaddr.wireaddr = normal_addrs[i]; tal_arr_expand(addrs, addr); } } @@ -1731,8 +1736,10 @@ static void try_connect_peer(struct daemon *daemon, /* Tell it to omit the existing hint (if that's a wireaddr itself) */ add_gossip_addrs(&addrs, gossip_addrs, - addrhint && addrhint->itype == ADDR_INTERNAL_WIREADDR - ? &addrhint->u.wireaddr : NULL); + addrhint + && addrhint->itype == ADDR_INTERNAL_WIREADDR + && !addrhint->u.wireaddr.is_websocket + ? &addrhint->u.wireaddr.wireaddr : NULL); if (tal_count(addrs) == 0) { /* Don't resolve via DNS seed if we're supposed to use proxy. */ diff --git a/connectd/peer_exchange_initmsg.c b/connectd/peer_exchange_initmsg.c index c16b43791..55f73107b 100644 --- a/connectd/peer_exchange_initmsg.c +++ b/connectd/peer_exchange_initmsg.c @@ -236,13 +236,15 @@ struct io_plan *peer_exchange_initmsg(struct io_conn *conn, * incoming connection, if the node is the receiver and the connection was done * via IP. */ - if (incoming && addr->itype == ADDR_INTERNAL_WIREADDR && - address_routable(&addr->u.wireaddr, true)) { - switch (addr->u.wireaddr.type) { + if (incoming + && addr->itype == ADDR_INTERNAL_WIREADDR + && !addr->u.wireaddr.is_websocket + && address_routable(&addr->u.wireaddr.wireaddr, true)) { + switch (addr->u.wireaddr.wireaddr.type) { case ADDR_TYPE_IPV4: case ADDR_TYPE_IPV6: tlvs->remote_addr = tal_arr(tlvs, u8, 0); - towire_wireaddr(&tlvs->remote_addr, &addr->u.wireaddr); + towire_wireaddr(&tlvs->remote_addr, &addr->u.wireaddr.wireaddr); break; /* Only report IP addresses back for now */ case ADDR_TYPE_TOR_V2_REMOVED: diff --git a/connectd/test/run-initiator-success.c b/connectd/test/run-initiator-success.c index cb92f51c7..f6d46d063 100644 --- a/connectd/test/run-initiator-success.c +++ b/connectd/test/run-initiator-success.c @@ -327,7 +327,7 @@ int main(int argc, char *argv[]) e_pub = pubkey("036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f7"); dummy.itype = ADDR_INTERNAL_WIREADDR; - dummy.u.wireaddr.addrlen = 0; + dummy.u.wireaddr.wireaddr.addrlen = 0; initiator_handshake((void *)tmpctx, &ls_pub, &rs_pub, &dummy, NULL, NORMAL_SOCKET, success, NULL); /* Should not exit! */ abort(); diff --git a/connectd/test/run-responder-success.c b/connectd/test/run-responder-success.c index fe6cbf70f..0b0d8c002 100644 --- a/connectd/test/run-responder-success.c +++ b/connectd/test/run-responder-success.c @@ -321,7 +321,7 @@ int main(int argc, char *argv[]) e_pub = pubkey("02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27"); dummy.itype = ADDR_INTERNAL_WIREADDR; - dummy.u.wireaddr.addrlen = 0; + dummy.u.wireaddr.wireaddr.addrlen = 0; responder_handshake((void *)tmpctx, &ls_pub, &dummy, NULL, NORMAL_SOCKET, success, NULL); /* Should not exit! */ abort(); diff --git a/devtools/gossipwith.c b/devtools/gossipwith.c index fc78b1918..c525d2ead 100644 --- a/devtools/gossipwith.c +++ b/devtools/gossipwith.c @@ -342,7 +342,10 @@ int main(int argc, char *argv[]) opt_usage_exit_fail("Don't support proxy use"); case ADDR_INTERNAL_WIREADDR: - switch (addr.u.wireaddr.type) { + if (addr.u.wireaddr.is_websocket) + opt_usage_exit_fail("Don't support websocket use"); + + switch (addr.u.wireaddr.wireaddr.type) { case ADDR_TYPE_TOR_V2_REMOVED: case ADDR_TYPE_TOR_V3: opt_usage_exit_fail("Don't support proxy use"); @@ -357,7 +360,7 @@ int main(int argc, char *argv[]) af = AF_INET6; break; } - ai = wireaddr_to_addrinfo(tmpctx, &addr.u.wireaddr); + ai = wireaddr_to_addrinfo(tmpctx, &addr.u.wireaddr.wireaddr); } if (af == -1 || ai == NULL) diff --git a/doc/lightning-getinfo.7.md b/doc/lightning-getinfo.7.md index fa4089a84..45fd550af 100644 --- a/doc/lightning-getinfo.7.md +++ b/doc/lightning-getinfo.7.md @@ -53,10 +53,17 @@ On success, an object is returned, containing: - **channel** (hex): negotiated channel features we (as channel initiator) publish in the channel\_announcement message - **invoice** (hex): features in our BOLT11 invoices - **binding** (array of objects, optional): The addresses we are listening on: - - **type** (string): Type of connection (one of "local socket", "ipv4", "ipv6", "torv2", "torv3") + - **type** (string): Type of connection (one of "local socket", "websocket", "ipv4", "ipv6", "torv2", "torv3") - **address** (string, optional): address in expected format for **type** - **port** (u16, optional): port number - - **socket** (string, optional): socket filename (only if **type** is "local socket") + + If **type** is "local socket": + + - **socket** (string): socket filename + + If **type** is "websocket": + + - **subtype** (string): type of address The following warnings may also be returned: @@ -132,4 +139,4 @@ RESOURCES Main web site: -[comment]: # ( SHA256STAMP:60310adb57a49cb425a4b0d424f176a0ffa4de312ed07855b5e5611a44a64fcf) +[comment]: # ( SHA256STAMP:0e6f06ba4f0f0264614d93d4eb7abc38eeb13c9619f7bd4e21203cdaba363a02) diff --git a/doc/lightning-listnodes.7.md b/doc/lightning-listnodes.7.md index 3f5425df2..0753be240 100644 --- a/doc/lightning-listnodes.7.md +++ b/doc/lightning-listnodes.7.md @@ -100,4 +100,4 @@ RESOURCES Main web site: -[comment]: # ( SHA256STAMP:f7177be7c118fecf2e701d45140ad2714a42b746871caa8cd89e42bdc466d21c) +[comment]: # ( SHA256STAMP:d74d92ee8839258837055e65823f74cae9775cf1c111565366c034c62e1c3021) diff --git a/doc/schemas/getinfo.schema.json b/doc/schemas/getinfo.schema.json index b10f0db8d..ceba996f8 100644 --- a/doc/schemas/getinfo.schema.json +++ b/doc/schemas/getinfo.schema.json @@ -176,13 +176,13 @@ "required": [ "type" ], - "additionalProperties": false, "properties": { "type": { "type": "string", "*FIXME*": "The variant in connect.schema.json is more complete", "enum": [ "local socket", + "websocket", "ipv4", "ipv6", "torv2", @@ -197,12 +197,92 @@ "port": { "type": "u16", "description": "port number" - }, - "socket": { - "type": "string", - "description": "socket filename (only if **type** is \"local socket\")" } - } + }, + "allOf": [ + { + "if": { + "properties": { + "type": { + "type": "string", + "enum": [ + "local socket" + ] + } + } + }, + "then": { + "additionalProperties": false, + "required": [ + "type", + "socket" + ], + "properties": { + "type": {}, + "socket": { + "type": "string", + "description": "socket filename" + } + } + }, + "else": { + "additionalProperties": false, + "required": [ + "type", + "address", + "port" + ], + "properties": { + "type": {}, + "address": {}, + "port": {}, + "subtype": {} + } + } + }, + { + "if": { + "properties": { + "type": { + "type": "string", + "enum": [ + "websocket" + ] + } + } + }, + "then": { + "additionalProperties": false, + "required": [ + "type", + "address", + "port", + "subtype" + ], + "properties": { + "type": {}, + "address": {}, + "port": {}, + "subtype": { + "type": "string", + "description": "type of address" + } + } + }, + "else": { + "additionalProperties": false, + "required": [ + "type" + ], + "properties": { + "type": {}, + "address": {}, + "port": {}, + "socket": {} + } + } + } + ] } }, "warning_bitcoind_sync": { diff --git a/doc/schemas/listnodes.schema.json b/doc/schemas/listnodes.schema.json index c927ad12c..38f848fa9 100644 --- a/doc/schemas/listnodes.schema.json +++ b/doc/schemas/listnodes.schema.json @@ -80,7 +80,7 @@ "torv2", "torv3" ], - "description": "Type of connection (until 23.08, `websocket` was also allowed)" + "description": "Type of connection (until 23.08, `websocket` was also allowed)" }, "port": { "type": "u16", diff --git a/lightningd/channel.c b/lightningd/channel.c index 0c21fddcc..1dc53c578 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -417,7 +417,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid, channel->scb = tal(channel, struct scb_chan); channel->scb->id = dbid; channel->scb->unused = 0; - channel->scb->addr = peer->addr.u.wireaddr; + channel->scb->addr = peer->addr.u.wireaddr.wireaddr; channel->scb->node_id = peer->id; channel->scb->funding = *funding; channel->scb->cid = *cid; diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c index 3901826bb..4046ccdb2 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -680,7 +680,8 @@ int connectd_init(struct lightningd *ld) wireaddrs = tal_arrz(tmpctx, struct wireaddr_internal, 1); listen_announce = tal_arr(tmpctx, enum addr_listen_announce, 1); wireaddrs->itype = ADDR_INTERNAL_ALLPROTO; - wireaddrs->u.port = ld->portnum; + wireaddrs->u.allproto.is_websocket = false; + wireaddrs->u.allproto.port = ld->portnum; *listen_announce = ADDR_LISTEN_AND_ANNOUNCE; } diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index 260118ea6..9a81f19c5 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -1265,7 +1265,7 @@ wallet_commit_channel(struct lightningd *ld, channel->scb = tal(channel, struct scb_chan); channel->scb->id = channel->dbid; channel->scb->unused = 0; - channel->scb->addr = channel->peer->addr.u.wireaddr; + channel->scb->addr = channel->peer->addr.u.wireaddr.wireaddr; channel->scb->node_id = channel->peer->id; channel->scb->funding = *funding; channel->scb->cid = channel->cid; diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 602721191..9dddddf58 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -1345,7 +1345,8 @@ static struct channel *stub_chan(struct command *cmd, struct wireaddr_internal wint; wint.itype = ADDR_INTERNAL_WIREADDR; - wint.u.wireaddr = addr; + wint.u.wireaddr.is_websocket = false; + wint.u.wireaddr.wireaddr = addr; peer = new_peer(cmd->ld, 0, &nodeid, diff --git a/lightningd/options.c b/lightningd/options.c index e61f2928a..6a59c5ca9 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -231,7 +231,7 @@ static size_t num_announced_types(enum wire_addr_type type, struct lightningd *l for (size_t i = 0; i < tal_count(ld->proposed_wireaddr); i++) { if (ld->proposed_wireaddr[i].itype != ADDR_INTERNAL_WIREADDR) continue; - if (ld->proposed_wireaddr[i].u.wireaddr.type != type) + if (ld->proposed_wireaddr[i].u.wireaddr.wireaddr.type != type) continue; if (ld->proposed_listen_announce[i] & ADDR_ANNOUNCE) num++; @@ -268,7 +268,7 @@ static char *opt_add_addr_withtype(const char *arg, /* Check they didn't specify some weird type! */ switch (wi.itype) { case ADDR_INTERNAL_WIREADDR: - switch (wi.u.wireaddr.type) { + switch (wi.u.wireaddr.wireaddr.type) { case ADDR_TYPE_IPV4: case ADDR_TYPE_IPV6: /* These can be either bind or announce */