mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-21 16:14:23 +01:00
gossipd: handle wildcard addresses correctly.
If we're given a wildcard address, we can't announce it like that: we need to try to turn it into a real address (using guess_address). Then we use that address. As a side-effect of this cleanup, we only announce *any* '--addr' if it's routable. This fix means that our tests have to force '--announce-addr' because otherwise localhost isn't routable. This means that gossipd really controls the addresses now, and breaks them into two arrays: what we bind to, and what we announce. That is now what we return to the master for json_getinfo(), which prints them as 'bindings' and 'addresses' respectively. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
committed by
Christian Decker
parent
52917ff6c9
commit
af065417e1
@@ -1,6 +1,7 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ccan/build_assert/build_assert.h>
|
#include <ccan/build_assert/build_assert.h>
|
||||||
|
#include <ccan/mem/mem.h>
|
||||||
#include <ccan/tal/str/str.h>
|
#include <ccan/tal/str/str.h>
|
||||||
#include <common/type_to_string.h>
|
#include <common/type_to_string.h>
|
||||||
#include <common/utils.h>
|
#include <common/utils.h>
|
||||||
@@ -164,6 +165,18 @@ bool wireaddr_to_ipv6(const struct wireaddr *addr, struct sockaddr_in6 *s6)
|
|||||||
return true;
|
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,
|
char *fmt_wireaddr_internal(const tal_t *ctx,
|
||||||
const struct wireaddr_internal *a)
|
const struct wireaddr_internal *a)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -75,6 +75,8 @@ void wireaddr_from_ipv6(struct wireaddr *addr,
|
|||||||
bool wireaddr_to_ipv4(const struct wireaddr *addr, struct sockaddr_in *s4);
|
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_to_ipv6(const struct wireaddr *addr, struct sockaddr_in6 *s6);
|
||||||
|
|
||||||
|
bool wireaddr_is_wildcard(const struct wireaddr *addr);
|
||||||
|
|
||||||
enum wireaddr_internal_type {
|
enum wireaddr_internal_type {
|
||||||
ADDR_INTERNAL_SOCKNAME,
|
ADDR_INTERNAL_SOCKNAME,
|
||||||
ADDR_INTERNAL_ALLPROTO,
|
ADDR_INTERNAL_ALLPROTO,
|
||||||
|
|||||||
125
gossipd/gossip.c
125
gossipd/gossip.c
@@ -129,8 +129,13 @@ struct daemon {
|
|||||||
|
|
||||||
u8 alias[33];
|
u8 alias[33];
|
||||||
u8 rgb[3];
|
u8 rgb[3];
|
||||||
struct wireaddr_internal *wireaddrs;
|
|
||||||
enum addr_listen_announce *listen_announce;
|
/* 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 */
|
/* To make sure our node_announcement timestamps increase */
|
||||||
u32 last_announce_timestamp;
|
u32 last_announce_timestamp;
|
||||||
@@ -566,15 +571,8 @@ static u8 *create_node_announcement(const tal_t *ctx, struct daemon *daemon,
|
|||||||
sig = tal(ctx, secp256k1_ecdsa_signature);
|
sig = tal(ctx, secp256k1_ecdsa_signature);
|
||||||
memset(sig, 0, sizeof(*sig));
|
memset(sig, 0, sizeof(*sig));
|
||||||
}
|
}
|
||||||
for (i = 0; i < tal_count(daemon->wireaddrs); i++) {
|
for (i = 0; i < tal_count(daemon->announcable); i++)
|
||||||
if (!(daemon->listen_announce[i] & ADDR_ANNOUNCE))
|
towire_wireaddr(&addresses, &daemon->announcable[i]);
|
||||||
continue;
|
|
||||||
/* You can only announce wiretypes! */
|
|
||||||
if (daemon->wireaddrs[i].itype != ADDR_INTERNAL_WIREADDR)
|
|
||||||
continue;
|
|
||||||
towire_wireaddr(&addresses,
|
|
||||||
&daemon->wireaddrs[i].u.wireaddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
announcement =
|
announcement =
|
||||||
towire_node_announcement(ctx, sig, features, timestamp,
|
towire_node_announcement(ctx, sig, features, timestamp,
|
||||||
@@ -1607,51 +1605,113 @@ static bool handle_wireaddr_listen(struct daemon *daemon,
|
|||||||
"Invalid listener wireaddress type %u", wireaddr->type);
|
"Invalid listener wireaddress type %u", wireaddr->type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setup_listeners(struct daemon *daemon)
|
/* If it's a wildcard, turns it into a real address pointing to internet */
|
||||||
|
static bool public_address(struct wireaddr *wireaddr)
|
||||||
|
{
|
||||||
|
if (wireaddr_is_wildcard(wireaddr)) {
|
||||||
|
if (!guess_address(wireaddr))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return address_routable(wireaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
struct sockaddr_un addrun;
|
||||||
int fd;
|
int fd;
|
||||||
|
struct wireaddr_internal *binding;
|
||||||
|
|
||||||
for (size_t i = 0; i < tal_count(daemon->wireaddrs); i++) {
|
binding = tal_arr(ctx, struct wireaddr_internal, 0);
|
||||||
struct wireaddr wa = daemon->wireaddrs[i].u.wireaddr;
|
daemon->announcable = tal_arr(daemon, struct wireaddr, 0);
|
||||||
|
|
||||||
if (!(daemon->listen_announce[i] & ADDR_LISTEN))
|
for (size_t i = 0; i < tal_count(daemon->proposed_wireaddr); i++) {
|
||||||
|
struct wireaddr_internal wa = daemon->proposed_wireaddr[i];
|
||||||
|
|
||||||
|
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;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
switch (daemon->wireaddrs[i].itype) {
|
switch (wa.itype) {
|
||||||
case ADDR_INTERNAL_SOCKNAME:
|
case ADDR_INTERNAL_SOCKNAME:
|
||||||
addrun.sun_family = AF_UNIX;
|
addrun.sun_family = AF_UNIX;
|
||||||
memcpy(addrun.sun_path, daemon->wireaddrs[i].u.sockname,
|
memcpy(addrun.sun_path, wa.u.sockname,
|
||||||
sizeof(addrun.sun_path));
|
sizeof(addrun.sun_path));
|
||||||
fd = make_listen_fd(AF_INET, &addrun, sizeof(addrun),
|
fd = make_listen_fd(AF_INET, &addrun, sizeof(addrun),
|
||||||
false);
|
false);
|
||||||
status_trace("Created socket listener on file %s",
|
status_trace("Created socket listener on file %s",
|
||||||
addrun.sun_path);
|
addrun.sun_path);
|
||||||
io_new_listener(daemon, fd, connection_in, daemon);
|
io_new_listener(daemon, fd, connection_in, daemon);
|
||||||
|
/* We don't announce socket names */
|
||||||
|
add_binding(&binding, &wa);
|
||||||
continue;
|
continue;
|
||||||
case ADDR_INTERNAL_ALLPROTO: {
|
case ADDR_INTERNAL_ALLPROTO: {
|
||||||
bool ipv6_ok;
|
bool ipv6_ok;
|
||||||
|
|
||||||
memset(wa.addr, 0, sizeof(wa.addr));
|
wa.itype = ADDR_INTERNAL_WIREADDR;
|
||||||
wa.type = ADDR_TYPE_IPV6;
|
wa.u.wireaddr.port = wa.u.port;
|
||||||
wa.addrlen = 16;
|
memset(wa.u.wireaddr.addr, 0,
|
||||||
|
sizeof(wa.u.wireaddr.addr));
|
||||||
|
|
||||||
ipv6_ok = handle_wireaddr_listen(daemon, &wa, true);
|
/* Try both IPv6 and IPv4. */
|
||||||
wa.type = ADDR_TYPE_IPV4;
|
wa.u.wireaddr.type = ADDR_TYPE_IPV6;
|
||||||
wa.addrlen = 4;
|
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(&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! */
|
/* OK if this fails, as long as one succeeds! */
|
||||||
handle_wireaddr_listen(daemon, &wa, ipv6_ok);
|
if (handle_wireaddr_listen(daemon, &wa.u.wireaddr,
|
||||||
|
ipv6_ok)) {
|
||||||
|
add_binding(&binding, &wa);
|
||||||
|
if (public_address(&wa.u.wireaddr))
|
||||||
|
add_announcable(daemon, &wa.u.wireaddr);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
case ADDR_INTERNAL_WIREADDR:
|
case ADDR_INTERNAL_WIREADDR:
|
||||||
handle_wireaddr_listen(daemon, &wa, false);
|
handle_wireaddr_listen(daemon, &wa.u.wireaddr, false);
|
||||||
|
add_binding(&binding, &wa);
|
||||||
|
if (public_address(&wa.u.wireaddr))
|
||||||
|
add_announcable(daemon, &wa.u.wireaddr);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Shouldn't happen. */
|
/* Shouldn't happen. */
|
||||||
status_failed(STATUS_FAIL_INTERNAL_ERROR,
|
status_failed(STATUS_FAIL_INTERNAL_ERROR,
|
||||||
"Invalid listener address type %u",
|
"Invalid listener address type %u",
|
||||||
daemon->wireaddrs[i].itype);
|
daemon->proposed_wireaddr[i].itype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return binding;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse an incoming gossip init message and assign config variables
|
/* Parse an incoming gossip init message and assign config variables
|
||||||
@@ -1667,8 +1727,8 @@ static struct io_plan *gossip_init(struct daemon_conn *master,
|
|||||||
if (!fromwire_gossipctl_init(
|
if (!fromwire_gossipctl_init(
|
||||||
daemon, msg, &daemon->broadcast_interval, &chain_hash,
|
daemon, msg, &daemon->broadcast_interval, &chain_hash,
|
||||||
&daemon->id, &daemon->globalfeatures,
|
&daemon->id, &daemon->globalfeatures,
|
||||||
&daemon->localfeatures, &daemon->wireaddrs,
|
&daemon->localfeatures, &daemon->proposed_wireaddr,
|
||||||
&daemon->listen_announce, daemon->rgb,
|
&daemon->proposed_listen_announce, daemon->rgb,
|
||||||
daemon->alias, &update_channel_interval, &daemon->reconnect)) {
|
daemon->alias, &update_channel_interval, &daemon->reconnect)) {
|
||||||
master_badmsg(WIRE_GOSSIPCTL_INIT, msg);
|
master_badmsg(WIRE_GOSSIPCTL_INIT, msg);
|
||||||
}
|
}
|
||||||
@@ -1691,18 +1751,21 @@ static struct io_plan *gossip_activate(struct daemon_conn *master,
|
|||||||
const u8 *msg)
|
const u8 *msg)
|
||||||
{
|
{
|
||||||
bool listen;
|
bool listen;
|
||||||
|
struct wireaddr_internal *binding;
|
||||||
|
|
||||||
if (!fromwire_gossipctl_activate(msg, &listen))
|
if (!fromwire_gossipctl_activate(msg, &listen))
|
||||||
master_badmsg(WIRE_GOSSIPCTL_ACTIVATE, msg);
|
master_badmsg(WIRE_GOSSIPCTL_ACTIVATE, msg);
|
||||||
|
|
||||||
if (listen)
|
if (listen)
|
||||||
setup_listeners(daemon);
|
binding = setup_listeners(tmpctx, daemon);
|
||||||
|
else
|
||||||
|
binding = NULL;
|
||||||
|
|
||||||
/* OK, we're ready! */
|
/* OK, we're ready! */
|
||||||
daemon_conn_send(&daemon->master,
|
daemon_conn_send(&daemon->master,
|
||||||
take(towire_gossipctl_activate_reply(NULL,
|
take(towire_gossipctl_activate_reply(NULL,
|
||||||
daemon->wireaddrs,
|
binding,
|
||||||
daemon->listen_announce)));
|
daemon->announcable)));
|
||||||
|
|
||||||
return daemon_conn_read_next(master->conn, master);
|
return daemon_conn_read_next(master->conn, master);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,11 +24,12 @@ gossipctl_activate,3025
|
|||||||
# Do we listen?
|
# Do we listen?
|
||||||
gossipctl_activate,,listen,bool
|
gossipctl_activate,,listen,bool
|
||||||
|
|
||||||
# Gossipd->master, I am ready, here are the final addresses.
|
# Gossipd->master, I am ready, here's the addresses I bound, can announce.
|
||||||
gossipctl_activate_reply,3125
|
gossipctl_activate_reply,3125
|
||||||
gossipctl_activate_reply,,num_wireaddrs,u16
|
gossipctl_activate_reply,,num_bindings,u16
|
||||||
gossipctl_activate_reply,,wireaddrs,num_wireaddrs*struct wireaddr_internal
|
gossipctl_activate_reply,,bindings,num_bindings*struct wireaddr_internal
|
||||||
gossipctl_activate_reply,,listen_announce,num_wireaddrs*enum addr_listen_announce
|
gossipctl_activate_reply,,num_announcable,u16
|
||||||
|
gossipctl_activate_reply,,announcable,num_announcable*struct wireaddr
|
||||||
|
|
||||||
# Master -> gossipd: Optional hint for where to find peer.
|
# Master -> gossipd: Optional hint for where to find peer.
|
||||||
gossipctl_peer_addrhint,3014
|
gossipctl_peer_addrhint,3014
|
||||||
|
|||||||
|
@@ -201,48 +201,39 @@ static bool IsRoutable(const struct wireaddr *addr)
|
|||||||
* then query address. */
|
* then query address. */
|
||||||
/* Returns 0 if protocol completely unsupported, ADDR_LISTEN if we
|
/* Returns 0 if protocol completely unsupported, ADDR_LISTEN if we
|
||||||
* can't reach addr, ADDR_LISTEN_AND_ANNOUNCE if we can (and fill saddr). */
|
* can't reach addr, ADDR_LISTEN_AND_ANNOUNCE if we can (and fill saddr). */
|
||||||
static enum addr_listen_announce get_local_sockname(int af, void *saddr,
|
static bool get_local_sockname(int af, void *saddr, socklen_t saddrlen)
|
||||||
socklen_t saddrlen)
|
|
||||||
{
|
{
|
||||||
int fd = socket(af, SOCK_DGRAM, 0);
|
int fd = socket(af, SOCK_DGRAM, 0);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
status_trace("Failed to create %u socket: %s",
|
status_trace("Failed to create %u socket: %s",
|
||||||
af, strerror(errno));
|
af, strerror(errno));
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connect(fd, saddr, saddrlen) != 0) {
|
if (connect(fd, saddr, saddrlen) != 0) {
|
||||||
status_trace("Failed to connect %u socket: %s",
|
status_trace("Failed to connect %u socket: %s",
|
||||||
af, strerror(errno));
|
af, strerror(errno));
|
||||||
close(fd);
|
close(fd);
|
||||||
return ADDR_LISTEN;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getsockname(fd, saddr, &saddrlen) != 0) {
|
if (getsockname(fd, saddr, &saddrlen) != 0) {
|
||||||
status_trace("Failed to get %u socket name: %s",
|
status_trace("Failed to get %u socket name: %s",
|
||||||
af, strerror(errno));
|
af, strerror(errno));
|
||||||
close(fd);
|
close(fd);
|
||||||
return ADDR_LISTEN;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
return ADDR_LISTEN_AND_ANNOUNCE;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return 0 if not available, or whether it's listenable-only or announceable.
|
bool guess_address(struct wireaddr *addr)
|
||||||
* If it's listenable only, will set wireaddr to all-zero address for universal
|
|
||||||
* binding. */
|
|
||||||
static enum addr_listen_announce guess_one_address(struct wireaddr *addr,
|
|
||||||
u16 portnum,
|
|
||||||
enum wire_addr_type type)
|
|
||||||
{
|
{
|
||||||
enum addr_listen_announce ret;
|
bool ret;
|
||||||
|
|
||||||
addr->type = type;
|
|
||||||
addr->port = portnum;
|
|
||||||
|
|
||||||
/* We point to Google nameservers, works unless you're inside Google :) */
|
/* We point to Google nameservers, works unless you're inside Google :) */
|
||||||
switch (type) {
|
switch (addr->type) {
|
||||||
case ADDR_TYPE_IPV4: {
|
case ADDR_TYPE_IPV4: {
|
||||||
struct sockaddr_in sin;
|
struct sockaddr_in sin;
|
||||||
sin.sin_port = htons(53);
|
sin.sin_port = htons(53);
|
||||||
@@ -252,7 +243,7 @@ static enum addr_listen_announce guess_one_address(struct wireaddr *addr,
|
|||||||
ret = get_local_sockname(AF_INET, &sin, sizeof(sin));
|
ret = get_local_sockname(AF_INET, &sin, sizeof(sin));
|
||||||
addr->addrlen = sizeof(sin.sin_addr);
|
addr->addrlen = sizeof(sin.sin_addr);
|
||||||
memcpy(addr->addr, &sin.sin_addr, addr->addrlen);
|
memcpy(addr->addr, &sin.sin_addr, addr->addrlen);
|
||||||
break;
|
return ret;
|
||||||
}
|
}
|
||||||
case ADDR_TYPE_IPV6: {
|
case ADDR_TYPE_IPV6: {
|
||||||
struct sockaddr_in6 sin6;
|
struct sockaddr_in6 sin6;
|
||||||
@@ -266,59 +257,15 @@ static enum addr_listen_announce guess_one_address(struct wireaddr *addr,
|
|||||||
ret = get_local_sockname(AF_INET6, &sin6, sizeof(sin6));
|
ret = get_local_sockname(AF_INET6, &sin6, sizeof(sin6));
|
||||||
addr->addrlen = sizeof(sin6.sin6_addr);
|
addr->addrlen = sizeof(sin6.sin6_addr);
|
||||||
memcpy(addr->addr, &sin6.sin6_addr, addr->addrlen);
|
memcpy(addr->addr, &sin6.sin6_addr, addr->addrlen);
|
||||||
break;
|
return ret;
|
||||||
}
|
}
|
||||||
case ADDR_TYPE_PADDING:
|
case ADDR_TYPE_PADDING:
|
||||||
status_trace("Padding address, ignoring");
|
break;
|
||||||
return 0;
|
}
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == 0)
|
bool address_routable(const struct wireaddr *wireaddr)
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* If we can reach it, but resulting address is unroutable, listen only */
|
|
||||||
if (ret == ADDR_LISTEN_AND_ANNOUNCE && !IsRoutable(addr)) {
|
|
||||||
status_trace("Address %s is not routable",
|
|
||||||
type_to_string(tmpctx, struct wireaddr, addr));
|
|
||||||
ret = ADDR_LISTEN;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret == ADDR_LISTEN) {
|
|
||||||
/* This corresponds to INADDR_ANY or in6addr_any */
|
|
||||||
memset(addr->addr, 0, addr->addrlen);
|
|
||||||
} else {
|
|
||||||
status_trace("Public address %s",
|
|
||||||
type_to_string(tmpctx, struct wireaddr, addr));
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void guess_addresses(struct wireaddr_internal **wireaddrs,
|
|
||||||
enum addr_listen_announce **listen_announce,
|
|
||||||
u16 portnum)
|
|
||||||
{
|
{
|
||||||
size_t n = tal_count(*wireaddrs);
|
return IsRoutable(wireaddr);
|
||||||
|
|
||||||
status_trace("Trying to guess public addresses...");
|
|
||||||
|
|
||||||
/* We allocate an extra, then remove if it's not needed. */
|
|
||||||
tal_resize(wireaddrs, n+1);
|
|
||||||
tal_resize(listen_announce, n+1);
|
|
||||||
|
|
||||||
(*wireaddrs)[n].itype = ADDR_INTERNAL_WIREADDR;
|
|
||||||
/* We do IPv6 first: on Linux, that binds to IPv4 too. */
|
|
||||||
(*listen_announce)[n] = guess_one_address(&(*wireaddrs)[n].u.wireaddr,
|
|
||||||
portnum, ADDR_TYPE_IPV6);
|
|
||||||
if ((*listen_announce)[n] != 0) {
|
|
||||||
n++;
|
|
||||||
tal_resize(wireaddrs, n+1);
|
|
||||||
tal_resize(listen_announce, n+1);
|
|
||||||
(*wireaddrs)[n].itype = ADDR_INTERNAL_WIREADDR;
|
|
||||||
}
|
|
||||||
(*listen_announce)[n] = guess_one_address(&(*wireaddrs)[n].u.wireaddr,
|
|
||||||
portnum, ADDR_TYPE_IPV4);
|
|
||||||
if ((*listen_announce)[n] == 0) {
|
|
||||||
tal_resize(wireaddrs, n);
|
|
||||||
tal_resize(listen_announce, n);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,10 @@
|
|||||||
#include <ccan/short_types/short_types.h>
|
#include <ccan/short_types/short_types.h>
|
||||||
#include <common/wireaddr.h>
|
#include <common/wireaddr.h>
|
||||||
|
|
||||||
void guess_addresses(struct wireaddr_internal **wireaddrs,
|
/* Address is a wildcard: try to guess what it looks like to outside world */
|
||||||
enum addr_listen_announce **listen_announce,
|
bool guess_address(struct wireaddr *wireaddr);
|
||||||
u16 portnum);
|
|
||||||
|
/* Is this address public? */
|
||||||
|
bool address_routable(const struct wireaddr *wireaddr);
|
||||||
|
|
||||||
#endif /* LIGHTNING_GOSSIPD_NETADDRESS_H */
|
#endif /* LIGHTNING_GOSSIPD_NETADDRESS_H */
|
||||||
|
|||||||
@@ -183,8 +183,8 @@ void gossip_init(struct lightningd *ld)
|
|||||||
u8 *msg;
|
u8 *msg;
|
||||||
int hsmfd;
|
int hsmfd;
|
||||||
u64 capabilities = HSM_CAP_ECDH | HSM_CAP_SIGN_GOSSIP;
|
u64 capabilities = HSM_CAP_ECDH | HSM_CAP_SIGN_GOSSIP;
|
||||||
struct wireaddr_internal *wireaddrs = ld->wireaddrs;
|
struct wireaddr_internal *wireaddrs = ld->proposed_wireaddr;
|
||||||
enum addr_listen_announce *listen_announce = ld->listen_announce;
|
enum addr_listen_announce *listen_announce = ld->proposed_listen_announce;
|
||||||
|
|
||||||
msg = towire_hsm_client_hsmfd(tmpctx, &ld->id, capabilities);
|
msg = towire_hsm_client_hsmfd(tmpctx, &ld->id, capabilities);
|
||||||
if (!wire_sync_write(ld->hsm_fd, msg))
|
if (!wire_sync_write(ld->hsm_fd, msg))
|
||||||
@@ -230,12 +230,9 @@ static void gossip_activate_done(struct subd *gossip UNUSED,
|
|||||||
{
|
{
|
||||||
struct lightningd *ld = gossip->ld;
|
struct lightningd *ld = gossip->ld;
|
||||||
|
|
||||||
/* Reply gives us the actual wireaddrs we're using */
|
|
||||||
tal_free(ld->wireaddrs);
|
|
||||||
tal_free(ld->listen_announce);
|
|
||||||
if (!fromwire_gossipctl_activate_reply(gossip->ld, reply,
|
if (!fromwire_gossipctl_activate_reply(gossip->ld, reply,
|
||||||
&ld->wireaddrs,
|
&ld->binding,
|
||||||
&ld->listen_announce))
|
&ld->announcable))
|
||||||
fatal("Bad gossipctl_activate_reply: %s",
|
fatal("Bad gossipctl_activate_reply: %s",
|
||||||
tal_hex(reply, reply));
|
tal_hex(reply, reply));
|
||||||
|
|
||||||
|
|||||||
@@ -150,31 +150,22 @@ static void json_getinfo(struct command *cmd,
|
|||||||
json_object_start(response, NULL);
|
json_object_start(response, NULL);
|
||||||
json_add_pubkey(response, "id", &cmd->ld->id);
|
json_add_pubkey(response, "id", &cmd->ld->id);
|
||||||
if (cmd->ld->listen) {
|
if (cmd->ld->listen) {
|
||||||
bool have_listen_no_announce = false;
|
|
||||||
if (deprecated_apis)
|
if (deprecated_apis)
|
||||||
json_add_num(response, "port", cmd->ld->portnum);
|
json_add_num(response, "port", cmd->ld->portnum);
|
||||||
|
|
||||||
/* These are the addresses we're announcing */
|
/* These are the addresses we're announcing */
|
||||||
json_array_start(response, "address");
|
json_array_start(response, "address");
|
||||||
for (size_t i = 0; i < tal_count(cmd->ld->wireaddrs); i++) {
|
for (size_t i = 0; i < tal_count(cmd->ld->announcable); i++)
|
||||||
if (cmd->ld->listen_announce[i] & ADDR_ANNOUNCE)
|
json_add_address(response, NULL, cmd->ld->announcable+i);
|
||||||
json_add_address_internal(response, NULL,
|
|
||||||
cmd->ld->wireaddrs+i);
|
|
||||||
else
|
|
||||||
have_listen_no_announce = true;
|
|
||||||
}
|
|
||||||
json_array_end(response);
|
json_array_end(response);
|
||||||
|
|
||||||
if (have_listen_no_announce) {
|
/* This is what we're actually bound to. */
|
||||||
json_array_start(response, "listen-only");
|
json_array_start(response, "binding");
|
||||||
for (size_t i = 0; i < tal_count(cmd->ld->wireaddrs); i++) {
|
for (size_t i = 0; i < tal_count(cmd->ld->binding); i++)
|
||||||
if (cmd->ld->listen_announce[i] == ADDR_LISTEN)
|
|
||||||
json_add_address_internal(response, NULL,
|
json_add_address_internal(response, NULL,
|
||||||
cmd->ld->wireaddrs+i);
|
cmd->ld->binding+i);
|
||||||
}
|
|
||||||
json_array_end(response);
|
json_array_end(response);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
json_add_string(response, "version", version());
|
json_add_string(response, "version", version());
|
||||||
json_add_num(response, "blockheight", get_block_height(cmd->ld->topology));
|
json_add_num(response, "blockheight", get_block_height(cmd->ld->topology));
|
||||||
json_add_string(response, "network", get_chainparams(cmd->ld)->network_name);
|
json_add_string(response, "network", get_chainparams(cmd->ld)->network_name);
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ static struct lightningd *new_lightningd(const tal_t *ctx)
|
|||||||
list_head_init(&ld->waitsendpay_commands);
|
list_head_init(&ld->waitsendpay_commands);
|
||||||
list_head_init(&ld->sendpay_commands);
|
list_head_init(&ld->sendpay_commands);
|
||||||
list_head_init(&ld->close_commands);
|
list_head_init(&ld->close_commands);
|
||||||
ld->wireaddrs = tal_arr(ld, struct wireaddr_internal, 0);
|
ld->proposed_wireaddr = tal_arr(ld, struct wireaddr_internal, 0);
|
||||||
ld->listen_announce = tal_arr(ld, enum addr_listen_announce, 0);
|
ld->proposed_listen_announce = tal_arr(ld, enum addr_listen_announce, 0);
|
||||||
ld->portnum = DEFAULT_PORT;
|
ld->portnum = DEFAULT_PORT;
|
||||||
ld->listen = true;
|
ld->listen = true;
|
||||||
ld->autolisten = true;
|
ld->autolisten = true;
|
||||||
|
|||||||
@@ -120,10 +120,14 @@ struct lightningd {
|
|||||||
/* Do we want to guess addresses to listen and announce? */
|
/* Do we want to guess addresses to listen and announce? */
|
||||||
bool autolisten;
|
bool autolisten;
|
||||||
|
|
||||||
/* Addresses to bind/announce to the network (tal_count()) */
|
/* Setup: Addresses to bind/announce to the network (tal_count()) */
|
||||||
struct wireaddr_internal *wireaddrs;
|
struct wireaddr_internal *proposed_wireaddr;
|
||||||
/* And the bitset for each, whether to listen, announce or both */
|
/* Setup: And the bitset for each, whether to listen, announce or both */
|
||||||
enum addr_listen_announce *listen_announce;
|
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. */
|
/* Bearer of all my secrets. */
|
||||||
int hsm_fd;
|
int hsm_fd;
|
||||||
|
|||||||
@@ -149,16 +149,16 @@ static char *opt_add_addr_withtype(const char *arg,
|
|||||||
struct lightningd *ld,
|
struct lightningd *ld,
|
||||||
enum addr_listen_announce ala)
|
enum addr_listen_announce ala)
|
||||||
{
|
{
|
||||||
size_t n = tal_count(ld->wireaddrs);
|
size_t n = tal_count(ld->proposed_wireaddr);
|
||||||
char const *err_msg;
|
char const *err_msg;
|
||||||
|
|
||||||
assert(arg != NULL);
|
assert(arg != NULL);
|
||||||
|
|
||||||
tal_resize(&ld->wireaddrs, n+1);
|
tal_resize(&ld->proposed_wireaddr, n+1);
|
||||||
tal_resize(&ld->listen_announce, n+1);
|
tal_resize(&ld->proposed_listen_announce, n+1);
|
||||||
ld->listen_announce[n] = ala;
|
ld->proposed_listen_announce[n] = ala;
|
||||||
|
|
||||||
if (!parse_wireaddr_internal(arg, &ld->wireaddrs[n], ld->portnum,
|
if (!parse_wireaddr_internal(arg, &ld->proposed_wireaddr[n], ld->portnum,
|
||||||
true, &err_msg)) {
|
true, &err_msg)) {
|
||||||
return tal_fmt(NULL, "Unable to parse address '%s': %s", arg, err_msg);
|
return tal_fmt(NULL, "Unable to parse address '%s': %s", arg, err_msg);
|
||||||
}
|
}
|
||||||
@@ -918,17 +918,20 @@ static void add_config(struct lightningd *ld,
|
|||||||
/* Covered by opt_add_addr below */
|
/* Covered by opt_add_addr below */
|
||||||
} else if (opt->cb_arg == (void *)opt_add_addr) {
|
} else if (opt->cb_arg == (void *)opt_add_addr) {
|
||||||
json_add_opt_addrs(response, name0,
|
json_add_opt_addrs(response, name0,
|
||||||
ld->wireaddrs, ld->listen_announce,
|
ld->proposed_wireaddr,
|
||||||
|
ld->proposed_listen_announce,
|
||||||
ADDR_LISTEN_AND_ANNOUNCE);
|
ADDR_LISTEN_AND_ANNOUNCE);
|
||||||
return;
|
return;
|
||||||
} else if (opt->cb_arg == (void *)opt_add_bind_addr) {
|
} else if (opt->cb_arg == (void *)opt_add_bind_addr) {
|
||||||
json_add_opt_addrs(response, name0,
|
json_add_opt_addrs(response, name0,
|
||||||
ld->wireaddrs, ld->listen_announce,
|
ld->proposed_wireaddr,
|
||||||
|
ld->proposed_listen_announce,
|
||||||
ADDR_LISTEN);
|
ADDR_LISTEN);
|
||||||
return;
|
return;
|
||||||
} else if (opt->cb_arg == (void *)opt_add_announce_addr) {
|
} else if (opt->cb_arg == (void *)opt_add_announce_addr) {
|
||||||
json_add_opt_addrs(response, name0,
|
json_add_opt_addrs(response, name0,
|
||||||
ld->wireaddrs, ld->listen_announce,
|
ld->proposed_wireaddr,
|
||||||
|
ld->proposed_listen_announce,
|
||||||
ADDR_ANNOUNCE);
|
ADDR_ANNOUNCE);
|
||||||
return;
|
return;
|
||||||
#if DEVELOPER
|
#if DEVELOPER
|
||||||
|
|||||||
@@ -4283,10 +4283,17 @@ class LightningDTests(BaseLightningDTests):
|
|||||||
|
|
||||||
def test_address(self):
|
def test_address(self):
|
||||||
l1 = self.node_factory.get_node()
|
l1 = self.node_factory.get_node()
|
||||||
assert len(l1.rpc.getinfo()['address']) == 1
|
addr = l1.rpc.getinfo()['address']
|
||||||
assert l1.rpc.getinfo()['address'][0]['type'] == 'ipv4'
|
assert len(addr) == 1
|
||||||
assert l1.rpc.getinfo()['address'][0]['address'] == '127.0.0.1'
|
assert addr[0]['type'] == 'ipv4'
|
||||||
assert int(l1.rpc.getinfo()['address'][0]['port']) == l1.port
|
assert addr[0]['address'] == '127.0.0.1'
|
||||||
|
assert int(addr[0]['port']) == l1.port
|
||||||
|
|
||||||
|
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):
|
def test_listconfigs(self):
|
||||||
l1 = self.node_factory.get_node()
|
l1 = self.node_factory.get_node()
|
||||||
|
|||||||
@@ -261,7 +261,9 @@ class LightningD(TailableProc):
|
|||||||
opts = {
|
opts = {
|
||||||
'bitcoin-datadir': bitcoin_dir,
|
'bitcoin-datadir': bitcoin_dir,
|
||||||
'lightning-dir': lightning_dir,
|
'lightning-dir': lightning_dir,
|
||||||
'addr': '127.0.0.1:{}'.format(port),
|
'bind-addr': '127.0.0.1:{}'.format(port),
|
||||||
|
# lightningd won't announce non-routable addresses by default.
|
||||||
|
'announce-addr': '127.0.0.1:{}'.format(port),
|
||||||
'allow-deprecated-apis': 'false',
|
'allow-deprecated-apis': 'false',
|
||||||
'override-fee-rates': '15000/7500/1000',
|
'override-fee-rates': '15000/7500/1000',
|
||||||
'network': 'regtest',
|
'network': 'regtest',
|
||||||
@@ -370,7 +372,7 @@ class LightningNode(object):
|
|||||||
def start(self):
|
def start(self):
|
||||||
self.daemon.start()
|
self.daemon.start()
|
||||||
# This shortcut is sufficient for our simple tests.
|
# This shortcut is sufficient for our simple tests.
|
||||||
self.port = self.rpc.getinfo()['address'][0]['port']
|
self.port = self.rpc.getinfo()['binding'][0]['port']
|
||||||
|
|
||||||
def stop(self, timeout=10):
|
def stop(self, timeout=10):
|
||||||
""" Attempt to do a clean shutdown, but kill if it hangs
|
""" Attempt to do a clean shutdown, but kill if it hangs
|
||||||
|
|||||||
Reference in New Issue
Block a user