diff --git a/common/test/run-ip_port_parsing.c b/common/test/run-ip_port_parsing.c index fc8eae762270..0773e3a3cf3c 100644 --- a/common/test/run-ip_port_parsing.c +++ b/common/test/run-ip_port_parsing.c @@ -8,12 +8,18 @@ /* Generated stub for fromwire */ const u8 *fromwire(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *copy UNNEEDED, size_t n UNNEEDED) { fprintf(stderr, "fromwire called!\n"); abort(); } +/* Generated stub for fromwire_fail */ +const void *fromwire_fail(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_fail called!\n"); abort(); } /* Generated stub for fromwire_u16 */ u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_u16 called!\n"); abort(); } /* Generated stub for fromwire_u8 */ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_u8 called!\n"); abort(); } +/* Generated stub for fromwire_u8_array */ +void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) +{ fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } /* Generated stub for towire */ void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) { fprintf(stderr, "towire called!\n"); abort(); } @@ -23,6 +29,9 @@ void towire_u16(u8 **pptr UNNEEDED, u16 v UNNEEDED) /* Generated stub for towire_u8 */ void towire_u8(u8 **pptr UNNEEDED, u8 v UNNEEDED) { fprintf(stderr, "towire_u8 called!\n"); abort(); } +/* Generated stub for towire_u8_array */ +void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNEEDED) +{ fprintf(stderr, "towire_u8_array called!\n"); abort(); } /* AUTOGENERATED MOCKS END */ int main(void) diff --git a/common/type_to_string.h b/common/type_to_string.h index bee4cbd677f9..83c485ed9431 100644 --- a/common/type_to_string.h +++ b/common/type_to_string.h @@ -20,6 +20,7 @@ union printable_types { const struct preimage *preimage; const struct channel_oneside *channel_oneside; const struct wireaddr *wireaddr; + const struct wireaddr_internal *wireaddr_internal; const secp256k1_pubkey *secp256k1_pubkey; const struct channel_id *channel_id; const struct short_channel_id *short_channel_id; diff --git a/common/wireaddr.c b/common/wireaddr.c index 71062ab48475..a5044eba63c7 100644 --- a/common/wireaddr.c +++ b/common/wireaddr.c @@ -1,5 +1,7 @@ #include #include +#include +#include #include #include #include @@ -8,6 +10,7 @@ #include #include #include +#include #include /* Returns false if we didn't parse it, and *cursor == NULL if malformed. */ @@ -42,6 +45,57 @@ 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); +} + +void towire_wireaddr_internal(u8 **pptr, const struct wireaddr_internal *addr) +{ + towire_u8(pptr, addr->itype); + switch (addr->itype) { + case ADDR_INTERNAL_SOCKNAME: + towire_u8_array(pptr, (const u8 *)addr->u.sockname, + sizeof(addr->u.sockname)); + return; + case ADDR_INTERNAL_ALLPROTO: + towire_u16(pptr, addr->u.port); + return; + case ADDR_INTERNAL_WIREADDR: + towire_wireaddr(pptr, &addr->u.wireaddr); + return; + } + abort(); +} + +bool fromwire_wireaddr_internal(const u8 **cursor, size_t *max, + struct wireaddr_internal *addr) +{ + addr->itype = fromwire_u8(cursor, max); + switch (addr->itype) { + case ADDR_INTERNAL_SOCKNAME: + fromwire_u8_array(cursor, max, (u8 *)addr->u.sockname, + sizeof(addr->u.sockname)); + /* Must be NUL terminated */ + if (!memchr(addr->u.sockname, 0, sizeof(addr->u.sockname))) + fromwire_fail(cursor, max); + return *cursor != NULL; + case ADDR_INTERNAL_ALLPROTO: + addr->u.port = fromwire_u16(cursor, max); + return *cursor != NULL; + case ADDR_INTERNAL_WIREADDR: + return fromwire_wireaddr(cursor, max, &addr->u.wireaddr); + } + fromwire_fail(cursor, max); + return false; +} + char *fmt_wireaddr(const tal_t *ctx, const struct wireaddr *a) { char addrstr[INET6_ADDRSTRLEN]; @@ -67,6 +121,77 @@ char *fmt_wireaddr(const tal_t *ctx, const struct wireaddr *a) } REGISTER_TYPE_TO_STRING(wireaddr, fmt_wireaddr); +void wireaddr_from_ipv4(struct wireaddr *addr, + const struct in_addr *ip4, + const u16 port) +{ + addr->type = ADDR_TYPE_IPV4; + addr->addrlen = sizeof(*ip4); + addr->port = port; + memset(addr->addr, 0, sizeof(addr->addr)); + memcpy(addr->addr, ip4, addr->addrlen); +} + +void wireaddr_from_ipv6(struct wireaddr *addr, + const struct in6_addr *ip6, + const u16 port) +{ + addr->type = ADDR_TYPE_IPV6; + addr->addrlen = sizeof(*ip6); + addr->port = port; + memset(addr->addr, 0, sizeof(addr->addr)); + memcpy(&addr->addr, ip6, addr->addrlen); +} + +bool wireaddr_to_ipv4(const struct wireaddr *addr, struct sockaddr_in *s4) +{ + if (addr->type != ADDR_TYPE_IPV4) + return false; + s4->sin_family = AF_INET; + s4->sin_port = htons(addr->port); + assert(addr->addrlen == sizeof(s4->sin_addr)); + memcpy(&s4->sin_addr, addr->addr, sizeof(s4->sin_addr)); + return true; +} + +bool wireaddr_to_ipv6(const struct wireaddr *addr, struct sockaddr_in6 *s6) +{ + if (addr->type != ADDR_TYPE_IPV6) + return false; + s6->sin6_family = AF_INET6; + s6->sin6_port = htons(addr->port); + assert(addr->addrlen == sizeof(s6->sin6_addr)); + memcpy(&s6->sin6_addr, addr->addr, sizeof(s6->sin6_addr)); + return true; +} + +bool wireaddr_is_wildcard(const struct wireaddr *addr) +{ + switch (addr->type) { + case ADDR_TYPE_IPV6: + case ADDR_TYPE_IPV4: + return memeqzero(addr->addr, addr->addrlen); + case ADDR_TYPE_PADDING: + return false; + } + abort(); +} + +char *fmt_wireaddr_internal(const tal_t *ctx, + const struct wireaddr_internal *a) +{ + switch (a->itype) { + case ADDR_INTERNAL_SOCKNAME: + return tal_fmt(ctx, "%s", a->u.sockname); + case ADDR_INTERNAL_ALLPROTO: + return tal_fmt(ctx, ":%u", a->u.port); + case ADDR_INTERNAL_WIREADDR: + return fmt_wireaddr(ctx, &a->u.wireaddr); + } + abort(); +} +REGISTER_TYPE_TO_STRING(wireaddr_internal, fmt_wireaddr_internal); + /* Valid forms: * * [anything]: @@ -137,18 +262,12 @@ bool wireaddr_from_hostname(struct wireaddr *addr, const char *hostname, } /* Use only the first found address */ if (addrinfo->ai_family == AF_INET) { - addr->type = ADDR_TYPE_IPV4; - addr->addrlen = 4; - addr->port = port; sa4 = (struct sockaddr_in *) addrinfo->ai_addr; - memcpy(&addr->addr, &sa4->sin_addr, addr->addrlen); + wireaddr_from_ipv4(addr, &sa4->sin_addr, port); res = true; } else if (addrinfo->ai_family == AF_INET6) { - addr->type = ADDR_TYPE_IPV6; - addr->addrlen = 16; - addr->port = port; sa6 = (struct sockaddr_in6 *) addrinfo->ai_addr; - memcpy(&addr->addr, &sa6->sin6_addr, addr->addrlen); + wireaddr_from_ipv6(addr, &sa6->sin6_addr, port); res = true; } @@ -182,16 +301,10 @@ bool parse_wireaddr(const char *arg, struct wireaddr *addr, u16 defport, memset(&addr->addr, 0, sizeof(addr->addr)); if (inet_pton(AF_INET, ip, &v4) == 1) { - addr->type = ADDR_TYPE_IPV4; - addr->addrlen = 4; - addr->port = port; - memcpy(&addr->addr, &v4, addr->addrlen); + wireaddr_from_ipv4(addr, &v4, port); res = true; } else if (inet_pton(AF_INET6, ip, &v6) == 1) { - addr->type = ADDR_TYPE_IPV6; - addr->addrlen = 16; - addr->port = port; - memcpy(&addr->addr, &v6, addr->addrlen); + wireaddr_from_ipv6(addr, &v6, port); res = true; } @@ -204,3 +317,56 @@ bool parse_wireaddr(const char *arg, struct wireaddr *addr, u16 defport, *err_msg = "Error parsing hostname"; return res; } + +bool parse_wireaddr_internal(const char *arg, struct wireaddr_internal *addr, + u16 port, bool wildcard_ok, const char **err_msg) +{ + u16 wildport; + char *ip; + + /* Addresses starting with '/' are local socket paths */ + if (arg[0] == '/') { + addr->itype = ADDR_INTERNAL_SOCKNAME; + + /* Check if the path is too long */ + if (strlen(arg) >= sizeof(addr->u.sockname)) { + if (err_msg) + *err_msg = "Socket name too long"; + return false; + } + strcpy(addr->u.sockname, arg); + return true; + } + + /* An empty string means IPv4 and IPv6 (which under Linux by default + * means just IPv6, and IPv4 gets autobound). */ + if (wildcard_ok + && separate_address_and_port(tmpctx, arg, &ip, &wildport) + && streq(ip, "")) { + addr->itype = ADDR_INTERNAL_ALLPROTO; + addr->u.port = wildport; + return true; + } + + addr->itype = ADDR_INTERNAL_WIREADDR; + return parse_wireaddr(arg, &addr->u.wireaddr, port, err_msg); +} + +void wireaddr_from_sockname(struct wireaddr_internal *addr, + const char *sockname) +{ + addr->itype = ADDR_INTERNAL_SOCKNAME; + memset(addr->u.sockname, 0, sizeof(addr->u.sockname)); + strncpy(addr->u.sockname, sockname, sizeof(addr->u.sockname)-1); +} + +bool wireaddr_to_sockname(const struct wireaddr_internal *addr, + struct sockaddr_un *sun) +{ + if (addr->itype != ADDR_INTERNAL_SOCKNAME) + return false; + sun->sun_family = AF_LOCAL; + BUILD_ASSERT(sizeof(sun->sun_path) == sizeof(addr->u.sockname)); + memcpy(sun->sun_path, addr->u.sockname, sizeof(addr->u.sockname)); + return true; +} diff --git a/common/wireaddr.h b/common/wireaddr.h index ade052295c40..994774c01268 100644 --- a/common/wireaddr.h +++ b/common/wireaddr.h @@ -6,6 +6,12 @@ #include #include +struct in6_addr; +struct in_addr; +struct sockaddr_in6; +struct sockaddr_in; +struct sockaddr_un; + /* BOLT #7: * * The following `address descriptor` types are defined: @@ -37,10 +43,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); @@ -48,4 +66,46 @@ char *fmt_wireaddr(const tal_t *ctx, const struct wireaddr *a); bool wireaddr_from_hostname(struct wireaddr *addr, const char *hostname, const u16 port, const char **err_msg); +void wireaddr_from_ipv4(struct wireaddr *addr, + const struct in_addr *ip4, + const u16 port); +void wireaddr_from_ipv6(struct wireaddr *addr, + const struct in6_addr *ip6, + const u16 port); +bool wireaddr_to_ipv4(const struct wireaddr *addr, struct sockaddr_in *s4); +bool wireaddr_to_ipv6(const struct wireaddr *addr, struct sockaddr_in6 *s6); + +bool wireaddr_is_wildcard(const struct wireaddr *addr); + +enum wireaddr_internal_type { + ADDR_INTERNAL_SOCKNAME, + ADDR_INTERNAL_ALLPROTO, + ADDR_INTERNAL_WIREADDR, +}; + +/* For internal use, where we can also supply a local socket, wildcard. */ +struct wireaddr_internal { + enum wireaddr_internal_type itype; + union { + /* ADDR_INTERNAL_SOCKNAME */ + struct wireaddr wireaddr; + /* ADDR_INTERNAL_ALLPROTO */ + u16 port; + /* ADDR_INTERNAL_WIREADDR */ + char sockname[108]; + } u; +}; +bool parse_wireaddr_internal(const char *arg, struct wireaddr_internal *addr, u16 port, bool wildcard_ok, const char **err_msg); + +void towire_wireaddr_internal(u8 **pptr, + const struct wireaddr_internal *addr); +bool fromwire_wireaddr_internal(const u8 **cursor, size_t *max, + struct wireaddr_internal *addr); +char *fmt_wireaddr_internal(const tal_t *ctx, + const struct wireaddr_internal *a); + +void wireaddr_from_sockname(struct wireaddr_internal *addr, + const char *sockname); +bool wireaddr_to_sockname(const struct wireaddr_internal *addr, + struct sockaddr_un *sun); #endif /* LIGHTNING_COMMON_WIREADDR_H */ diff --git a/gossipd/Makefile b/gossipd/Makefile index 8d9274d4000a..adecacc0a717 100644 --- a/gossipd/Makefile +++ b/gossipd/Makefile @@ -16,6 +16,7 @@ LIGHTNINGD_GOSSIP_HEADERS := gossipd/gen_gossip_wire.h \ gossipd/gen_gossip_store.h \ gossipd/gossip_store.h \ gossipd/handshake.h \ + gossipd/netaddress.h \ gossipd/routing.h \ gossipd/broadcast.h LIGHTNINGD_GOSSIP_SRC := gossipd/gossip.c \ diff --git a/gossipd/gossip.c b/gossipd/gossip.c index d5e9e41b1740..4afa2fda38ab 100644 --- a/gossipd/gossip.c +++ b/gossipd/gossip.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -127,13 +129,19 @@ struct daemon { u8 alias[33]; u8 rgb[3]; - struct wireaddr *wireaddrs; + + /* Addresses master told us to use */ + struct wireaddr_internal *proposed_wireaddr; + enum addr_listen_announce *proposed_listen_announce; + + /* What we actually announce. */ + struct wireaddr *announcable; /* To make sure our node_announcement timestamps increase */ u32 last_announce_timestamp; - /* Only matters if DEVELOPER defined */ - bool no_reconnect; + /* Automatically reconnect. */ + bool reconnect; }; /* Peers we're trying to reach. */ @@ -147,7 +155,7 @@ struct reaching { struct pubkey id; /* FIXME: Support multiple address. */ - struct wireaddr addr; + struct wireaddr_internal addr; /* Whether connect command is waiting for the result. */ bool master_needs_response; @@ -190,7 +198,7 @@ struct peer { struct pubkey id; /* Where it's connected to. */ - struct wireaddr addr; + struct wireaddr_internal addr; /* Feature bitmaps. */ u8 *gfeatures, *lfeatures; @@ -212,7 +220,7 @@ struct addrhint { struct pubkey id; /* FIXME: use array... */ - struct wireaddr addr; + struct wireaddr_internal addr; }; /* FIXME: Reorder */ @@ -307,7 +315,7 @@ new_local_peer_state(struct peer *peer, const struct crypto_state *cs) static struct peer *new_peer(const tal_t *ctx, struct daemon *daemon, const struct pubkey *their_id, - const struct wireaddr *addr, + const struct wireaddr_internal *addr, const struct crypto_state *cs) { struct peer *peer = tal(ctx, struct peer); @@ -520,7 +528,7 @@ static struct io_plan *read_init(struct io_conn *conn, struct peer *peer) * we have the features. */ static struct io_plan *init_new_peer(struct io_conn *conn, const struct pubkey *their_id, - const struct wireaddr *addr, + const struct wireaddr_internal *addr, const struct crypto_state *cs, struct daemon *daemon) { @@ -563,8 +571,8 @@ 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->announcable); i++) + towire_wireaddr(&addresses, &daemon->announcable[i]); announcement = towire_node_announcement(ctx, sig, features, timestamp, @@ -1380,10 +1388,14 @@ static struct io_plan *ping_req(struct io_conn *conn, struct daemon *daemon, return daemon_conn_read_next(conn, &daemon->master); } -static int make_listen_fd(int domain, void *addr, socklen_t len, bool reportfail) +static int make_listen_fd(int domain, void *addr, socklen_t len, bool mayfail) { int fd = socket(domain, SOCK_STREAM, 0); if (fd < 0) { + if (!mayfail) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Failed to create %u socket: %s", + domain, strerror(errno)); status_trace("Failed to create %u socket: %s", domain, strerror(errno)); return -1; @@ -1398,17 +1410,20 @@ static int make_listen_fd(int domain, void *addr, socklen_t len, bool reportfail strerror(errno)); if (bind(fd, addr, len) != 0) { - if (reportfail) - status_broken("Failed to bind on %u socket: %s", + if (!mayfail) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Failed to bind on %u socket: %s", domain, strerror(errno)); + status_trace("Failed to create %u socket: %s", + domain, strerror(errno)); goto fail; } } if (listen(fd, 5) != 0) { - status_broken("Failed to listen on %u socket: %s", + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Failed to listen on %u socket: %s", domain, strerror(errno)); - goto fail; } return fd; @@ -1517,7 +1532,7 @@ static void gossip_refresh_network(struct daemon *daemon) static struct io_plan *connection_in(struct io_conn *conn, struct daemon *daemon) { - struct wireaddr addr; + struct wireaddr_internal addr; struct sockaddr_storage s = {}; socklen_t len = sizeof(s); @@ -1529,18 +1544,18 @@ static struct io_plan *connection_in(struct io_conn *conn, struct daemon *daemon if (s.ss_family == AF_INET6) { struct sockaddr_in6 *s6 = (void *)&s; - addr.type = ADDR_TYPE_IPV6; - addr.addrlen = sizeof(s6->sin6_addr); - BUILD_ASSERT(sizeof(s6->sin6_addr) <= sizeof(addr.addr)); - memcpy(addr.addr, &s6->sin6_addr, addr.addrlen); - addr.port = ntohs(s6->sin6_port); + addr.itype = ADDR_INTERNAL_WIREADDR; + wireaddr_from_ipv6(&addr.u.wireaddr, + &s6->sin6_addr, ntohs(s6->sin6_port)); } else if (s.ss_family == AF_INET) { struct sockaddr_in *s4 = (void *)&s; - addr.type = ADDR_TYPE_IPV4; - addr.addrlen = sizeof(s4->sin_addr); - BUILD_ASSERT(sizeof(s4->sin_addr) <= sizeof(addr.addr)); - memcpy(addr.addr, &s4->sin_addr, addr.addrlen); - addr.port = ntohs(s4->sin_port); + addr.itype = ADDR_INTERNAL_WIREADDR; + wireaddr_from_ipv4(&addr.u.wireaddr, + &s4->sin_addr, ntohs(s4->sin_port)); + } else if (s.ss_family == AF_UNIX) { + struct sockaddr_un *sun = (void *)&s; + addr.itype = ADDR_INTERNAL_SOCKNAME; + memcpy(addr.u.sockname, sun->sun_path, sizeof(sun->sun_path)); } else { status_broken("Unknown socket type %i for incoming conn", s.ss_family); @@ -1552,69 +1567,151 @@ 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) +/* Return true if it created socket successfully. */ +static bool handle_wireaddr_listen(struct daemon *daemon, + const struct wireaddr *wireaddr, + bool mayfail) { + int fd; 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; + switch (wireaddr->type) { + case ADDR_TYPE_IPV4: + wireaddr_to_ipv4(wireaddr, &addr); + /* We might fail if IPv6 bound to port first */ + fd = make_listen_fd(AF_INET, &addr, sizeof(addr), mayfail); + if (fd >= 0) { + status_trace("Created IPv4 listener on port %u", + wireaddr->port); + io_new_listener(daemon, fd, connection_in, daemon); + return true; + } + return false; + case ADDR_TYPE_IPV6: + wireaddr_to_ipv6(wireaddr, &addr6); + fd = make_listen_fd(AF_INET6, &addr6, sizeof(addr6), mayfail); + if (fd >= 0) { + status_trace("Created IPv6 listener on port %u", + wireaddr->port); + io_new_listener(daemon, fd, connection_in, daemon); + return true; + } + return false; + case ADDR_TYPE_PADDING: + break; } + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Invalid listener wireaddress type %u", wireaddr->type); +} + +/* If it's a wildcard, turns it into a real address pointing to internet */ +static bool public_address(struct daemon *daemon, struct wireaddr *wireaddr) +{ + if (wireaddr_is_wildcard(wireaddr)) { + if (!guess_address(wireaddr)) + return false; + } + + return address_routable(wireaddr, daemon->rstate->dev_allow_localhost); +} + +static void add_announcable(struct daemon *daemon, const struct wireaddr *addr) +{ + size_t n = tal_count(daemon->announcable); + tal_resize(&daemon->announcable, n+1); + daemon->announcable[n] = *addr; +} + +static void add_binding(struct wireaddr_internal **binding, + const struct wireaddr_internal *addr) +{ + size_t n = tal_count(*binding); + tal_resize(binding, n+1); + (*binding)[n] = *addr; +} - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - addr.sin_port = htons(portnum); +/* Initializes daemon->announcable array, returns addresses we bound to. */ +static struct wireaddr_internal *setup_listeners(const tal_t *ctx, + struct daemon *daemon) +{ + struct sockaddr_un addrun; + int fd; + struct wireaddr_internal *binding; - memset(&addr6, 0, sizeof(addr6)); - addr6.sin6_family = AF_INET6; - addr6.sin6_addr = in6addr_any; - addr6.sin6_port = htons(portnum); + binding = tal_arr(ctx, struct wireaddr_internal, 0); + daemon->announcable = tal_arr(daemon, struct wireaddr, 0); - /* 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 = {}; + for (size_t i = 0; i < tal_count(daemon->proposed_wireaddr); i++) { + struct wireaddr_internal wa = daemon->proposed_wireaddr[i]; - 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); + if (!(daemon->proposed_listen_announce[i] & ADDR_LISTEN)) { + assert(daemon->proposed_listen_announce[i] + & ADDR_ANNOUNCE); + /* You can only announce wiretypes! */ + assert(daemon->proposed_wireaddr[i].itype + == ADDR_INTERNAL_WIREADDR); + add_announcable(daemon, &wa.u.wireaddr); + 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 (wa.itype) { + case ADDR_INTERNAL_SOCKNAME: + addrun.sun_family = AF_UNIX; + memcpy(addrun.sun_path, wa.u.sockname, + sizeof(addrun.sun_path)); + fd = make_listen_fd(AF_INET, &addrun, sizeof(addrun), + false); + status_trace("Created socket listener on file %s", + addrun.sun_path); + io_new_listener(daemon, fd, connection_in, daemon); + /* We don't announce socket names */ + add_binding(&binding, &wa); + continue; + case ADDR_INTERNAL_ALLPROTO: { + bool ipv6_ok; + + wa.itype = ADDR_INTERNAL_WIREADDR; + wa.u.wireaddr.port = wa.u.port; + memset(wa.u.wireaddr.addr, 0, + sizeof(wa.u.wireaddr.addr)); + + /* Try both IPv6 and IPv4. */ + wa.u.wireaddr.type = ADDR_TYPE_IPV6; + wa.u.wireaddr.addrlen = 16; + + ipv6_ok = handle_wireaddr_listen(daemon, &wa.u.wireaddr, + true); + if (ipv6_ok) { + add_binding(&binding, &wa); + if (public_address(daemon, &wa.u.wireaddr)) + add_announcable(daemon, &wa.u.wireaddr); + } + wa.u.wireaddr.type = ADDR_TYPE_IPV4; + wa.u.wireaddr.addrlen = 4; + /* OK if this fails, as long as one succeeds! */ + if (handle_wireaddr_listen(daemon, &wa.u.wireaddr, + ipv6_ok)) { + add_binding(&binding, &wa); + if (public_address(daemon, &wa.u.wireaddr)) + add_announcable(daemon, &wa.u.wireaddr); + } + continue; + } + case ADDR_INTERNAL_WIREADDR: + handle_wireaddr_listen(daemon, &wa.u.wireaddr, false); + add_binding(&binding, &wa); + if (public_address(daemon, &wa.u.wireaddr)) + add_announcable(daemon, &wa.u.wireaddr); + continue; } + /* Shouldn't happen. */ + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Invalid listener address type %u", + daemon->proposed_wireaddr[i].itype); } - if (fd1 < 0 && fd2 < 0) - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Could not bind to a network address on port %u", - portnum); + return binding; } /* Parse an incoming gossip init message and assign config variables @@ -1626,17 +1723,21 @@ static struct io_plan *gossip_init(struct daemon_conn *master, { struct bitcoin_blkid chain_hash; u32 update_channel_interval; + bool dev_allow_localhost; if (!fromwire_gossipctl_init( daemon, msg, &daemon->broadcast_interval, &chain_hash, &daemon->id, &daemon->globalfeatures, - &daemon->localfeatures, &daemon->wireaddrs, daemon->rgb, - daemon->alias, &update_channel_interval, &daemon->no_reconnect)) { + &daemon->localfeatures, &daemon->proposed_wireaddr, + &daemon->proposed_listen_announce, daemon->rgb, + daemon->alias, &update_channel_interval, &daemon->reconnect, + &dev_allow_localhost)) { master_badmsg(WIRE_GOSSIPCTL_INIT, msg); } /* Prune time is twice update time */ daemon->rstate = new_routing_state(daemon, &chain_hash, &daemon->id, - update_channel_interval * 2); + update_channel_interval * 2, + dev_allow_localhost); /* Load stored gossip messages */ gossip_store_load(daemon->rstate, daemon->rstate->store); @@ -1652,16 +1753,22 @@ static struct io_plan *gossip_activate(struct daemon_conn *master, struct daemon *daemon, const u8 *msg) { - u16 port; + bool listen; + struct wireaddr_internal *binding; - if (!fromwire_gossipctl_activate(msg, &port)) + if (!fromwire_gossipctl_activate(msg, &listen)) master_badmsg(WIRE_GOSSIPCTL_ACTIVATE, msg); - setup_listeners(daemon, port); + if (listen) + binding = setup_listeners(tmpctx, daemon); + else + binding = NULL; /* OK, we're ready! */ daemon_conn_send(&daemon->master, - take(towire_gossipctl_activate_reply(NULL))); + take(towire_gossipctl_activate_reply(NULL, + binding, + daemon->announcable))); return daemon_conn_read_next(master->conn, master); } @@ -1697,7 +1804,7 @@ static struct io_plan *resolve_channel_req(struct io_conn *conn, static struct io_plan *handshake_out_success(struct io_conn *conn, const struct pubkey *id, - const struct wireaddr *addr, + const struct wireaddr_internal *addr, const struct crypto_state *cs, struct reaching *reach) { @@ -1762,6 +1869,7 @@ static struct io_plan *conn_init(struct io_conn *conn, struct reaching *reach) struct addrinfo ai; struct sockaddr_in sin; struct sockaddr_in6 sin6; + struct sockaddr_un sun; /* FIXME: make generic */ ai.ai_flags = 0; @@ -1770,29 +1878,36 @@ static struct io_plan *conn_init(struct io_conn *conn, struct reaching *reach) ai.ai_canonname = NULL; ai.ai_next = NULL; - switch (reach->addr.type) { - case ADDR_TYPE_IPV4: - ai.ai_family = AF_INET; - sin.sin_family = AF_INET; - sin.sin_port = htons(reach->addr.port); - memcpy(&sin.sin_addr, reach->addr.addr, sizeof(sin.sin_addr)); + switch (reach->addr.itype) { + case ADDR_INTERNAL_SOCKNAME: + wireaddr_to_sockname(&reach->addr, &sun); + ai.ai_family = sun.sun_family; ai.ai_addrlen = sizeof(sin); - ai.ai_addr = (struct sockaddr *)&sin; + ai.ai_addr = (struct sockaddr *)&sun; break; - case ADDR_TYPE_IPV6: - ai.ai_family = AF_INET6; - memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_family = AF_INET6; - sin6.sin6_port = htons(reach->addr.port); - memcpy(&sin6.sin6_addr, reach->addr.addr, sizeof(sin6.sin6_addr)); - ai.ai_addrlen = sizeof(sin6); - ai.ai_addr = (struct sockaddr *)&sin6; + case ADDR_INTERNAL_ALLPROTO: + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Can't reach to all protocols"); break; - case ADDR_TYPE_PADDING: - /* Shouldn't happen. */ - return io_close(conn); + case ADDR_INTERNAL_WIREADDR: + switch (reach->addr.u.wireaddr.type) { + case ADDR_TYPE_IPV4: + wireaddr_to_ipv4(&reach->addr.u.wireaddr, &sin); + ai.ai_family = sin.sin_family; + ai.ai_addrlen = sizeof(sin); + ai.ai_addr = (struct sockaddr *)&sin; + break; + case ADDR_TYPE_IPV6: + wireaddr_to_ipv6(&reach->addr.u.wireaddr, &sin6); + ai.ai_family = sin6.sin6_family; + ai.ai_addrlen = sizeof(sin6); + ai.ai_addr = (struct sockaddr *)&sin6; + break; + case ADDR_TYPE_PADDING: + /* Shouldn't happen. */ + return io_close(conn); + } } - io_set_finish(conn, connect_failed, reach); return io_connect(conn, &ai, connection_out, reach); } @@ -1813,12 +1928,14 @@ seed_resolve_addr(const tal_t *ctx, const struct pubkey *id, const u16 port) status_trace("Resolving %s", addr); a = tal(ctx, struct addrhint); - if (!wireaddr_from_hostname(&a->addr, addr, port, NULL)) { + a->addr.itype = ADDR_INTERNAL_WIREADDR; + if (!wireaddr_from_hostname(&a->addr.u.wireaddr, addr, port, NULL)) { status_trace("Could not resolve %s", addr); return tal_free(a); } else { status_trace("Resolved %s to %s", addr, - type_to_string(ctx, struct wireaddr, &a->addr)); + type_to_string(ctx, struct wireaddr, + &a->addr.u.wireaddr)); return a; } } @@ -1830,7 +1947,6 @@ gossip_resolve_addr(const tal_t *ctx, const struct pubkey *id) { struct node *node; - struct addrhint *a; /* Get from routing state. */ node = get_node(rstate, id); @@ -1838,24 +1954,30 @@ gossip_resolve_addr(const tal_t *ctx, /* No matching node? */ if (!node) return NULL; - /* Node has no addresses? */ - if (tal_count(node->addresses) == 0) - return NULL; /* FIXME: When struct addrhint can contain more than one address, - * we should copy all addresses. - * For now getting first address should be fine. */ - a = tal(ctx, struct addrhint); - a->addr = node->addresses[0]; + * we should copy all routable addresses. */ + for (size_t i = 0; i < tal_count(node->addresses); i++) { + struct addrhint *a; + + if (!address_routable(&node->addresses[i], + rstate->dev_allow_localhost)) + continue; - return a; + a = tal(ctx, struct addrhint); + a->addr.itype = ADDR_INTERNAL_WIREADDR; + a->addr.u.wireaddr = node->addresses[i]; + return a; + } + + return NULL; } static void try_reach_peer(struct daemon *daemon, const struct pubkey *id, bool master_needs_response) { struct addrhint *a; - int fd; + int fd, af; struct reaching *reach; u8 *msg; struct peer *peer = find_peer(daemon, id); @@ -1908,23 +2030,36 @@ static void try_reach_peer(struct daemon *daemon, const struct pubkey *id, } /* Might not even be able to create eg. IPv6 sockets */ - switch (a->addr.type) { - case ADDR_TYPE_IPV4: - fd = socket(AF_INET, SOCK_STREAM, 0); - break; - case ADDR_TYPE_IPV6: - fd = socket(AF_INET6, SOCK_STREAM, 0); + af = -1; + switch (a->addr.itype) { + case ADDR_INTERNAL_SOCKNAME: + af = AF_LOCAL; break; - default: + case ADDR_INTERNAL_ALLPROTO: + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Can't reach ALLPROTO"); + case ADDR_INTERNAL_WIREADDR: + switch (a->addr.u.wireaddr.type) { + case ADDR_TYPE_IPV4: + af = AF_INET; + break; + case ADDR_TYPE_IPV6: + af = AF_INET6; + break; + case ADDR_TYPE_PADDING: + break; + } + } + if (af == -1) { fd = -1; errno = EPROTONOSUPPORT; - break; - } + } else + fd = socket(af, SOCK_STREAM, 0); if (fd < 0) { char *err = tal_fmt(tmpctx, "Can't open %i socket for %s (%s), giving up", - a->addr.type, + af, type_to_string(tmpctx, struct pubkey, id), strerror(errno)); status_debug("%s", err); @@ -1955,12 +2090,11 @@ static void retry_important(struct important_peerid *imp) /* In case we've come off a timer, don't leave dangling pointer */ imp->reconnect_timer = NULL; -#if DEVELOPER - /* With --dev-no-reconnect, we only want explicit + /* With --dev-no-reconnect or --offline, we only want explicit * connects */ - if (imp->daemon->no_reconnect) + if (!imp->daemon->reconnect) return; -#endif + try_reach_peer(imp->daemon, &imp->id, false); } @@ -2068,7 +2202,7 @@ static struct io_plan *get_peers(struct io_conn *conn, struct peer *peer; size_t n = 0; struct pubkey *id = tal_arr(conn, struct pubkey, n); - struct wireaddr *wireaddr = tal_arr(conn, struct wireaddr, n); + struct wireaddr_internal *wireaddr = tal_arr(conn, struct wireaddr_internal, n); const struct gossip_getnodes_entry **nodes; struct pubkey *specific_id = NULL; struct node_map_iter it; diff --git a/gossipd/gossip_wire.csv b/gossipd/gossip_wire.csv index 60e879f14f3a..d7023b9246ef 100644 --- a/gossipd/gossip_wire.csv +++ b/gossipd/gossip_wire.csv @@ -12,25 +12,30 @@ gossipctl_init,,gfeatures,gflen*u8 gossipctl_init,,lflen,u16 gossipctl_init,,lfeatures,lflen*u8 gossipctl_init,,num_wireaddrs,u16 -gossipctl_init,,wireaddrs,num_wireaddrs*struct wireaddr +gossipctl_init,,wireaddrs,num_wireaddrs*struct wireaddr_internal +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 -# DEVELOPER only -gossipctl_init,,no_reconnect,bool +gossipctl_init,,reconnect,bool +gossipctl_init,,dev_allow_localhost,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. +# Gossipd->master, I am ready, here's the addresses I bound, can announce. gossipctl_activate_reply,3125 +gossipctl_activate_reply,,num_bindings,u16 +gossipctl_activate_reply,,bindings,num_bindings*struct wireaddr_internal +gossipctl_activate_reply,,num_announcable,u16 +gossipctl_activate_reply,,announcable,num_announcable*struct wireaddr # Master -> gossipd: Optional hint for where to find peer. gossipctl_peer_addrhint,3014 gossipctl_peer_addrhint,,id,struct pubkey -gossipctl_peer_addrhint,,addr,struct wireaddr +gossipctl_peer_addrhint,,addr,struct wireaddr_internal # Master -> gossipd: connect to a peer. gossipctl_connect_to_peer,3001 @@ -53,7 +58,7 @@ gossipctl_peer_important,,important,bool # Gossipd -> master: we got a peer. Two fds: peer and gossip gossip_peer_connected,3002 gossip_peer_connected,,id,struct pubkey -gossip_peer_connected,,addr,struct wireaddr +gossip_peer_connected,,addr,struct wireaddr_internal gossip_peer_connected,,crypto_state,struct crypto_state gossip_peer_connected,,gflen,u16 gossip_peer_connected,,gfeatures,gflen*u8 @@ -63,7 +68,7 @@ gossip_peer_connected,,lfeatures,lflen*u8 # Gossipd -> master: peer sent non-gossip packet. Two fds: peer and gossip gossip_peer_nongossip,3003 gossip_peer_nongossip,,id,struct pubkey -gossip_peer_nongossip,,addr,struct wireaddr +gossip_peer_nongossip,,addr,struct wireaddr_internal gossip_peer_nongossip,,crypto_state,struct crypto_state gossip_peer_nongossip,,gflen,u16 gossip_peer_nongossip,,gfeatures,gflen*u8 @@ -78,7 +83,7 @@ gossipctl_release_peer,,id,struct pubkey # Gossipd -> master: reply to gossip_release_peer. Two fds: peer and gossip. gossipctl_release_peer_reply,3104 -gossipctl_release_peer_reply,,addr,struct wireaddr +gossipctl_release_peer_reply,,addr,struct wireaddr_internal gossipctl_release_peer_reply,,crypto_state,struct crypto_state gossipctl_release_peer_reply,,gflen,u16 gossipctl_release_peer_reply,,gfeatures,gflen*u8 @@ -162,7 +167,7 @@ gossip_getpeers_request,,id,num*struct pubkey gossip_getpeers_reply,3111 gossip_getpeers_reply,,num,u16 gossip_getpeers_reply,,id,num*struct pubkey -gossip_getpeers_reply,,addr,num*struct wireaddr +gossip_getpeers_reply,,addr,num*struct wireaddr_internal gossip_getpeers_reply,,numnodes,u16 gossip_getpeers_reply,,nodes,numnodes*struct gossip_getnodes_entry diff --git a/gossipd/handshake.c b/gossipd/handshake.c index 26dbf1c9cd40..5c9e893c3dc3 100644 --- a/gossipd/handshake.c +++ b/gossipd/handshake.c @@ -170,7 +170,7 @@ struct handshake { struct act_three act3; /* Where is connection from/to */ - struct wireaddr addr; + struct wireaddr_internal addr; /* Who we are */ struct pubkey my_id; @@ -183,7 +183,7 @@ struct handshake { /* Function to call once handshake complete. */ struct io_plan *(*cb)(struct io_conn *conn, const struct pubkey *their_id, - const struct wireaddr *wireaddr, + const struct wireaddr_internal *wireaddr, const struct crypto_state *cs, void *cbarg); void *cbarg; @@ -353,12 +353,12 @@ static struct io_plan *handshake_succeeded(struct io_conn *conn, struct crypto_state cs; struct io_plan *(*cb)(struct io_conn *conn, const struct pubkey *their_id, - const struct wireaddr *addr, + const struct wireaddr_internal *addr, const struct crypto_state *cs, void *cbarg); void *cbarg; struct pubkey their_id; - struct wireaddr addr; + struct wireaddr_internal addr; /* BOLT #8: * @@ -965,10 +965,10 @@ static struct io_plan *act_one_responder(struct io_conn *conn, struct io_plan *responder_handshake_(struct io_conn *conn, const struct pubkey *my_id, - const struct wireaddr *addr, + const struct wireaddr_internal *addr, struct io_plan *(*cb)(struct io_conn *, const struct pubkey *, - const struct wireaddr *, + const struct wireaddr_internal *, const struct crypto_state *, void *cbarg), void *cbarg) @@ -987,10 +987,10 @@ struct io_plan *responder_handshake_(struct io_conn *conn, struct io_plan *initiator_handshake_(struct io_conn *conn, const struct pubkey *my_id, const struct pubkey *their_id, - const struct wireaddr *addr, + const struct wireaddr_internal *addr, struct io_plan *(*cb)(struct io_conn *, const struct pubkey *, - const struct wireaddr *, + const struct wireaddr_internal *, const struct crypto_state *, void *cbarg), void *cbarg) diff --git a/gossipd/handshake.h b/gossipd/handshake.h index fea357fccdc4..6bc07db3275b 100644 --- a/gossipd/handshake.h +++ b/gossipd/handshake.h @@ -5,7 +5,7 @@ struct crypto_state; struct io_conn; -struct wireaddr; +struct wireaddr_internal; struct pubkey; #define initiator_handshake(conn, my_id, their_id, addr, cb, cbarg) \ @@ -14,7 +14,7 @@ struct pubkey; (cb), (cbarg), \ struct io_conn *, \ const struct pubkey *, \ - const struct wireaddr *, \ + const struct wireaddr_internal *, \ const struct crypto_state *), \ (cbarg)) @@ -22,10 +22,10 @@ struct pubkey; struct io_plan *initiator_handshake_(struct io_conn *conn, const struct pubkey *my_id, const struct pubkey *their_id, - const struct wireaddr *addr, + const struct wireaddr_internal *addr, struct io_plan *(*cb)(struct io_conn *, const struct pubkey *, - const struct wireaddr *, + const struct wireaddr_internal *, const struct crypto_state *, void *cbarg), void *cbarg); @@ -37,16 +37,16 @@ struct io_plan *initiator_handshake_(struct io_conn *conn, (cb), (cbarg), \ struct io_conn *, \ const struct pubkey *, \ - const struct wireaddr *, \ + const struct wireaddr_internal *, \ const struct crypto_state *), \ (cbarg)) struct io_plan *responder_handshake_(struct io_conn *conn, const struct pubkey *my_id, - const struct wireaddr *addr, + const struct wireaddr_internal *addr, struct io_plan *(*cb)(struct io_conn *, const struct pubkey *, - const struct wireaddr *, + const struct wireaddr_internal *, const struct crypto_state *, void *cbarg), void *cbarg); diff --git a/lightningd/netaddress.c b/gossipd/netaddress.c similarity index 78% rename from lightningd/netaddress.c rename to gossipd/netaddress.c index 4231a6977ef2..7d3d4b41f1c2 100644 --- a/lightningd/netaddress.c +++ b/gossipd/netaddress.c @@ -1,10 +1,9 @@ #include #include -#include +#include +#include #include -#include -#include -#include +#include #include #include #include @@ -200,26 +199,27 @@ static bool IsRoutable(const struct wireaddr *addr) /* Trick I learned from Harald Welte: create UDP socket, connect() and * then query address. */ -static bool get_local_sockname(struct lightningd *ld, - int af, void *saddr, socklen_t saddrlen) +/* Returns 0 if protocol completely unsupported, ADDR_LISTEN if we + * can't reach addr, ADDR_LISTEN_AND_ANNOUNCE if we can (and fill saddr). */ +static bool get_local_sockname(int af, void *saddr, socklen_t saddrlen) { int fd = socket(af, SOCK_DGRAM, 0); if (fd < 0) { - log_debug(ld->log, "Failed to create %u socket: %s", - af, strerror(errno)); + status_trace("Failed to create %u socket: %s", + af, strerror(errno)); return false; } if (connect(fd, saddr, saddrlen) != 0) { - log_debug(ld->log, "Failed to connect %u socket: %s", - af, strerror(errno)); + status_trace("Failed to connect %u socket: %s", + af, strerror(errno)); close(fd); return false; } if (getsockname(fd, saddr, &saddrlen) != 0) { - log_debug(ld->log, "Failed to get %u socket name: %s", - af, strerror(errno)); + status_trace("Failed to get %u socket name: %s", + af, strerror(errno)); close(fd); return false; } @@ -228,27 +228,22 @@ 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) +bool guess_address(struct wireaddr *addr) { - addr->type = type; - addr->port = portnum; + bool ret; /* We point to Google nameservers, works unless you're inside Google :) */ - switch (type) { + switch (addr->type) { case ADDR_TYPE_IPV4: { struct sockaddr_in sin; sin.sin_port = htons(53); /* 8.8.8.8 */ sin.sin_addr.s_addr = 0x08080808; sin.sin_family = AF_INET; - if (!get_local_sockname(ld, AF_INET, &sin, sizeof(sin))) - return false; + ret = get_local_sockname(AF_INET, &sin, sizeof(sin)); addr->addrlen = sizeof(sin.sin_addr); memcpy(addr->addr, &sin.sin_addr, addr->addrlen); - break; + return ret; } case ADDR_TYPE_IPV6: { struct sockaddr_in6 sin6; @@ -259,40 +254,20 @@ static bool guess_one_address(struct lightningd *ld, sin6.sin6_port = htons(53); 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; + ret = get_local_sockname(AF_INET6, &sin6, sizeof(sin6)); addr->addrlen = sizeof(sin6.sin6_addr); memcpy(addr->addr, &sin6.sin6_addr, addr->addrlen); - break; + return ret; } case ADDR_TYPE_PADDING: - log_debug(ld->log, "Padding address, ignoring"); - return false; - } - - if (!IsRoutable(addr)) { - log_debug(ld->log, "Address %s is not routable", - type_to_string(tmpctx, struct wireaddr, addr)); - return false; + break; } - - log_debug(ld->log, "Public address %s", - type_to_string(tmpctx, struct wireaddr, addr)); - return true; + abort(); } -void guess_addresses(struct lightningd *ld) +bool address_routable(const struct wireaddr *wireaddr, bool allow_localhost) { - size_t n = tal_count(ld->wireaddrs); - - log_debug(ld->log, "Trying to guess public addresses..."); - - /* 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)) { - n++; - tal_resize(&ld->wireaddrs, n+1); - } - if (!guess_one_address(ld, &ld->wireaddrs[n], ld->portnum, ADDR_TYPE_IPV6)) - tal_resize(&ld->wireaddrs, n); + if (allow_localhost && IsLocal(wireaddr)) + return true; + return IsRoutable(wireaddr); } diff --git a/gossipd/netaddress.h b/gossipd/netaddress.h new file mode 100644 index 000000000000..27ce71853730 --- /dev/null +++ b/gossipd/netaddress.h @@ -0,0 +1,14 @@ +#ifndef LIGHTNING_GOSSIPD_NETADDRESS_H +#define LIGHTNING_GOSSIPD_NETADDRESS_H +#include "config.h" +#include +#include + +/* Address is a wildcard: try to guess what it looks like to outside world */ +bool guess_address(struct wireaddr *wireaddr); + +/* Is this address public? */ +bool address_routable(const struct wireaddr *wireaddr, + bool allow_localhost); + +#endif /* LIGHTNING_GOSSIPD_NETADDRESS_H */ diff --git a/gossipd/routing.c b/gossipd/routing.c index d7930588ebc1..81cc03b84bf0 100644 --- a/gossipd/routing.c +++ b/gossipd/routing.c @@ -86,7 +86,8 @@ static struct node_map *empty_node_map(const tal_t *ctx) struct routing_state *new_routing_state(const tal_t *ctx, const struct bitcoin_blkid *chain_hash, const struct pubkey *local_id, - u32 prune_timeout) + u32 prune_timeout, + bool dev_allow_localhost) { struct routing_state *rstate = tal(ctx, struct routing_state); rstate->nodes = empty_node_map(rstate); @@ -95,6 +96,7 @@ struct routing_state *new_routing_state(const tal_t *ctx, rstate->local_id = *local_id; rstate->prune_timeout = prune_timeout; rstate->store = gossip_store_new(rstate); + rstate->dev_allow_localhost = dev_allow_localhost; list_head_init(&rstate->pending_cannouncement); uintmap_init(&rstate->chanmap); diff --git a/gossipd/routing.h b/gossipd/routing.h index 6c131207434b..45867b32aaf7 100644 --- a/gossipd/routing.h +++ b/gossipd/routing.h @@ -162,6 +162,9 @@ struct routing_state { * restarts */ struct gossip_store *store; + /* For testing, we announce and accept localhost */ + bool dev_allow_localhost; + /* A map of channels indexed by short_channel_ids */ UINTMAP(struct chan *) chanmap; }; @@ -183,7 +186,8 @@ struct route_hop { struct routing_state *new_routing_state(const tal_t *ctx, const struct bitcoin_blkid *chain_hash, const struct pubkey *local_id, - u32 prune_timeout); + u32 prune_timeout, + bool dev_allow_localhost); struct chan *new_chan(struct routing_state *rstate, const struct short_channel_id *scid, diff --git a/gossipd/test/run-bench-find_route.c b/gossipd/test/run-bench-find_route.c index 6a7f85c5a919..2b24a12b0d4d 100644 --- a/gossipd/test/run-bench-find_route.c +++ b/gossipd/test/run-bench-find_route.c @@ -219,7 +219,7 @@ int main(int argc, char *argv[]) | SECP256K1_CONTEXT_SIGN); setup_tmpctx(); - rstate = new_routing_state(tmpctx, &zerohash, &me, 0); + rstate = new_routing_state(tmpctx, &zerohash, &me, 0, false); opt_register_noarg("--perfme", opt_set_bool, &perfme, "Run perfme-start and perfme-stop around benchmark"); diff --git a/gossipd/test/run-find_route-specific.c b/gossipd/test/run-find_route-specific.c index 9a980327a872..c1d5fd1abd06 100644 --- a/gossipd/test/run-find_route-specific.c +++ b/gossipd/test/run-find_route-specific.c @@ -152,7 +152,7 @@ int main(void) strlen("02ea622d5c8d6143f15ed3ce1d501dd0d3d09d3b1c83a44d0034949f8a9ab60f06"), &c); - rstate = new_routing_state(tmpctx, &zerohash, &a, 0); + rstate = new_routing_state(tmpctx, &zerohash, &a, 0, false); /* [{'active': True, 'short_id': '6990:2:1/1', 'fee_per_kw': 10, 'delay': 5, 'flags': 1, 'destination': '0230ad0e74ea03976b28fda587bb75bdd357a1938af4424156a18265167f5e40ae', 'source': '02ea622d5c8d6143f15ed3ce1d501dd0d3d09d3b1c83a44d0034949f8a9ab60f06', 'last_update': 1504064344}, */ nc = get_or_make_connection(rstate, &c, &b, "6990:2:1"); diff --git a/gossipd/test/run-find_route.c b/gossipd/test/run-find_route.c index 2eefc9eff8e4..e166c04184d1 100644 --- a/gossipd/test/run-find_route.c +++ b/gossipd/test/run-find_route.c @@ -188,7 +188,7 @@ int main(void) memset(&tmp, 'a', sizeof(tmp)); pubkey_from_privkey(&tmp, &a); - rstate = new_routing_state(tmpctx, &zerohash, &a, 0); + rstate = new_routing_state(tmpctx, &zerohash, &a, 0, false); new_node(rstate, &a); diff --git a/gossipd/test/run-initiator-success.c b/gossipd/test/run-initiator-success.c index 3932deeacad0..2efeb4e7d753 100644 --- a/gossipd/test/run-initiator-success.c +++ b/gossipd/test/run-initiator-success.c @@ -176,7 +176,7 @@ static struct io_plan *test_read(struct io_conn *conn, static struct io_plan *success(struct io_conn *conn UNUSED, const struct pubkey *them, - const struct wireaddr *addr UNUSED, + const struct wireaddr_internal *addr UNUSED, const struct crypto_state *cs, void *unused UNUSED) { @@ -201,7 +201,7 @@ int main(void) { setup_locale(); - struct wireaddr dummy; + struct wireaddr_internal dummy; secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); @@ -223,7 +223,8 @@ int main(void) e_priv = privkey("1212121212121212121212121212121212121212121212121212121212121212"); e_pub = pubkey("036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f7"); - dummy.addrlen = 0; + dummy.itype = ADDR_INTERNAL_WIREADDR; + dummy.u.wireaddr.addrlen = 0; initiator_handshake((void *)tmpctx, &ls_pub, &rs_pub, &dummy, success, NULL); /* Should not exit! */ abort(); diff --git a/gossipd/test/run-responder-success.c b/gossipd/test/run-responder-success.c index a65c4c96f159..2130edc1187f 100644 --- a/gossipd/test/run-responder-success.c +++ b/gossipd/test/run-responder-success.c @@ -175,7 +175,7 @@ static struct io_plan *test_read(struct io_conn *conn, static struct io_plan *success(struct io_conn *conn UNUSED, const struct pubkey *them UNUSED, - const struct wireaddr *addr UNUSED, + const struct wireaddr_internal *addr UNUSED, const struct crypto_state *cs, void *unused UNUSED) { @@ -198,7 +198,7 @@ int main(void) { setup_locale(); - struct wireaddr dummy; + struct wireaddr_internal dummy; secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); @@ -218,7 +218,8 @@ int main(void) e_priv = privkey("2222222222222222222222222222222222222222222222222222222222222222"); e_pub = pubkey("02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27"); - dummy.addrlen = 0; + dummy.itype = ADDR_INTERNAL_WIREADDR; + dummy.u.wireaddr.addrlen = 0; responder_handshake((void *)tmpctx, &ls_pub, &dummy, success, NULL); /* Should not exit! */ abort(); diff --git a/lightningd/Makefile b/lightningd/Makefile index 0615a70a3539..d925c4c0d9fe 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -66,7 +66,6 @@ LIGHTNINGD_SRC := \ lightningd/lightningd.c \ lightningd/log.c \ lightningd/log_status.c \ - lightningd/netaddress.c \ lightningd/onchain_control.c \ lightningd/opening_control.c \ lightningd/opt_time.c \ diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c index 3fa915e3ccd4..9ee955b38886 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -85,7 +85,7 @@ static void json_connect(struct command *cmd, char *atptr; char *ataddr = NULL; const char *name; - struct wireaddr addr; + struct wireaddr_internal addr; u8 *msg; const char *err_msg; @@ -139,22 +139,22 @@ static void json_connect(struct command *cmd, /* Was there parseable host name? */ if (name) { + u32 port; /* Is there a port? */ if (porttok) { - u32 port; - if (!json_tok_number(buffer, porttok, &port)) { + if (!json_tok_number(buffer, porttok, &port) || !port) { command_fail(cmd, "Port %.*s not valid", porttok->end - porttok->start, buffer + porttok->start); return; } - addr.port = port; } else { - addr.port = DEFAULT_PORT; + port = DEFAULT_PORT; } - if (!parse_wireaddr(name, &addr, addr.port, &err_msg) || !addr.port) { + if (!parse_wireaddr_internal(name, &addr, port, false, + &err_msg)) { command_fail(cmd, "Host %s:%u not valid: %s", - name, addr.port, err_msg ? err_msg : "port is 0"); + name, port, err_msg ? err_msg : "port is 0"); return; } diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 09a3227686cd..ba895748df8c 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -35,7 +35,7 @@ static void peer_nongossip(struct subd *gossip, const u8 *msg, { struct pubkey id; struct crypto_state cs; - struct wireaddr addr; + struct wireaddr_internal addr; u8 *gfeatures, *lfeatures, *in_pkt; if (!fromwire_gossip_peer_nongossip(msg, msg, @@ -183,10 +183,12 @@ void gossip_init(struct lightningd *ld) u8 *msg; int hsmfd; u64 capabilities = HSM_CAP_ECDH | HSM_CAP_SIGN_GOSSIP; + struct wireaddr_internal *wireaddrs = ld->proposed_wireaddr; + enum addr_listen_announce *listen_announce = ld->proposed_listen_announce; + bool allow_localhost = false; #if DEVELOPER - bool no_reconnect = ld->no_reconnect; -#else - bool no_reconnect = false; + if (ld->dev_allow_localhost) + allow_localhost = true; #endif msg = towire_hsm_client_hsmfd(tmpctx, &ld->id, capabilities); @@ -207,27 +209,46 @@ void gossip_init(struct lightningd *ld) if (!ld->gossip) err(1, "Could not subdaemon gossip"); + /* If no addr specified, hand wildcard to gossipd */ + if (tal_count(wireaddrs) == 0 && ld->autolisten) { + 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; + *listen_announce = ADDR_LISTEN_AND_ANNOUNCE; + } + msg = towire_gossipctl_init( 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, - ld->alias, ld->config.channel_update_interval, no_reconnect); + get_offered_local_features(tmpctx), wireaddrs, + listen_announce, ld->rgb, + ld->alias, ld->config.channel_update_interval, ld->reconnect, + allow_localhost); subd_send_msg(ld->gossip, msg); } static void gossip_activate_done(struct subd *gossip UNUSED, - const u8 *reply UNUSED, + const u8 *reply, const int *fds UNUSED, void *unused UNUSED) { + struct lightningd *ld = gossip->ld; + + if (!fromwire_gossipctl_activate_reply(gossip->ld, reply, + &ld->binding, + &ld->announcable)) + fatal("Bad gossipctl_activate_reply: %s", + tal_hex(reply, reply)); + /* Break out of loop, so we can begin */ io_break(gossip); } void gossip_activate(struct lightningd *ld) { - const u8 *msg = towire_gossipctl_activate(NULL, ld->portnum); + 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/json.c b/lightningd/json.c index 05ab73bb3fc3..b401ca00a935 100644 --- a/lightningd/json.c +++ b/lightningd/json.c @@ -1,6 +1,7 @@ #include "json.h" #include #include +#include #include #include #include @@ -142,3 +143,26 @@ void json_add_address(struct json_result *response, const char *fieldname, json_object_end(response); } +void json_add_address_internal(struct json_result *response, + const char *fieldname, + const struct wireaddr_internal *addr) +{ + switch (addr->itype) { + case ADDR_INTERNAL_SOCKNAME: + json_object_start(response, fieldname); + json_add_string(response, "type", "local socket"); + json_add_string(response, "socket", addr->u.sockname); + json_object_end(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); + json_object_end(response); + return; + case ADDR_INTERNAL_WIREADDR: + json_add_address(response, fieldname, &addr->u.wireaddr); + return; + } + abort(); +} diff --git a/lightningd/json.h b/lightningd/json.h index 2e4230d3b4bb..29b629884a82 100644 --- a/lightningd/json.h +++ b/lightningd/json.h @@ -19,6 +19,7 @@ struct route_hop; struct short_channel_id; struct wallet_payment; struct wireaddr; +struct wireaddr_internal; /* Output a route array. */ void json_add_route(struct json_result *r, char const *n, @@ -58,5 +59,8 @@ bool json_tok_channel_id(const char *buffer, const jsmntok_t *tok, void json_add_address(struct json_result *response, const char *fieldname, const struct wireaddr *addr); - +/* JSON serialize a network address for a node. */ +void json_add_address_internal(struct json_result *response, + const char *fieldname, + const struct wireaddr_internal *addr); #endif /* LIGHTNING_LIGHTNINGD_JSON_H */ diff --git a/lightningd/jsonrpc.c b/lightningd/jsonrpc.c index 02a109377468..8fda08270bb1 100644 --- a/lightningd/jsonrpc.c +++ b/lightningd/jsonrpc.c @@ -149,11 +149,21 @@ static void json_getinfo(struct command *cmd, json_object_start(response, NULL); json_add_pubkey(response, "id", &cmd->ld->id); - if (cmd->ld->portnum) { - json_add_num(response, "port", cmd->ld->portnum); + if (cmd->ld->listen) { + 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->announcable); i++) + json_add_address(response, NULL, cmd->ld->announcable+i); + json_array_end(response); + + /* This is what we're actually bound to. */ + json_array_start(response, "binding"); + for (size_t i = 0; i < tal_count(cmd->ld->binding); i++) + json_add_address_internal(response, NULL, + cmd->ld->binding+i); json_array_end(response); } json_add_string(response, "version", version()); diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index 4861d9149e58..5a297563bfea 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -51,7 +51,7 @@ static struct lightningd *new_lightningd(const tal_t *ctx) ld->dev_debug_subdaemon = NULL; ld->dev_disconnect_fd = -1; ld->dev_subdaemon_fail = false; - ld->no_reconnect = false; + ld->dev_allow_localhost = false; if (getenv("LIGHTNINGD_DEV_MEMLEAK")) memleak_init(ld, backtrace_state); @@ -70,8 +70,12 @@ static struct lightningd *new_lightningd(const tal_t *ctx) list_head_init(&ld->waitsendpay_commands); list_head_init(&ld->sendpay_commands); list_head_init(&ld->close_commands); - ld->wireaddrs = tal_arr(ld, struct wireaddr, 0); + ld->proposed_wireaddr = tal_arr(ld, struct wireaddr_internal, 0); + ld->proposed_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); ld->debug_subdaemon_io = NULL; diff --git a/lightningd/lightningd.h b/lightningd/lightningd.h index b17c50df7d8e..d711a58b6129 100644 --- a/lightningd/lightningd.h +++ b/lightningd/lightningd.h @@ -111,8 +111,23 @@ struct lightningd { /* Port we're listening on */ u16 portnum; - /* Addresses to announce to the network (tal_count()) */ - struct wireaddr *wireaddrs; + /* Do we want to reconnect to other peers? */ + bool reconnect; + + /* Do we want to listen for other peers? */ + bool listen; + + /* Do we want to guess addresses to listen and announce? */ + bool autolisten; + + /* Setup: Addresses to bind/announce to the network (tal_count()) */ + struct wireaddr_internal *proposed_wireaddr; + /* Setup: And the bitset for each, whether to listen, announce or both */ + enum addr_listen_announce *proposed_listen_announce; + + /* Actual bindings and announcables from gossipd */ + struct wireaddr_internal *binding; + struct wireaddr *announcable; /* Bearer of all my secrets. */ int hsm_fd; @@ -160,9 +175,6 @@ struct lightningd { /* May be useful for non-developers debugging in the field */ char *debug_subdaemon_io; - /* Disable automatic reconnects */ - bool no_reconnect; - /* Initial autocleaninvoice settings. */ u64 ini_autocleaninvoice_cycle; u64 ini_autocleaninvoice_expiredby; @@ -177,6 +189,9 @@ struct lightningd { /* If we have --dev-fail-on-subdaemon-fail */ bool dev_subdaemon_fail; + /* Allow and accept localhost node_announcement addresses */ + bool dev_allow_localhost; + /* Things we've marked as not leaking. */ const void **notleaks; #endif /* DEVELOPER */ diff --git a/lightningd/netaddress.h b/lightningd/netaddress.h deleted file mode 100644 index a2428a9e7487..000000000000 --- a/lightningd/netaddress.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef LIGHTNING_LIGHTNINGD_NETADDRESS_H -#define LIGHTNING_LIGHTNINGD_NETADDRESS_H -#include "config.h" -#include - -struct lightningd; - -void guess_addresses(struct lightningd *ld); - - -#endif /* LIGHTNING_LIGHTNINGD_NETADDRESS_H */ diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 46aea9725d5d..77f101fd5244 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -257,13 +257,6 @@ void tell_gossipd_peer_is_important(struct lightningd *ld, { u8 *msg; -#if DEVELOPER - /* Don't schedule an attempt if we disabled reconnections with - * the `--dev-no-reconnect` flag */ - if (ld->no_reconnect) - return; -#endif /* DEVELOPER */ - /* Tell gossipd we need to keep connection to this peer */ msg = towire_gossipctl_peer_important(NULL, &channel->peer->id, true); subd_send_msg(ld->gossip, take(msg)); @@ -593,7 +586,7 @@ static struct uncommitted_channel * new_uncommitted_channel(struct lightningd *ld, struct funding_channel *fc, const struct pubkey *peer_id, - const struct wireaddr *addr) + const struct wireaddr_internal *addr) { struct uncommitted_channel *uc = tal(ld, struct uncommitted_channel); char *idname; @@ -678,7 +671,7 @@ static void channel_config(struct lightningd *ld, u8 *peer_accept_channel(const tal_t *ctx, struct lightningd *ld, const struct pubkey *peer_id, - const struct wireaddr *addr, + const struct wireaddr_internal *addr, const struct crypto_state *cs, const u8 *gfeatures UNUSED, const u8 *lfeatures UNUSED, int peer_fd, int gossip_fd, @@ -752,7 +745,7 @@ u8 *peer_accept_channel(const tal_t *ctx, static void peer_offer_channel(struct lightningd *ld, struct funding_channel *fc, - const struct wireaddr *addr, + const struct wireaddr_internal *addr, const struct crypto_state *cs, const u8 *gfeatures UNUSED, const u8 *lfeatures UNUSED, int peer_fd, int gossip_fd) @@ -833,7 +826,7 @@ static void gossip_peer_released(struct subd *gossip, struct lightningd *ld = gossip->ld; struct crypto_state cs; u8 *gfeatures, *lfeatures; - struct wireaddr addr; + struct wireaddr_internal addr; struct channel *c; struct uncommitted_channel *uc; @@ -876,7 +869,7 @@ static void gossip_peer_released(struct subd *gossip, * released. */ bool handle_opening_channel(struct lightningd *ld, const struct pubkey *id, - const struct wireaddr *addr, + const struct wireaddr_internal *addr, const struct crypto_state *cs, const u8 *gfeatures, const u8 *lfeatures, int peer_fd, int gossip_fd) diff --git a/lightningd/opening_control.h b/lightningd/opening_control.h index bbd2781af30e..eca131decc8a 100644 --- a/lightningd/opening_control.h +++ b/lightningd/opening_control.h @@ -9,7 +9,7 @@ struct json_result; struct lightningd; struct pubkey; struct uncommitted_channel; -struct wireaddr; +struct wireaddr_internal; void json_add_uncommitted_channel(struct json_result *response, const struct uncommitted_channel *uc); @@ -21,7 +21,7 @@ void json_add_uncommitted_channel(struct json_result *response, u8 *peer_accept_channel(const tal_t *ctx, struct lightningd *ld, const struct pubkey *peer_id, - const struct wireaddr *addr, + const struct wireaddr_internal *addr, const struct crypto_state *cs, const u8 *gfeatures, const u8 *lfeatures, int peer_fd, int gossip_fd, @@ -32,7 +32,7 @@ u8 *peer_accept_channel(const tal_t *ctx, * so we could open a channel? Returns true if it took over. */ bool handle_opening_channel(struct lightningd *ld, const struct pubkey *id, - const struct wireaddr *addr, + const struct wireaddr_internal *addr, const struct crypto_state *cs, const u8 *gfeatures, const u8 *lfeatures, int peer_fd, int gossip_fd); diff --git a/lightningd/options.c b/lightningd/options.c index 12a973e1efeb..0f83e1cb1657 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -102,11 +101,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 +117,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,23 +145,51 @@ static char *opt_set_s32(const char *arg, s32 *u) return NULL; } -static char *opt_add_ipaddr(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); + size_t n = tal_count(ld->proposed_wireaddr); char const *err_msg; assert(arg != NULL); - tal_resize(&ld->wireaddrs, n+1); + tal_resize(&ld->proposed_wireaddr, n+1); + tal_resize(&ld->proposed_listen_announce, n+1); + ld->proposed_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); + if (!parse_wireaddr_internal(arg, &ld->proposed_wireaddr[n], ld->portnum, + true, &err_msg)) { + return tal_fmt(NULL, "Unable to parse address '%s': %s", arg, err_msg); } return NULL; } +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"); + if (!deprecated_apis) + return "--ipaddr is deprecated"; + return opt_add_addr(arg, ld); +} + static void opt_show_u64(char buf[OPT_SHOW_LEN], const u64 *u) { snprintf(buf, OPT_SHOW_LEN, "%"PRIu64, *u); @@ -169,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); @@ -259,8 +289,9 @@ static char *opt_set_fee_rates(const char *arg, struct chain_topology *topo) static char *opt_set_offline(struct lightningd *ld) { - ld->portnum = 0; - ld->no_reconnect = true; + ld->reconnect = false; + ld->listen = false; + return NULL; } @@ -327,10 +358,22 @@ static void config_register_opts(struct lightningd *ld) &ld->config.fee_per_satoshi, "Microsatoshi fee for every satoshi in HTLC"); opt_register_arg("--ipaddr", opt_add_ipaddr, NULL, + ld, opt_hidden); + opt_register_arg("--addr", opt_add_addr, NULL, + ld, + "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 the IP address (v4 or v6) to announce to the network for incoming connections"); + "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"); + "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, @@ -340,10 +383,10 @@ static void config_register_opts(struct lightningd *ld) "Alias for --network=testnet"); opt_register_early_noarg("--mainnet", opt_set_mainnet, ld, "Alias for --network=bitcoin"); - opt_register_arg("--allow-deprecated-apis", - opt_set_bool_arg, opt_show_bool, - &deprecated_apis, - "Enable deprecated options, JSONRPC commands, fields, etc."); + opt_register_early_arg("--allow-deprecated-apis", + opt_set_bool_arg, opt_show_bool, + &deprecated_apis, + "Enable deprecated options, JSONRPC commands, fields, etc."); opt_register_arg("--debug-subdaemon-io", opt_set_charp, NULL, &ld->debug_subdaemon_io, "Enable full peer IO logging in subdaemons ending in this string (can also send SIGUSR1 to toggle)"); @@ -360,8 +403,8 @@ static void config_register_opts(struct lightningd *ld) #if DEVELOPER static void dev_register_opts(struct lightningd *ld) { - opt_register_noarg("--dev-no-reconnect", opt_set_bool, - &ld->no_reconnect, + opt_register_noarg("--dev-no-reconnect", opt_set_invbool, + &ld->reconnect, "Disable automatic reconnect attempts"); opt_register_noarg("--dev-fail-on-subdaemon-fail", opt_set_bool, &ld->dev_subdaemon_fail, opt_hidden); @@ -372,6 +415,9 @@ static void dev_register_opts(struct lightningd *ld) "Time between gossip broadcasts in milliseconds"); opt_register_arg("--dev-disconnect=", opt_subd_dev_disconnect, NULL, ld, "File containing disconnection points"); + opt_register_noarg("--dev-allow-localhost", opt_set_bool, + &ld->dev_allow_localhost, + "Announce and allow announcments for localhost address"); } #endif @@ -638,8 +684,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"); @@ -766,12 +812,6 @@ void handle_opts(struct lightningd *ld, int argc, char *argv[]) errx(1, "no arguments accepted"); check_config(ld); - - if (ld->portnum && tal_count(ld->wireaddrs) == 0) - guess_addresses(ld); - else - log_debug(ld->log, "Not guessing addresses: %s", - ld->portnum ? "manually set" : "port set to zero"); } /* FIXME: This is a hack! Expose somehow in ccan/opt.*/ @@ -790,6 +830,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_internal *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_internal(name0, wireaddrs+i)); + } +} + static void add_config(struct lightningd *ld, struct json_result *response, const struct opt_table *opt, @@ -804,12 +859,18 @@ static void add_config(struct lightningd *ld, /* These two show up as --network= */ || opt->cb == (void *)opt_set_testnet || opt->cb == (void *)opt_set_mainnet - || opt->cb == (void *)opt_set_offline /* will show up as port=0 and --no-reconnect */ || opt->cb == (void *)test_daemons_and_exit) { /* These are not important */ } else if (opt->cb == (void *)opt_set_bool) { const bool *b = opt->u.carg; answer = tal_fmt(name0, "%s", *b ? "true" : "false"); + } else if (opt->cb == (void *)opt_set_invbool) { + const bool *b = opt->u.carg; + answer = tal_fmt(name0, "%s", !*b ? "true" : "false"); + } else if (opt->cb == (void *)opt_set_offline) { + answer = tal_fmt(name0, "%s", + (!ld->reconnect && !ld->listen) + ? "true" : "false"); } else { /* Insert more decodes here! */ abort(); @@ -853,14 +914,28 @@ 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) { - /* 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)); - } + /* Covered by opt_add_addr below */ + } else if (opt->cb_arg == (void *)opt_add_addr) { + json_add_opt_addrs(response, name0, + ld->proposed_wireaddr, + ld->proposed_listen_announce, + ADDR_LISTEN_AND_ANNOUNCE); + return; + } else if (opt->cb_arg == (void *)opt_add_bind_addr) { + json_add_opt_addrs(response, name0, + ld->proposed_wireaddr, + ld->proposed_listen_announce, + ADDR_LISTEN); + return; + } else if (opt->cb_arg == (void *)opt_add_announce_addr) { + json_add_opt_addrs(response, name0, + ld->proposed_wireaddr, + ld->proposed_listen_announce, + ADDR_ANNOUNCE); return; #if DEVELOPER } else if (strstarts(name, "dev-")) { diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 3730409dc218..77b1ad0870b2 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -78,7 +77,7 @@ static void copy_to_parent_log(const char *prefix, struct peer *new_peer(struct lightningd *ld, u64 dbid, const struct pubkey *id, - const struct wireaddr *addr) + const struct wireaddr_internal *addr) { /* We are owned by our channels, and freed manually by destroy_channel */ struct peer *peer = tal(NULL, struct peer); @@ -87,10 +86,13 @@ struct peer *new_peer(struct lightningd *ld, u64 dbid, peer->dbid = dbid; peer->id = *id; peer->uncommitted_channel = NULL; + /* FIXME: This is always set, right? */ if (addr) peer->addr = *addr; - else - peer->addr.type = ADDR_TYPE_PADDING; + else { + peer->addr.itype = ADDR_INTERNAL_WIREADDR; + peer->addr.u.wireaddr.type = ADDR_TYPE_PADDING; + } list_head_init(&peer->channels); peer->direction = get_channel_direction(&peer->ld->id, &peer->id); @@ -424,7 +426,7 @@ void peer_connected(struct lightningd *ld, const u8 *msg, u8 *global_features; u8 *local_features; struct channel *channel; - struct wireaddr addr; + struct wireaddr_internal addr; struct uncommitted_channel *uc; if (!fromwire_gossip_peer_connected(msg, msg, @@ -544,7 +546,7 @@ static struct channel *channel_by_channel_id(struct peer *peer, /* We only get here IF we weren't trying to connect to it. */ void peer_sent_nongossip(struct lightningd *ld, const struct pubkey *id, - const struct wireaddr *addr, + const struct wireaddr_internal *addr, const struct crypto_state *cs, const u8 *gfeatures, const u8 *lfeatures, @@ -746,7 +748,7 @@ static void gossipd_getpeers_complete(struct subd *gossip, const u8 *msg, { /* This is a little sneaky... */ struct pubkey *ids; - struct wireaddr *addrs; + struct wireaddr_internal *addrs; struct gossip_getnodes_entry **nodes; struct json_result *response = new_json_result(gpa->cmd); struct peer *p; @@ -781,10 +783,11 @@ static void gossipd_getpeers_complete(struct subd *gossip, const u8 *msg, if (connected) { json_array_start(response, "netaddr"); - if (p->addr.type != ADDR_TYPE_PADDING) + if (p->addr.itype != ADDR_INTERNAL_WIREADDR + || p->addr.u.wireaddr.type != ADDR_TYPE_PADDING) json_add_string(response, NULL, type_to_string(response, - struct wireaddr, + struct wireaddr_internal, &p->addr)); json_array_end(response); } @@ -922,9 +925,11 @@ static void gossipd_getpeers_complete(struct subd *gossip, const u8 *msg, json_add_pubkey(response, "id", ids+i); json_add_node_decoration(response, nodes, ids+i); json_array_start(response, "netaddr"); - if (addrs[i].type != ADDR_TYPE_PADDING) + if (addrs[i].itype != ADDR_INTERNAL_WIREADDR + || addrs[i].u.wireaddr.type != ADDR_TYPE_PADDING) json_add_string(response, NULL, - type_to_string(response, struct wireaddr, + type_to_string(response, + struct wireaddr_internal, addrs + i)); json_array_end(response); json_add_bool(response, "connected", true); diff --git a/lightningd/peer_control.h b/lightningd/peer_control.h index eb56bcb64440..c87bed3f9754 100644 --- a/lightningd/peer_control.h +++ b/lightningd/peer_control.h @@ -41,7 +41,7 @@ struct peer { struct log_book *log_book; /* Where we connected to, or it connected from. */ - struct wireaddr addr; + struct wireaddr_internal addr; /* If we open a channel our direction will be this */ u8 direction; @@ -56,7 +56,7 @@ struct peer *find_peer_by_dbid(struct lightningd *ld, u64 dbid); struct peer *new_peer(struct lightningd *ld, u64 dbid, const struct pubkey *id, - const struct wireaddr *addr); + const struct wireaddr_internal *addr); /* Also removes from db. */ void delete_peer(struct peer *peer); @@ -78,7 +78,7 @@ void peer_connected(struct lightningd *ld, const u8 *msg, void peer_sent_nongossip(struct lightningd *ld, const struct pubkey *id, - const struct wireaddr *addr, + const struct wireaddr_internal *addr, const struct crypto_state *cs, const u8 *gfeatures, const u8 *lfeatures, diff --git a/tests/test_gossip.py b/tests/test_gossip.py index 963cc183cd90..e595d863d71e 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 0444fb894c10..c0251352cb87 100644 --- a/tests/test_lightningd.py +++ b/tests/test_lightningd.py @@ -208,7 +208,7 @@ def get_node(self, disconnect=None, options=None, may_fail=False, may_reconnect= ] try: - node.daemon.start() + node.start() except Exception: node.daemon.stop() raise @@ -329,7 +329,7 @@ def tearDown(self): class LightningDTests(BaseLightningDTests): def connect(self, may_reconnect=False): l1, l2 = self.node_factory.get_nodes(2, opts={'may_reconnect': may_reconnect}) - ret = l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + ret = l1.rpc.connect(l2.info['id'], 'localhost', l2.port) assert ret['id'] == l2.info['id'] @@ -639,10 +639,10 @@ def test_connect(self): l2.daemon.wait_for_log('hand_back_peer {}: now local again'.format(l1.info['id'])) # Reconnect should be a noop - ret = l1.rpc.connect(l2.info['id'], 'localhost', port=l2.info['port']) + ret = l1.rpc.connect(l2.info['id'], 'localhost', port=l2.port) assert ret['id'] == l2.info['id'] - ret = l2.rpc.connect(l1.info['id'], host='localhost', port=l1.info['port']) + ret = l2.rpc.connect(l1.info['id'], host='localhost', port=l1.port) assert ret['id'] == l1.info['id'] # Should still only have one peer! @@ -662,16 +662,17 @@ def test_connect(self): # Should get reasonable error if wrong key for peer. self.assertRaisesRegex(ValueError, "Cryptographic handshake: ", - l1.rpc.connect, '032cf15d1ad9c4a08d26eab1918f732d8ef8fdc6abb9640bf3db174372c491304e', 'localhost', l2.info['port']) + l1.rpc.connect, '032cf15d1ad9c4a08d26eab1918f732d8ef8fdc6abb9640bf3db174372c491304e', 'localhost', l2.port) + @unittest.skipIf(not DEVELOPER, "needs --dev-allow-localhost") def test_connect_by_gossip(self): """Test connecting to an unknown peer using node gossip """ l1 = self.node_factory.get_node() l2 = self.node_factory.get_node() - l3 = self.node_factory.get_node(options={"ipaddr": "127.0.0.1"}) + l3 = self.node_factory.get_node() - l2.rpc.connect(l3.info['id'], 'localhost', l3.info['port']) + l2.rpc.connect(l3.info['id'], 'localhost', l3.port) # Nodes are gossiped only if they have channels chanid = self.fund_channel(l2, l3, 10**6) @@ -681,7 +682,7 @@ def test_connect_by_gossip(self): l2.daemon.wait_for_logs(['Received node_announcement for node {}'.format(l3.info['id'])]) # Let l1 learn of l3 by node gossip - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l1.daemon.wait_for_logs(['Received node_announcement for node {}'.format(l3.info['id'])]) # Have l1 connect to l3 without explicit host and port. @@ -695,31 +696,30 @@ def test_connect_standard_addr(self): l3 = self.node_factory.get_node() # node@host - ret = l1.rpc.connect("{}@{}".format(l2.info['id'], 'localhost'), port=l2.info['port']) + ret = l1.rpc.connect("{}@{}".format(l2.info['id'], 'localhost'), port=l2.port) assert ret['id'] == l2.info['id'] # node@host:port - ret = l1.rpc.connect("{}@localhost:{}".format(l3.info['id'], l3.info['port'])) + ret = l1.rpc.connect("{}@localhost:{}".format(l3.info['id'], l3.port)) assert ret['id'] == l3.info['id'] # node@[ipv6]:port --- not supported by our CI - # ret = l1.rpc.connect("{}@[::1]:{}".format(l3.info['id'], l3.info['port'])) + # ret = l1.rpc.connect("{}@[::1]:{}".format(l3.info['id'], l3.port)) # assert ret['id'] == l3.info['id'] def test_reconnect_channel_peers(self): l1 = self.node_factory.get_node(may_reconnect=True) l2 = self.node_factory.get_node(may_reconnect=True) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.fund_channel(l1, l2, 10**6) - l2.stop() - l2.daemon.start() + l2.restart() # Should reconnect. wait_for(lambda: l1.rpc.listpeers(l2.info['id'])['peers'][0]['connected']) wait_for(lambda: l2.rpc.listpeers(l1.info['id'])['peers'][0]['connected']) # Connect command should succeed. - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) # Stop l2 and wait for l1 to notice. l2.stop() @@ -728,18 +728,18 @@ def test_reconnect_channel_peers(self): # Now should fail. self.assertRaisesRegex(ValueError, "Connection refused", - l1.rpc.connect, l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect, l2.info['id'], 'localhost', l2.port) # Wait for exponential backoff to give us a 2 second window. l1.daemon.wait_for_log('...will try again in 2 seconds') # It should now succeed when it restarts. - l2.daemon.start() + l2.start() # Multiples should be fine! - fut1 = self.executor.submit(l1.rpc.connect, l2.info['id'], 'localhost', l2.info['port']) - fut2 = self.executor.submit(l1.rpc.connect, l2.info['id'], 'localhost', l2.info['port']) - fut3 = self.executor.submit(l1.rpc.connect, l2.info['id'], 'localhost', l2.info['port']) + fut1 = self.executor.submit(l1.rpc.connect, l2.info['id'], 'localhost', l2.port) + fut2 = self.executor.submit(l1.rpc.connect, l2.info['id'], 'localhost', l2.port) + fut3 = self.executor.submit(l1.rpc.connect, l2.info['id'], 'localhost', l2.port) fut1.result(10) fut2.result(10) fut3.result(10) @@ -1246,7 +1246,7 @@ def test_report_routing_failure(self): # l1-l2-l3-l4. def fund_from_to_payer(lsrc, ldst, lpayer): - lsrc.rpc.connect(ldst.info['id'], 'localhost', ldst.info['port']) + lsrc.rpc.connect(ldst.info['id'], 'localhost', ldst.port) c = self.fund_channel(lsrc, ldst, 10000000) self.wait_for_routes(lpayer, [c]) @@ -1276,7 +1276,7 @@ def test_bad_opening(self): # l1 asks for a too-long locktime l1 = self.node_factory.get_node(options={'locktime-blocks': 100}) l2 = self.node_factory.get_node(options={'max-locktime-blocks': 99}) - ret = l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + ret = l1.rpc.connect(l2.info['id'], 'localhost', l2.port) assert ret['id'] == l2.info['id'] @@ -1387,7 +1387,7 @@ def test_closing_while_disconnected(self): l1.rpc.close, chan, False, 0) l1.daemon.wait_for_log(' to CHANNELD_SHUTTING_DOWN') - l2.daemon.start() + l2.start() l1.daemon.wait_for_log(' to CLOSINGD_SIGEXCHANGE') l2.daemon.wait_for_log(' to CLOSINGD_SIGEXCHANGE') @@ -1416,7 +1416,7 @@ def test_db_upgrade(self): l1.db_manip("CREATE TABLE version (version INTEGER);") l1.db_manip("INSERT INTO version VALUES (1);") - l1.daemon.start() + l1.start() upgrades = l1.db_query("SELECT * from db_upgrades;") assert len(upgrades) == 1 assert(upgrades[0]['upgrade_from'] == 1) @@ -1465,7 +1465,7 @@ def test_closing_different_fees(self): }) p.feerate = feerate p.amount = amount - l1.rpc.connect(p.info['id'], 'localhost', p.info['port']) + l1.rpc.connect(p.info['id'], 'localhost', p.port) peers.append(p) for p in peers: @@ -1584,7 +1584,7 @@ def test_onchain_first_commit(self): # Make locktime different, as we once had them reversed! l2 = self.node_factory.get_node(options={'locktime-blocks': 10}) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.give_funds(l1, 10**6 + 1000000) @@ -1671,7 +1671,7 @@ def test_onchaind_replay(self): l2 = self.node_factory.get_node(options=options) btc = l1.bitcoin - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.fund_channel(l1, l2, 10**6) rhash = l2.rpc.invoice(10**8, 'onchaind_replay', 'desc')['payment_hash'] @@ -1722,7 +1722,7 @@ def test_onchain_dust_out(self): l1 = self.node_factory.get_node(disconnect=disconnects) l2 = self.node_factory.get_node() - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.fund_channel(l1, l2, 10**6) # Must be dust! @@ -1767,8 +1767,7 @@ def test_onchain_dust_out(self): l2.daemon.wait_for_log('onchaind complete, forgetting peer') # Restart l1, it should not crash! - l1.stop() - l1.daemon.start() + l1.restart() # Now, 100 blocks and l1 should be done. bitcoind.generate_block(6) @@ -1785,10 +1784,10 @@ def test_onchain_timeout(self): l1 = self.node_factory.get_node(disconnect=disconnects) l2 = self.node_factory.get_node() - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l2 = self.node_factory.get_node() - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.fund_channel(l1, l2, 10**6) rhash = l2.rpc.invoice(10**8, 'onchain_timeout', 'desc')['payment_hash'] @@ -1856,8 +1855,8 @@ def test_onchain_middleman(self): l3 = self.node_factory.get_node() # l2 connects to both, so l1 can't reconnect and thus l2 drops to chain - l2.rpc.connect(l1.info['id'], 'localhost', l1.info['port']) - l2.rpc.connect(l3.info['id'], 'localhost', l3.info['port']) + l2.rpc.connect(l1.info['id'], 'localhost', l1.port) + l2.rpc.connect(l3.info['id'], 'localhost', l3.port) self.fund_channel(l2, l1, 10**6) c23 = self.fund_channel(l2, l3, 10**6) @@ -1929,7 +1928,7 @@ def test_penalty_inhtlc(self): l1 = self.node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED-nocommit'], may_fail=True) l2 = self.node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED-nocommit']) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.fund_channel(l1, l2, 10**6) # Now, this will get stuck due to l1 commit being disabled.. @@ -1992,7 +1991,7 @@ def test_penalty_outhtlc(self): l1 = self.node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED*3-nocommit'], may_fail=True) l2 = self.node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED*3-nocommit']) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.fund_channel(l1, l2, 10**6) # Move some across to l2. @@ -2059,7 +2058,7 @@ def test_onchain_feechange(self): l2 = self.node_factory.get_node(disconnect=disconnects, may_reconnect=True) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.fund_channel(l1, l2, 10**6) rhash = l2.rpc.invoice(10**8, 'onchain_timeout', 'desc')['payment_hash'] @@ -2093,7 +2092,7 @@ def test_onchain_feechange(self): l1.stop() l1.daemon.cmd_line.append('--override-fee-rates=20000/9000/2000') - l1.daemon.start() + l1.start() # We recognize different proposal as ours. l1.daemon.wait_for_log('Resolved THEIR_UNILATERAL/OUR_HTLC by our proposal OUR_HTLC_TIMEOUT_TO_US') @@ -2133,7 +2132,7 @@ def test_onchain_all_dust(self): l1 = self.node_factory.get_node(options={'dev-no-reconnect': None}) l2 = self.node_factory.get_node(disconnect=disconnects) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.fund_channel(l1, l2, 10**6) rhash = l2.rpc.invoice(10**8, 'onchain_timeout', 'desc')['payment_hash'] @@ -2239,7 +2238,7 @@ def test_permfail_new_commit(self): l1 = self.node_factory.get_node(options={'dev-no-reconnect': None}) l2 = self.node_factory.get_node(disconnect=disconnects) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.fund_channel(l1, l2, 10**6) # This will fail at l2's end. @@ -2275,7 +2274,7 @@ def test_permfail_htlc_in(self): l1 = self.node_factory.get_node(options={'dev-no-reconnect': None}) l2 = self.node_factory.get_node(disconnect=disconnects) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.fund_channel(l1, l2, 10**6) # This will fail at l2's end. @@ -2317,7 +2316,7 @@ def test_permfail_htlc_out(self): l1 = self.node_factory.get_node(options={'dev-no-reconnect': None}) l2 = self.node_factory.get_node(disconnect=disconnects) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.fund_channel(l2, l1, 10**6) # This will fail at l2's end. @@ -2440,7 +2439,7 @@ def test_gossip_weirdalias(self): assert l2.daemon.is_in_log('Server started with public key .* alias {}' .format(normal_name)) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.fund_channel(l2, l1, 10**6) bitcoind.rpc.generate(6) @@ -2468,9 +2467,9 @@ def test_gossip_persistence(self): l3 = self.node_factory.get_node(options=opts) l4 = self.node_factory.get_node(options=opts) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) - l2.rpc.connect(l3.info['id'], 'localhost', l3.info['port']) - l3.rpc.connect(l4.info['id'], 'localhost', l4.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + l2.rpc.connect(l3.info['id'], 'localhost', l3.port) + l3.rpc.connect(l4.info['id'], 'localhost', l4.port) self.fund_channel(l1, l2, 10**6) self.fund_channel(l2, l3, 10**6) @@ -2581,11 +2580,11 @@ def test_routing_gossip_reconnect(self): may_reconnect=True) l2 = self.node_factory.get_node(may_reconnect=True) l3 = self.node_factory.get_node() - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l1.openchannel(l2, 20000) # Now open new channels and everybody should sync - l2.rpc.connect(l3.info['id'], 'localhost', l3.info['port']) + l2.rpc.connect(l3.info['id'], 'localhost', l3.port) l2.openchannel(l3, 20000) # Settle the gossip @@ -2597,8 +2596,8 @@ def test_second_channel(self): l2 = self.node_factory.get_node() l3 = self.node_factory.get_node() - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) - l1.rpc.connect(l3.info['id'], 'localhost', l3.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + l1.rpc.connect(l3.info['id'], 'localhost', l3.port) self.fund_channel(l1, l2, 10**6) self.fund_channel(l1, l3, 10**6) @@ -2609,7 +2608,7 @@ def test_routing_gossip(self): for i in range(len(nodes) - 1): src, dst = nodes[i], nodes[i + 1] - src.rpc.connect(dst.info['id'], 'localhost', dst.info['port']) + src.rpc.connect(dst.info['id'], 'localhost', dst.port) src.openchannel(dst, 20000) # Allow announce messages. @@ -2648,7 +2647,7 @@ def test_forward(self): # Connect 1 -> 2 -> 3. l1, l2 = self.connect() l3 = self.node_factory.get_node() - ret = l2.rpc.connect(l3.info['id'], 'localhost', l3.info['port']) + ret = l2.rpc.connect(l3.info['id'], 'localhost', l3.port) assert ret['id'] == l3.info['id'] @@ -2744,13 +2743,13 @@ def test_forward_different_fees_and_cltv(self): l2 = self.node_factory.get_node(options={'cltv-delta': 20, 'fee-base': 200, 'fee-per-satoshi': 2000}) l3 = self.node_factory.get_node(options={'cltv-delta': 30, 'cltv-final': 9, 'fee-base': 300, 'fee-per-satoshi': 3000}) - ret = l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + ret = l1.rpc.connect(l2.info['id'], 'localhost', l2.port) assert ret['id'] == l2.info['id'] l1.daemon.wait_for_log('Handing back peer .* to master') l2.daemon.wait_for_log('Handing back peer .* to master') - ret = l2.rpc.connect(l3.info['id'], 'localhost', l3.info['port']) + ret = l2.rpc.connect(l3.info['id'], 'localhost', l3.port) assert ret['id'] == l3.info['id'] l2.daemon.wait_for_log('Handing back peer .* to master') @@ -2848,13 +2847,13 @@ def test_forward_pad_fees_and_cltv(self): l2 = self.node_factory.get_node(options={'cltv-delta': 20, 'fee-base': 200, 'fee-per-satoshi': 2000}) l3 = self.node_factory.get_node(options={'cltv-delta': 30, 'cltv-final': 9, 'fee-base': 300, 'fee-per-satoshi': 3000}) - ret = l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + ret = l1.rpc.connect(l2.info['id'], 'localhost', l2.port) assert ret['id'] == l2.info['id'] l1.daemon.wait_for_log('Handing back peer .* to master') l2.daemon.wait_for_log('Handing back peer .* to master') - ret = l2.rpc.connect(l3.info['id'], 'localhost', l3.info['port']) + ret = l2.rpc.connect(l3.info['id'], 'localhost', l3.port) assert ret['id'] == l3.info['id'] l2.daemon.wait_for_log('Handing back peer .* to master') @@ -2893,7 +2892,7 @@ def test_htlc_sig_persistence(self): l1 = self.node_factory.get_node(options={'dev-no-reconnect': None}) l2 = self.node_factory.get_node(disconnect=['+WIRE_COMMITMENT_SIGNED']) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.fund_channel(l1, l2, 10**6) f = self.executor.submit(self.pay, l1, l2, 31337000) l1.daemon.wait_for_log(r'HTLC out 0 RCVD_ADD_ACK_COMMIT->SENT_ADD_ACK_REVOCATION') @@ -2909,7 +2908,7 @@ def test_htlc_sig_persistence(self): l2.rpc.dev_fail(l1.info['id']) l2.stop() l1.bitcoin.rpc.generate(1) - l1.daemon.start() + l1.start() assert l1.daemon.is_in_log(r'Loaded 1 HTLC signatures from DB') l1.daemon.wait_for_logs([ @@ -2938,7 +2937,7 @@ def test_htlc_out_timeout(self): options={'dev-no-reconnect': None}) l2 = self.node_factory.get_node() - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) chanid = self.fund_channel(l1, l2, 10**6) # Wait for route propagation. @@ -2994,7 +2993,7 @@ def test_htlc_in_timeout(self): options={'dev-no-reconnect': None}) l2 = self.node_factory.get_node() - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) chanid = self.fund_channel(l1, l2, 10**6) self.wait_for_routes(l1, [chanid]) @@ -3044,12 +3043,12 @@ def test_disconnect(self): l2 = self.node_factory.get_node() self.assertRaises(ValueError, l1.rpc.connect, - l2.info['id'], 'localhost', l2.info['port']) + l2.info['id'], 'localhost', l2.port) self.assertRaises(ValueError, l1.rpc.connect, - l2.info['id'], 'localhost', l2.info['port']) + l2.info['id'], 'localhost', l2.port) self.assertRaises(ValueError, l1.rpc.connect, - l2.info['id'], 'localhost', l2.info['port']) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l2.info['id'], 'localhost', l2.port) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) # Should have 3 connect fails. for d in disconnects: @@ -3074,12 +3073,12 @@ def test_disconnect_funder(self): self.give_funds(l1, 2000000) for d in disconnects: - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.assertRaises(ValueError, l1.rpc.fundchannel, l2.info['id'], 20000) assert l1.rpc.getpeer(l2.info['id']) is None # This one will succeed. - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l1.rpc.fundchannel(l2.info['id'], 20000) # Should still only have one peer! @@ -3098,12 +3097,12 @@ def test_disconnect_fundee(self): self.give_funds(l1, 2000000) for d in disconnects: - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.assertRaises(ValueError, l1.rpc.fundchannel, l2.info['id'], 20000) assert l1.rpc.getpeer(l2.info['id']) is None # This one will succeed. - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l1.rpc.fundchannel(l2.info['id'], 20000) # Should still only have one peer! @@ -3120,7 +3119,7 @@ def test_disconnect_half_signed(self): self.give_funds(l1, 2000000) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.assertRaises(ValueError, l1.rpc.fundchannel, l2.info['id'], 20000) # Fundee remembers, funder doesn't. @@ -3137,7 +3136,7 @@ def test_reconnect_signed(self): self.give_funds(l1, 2000000) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l1.rpc.fundchannel(l2.info['id'], 20000) # They haven't forgotten each other. @@ -3160,7 +3159,7 @@ def test_reconnect_openingd(self): l1 = self.node_factory.get_node(may_reconnect=True) l2 = self.node_factory.get_node(disconnect=disconnects, may_reconnect=True) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.give_funds(l1, 2000000) @@ -3169,7 +3168,7 @@ def test_reconnect_openingd(self): assert l1.rpc.getpeer(l2.info['id']) is None # Reconnect. - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) # We should get a message about reconnecting, but order unsynced. l2.daemon.wait_for_logs(['gossipd.*reconnect for active peer', @@ -3191,7 +3190,7 @@ def test_reconnect_normal(self): l1 = self.node_factory.get_node(disconnect=disconnects, may_reconnect=True) l2 = self.node_factory.get_node(may_reconnect=True) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.fund_channel(l1, l2, 10**6) @@ -3205,7 +3204,7 @@ def test_reconnect_sender_add1(self): l1 = self.node_factory.get_node(disconnect=disconnects, may_reconnect=True) l2 = self.node_factory.get_node(may_reconnect=True) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.fund_channel(l1, l2, 10**6) @@ -3235,7 +3234,7 @@ def test_reconnect_sender_add(self): l1 = self.node_factory.get_node(disconnect=disconnects, may_reconnect=True) l2 = self.node_factory.get_node(may_reconnect=True) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.fund_channel(l1, l2, 10**6) @@ -3262,7 +3261,7 @@ def test_reconnect_receiver_add(self): l1 = self.node_factory.get_node(may_reconnect=True) l2 = self.node_factory.get_node(disconnect=disconnects, may_reconnect=True) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.fund_channel(l1, l2, 10**6) @@ -3293,7 +3292,7 @@ def test_reconnect_receiver_fulfill(self): l1 = self.node_factory.get_node(may_reconnect=True) l2 = self.node_factory.get_node(disconnect=disconnects, may_reconnect=True) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.fund_channel(l1, l2, 10**6) @@ -3315,7 +3314,7 @@ def test_shutdown_reconnect(self): l1 = self.node_factory.get_node(disconnect=disconnects, may_reconnect=True) l2 = self.node_factory.get_node(may_reconnect=True) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) chan = self.fund_channel(l1, l2, 10**6) self.pay(l1, l2, 200000000) @@ -3342,7 +3341,7 @@ def test_shutdown_awaiting_lockin(self): l1 = self.node_factory.get_node() l2 = self.node_factory.get_node(options={'anchor-confirms': 3}) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.give_funds(l1, 10**6 + 1000000) chanid = l1.rpc.fundchannel(l2.info['id'], 10**6)['channel_id'] @@ -3381,7 +3380,7 @@ def test_closing_negotiation_reconnect(self): '+WIRE_CLOSING_SIGNED'] l1 = self.node_factory.get_node(disconnect=disconnects, may_reconnect=True) l2 = self.node_factory.get_node(may_reconnect=True) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) chan = self.fund_channel(l1, l2, 10**6) self.pay(l1, l2, 200000000) @@ -3411,7 +3410,7 @@ def test_bech32_funding(self): l2 = self.node_factory.get_node(random_hsm=True) # connect - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) # fund a bech32 address and then open a channel with it res = l1.openchannel(l2, 20000, 'bech32') @@ -3592,7 +3591,7 @@ def test_funding_fail(self): l1 = self.node_factory.get_node(random_hsm=True) max_locktime = 3 * 6 * 24 l2 = self.node_factory.get_node(options={'locktime-blocks': max_locktime + 1}) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) funds = 1000000 @@ -3612,7 +3611,7 @@ def test_funding_fail(self): # Restart l2 without ridiculous locktime. del l2.daemon.opts['locktime-blocks'] l2.restart() - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) # We don't have enough left to cover fees if we try to spend it all. self.assertRaisesRegex(ValueError, r'Cannot afford funding transaction', @@ -3629,7 +3628,7 @@ def test_funding_toolarge(self): """Try to create a giant channel""" l1 = self.node_factory.get_node() l2 = self.node_factory.get_node() - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) # Send funds. amount = 2**24 @@ -3654,7 +3653,7 @@ def test_lockin_between_restart(self): l1 = self.node_factory.get_node(may_reconnect=True) l2 = self.node_factory.get_node(options={'anchor-confirms': 3}, may_reconnect=True) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.give_funds(l1, 10**6 + 1000000) l1.rpc.fundchannel(l2.info['id'], 10**6)['tx'] @@ -3666,7 +3665,7 @@ def test_lockin_between_restart(self): bitcoind.generate_block(120) # Restart - l1.daemon.start() + l1.start() # All should be good. l1.daemon.wait_for_log(' to CHANNELD_NORMAL') @@ -3687,7 +3686,7 @@ def test_funding_while_offline(self): bitcoind.generate_block(120) # Restart - l1.daemon.start() + l1.start() sync_blockheight([l1]) assert len(l1.rpc.listfunds()['outputs']) == 1 @@ -3729,7 +3728,7 @@ def test_channel_persistence(self): l1 = self.node_factory.get_node(may_reconnect=True) l2 = self.node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED-nocommit'], may_reconnect=True) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) # Neither node should have a channel open, they are just connected for n in (l1, l2): @@ -3760,7 +3759,7 @@ def test_channel_persistence(self): wait_for(lambda: 'connected' not in l1.rpc.listpeers()['peers'][0]['channels'][0]) # Now restart l2 and it should reload peers/channels from the DB - l2.daemon.start() + l2.start() wait_for(lambda: len(l2.rpc.listpeers()['peers']) == 1) # Wait for the restored HTLC to finish @@ -3776,8 +3775,7 @@ def test_channel_persistence(self): assert l2.rpc.listpeers()['peers'][0]['channels'][0]['msatoshi_to_us'] == 20000 # Finally restart l1, and make sure it remembers - l1.stop() - l1.daemon.start() + l1.restart() assert l1.rpc.listpeers()['peers'][0]['channels'][0]['msatoshi_to_us'] == 99980000 # Now make sure l1 is watching for unilateral closes @@ -3796,7 +3794,7 @@ def test_payment_success_persistence(self): options={'dev-no-reconnect': None}, may_reconnect=True) l2 = self.node_factory.get_node(may_reconnect=True) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) chanid = self.fund_channel(l1, l2, 100000) @@ -3815,7 +3813,7 @@ def test_payment_success_persistence(self): del l1.daemon.opts['dev-disconnect'] # Should reconnect, and sort the payment out. - l1.daemon.start() + l1.start() wait_for(lambda: l1.rpc.listpayments()['payments'][0]['status'] != 'pending') @@ -3836,7 +3834,7 @@ def test_payment_failed_persistence(self): options={'dev-no-reconnect': None}, may_reconnect=True) l2 = self.node_factory.get_node(may_reconnect=True) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.fund_channel(l1, l2, 100000) @@ -3859,7 +3857,7 @@ def test_payment_failed_persistence(self): time.sleep(3) # Should reconnect, and fail the payment - l1.daemon.start() + l1.start() wait_for(lambda: l1.rpc.listpayments()['payments'][0]['status'] != 'pending') @@ -3875,7 +3873,7 @@ def test_payment_duplicate_uncommitted(self): l1 = self.node_factory.get_node(disconnect=['=WIRE_UPDATE_ADD_HTLC-nocommit']) l2 = self.node_factory.get_node() - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) self.fund_channel(l1, l2, 100000) @@ -3908,8 +3906,8 @@ def test_gossip_badsig(self): l3 = self.node_factory.get_node() # l2 connects to both, so l1 can't reconnect and thus l2 drops to chain - l2.rpc.connect(l1.info['id'], 'localhost', l1.info['port']) - l2.rpc.connect(l3.info['id'], 'localhost', l3.info['port']) + l2.rpc.connect(l1.info['id'], 'localhost', l1.port) + l2.rpc.connect(l3.info['id'], 'localhost', l3.port) self.fund_channel(l2, l1, 10**6) self.fund_channel(l2, l3, 10**6) @@ -4041,8 +4039,7 @@ def test_channel_reenable(self): wait_for(lambda: [c['active'] for c in l1.rpc.listchannels()['channels']] == [True, True]) # Restart l2, will cause l1 to reconnect - l2.stop() - l2.daemon.start() + l2.restart() # Now they should sync and re-establish again l1.daemon.wait_for_logs(['Received channel_update for channel \\d+:1:1.1.', @@ -4139,7 +4136,7 @@ def test_fee_limits(self): # Try with node which sets --ignore-fee-limits l3 = self.node_factory.get_node(options={'ignore-fee-limits': 'true'}) - l1.rpc.connect(l3.info['id'], 'localhost', l3.info['port']) + l1.rpc.connect(l3.info['id'], 'localhost', l3.port) chan = self.fund_channel(l1, l3, 10**6) @@ -4163,7 +4160,7 @@ def test_update_fee_reconnect(self): disconnects = ['+WIRE_COMMITMENT_SIGNED'] l1 = self.node_factory.get_node(disconnect=disconnects, may_reconnect=True) l2 = self.node_factory.get_node(may_reconnect=True) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) chan = self.fund_channel(l1, l2, 10**6) @@ -4202,7 +4199,7 @@ def test_io_logging(self): l1 = self.node_factory.get_node(options={'debug-subdaemon-io': 'channeld', 'log-level': 'io'}) l2 = self.node_factory.get_node() - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) # Fundchannel manually so we get channeld pid. self.give_funds(l1, 10**6 + 1000000) @@ -4285,6 +4282,23 @@ def test_pay_disconnect(self): bitcoind.generate_block(1) l1.daemon.wait_for_log('ONCHAIN') + def test_address(self): + l1 = self.node_factory.get_node() + addr = l1.rpc.getinfo()['address'] + if 'dev-allow-localhost' in l1.daemon.opts: + assert len(addr) == 1 + assert addr[0]['type'] == 'ipv4' + assert addr[0]['address'] == '127.0.0.1' + assert int(addr[0]['port']) == l1.port + else: + assert len(addr) == 0 + + bind = l1.rpc.getinfo()['binding'] + assert len(bind) == 1 + assert bind[0]['type'] == 'ipv4' + assert bind[0]['address'] == '127.0.0.1' + assert int(bind[0]['port']) == l1.port + def test_listconfigs(self): l1 = self.node_factory.get_node() @@ -4292,7 +4306,6 @@ def test_listconfigs(self): # See utils.py assert configs['bitcoin-datadir'] == bitcoind.bitcoin_dir assert configs['lightning-dir'] == l1.daemon.lightning_dir - assert configs['port'] == l1.info['port'] assert configs['allow-deprecated-apis'] is False assert configs['override-fee-rates'] == '15000/7500/1000' assert configs['network'] == 'regtest' @@ -4311,7 +4324,7 @@ def test_multiple_channels(self): for i in range(3): # FIXME: we shouldn't disconnect on close? - ret = l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + ret = l1.rpc.connect(l2.info['id'], 'localhost', l2.port) assert ret['id'] == l2.info['id'] l1.daemon.wait_for_log('Handing back peer .* to master') @@ -4424,7 +4437,7 @@ def test_forget_channel(self): l1 = self.node_factory.get_node() l2 = self.node_factory.get_node() self.give_funds(l1, 10**6) - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l1.rpc.fundchannel(l2.info['id'], 10**5) assert len(l1.rpc.listpeers()['peers']) == 1 @@ -4517,8 +4530,8 @@ def test_disconnectpeer(self): l1 = self.node_factory.get_node() l2 = self.node_factory.get_node() l3 = self.node_factory.get_node() - l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) - l1.rpc.connect(l3.info['id'], 'localhost', l3.info['port']) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + l1.rpc.connect(l3.info['id'], 'localhost', l3.port) # Gossiping assert l1.rpc.getpeer(l2.info['id'])['state'] == "GOSSIPING" @@ -4575,7 +4588,7 @@ def test_rescan(self): l1.daemon.opts['rescan'] = -500000 l1.stop() btc.rpc.generate(4) - l1.daemon.start() + l1.start() l1.daemon.wait_for_log(r'Adding block 105') assert not l1.daemon.is_in_log(r'Adding block 102') diff --git a/tests/utils.py b/tests/utils.py index 25e5c88c9349..d4441de13595 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -261,7 +261,7 @@ def __init__(self, lightning_dir, bitcoin_dir, port=9735, random_hsm=False, node 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', @@ -281,6 +281,8 @@ def __init__(self, lightning_dir, bitcoin_dir, port=9735, random_hsm=False, node f.write(seed) if DEVELOPER: self.opts['dev-broadcast-interval'] = 1000 + # lightningd won't announce non-routable addresses by default. + self.opts['dev-allow-localhost'] = None self.prefix = 'lightningd-%d' % (node_id) @property @@ -319,44 +321,6 @@ def __init__(self, daemon, rpc, btc, executor, may_fail=False, may_reconnect=Fal self.may_fail = may_fail self.may_reconnect = may_reconnect - # Use batch if you're doing more than one async. - def connect(self, remote_node, capacity, async=False): - # Collect necessary information - addr = self.rpc.newaddr()['address'] - txid = self.bitcoin.rpc.sendtoaddress(addr, capacity) - tx = self.bitcoin.rpc.gettransaction(txid) - start_size = self.bitcoin.rpc.getmempoolinfo()['size'] - - def call_connect(): - try: - self.rpc.connect('127.0.0.1', remote_node.daemon.port, tx['hex'], async=False) - except Exception: - pass - t = threading.Thread(target=call_connect) - t.daemon = True - t.start() - - def wait_connected(): - # Up to 10 seconds to get tx into mempool. - start_time = time.time() - while self.bitcoin.rpc.getmempoolinfo()['size'] == start_size: - if time.time() > start_time + 10: - raise TimeoutError('No new transactions in mempool') - time.sleep(0.1) - - self.bitcoin.generate_block(1) - - # fut.result(timeout=5) - - # Now wait for confirmation - self.daemon.wait_for_log(" to CHANNELD_NORMAL|STATE_NORMAL") - remote_node.daemon.wait_for_log(" to CHANNELD_NORMAL|STATE_NORMAL") - - if async: - return self.executor.submit(wait_connected) - else: - return wait_connected() - def openchannel(self, remote_node, capacity, addrtype="p2sh-segwit"): addr, wallettxid = self.fundwallet(capacity, addrtype) fundingtx = self.rpc.fundchannel(remote_node.info['id'], capacity) @@ -405,6 +369,11 @@ def db_manip(self, query): c.close() db.close() + def start(self): + self.daemon.start() + # This shortcut is sufficient for our simple tests. + self.port = self.rpc.getinfo()['binding'][0]['port'] + def stop(self, timeout=10): """ Attempt to do a clean shutdown, but kill if it hangs """ @@ -441,7 +410,7 @@ def restart(self, timeout=10, clean=True): else: self.daemon.stop() - self.daemon.start() + self.start() def fund_channel(self, l2, amount): diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 34856bb73c74..1ed45842f10b 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -81,10 +81,10 @@ bool fromwire_gossipctl_peer_disconnect_reply(const void *p UNNEEDED) bool fromwire_gossipctl_peer_disconnect_replyfail(const void *p UNNEEDED, bool *isconnected UNNEEDED) { fprintf(stderr, "fromwire_gossipctl_peer_disconnect_replyfail called!\n"); abort(); } /* Generated stub for fromwire_gossip_getpeers_reply */ -bool fromwire_gossip_getpeers_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct pubkey **id UNNEEDED, struct wireaddr **addr UNNEEDED, struct gossip_getnodes_entry ***nodes UNNEEDED) +bool fromwire_gossip_getpeers_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct pubkey **id UNNEEDED, struct wireaddr_internal **addr UNNEEDED, struct gossip_getnodes_entry ***nodes UNNEEDED) { fprintf(stderr, "fromwire_gossip_getpeers_reply called!\n"); abort(); } /* Generated stub for fromwire_gossip_peer_connected */ -bool fromwire_gossip_peer_connected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct pubkey *id UNNEEDED, struct wireaddr *addr UNNEEDED, struct crypto_state *crypto_state UNNEEDED, u8 **gfeatures UNNEEDED, u8 **lfeatures UNNEEDED) +bool fromwire_gossip_peer_connected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct pubkey *id UNNEEDED, struct wireaddr_internal *addr UNNEEDED, struct crypto_state *crypto_state UNNEEDED, u8 **gfeatures UNNEEDED, u8 **lfeatures UNNEEDED) { fprintf(stderr, "fromwire_gossip_peer_connected called!\n"); abort(); } /* Generated stub for get_feerate */ u32 get_feerate(const struct chain_topology *topo UNNEEDED, enum feerate feerate UNNEEDED) @@ -98,7 +98,7 @@ u8 *get_offered_local_features(const tal_t *ctx UNNEEDED) /* Generated stub for handle_opening_channel */ bool handle_opening_channel(struct lightningd *ld UNNEEDED, const struct pubkey *id UNNEEDED, - const struct wireaddr *addr UNNEEDED, + const struct wireaddr_internal *addr UNNEEDED, const struct crypto_state *cs UNNEEDED, const u8 *gfeatures UNNEEDED, const u8 *lfeatures UNNEEDED, int peer_fd UNNEEDED, int gossip_fd UNNEEDED) @@ -318,7 +318,7 @@ void outpointfilter_remove(struct outpointfilter *of UNNEEDED, u8 *peer_accept_channel(const tal_t *ctx UNNEEDED, struct lightningd *ld UNNEEDED, const struct pubkey *peer_id UNNEEDED, - const struct wireaddr *addr UNNEEDED, + const struct wireaddr_internal *addr UNNEEDED, const struct crypto_state *cs UNNEEDED, const u8 *gfeatures UNNEEDED, const u8 *lfeatures UNNEEDED, int peer_fd UNNEEDED, int gossip_fd UNNEEDED, @@ -378,7 +378,7 @@ u8 *towire_errorfmt(const tal_t *ctx UNNEEDED, u8 *towire_gossipctl_hand_back_peer(const tal_t *ctx UNNEEDED, const struct pubkey *id UNNEEDED, const struct crypto_state *crypto_state UNNEEDED, const u8 *msg UNNEEDED) { fprintf(stderr, "towire_gossipctl_hand_back_peer called!\n"); abort(); } /* Generated stub for towire_gossipctl_peer_addrhint */ -u8 *towire_gossipctl_peer_addrhint(const tal_t *ctx UNNEEDED, const struct pubkey *id UNNEEDED, const struct wireaddr *addr UNNEEDED) +u8 *towire_gossipctl_peer_addrhint(const tal_t *ctx UNNEEDED, const struct pubkey *id UNNEEDED, const struct wireaddr_internal *addr UNNEEDED) { fprintf(stderr, "towire_gossipctl_peer_addrhint called!\n"); abort(); } /* Generated stub for towire_gossipctl_peer_disconnect */ u8 *towire_gossipctl_peer_disconnect(const tal_t *ctx UNNEEDED, const struct pubkey *id UNNEEDED) diff --git a/wallet/wallet.c b/wallet/wallet.c index e288465c2e29..cead5db5dd52 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -493,7 +493,7 @@ static struct peer *wallet_peer_load(struct wallet *w, const u64 dbid) const unsigned char *addrstr; struct peer *peer; struct pubkey id; - struct wireaddr *addrp, addr; + struct wireaddr_internal *addrp, addr; sqlite3_stmt *stmt = db_query(w->db, @@ -510,7 +510,7 @@ static struct peer *wallet_peer_load(struct wallet *w, const u64 dbid) addrstr = sqlite3_column_text(stmt, 2); if (addrstr) { addrp = &addr; - if (!parse_wireaddr((const char*)addrstr, addrp, DEFAULT_PORT, NULL)) { + if (!parse_wireaddr_internal((const char*)addrstr, addrp, DEFAULT_PORT, false, NULL)) { db_stmt_done(stmt); return NULL; } @@ -970,11 +970,12 @@ void wallet_channel_insert(struct wallet *w, struct channel *chan) /* Need to create the peer first */ stmt = db_prepare(w->db, "INSERT INTO peers (node_id, address) VALUES (?, ?);"); sqlite3_bind_pubkey(stmt, 1, &chan->peer->id); - if (chan->peer->addr.type == ADDR_TYPE_PADDING) + if (chan->peer->addr.itype == ADDR_INTERNAL_WIREADDR + && chan->peer->addr.u.wireaddr.type == ADDR_TYPE_PADDING) sqlite3_bind_null(stmt, 2); else sqlite3_bind_text(stmt, 2, - type_to_string(tmpctx, struct wireaddr, &chan->peer->addr), + type_to_string(tmpctx, struct wireaddr_internal, &chan->peer->addr), -1, SQLITE_TRANSIENT); db_exec_prepared(w->db, stmt); chan->peer->dbid = sqlite3_last_insert_rowid(w->db->sql);