common: add new internal type for websockets.

Now it's not a public type, we need a way to refer to it.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2023-05-30 13:58:18 +09:30
parent 7b843e8e58
commit a6772e9dec
21 changed files with 285 additions and 126 deletions

View file

@ -63,7 +63,8 @@
"ipv6": 2, "ipv6": 2,
"local socket": 0, "local socket": 0,
"torv2": 3, "torv2": 3,
"torv3": 4 "torv3": 4,
"websocket": 5
}, },
"GetrouteRouteStyle": { "GetrouteRouteStyle": {
"tlv": 0 "tlv": 0

View file

@ -113,6 +113,7 @@ message GetinfoBinding {
// Getinfo.binding[].type // Getinfo.binding[].type
enum GetinfoBindingType { enum GetinfoBindingType {
LOCAL_SOCKET = 0; LOCAL_SOCKET = 0;
WEBSOCKET = 5;
IPV4 = 1; IPV4 = 1;
IPV6 = 2; IPV6 = 2;
TORV2 = 3; TORV2 = 3;

11
cln-rpc/src/model.rs generated
View file

@ -1476,6 +1476,8 @@ pub mod responses {
pub enum GetinfoBindingType { pub enum GetinfoBindingType {
#[serde(rename = "local socket")] #[serde(rename = "local socket")]
LOCAL_SOCKET, LOCAL_SOCKET,
#[serde(rename = "websocket")]
WEBSOCKET,
#[serde(rename = "ipv4")] #[serde(rename = "ipv4")]
IPV4, IPV4,
#[serde(rename = "ipv6")] #[serde(rename = "ipv6")]
@ -1491,10 +1493,11 @@ pub mod responses {
fn try_from(c: i32) -> Result<GetinfoBindingType, anyhow::Error> { fn try_from(c: i32) -> Result<GetinfoBindingType, anyhow::Error> {
match c { match c {
0 => Ok(GetinfoBindingType::LOCAL_SOCKET), 0 => Ok(GetinfoBindingType::LOCAL_SOCKET),
1 => Ok(GetinfoBindingType::IPV4), 1 => Ok(GetinfoBindingType::WEBSOCKET),
2 => Ok(GetinfoBindingType::IPV6), 2 => Ok(GetinfoBindingType::IPV4),
3 => Ok(GetinfoBindingType::TORV2), 3 => Ok(GetinfoBindingType::IPV6),
4 => Ok(GetinfoBindingType::TORV3), 4 => Ok(GetinfoBindingType::TORV2),
5 => Ok(GetinfoBindingType::TORV3),
o => Err(anyhow::anyhow!("Unknown variant {} for enum GetinfoBindingType", o)), o => Err(anyhow::anyhow!("Unknown variant {} for enum GetinfoBindingType", o)),
} }
} }

View file

@ -493,35 +493,54 @@ void json_add_short_channel_id(struct json_stream *response,
short_channel_id_outnum(scid)); 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, void json_add_address(struct json_stream *response, const char *fieldname,
const struct wireaddr *addr) const struct wireaddr *addr)
{ {
json_object_start(response, fieldname); json_object_start(response, fieldname);
if (addr->type == ADDR_TYPE_IPV4) { json_add_address_fields(response, addr, "type");
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_object_end(response); json_object_end(response);
} }
@ -538,8 +557,13 @@ void json_add_address_internal(struct json_stream *response,
return; return;
case ADDR_INTERNAL_ALLPROTO: case ADDR_INTERNAL_ALLPROTO:
json_object_start(response, fieldname); json_object_start(response, fieldname);
json_add_string(response, "type", "any protocol"); if (addr->u.allproto.is_websocket) {
json_add_num(response, "port", addr->u.port); 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); json_object_end(response);
return; return;
case ADDR_INTERNAL_AUTOTOR: case ADDR_INTERNAL_AUTOTOR:
@ -562,7 +586,14 @@ void json_add_address_internal(struct json_stream *response,
json_object_end(response); json_object_end(response);
return; return;
case ADDR_INTERNAL_WIREADDR: 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; return;
} }
abort(); abort();

View file

@ -134,25 +134,29 @@ int main(int argc, char *argv[])
/* Simple IPv4 address. */ /* Simple IPv4 address. */
assert(parse_wireaddr_internal(tmpctx, "127.0.0.1", DEFAULT_PORT, false, &addr) == NULL); assert(parse_wireaddr_internal(tmpctx, "127.0.0.1", DEFAULT_PORT, false, &addr) == NULL);
expect->itype = ADDR_INTERNAL_WIREADDR; 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)); assert(wireaddr_internal_eq(&addr, expect));
/* IPv4 address with port. */ /* IPv4 address with port. */
assert(parse_wireaddr_internal(tmpctx, "127.0.0.1:1", DEFAULT_PORT, false, &addr) == NULL); assert(parse_wireaddr_internal(tmpctx, "127.0.0.1:1", DEFAULT_PORT, false, &addr) == NULL);
expect->itype = ADDR_INTERNAL_WIREADDR; 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)); assert(wireaddr_internal_eq(&addr, expect));
/* Simple IPv6 address. */ /* Simple IPv6 address. */
assert(parse_wireaddr_internal(tmpctx, "::1", DEFAULT_PORT, false, &addr) == NULL); assert(parse_wireaddr_internal(tmpctx, "::1", DEFAULT_PORT, false, &addr) == NULL);
expect->itype = ADDR_INTERNAL_WIREADDR; 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)); assert(wireaddr_internal_eq(&addr, expect));
/* IPv6 address with port. */ /* IPv6 address with port. */
assert(parse_wireaddr_internal(tmpctx, "[::1]:1", DEFAULT_PORT, false, &addr) == NULL); assert(parse_wireaddr_internal(tmpctx, "[::1]:1", DEFAULT_PORT, false, &addr) == NULL);
expect->itype = ADDR_INTERNAL_WIREADDR; 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)); assert(wireaddr_internal_eq(&addr, expect));
/* autotor address */ /* autotor address */

View file

@ -98,10 +98,12 @@ void towire_wireaddr_internal(u8 **pptr, const struct wireaddr_internal *addr)
towire_u16(pptr, addr->u.torservice.port); towire_u16(pptr, addr->u.torservice.port);
return; return;
case ADDR_INTERNAL_ALLPROTO: 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; return;
case ADDR_INTERNAL_WIREADDR: 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; return;
case ADDR_INTERNAL_FORPROXY: case ADDR_INTERNAL_FORPROXY:
towire_u8_array(pptr, (const u8 *)addr->u.unresolved.name, 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); fromwire_fail(cursor, max);
return *cursor != NULL; return *cursor != NULL;
case ADDR_INTERNAL_ALLPROTO: 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; return *cursor != NULL;
case ADDR_INTERNAL_AUTOTOR: case ADDR_INTERNAL_AUTOTOR:
fromwire_wireaddr(cursor, max, &addr->u.torservice.address); 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); addr->u.torservice.port = fromwire_u16(cursor, max);
return *cursor != NULL; return *cursor != NULL;
case ADDR_INTERNAL_WIREADDR: 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: case ADDR_INTERNAL_FORPROXY:
fromwire_u8_array(cursor, max, (u8 *)addr->u.unresolved.name, fromwire_u8_array(cursor, max, (u8 *)addr->u.unresolved.name,
sizeof(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: case ADDR_INTERNAL_SOCKNAME:
return tal_fmt(ctx, "%s", a->u.sockname); return tal_fmt(ctx, "%s", a->u.sockname);
case ADDR_INTERNAL_ALLPROTO: 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: 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: case ADDR_INTERNAL_FORPROXY:
return tal_fmt(ctx, "%s:%u", return tal_fmt(ctx, "%s:%u",
a->u.unresolved.name, a->u.unresolved.port); 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: case ADDR_INTERNAL_SOCKNAME:
return streq(a->u.sockname, b->u.sockname); return streq(a->u.sockname, b->u.sockname);
case ADDR_INTERNAL_ALLPROTO: 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: case ADDR_INTERNAL_STATICTOR:
if (!memeq(a->u.torservice.blob, sizeof(a->u.torservice.blob), if (!memeq(a->u.torservice.blob, sizeof(a->u.torservice.blob),
b->u.torservice.blob, sizeof(b->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 false;
return a->u.unresolved.port == b->u.unresolved.port; return a->u.unresolved.port == b->u.unresolved.port;
case ADDR_INTERNAL_WIREADDR: 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(); abort();
} }
@ -696,16 +706,18 @@ const char *parse_wireaddr_internal(const tal_t *ctx,
* means just IPv6, and IPv4 gets autobound). */ * means just IPv6, and IPv4 gets autobound). */
if (ip && streq(ip, "")) { if (ip && streq(ip, "")) {
addr->itype = ADDR_INTERNAL_ALLPROTO; addr->itype = ADDR_INTERNAL_ALLPROTO;
addr->u.port = splitport; addr->u.allproto.is_websocket = false;
addr->u.allproto.port = splitport;
return NULL; return NULL;
} }
needed_dns = false; needed_dns = false;
err = parse_wireaddr(ctx, arg, default_port, err = parse_wireaddr(ctx, arg, default_port,
dns_lookup_ok ? NULL : &needed_dns, dns_lookup_ok ? NULL : &needed_dns,
&addr->u.wireaddr); &addr->u.wireaddr.wireaddr);
if (!err) { if (!err) {
addr->itype = ADDR_INTERNAL_WIREADDR; addr->itype = ADDR_INTERNAL_WIREADDR;
addr->u.wireaddr.is_websocket = false;
return NULL; return NULL;
} }
@ -779,7 +791,7 @@ struct addrinfo *wireaddr_internal_to_addrinfo(const tal_t *ctx,
case ADDR_INTERNAL_FORPROXY: case ADDR_INTERNAL_FORPROXY:
break; break;
case ADDR_INTERNAL_WIREADDR: case ADDR_INTERNAL_WIREADDR:
return wireaddr_to_addrinfo(ctx, &wireaddr->u.wireaddr); return wireaddr_to_addrinfo(ctx, &wireaddr->u.wireaddr.wireaddr);
} }
abort(); abort();
} }
@ -859,7 +871,7 @@ bool all_tor_addresses(const struct wireaddr_internal *wireaddr)
case ADDR_INTERNAL_STATICTOR: case ADDR_INTERNAL_STATICTOR:
continue; continue;
case ADDR_INTERNAL_WIREADDR: case ADDR_INTERNAL_WIREADDR:
switch (wireaddr[i].u.wireaddr.type) { switch (wireaddr[i].u.wireaddr.wireaddr.type) {
case ADDR_TYPE_IPV4: case ADDR_TYPE_IPV4:
case ADDR_TYPE_IPV6: case ADDR_TYPE_IPV6:
case ADDR_TYPE_DNS: case ADDR_TYPE_DNS:

View file

@ -127,9 +127,15 @@ struct wireaddr_internal {
enum wireaddr_internal_type itype; enum wireaddr_internal_type itype;
union { union {
/* ADDR_INTERNAL_WIREADDR */ /* ADDR_INTERNAL_WIREADDR */
struct wireaddr wireaddr; struct waddr {
struct wireaddr wireaddr;
bool is_websocket;
} wireaddr;
/* ADDR_INTERNAL_ALLPROTO */ /* ADDR_INTERNAL_ALLPROTO */
u16 port; struct allproto {
u16 port;
bool is_websocket;
} allproto;
/* ADDR_INTERNAL_AUTOTOR /* ADDR_INTERNAL_AUTOTOR
* ADDR_INTERNAL_STATICTOR */ * ADDR_INTERNAL_STATICTOR */
struct torservice { struct torservice {

View file

@ -410,12 +410,12 @@ static bool get_remote_address(struct io_conn *conn,
if (s.ss_family == AF_INET6) { if (s.ss_family == AF_INET6) {
struct sockaddr_in6 *s6 = (void *)&s; struct sockaddr_in6 *s6 = (void *)&s;
addr->itype = ADDR_INTERNAL_WIREADDR; 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)); &s6->sin6_addr, ntohs(s6->sin6_port));
} else if (s.ss_family == AF_INET) { } else if (s.ss_family == AF_INET) {
struct sockaddr_in *s4 = (void *)&s; struct sockaddr_in *s4 = (void *)&s;
addr->itype = ADDR_INTERNAL_WIREADDR; 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)); &s4->sin_addr, ntohs(s4->sin_port));
} else if (s.ss_family == AF_UNIX) { } else if (s.ss_family == AF_UNIX) {
struct sockaddr_un *sun = (void *)&s; 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; struct conn_in conn_in_arg;
conn_in_arg.addr.u.wireaddr.is_websocket = false;
if (!get_remote_address(conn, &conn_in_arg.addr)) if (!get_remote_address(conn, &conn_in_arg.addr))
return io_close(conn); return io_close(conn);
@ -487,6 +488,7 @@ static struct io_plan *websocket_connection_in(struct io_conn *conn,
int err; int err;
struct conn_in conn_in_arg; struct conn_in conn_in_arg;
conn_in_arg.addr.u.wireaddr.is_websocket = true;
if (!get_remote_address(conn, &conn_in_arg.addr)) if (!get_remote_address(conn, &conn_in_arg.addr))
return io_close(conn); return io_close(conn);
@ -724,10 +726,10 @@ static struct io_plan *conn_init(struct io_conn *conn,
break; break;
case ADDR_INTERNAL_WIREADDR: case ADDR_INTERNAL_WIREADDR:
/* DNS should have been resolved before */ /* 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. */ /* If it was a Tor address, we wouldn't be here. */
assert(!is_toraddr((char*)addr->u.wireaddr.addr)); assert(!is_toraddr((char*)addr->u.wireaddr.wireaddr.addr));
ai = wireaddr_to_addrinfo(tmpctx, &addr->u.wireaddr); ai = wireaddr_to_addrinfo(tmpctx, &addr->u.wireaddr.wireaddr);
break; break;
} }
assert(ai); assert(ai);
@ -751,8 +753,8 @@ static struct io_plan *conn_proxy_init(struct io_conn *conn,
port = addr->u.unresolved.port; port = addr->u.unresolved.port;
break; break;
case ADDR_INTERNAL_WIREADDR: case ADDR_INTERNAL_WIREADDR:
host = fmt_wireaddr_without_port(tmpctx, &addr->u.wireaddr); host = fmt_wireaddr_without_port(tmpctx, &addr->u.wireaddr.wireaddr);
port = addr->u.wireaddr.port; port = addr->u.wireaddr.wireaddr.port;
break; break;
case ADDR_INTERNAL_SOCKNAME: case ADDR_INTERNAL_SOCKNAME:
case ADDR_INTERNAL_ALLPROTO: case ADDR_INTERNAL_ALLPROTO:
@ -818,7 +820,7 @@ static void try_connect_one_addr(struct connecting *connect)
use_proxy = true; use_proxy = true;
break; break;
case ADDR_INTERNAL_WIREADDR: case ADDR_INTERNAL_WIREADDR:
switch (addr->u.wireaddr.type) { switch (addr->u.wireaddr.wireaddr.type) {
case ADDR_TYPE_TOR_V2_REMOVED: case ADDR_TYPE_TOR_V2_REMOVED:
af = -1; af = -1;
break; break;
@ -848,9 +850,9 @@ static void try_connect_one_addr(struct connecting *connect)
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
hints.ai_protocol = 0; hints.ai_protocol = 0;
hints.ai_flags = AI_ADDRCONFIG; 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", tal_fmt(tmpctx, "%d",
addr->u.wireaddr.port), addr->u.wireaddr.wireaddr.port),
&hints, &ais); &hints, &ais);
if (gai_err != 0) { if (gai_err != 0) {
tal_append_fmt(&connect->errors, 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 ... */ /* create new addrhints on-the-fly per result ... */
for (aii = ais; aii; aii = aii->ai_next) { for (aii = ais; aii; aii = aii->ai_next) {
addrhint.itype = ADDR_INTERNAL_WIREADDR; addrhint.itype = ADDR_INTERNAL_WIREADDR;
addrhint.u.wireaddr.is_websocket = false;
if (aii->ai_family == AF_INET) { if (aii->ai_family == AF_INET) {
sa4 = (struct sockaddr_in *) aii->ai_addr; sa4 = (struct sockaddr_in *) aii->ai_addr;
wireaddr_from_ipv4(&addrhint.u.wireaddr, wireaddr_from_ipv4(&addrhint.u.wireaddr.wireaddr,
&sa4->sin_addr, &sa4->sin_addr,
addr->u.wireaddr.port); addr->u.wireaddr.wireaddr.port);
} else if (aii->ai_family == AF_INET6) { } else if (aii->ai_family == AF_INET6) {
sa6 = (struct sockaddr_in6 *) aii->ai_addr; sa6 = (struct sockaddr_in6 *) aii->ai_addr;
wireaddr_from_ipv6(&addrhint.u.wireaddr, wireaddr_from_ipv6(&addrhint.u.wireaddr.wireaddr,
&sa6->sin6_addr, &sa6->sin6_addr,
addr->u.wireaddr.port); addr->u.wireaddr.wireaddr.port);
} else { } else {
/* skip unsupported ai_family */ /* skip unsupported ai_family */
continue; continue;
@ -1038,15 +1041,15 @@ fail:
static struct listen_fd *handle_wireaddr_listen(const tal_t *ctx, static struct listen_fd *handle_wireaddr_listen(const tal_t *ctx,
const struct wireaddr_internal *wi, const struct wireaddr_internal *wi,
bool listen_mayfail, bool listen_mayfail,
enum is_websocket is_websocket,
char **errstr) char **errstr)
{ {
struct sockaddr_in addr; struct sockaddr_in addr;
struct sockaddr_in6 addr6; struct sockaddr_in6 addr6;
const struct wireaddr *wireaddr; const struct wireaddr *wireaddr;
bool is_websocket = wi->u.wireaddr.is_websocket;
assert(wi->itype == ADDR_INTERNAL_WIREADDR); 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 /* Note the use of a switch() over enum here, even though it must be
* IPv4 or IPv6 here; that will catch future changes. */ * 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++) { for (size_t i = 0; i < tal_count(listen_fds); i++) {
if (listen_fds[i]->wi.itype != ADDR_INTERNAL_WIREADDR) if (listen_fds[i]->wi.itype != ADDR_INTERNAL_WIREADDR)
continue; continue;
if (listen_fds[i]->wi.u.wireaddr.type != ADDR_TYPE_IPV4 if (listen_fds[i]->wi.u.wireaddr.is_websocket)
&& listen_fds[i]->wi.u.wireaddr.type != ADDR_TYPE_IPV6)
continue; 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; return NULL;
} }
@ -1164,7 +1169,7 @@ setup_listeners(const tal_t *ctx,
/* You can only announce wiretypes, not internal formats! */ /* You can only announce wiretypes, not internal formats! */
assert(proposed_wireaddr[i].itype assert(proposed_wireaddr[i].itype
== ADDR_INTERNAL_WIREADDR); == ADDR_INTERNAL_WIREADDR);
add_announceable(announceable, &wa.u.wireaddr); add_announceable(announceable, &wa.u.wireaddr.wireaddr);
} }
/* Now look for listening addresses. */ /* Now look for listening addresses. */
@ -1204,42 +1209,41 @@ setup_listeners(const tal_t *ctx,
bool ipv6_ok; bool ipv6_ok;
wa.itype = ADDR_INTERNAL_WIREADDR; 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. */ /* First, create wildcard IPv6 address. */
wa.u.wireaddr.type = ADDR_TYPE_IPV6; wa.u.wireaddr.wireaddr.type = ADDR_TYPE_IPV6;
wa.u.wireaddr.addrlen = 16; wa.u.wireaddr.wireaddr.addrlen = 16;
memset(wa.u.wireaddr.addr, 0, memset(wa.u.wireaddr.wireaddr.addr, 0,
sizeof(wa.u.wireaddr.addr)); sizeof(wa.u.wireaddr.wireaddr.addr));
/* This may fail due to no IPv6 support. */ /* This may fail due to no IPv6 support. */
lfd = handle_wireaddr_listen(ctx, &wa, false, lfd = handle_wireaddr_listen(ctx, &wa, false, errstr);
NORMAL_SOCKET, errstr);
if (lfd) { if (lfd) {
tal_arr_expand(&listen_fds, tal_arr_expand(&listen_fds,
tal_steal(listen_fds, lfd)); tal_steal(listen_fds, lfd));
if (announce if (announce
&& public_address(daemon, &wa.u.wireaddr)) && public_address(daemon, &wa.u.wireaddr.wireaddr))
add_announceable(announceable, add_announceable(announceable,
&wa.u.wireaddr); &wa.u.wireaddr.wireaddr);
} }
ipv6_ok = (lfd != NULL); ipv6_ok = (lfd != NULL);
/* Now, create wildcard IPv4 address. */ /* Now, create wildcard IPv4 address. */
wa.u.wireaddr.type = ADDR_TYPE_IPV4; wa.u.wireaddr.wireaddr.type = ADDR_TYPE_IPV4;
wa.u.wireaddr.addrlen = 4; wa.u.wireaddr.wireaddr.addrlen = 4;
memset(wa.u.wireaddr.addr, 0, memset(wa.u.wireaddr.wireaddr.addr, 0,
sizeof(wa.u.wireaddr.addr)); sizeof(wa.u.wireaddr.wireaddr.addr));
/* This listen *may* fail, as long as IPv6 succeeds! */ /* This listen *may* fail, as long as IPv6 succeeds! */
lfd = handle_wireaddr_listen(ctx, &wa, ipv6_ok, lfd = handle_wireaddr_listen(ctx, &wa, ipv6_ok, errstr);
NORMAL_SOCKET, errstr);
if (lfd) { if (lfd) {
tal_arr_expand(&listen_fds, tal_arr_expand(&listen_fds,
tal_steal(listen_fds, lfd)); tal_steal(listen_fds, lfd));
if (announce if (announce
&& public_address(daemon, &wa.u.wireaddr)) && public_address(daemon, &wa.u.wireaddr.wireaddr))
add_announceable(announceable, add_announceable(announceable,
&wa.u.wireaddr); &wa.u.wireaddr.wireaddr);
} else if (!ipv6_ok) { } else if (!ipv6_ok) {
/* Both failed, return now, errstr set. */ /* Both failed, return now, errstr set. */
return NULL; return NULL;
@ -1248,13 +1252,12 @@ setup_listeners(const tal_t *ctx,
} }
/* This is a vanilla wireaddr as per BOLT #7 */ /* This is a vanilla wireaddr as per BOLT #7 */
case ADDR_INTERNAL_WIREADDR: case ADDR_INTERNAL_WIREADDR:
lfd = handle_wireaddr_listen(ctx, &wa, false, lfd = handle_wireaddr_listen(ctx, &wa, false, errstr);
NORMAL_SOCKET, errstr);
if (!lfd) if (!lfd)
return NULL; return NULL;
tal_arr_expand(&listen_fds, tal_steal(listen_fds, lfd)); tal_arr_expand(&listen_fds, tal_steal(listen_fds, lfd));
if (announce && public_address(daemon, &wa.u.wireaddr)) if (announce && public_address(daemon, &wa.u.wireaddr.wireaddr))
add_announceable(announceable, &wa.u.wireaddr); add_announceable(announceable, &wa.u.wireaddr.wireaddr);
continue; continue;
case ADDR_INTERNAL_FORPROXY: case ADDR_INTERNAL_FORPROXY:
break; break;
@ -1288,14 +1291,14 @@ setup_listeners(const tal_t *ctx,
/* Override with websocket port */ /* Override with websocket port */
addr = listen_fds[i]->wi; 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; /* We set mayfail on all but the first websocket;
* it's quite common to have multple overlapping * it's quite common to have multple overlapping
* addresses. */ * addresses. */
lfd = handle_wireaddr_listen(ctx, &addr, lfd = handle_wireaddr_listen(ctx, &addr, announced_some,
announced_some, errstr);
WEBSOCKET, errstr);
if (!lfd) if (!lfd)
continue; continue;
@ -1610,10 +1613,11 @@ static void add_seed_addrs(struct wireaddr_internal **addrs,
continue; continue;
struct wireaddr_internal a; struct wireaddr_internal a;
a.itype = ADDR_INTERNAL_WIREADDR; 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], status_peer_debug(id, "Resolved %s to %s", hostnames[i],
type_to_string(tmpctx, struct wireaddr, type_to_string(tmpctx, struct wireaddr,
&a.u.wireaddr)); &a.u.wireaddr.wireaddr));
tal_arr_expand(addrs, a); tal_arr_expand(addrs, a);
} }
/* Other seeds will likely have the same information. */ /* 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) { if (((u64)1 << normal_addrs[i].type) & types) {
struct wireaddr_internal addr; struct wireaddr_internal addr;
addr.itype = ADDR_INTERNAL_WIREADDR; 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); 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) */ /* Tell it to omit the existing hint (if that's a wireaddr itself) */
add_gossip_addrs(&addrs, gossip_addrs, add_gossip_addrs(&addrs, gossip_addrs,
addrhint && addrhint->itype == ADDR_INTERNAL_WIREADDR addrhint
? &addrhint->u.wireaddr : NULL); && addrhint->itype == ADDR_INTERNAL_WIREADDR
&& !addrhint->u.wireaddr.is_websocket
? &addrhint->u.wireaddr.wireaddr : NULL);
if (tal_count(addrs) == 0) { if (tal_count(addrs) == 0) {
/* Don't resolve via DNS seed if we're supposed to use proxy. */ /* Don't resolve via DNS seed if we're supposed to use proxy. */

View file

@ -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 * incoming connection, if the node is the receiver and the connection was done
* via IP. * via IP.
*/ */
if (incoming && addr->itype == ADDR_INTERNAL_WIREADDR && if (incoming
address_routable(&addr->u.wireaddr, true)) { && addr->itype == ADDR_INTERNAL_WIREADDR
switch (addr->u.wireaddr.type) { && !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_IPV4:
case ADDR_TYPE_IPV6: case ADDR_TYPE_IPV6:
tlvs->remote_addr = tal_arr(tlvs, u8, 0); 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; break;
/* Only report IP addresses back for now */ /* Only report IP addresses back for now */
case ADDR_TYPE_TOR_V2_REMOVED: case ADDR_TYPE_TOR_V2_REMOVED:

View file

@ -327,7 +327,7 @@ int main(int argc, char *argv[])
e_pub = pubkey("036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f7"); e_pub = pubkey("036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f7");
dummy.itype = ADDR_INTERNAL_WIREADDR; 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); initiator_handshake((void *)tmpctx, &ls_pub, &rs_pub, &dummy, NULL, NORMAL_SOCKET, success, NULL);
/* Should not exit! */ /* Should not exit! */
abort(); abort();

View file

@ -321,7 +321,7 @@ int main(int argc, char *argv[])
e_pub = pubkey("02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27"); e_pub = pubkey("02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27");
dummy.itype = ADDR_INTERNAL_WIREADDR; 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); responder_handshake((void *)tmpctx, &ls_pub, &dummy, NULL, NORMAL_SOCKET, success, NULL);
/* Should not exit! */ /* Should not exit! */
abort(); abort();

View file

@ -342,7 +342,10 @@ int main(int argc, char *argv[])
opt_usage_exit_fail("Don't support proxy use"); opt_usage_exit_fail("Don't support proxy use");
case ADDR_INTERNAL_WIREADDR: 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_V2_REMOVED:
case ADDR_TYPE_TOR_V3: case ADDR_TYPE_TOR_V3:
opt_usage_exit_fail("Don't support proxy use"); opt_usage_exit_fail("Don't support proxy use");
@ -357,7 +360,7 @@ int main(int argc, char *argv[])
af = AF_INET6; af = AF_INET6;
break; break;
} }
ai = wireaddr_to_addrinfo(tmpctx, &addr.u.wireaddr); ai = wireaddr_to_addrinfo(tmpctx, &addr.u.wireaddr.wireaddr);
} }
if (af == -1 || ai == NULL) if (af == -1 || ai == NULL)

View file

@ -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 - **channel** (hex): negotiated channel features we (as channel initiator) publish in the channel\_announcement message
- **invoice** (hex): features in our BOLT11 invoices - **invoice** (hex): features in our BOLT11 invoices
- **binding** (array of objects, optional): The addresses we are listening on: - **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** - **address** (string, optional): address in expected format for **type**
- **port** (u16, optional): port number - **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: The following warnings may also be returned:
@ -132,4 +139,4 @@ RESOURCES
Main web site: <https://github.com/ElementsProject/lightning> Main web site: <https://github.com/ElementsProject/lightning>
[comment]: # ( SHA256STAMP:60310adb57a49cb425a4b0d424f176a0ffa4de312ed07855b5e5611a44a64fcf) [comment]: # ( SHA256STAMP:0e6f06ba4f0f0264614d93d4eb7abc38eeb13c9619f7bd4e21203cdaba363a02)

View file

@ -100,4 +100,4 @@ RESOURCES
Main web site: <https://github.com/ElementsProject/lightning> Main web site: <https://github.com/ElementsProject/lightning>
[comment]: # ( SHA256STAMP:f7177be7c118fecf2e701d45140ad2714a42b746871caa8cd89e42bdc466d21c) [comment]: # ( SHA256STAMP:d74d92ee8839258837055e65823f74cae9775cf1c111565366c034c62e1c3021)

View file

@ -176,13 +176,13 @@
"required": [ "required": [
"type" "type"
], ],
"additionalProperties": false,
"properties": { "properties": {
"type": { "type": {
"type": "string", "type": "string",
"*FIXME*": "The variant in connect.schema.json is more complete", "*FIXME*": "The variant in connect.schema.json is more complete",
"enum": [ "enum": [
"local socket", "local socket",
"websocket",
"ipv4", "ipv4",
"ipv6", "ipv6",
"torv2", "torv2",
@ -197,12 +197,92 @@
"port": { "port": {
"type": "u16", "type": "u16",
"description": "port number" "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": { "warning_bitcoind_sync": {

View file

@ -80,7 +80,7 @@
"torv2", "torv2",
"torv3" "torv3"
], ],
"description": "Type of connection (until 23.08, `websocket` was also allowed)" "description": "Type of connection (until 23.08, `websocket` was also allowed)"
}, },
"port": { "port": {
"type": "u16", "type": "u16",

View file

@ -417,7 +417,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid,
channel->scb = tal(channel, struct scb_chan); channel->scb = tal(channel, struct scb_chan);
channel->scb->id = dbid; channel->scb->id = dbid;
channel->scb->unused = 0; 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->node_id = peer->id;
channel->scb->funding = *funding; channel->scb->funding = *funding;
channel->scb->cid = *cid; channel->scb->cid = *cid;

View file

@ -680,7 +680,8 @@ int connectd_init(struct lightningd *ld)
wireaddrs = tal_arrz(tmpctx, struct wireaddr_internal, 1); wireaddrs = tal_arrz(tmpctx, struct wireaddr_internal, 1);
listen_announce = tal_arr(tmpctx, enum addr_listen_announce, 1); listen_announce = tal_arr(tmpctx, enum addr_listen_announce, 1);
wireaddrs->itype = ADDR_INTERNAL_ALLPROTO; 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; *listen_announce = ADDR_LISTEN_AND_ANNOUNCE;
} }

View file

@ -1265,7 +1265,7 @@ wallet_commit_channel(struct lightningd *ld,
channel->scb = tal(channel, struct scb_chan); channel->scb = tal(channel, struct scb_chan);
channel->scb->id = channel->dbid; channel->scb->id = channel->dbid;
channel->scb->unused = 0; 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->node_id = channel->peer->id;
channel->scb->funding = *funding; channel->scb->funding = *funding;
channel->scb->cid = channel->cid; channel->scb->cid = channel->cid;

View file

@ -1345,7 +1345,8 @@ static struct channel *stub_chan(struct command *cmd,
struct wireaddr_internal wint; struct wireaddr_internal wint;
wint.itype = ADDR_INTERNAL_WIREADDR; 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, peer = new_peer(cmd->ld,
0, 0,
&nodeid, &nodeid,

View file

@ -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++) { for (size_t i = 0; i < tal_count(ld->proposed_wireaddr); i++) {
if (ld->proposed_wireaddr[i].itype != ADDR_INTERNAL_WIREADDR) if (ld->proposed_wireaddr[i].itype != ADDR_INTERNAL_WIREADDR)
continue; continue;
if (ld->proposed_wireaddr[i].u.wireaddr.type != type) if (ld->proposed_wireaddr[i].u.wireaddr.wireaddr.type != type)
continue; continue;
if (ld->proposed_listen_announce[i] & ADDR_ANNOUNCE) if (ld->proposed_listen_announce[i] & ADDR_ANNOUNCE)
num++; num++;
@ -268,7 +268,7 @@ static char *opt_add_addr_withtype(const char *arg,
/* Check they didn't specify some weird type! */ /* Check they didn't specify some weird type! */
switch (wi.itype) { switch (wi.itype) {
case ADDR_INTERNAL_WIREADDR: case ADDR_INTERNAL_WIREADDR:
switch (wi.u.wireaddr.type) { switch (wi.u.wireaddr.wireaddr.type) {
case ADDR_TYPE_IPV4: case ADDR_TYPE_IPV4:
case ADDR_TYPE_IPV6: case ADDR_TYPE_IPV6:
/* These can be either bind or announce */ /* These can be either bind or announce */