Browse Source

Clean up network options.

It's become clear that our network options are insufficient, with the coming
addition of Tor and unix domain support.

Currently:

1. We always bind to local IPv4 and IPv6 sockets, unless --port=0, --offline,
   or any address is specified explicitly.  If they're routable, we announce.
2. --addr is used to announce, but not to control binding.

After this change:

1. --port is deprecated.
2. --addr controls what we bind to and announce.
3. --bind-addr/--announce-addr can be used to control one and not the other.
4. Unless --autolisten=0, we add local IPv4 & IPv6 port 9735 (and announce if they are routable).
5. --offline still overrides listening (though announcing is still the same).

This means we can bind to as many ports/interfaces as we want, and for
special effects we can announce different things (eg. we're sitting
behind a port forward or a proxy).

What remains to implement is semi-automatic binding: we should be able
to say '--addr=0.0.0.0:9999' and have the address resolve at bind
time, or even '--addr=0.0.0.0:0' and have the port autoresolve too
(you could determine what it was from 'lightning-cli getinfo'.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 7 years ago
committed by Christian Decker
parent
commit
fe96fe10c7
  1. 11
      common/wireaddr.c
  2. 12
      common/wireaddr.h
  3. 113
      gossipd/gossip.c
  4. 5
      gossipd/gossip_wire.csv
  5. 6
      lightningd/gossip_control.c
  6. 25
      lightningd/jsonrpc.c
  7. 2
      lightningd/lightningd.c
  8. 7
      lightningd/lightningd.h
  9. 34
      lightningd/netaddress.c
  10. 98
      lightningd/options.c
  11. 4
      tests/test_gossip.py
  12. 1
      tests/test_lightningd.py
  13. 5
      tests/utils.py

11
common/wireaddr.c

@ -42,6 +42,17 @@ void towire_wireaddr(u8 **pptr, const struct wireaddr *addr)
towire_u16(pptr, addr->port); 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);
}
char *fmt_wireaddr(const tal_t *ctx, const struct wireaddr *a) char *fmt_wireaddr(const tal_t *ctx, const struct wireaddr *a)
{ {
char addrstr[INET6_ADDRSTRLEN]; char addrstr[INET6_ADDRSTRLEN];

12
common/wireaddr.h

@ -37,10 +37,22 @@ struct wireaddr {
u16 port; 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 */ /* Inserts a single ADDR_TYPE_PADDING if addr is NULL */
void towire_wireaddr(u8 **pptr, const struct wireaddr *addr); void towire_wireaddr(u8 **pptr, const struct wireaddr *addr);
bool fromwire_wireaddr(const u8 **cursor, size_t *max, 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); 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); char *fmt_wireaddr(const tal_t *ctx, const struct wireaddr *a);

113
gossipd/gossip.c

@ -128,6 +128,7 @@ struct daemon {
u8 alias[33]; u8 alias[33];
u8 rgb[3]; u8 rgb[3];
struct wireaddr *wireaddrs; struct wireaddr *wireaddrs;
enum addr_listen_announce *listen_announce;
/* To make sure our node_announcement timestamps increase */ /* To make sure our node_announcement timestamps increase */
u32 last_announce_timestamp; u32 last_announce_timestamp;
@ -563,8 +564,10 @@ 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->wireaddrs); i++) {
if (daemon->listen_announce[i] & ADDR_ANNOUNCE)
towire_wireaddr(&addresses, daemon->wireaddrs+i); towire_wireaddr(&addresses, daemon->wireaddrs+i);
}
announcement = announcement =
towire_node_announcement(ctx, sig, features, timestamp, towire_node_announcement(ctx, sig, features, timestamp,
@ -1552,69 +1555,63 @@ static struct io_plan *connection_in(struct io_conn *conn, struct daemon *daemon
init_new_peer, daemon); init_new_peer, daemon);
} }
static void setup_listeners(struct daemon *daemon, u16 portnum) static void setup_listeners(struct daemon *daemon)
{ {
bool had_ipv6_wildcard = false;
struct sockaddr_in addr; struct sockaddr_in addr;
struct sockaddr_in6 addr6; struct sockaddr_in6 addr6;
socklen_t len; int fd;
int fd1, fd2;
if (!portnum) { for (size_t i = 0; i < tal_count(daemon->wireaddrs); i++) {
status_info("Zero portnum, not listening for incoming"); if (!(daemon->listen_announce[i] & ADDR_LISTEN))
return; continue;
}
memset(&addr, 0, sizeof(addr)); switch (daemon->wireaddrs[i].type) {
case ADDR_TYPE_IPV4:
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(daemon->wireaddrs[i].port);
addr.sin_port = htons(portnum); assert(daemon->wireaddrs[i].addrlen
== sizeof(addr.sin_addr));
memcpy(&addr.sin_addr,
daemon->wireaddrs[i].addr,
sizeof(addr.sin_addr));
/* We might fail if IPv6 bound to port first */
fd = make_listen_fd(AF_INET, &addr, sizeof(addr),
!had_ipv6_wildcard);
if (fd >= 0) {
status_trace("Created IPv4 listener on port %u",
daemon->wireaddrs[i].port);
io_new_listener(daemon, fd, connection_in,
daemon);
}
continue;
case ADDR_TYPE_IPV6:
memset(&addr6, 0, sizeof(addr6)); memset(&addr6, 0, sizeof(addr6));
addr6.sin6_family = AF_INET6; addr6.sin6_family = AF_INET6;
addr6.sin6_addr = in6addr_any; addr6.sin6_port = htons(daemon->wireaddrs[i].port);
addr6.sin6_port = htons(portnum); assert(daemon->wireaddrs[i].addrlen
== sizeof(addr6.sin6_addr));
/* IPv6, since on Linux that (usually) binds to IPv4 too. */ memcpy(&addr6.sin6_addr, daemon->wireaddrs[i].addr,
fd1 = make_listen_fd(AF_INET6, &addr6, sizeof(addr6), true); sizeof(addr6.sin6_addr));
if (fd1 >= 0) { if (memeqzero(&addr6.sin6_addr, sizeof(addr6.sin6_addr)))
struct sockaddr_in6 in6 = {}; had_ipv6_wildcard = true;
fd = make_listen_fd(AF_INET6, &addr6, sizeof(addr6),
len = sizeof(in6); true);
if (getsockname(fd1, (void *)&in6, &len) != 0) { if (fd >= 0) {
status_broken("Failed get IPv6 sockname: %s", status_trace("Created IPv6 listener on port %u",
strerror(errno)); daemon->wireaddrs[i].port);
close_noerr(fd1); io_new_listener(daemon, fd, connection_in,
fd1 = -1; daemon);
} 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);
}
}
/* 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);
} }
continue;
case ADDR_TYPE_PADDING:
break;
} }
/* Shouldn't happen. */
if (fd1 < 0 && fd2 < 0)
status_failed(STATUS_FAIL_INTERNAL_ERROR, status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Could not bind to a network address on port %u", "Invalid listener address type %u",
portnum); daemon->wireaddrs[i].type);
}
} }
/* Parse an incoming gossip init message and assign config variables /* Parse an incoming gossip init message and assign config variables
@ -1630,7 +1627,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->rgb, &daemon->localfeatures, &daemon->wireaddrs,
&daemon->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);
} }
@ -1652,12 +1650,13 @@ static struct io_plan *gossip_activate(struct daemon_conn *master,
struct daemon *daemon, struct daemon *daemon,
const u8 *msg) const u8 *msg)
{ {
u16 port; bool listen;
if (!fromwire_gossipctl_activate(msg, &port)) if (!fromwire_gossipctl_activate(msg, &listen))
master_badmsg(WIRE_GOSSIPCTL_ACTIVATE, msg); master_badmsg(WIRE_GOSSIPCTL_ACTIVATE, msg);
setup_listeners(daemon, port); if (listen)
setup_listeners(daemon);
/* OK, we're ready! */ /* OK, we're ready! */
daemon_conn_send(&daemon->master, daemon_conn_send(&daemon->master,

5
gossipd/gossip_wire.csv

@ -13,6 +13,7 @@ gossipctl_init,,lflen,u16
gossipctl_init,,lfeatures,lflen*u8 gossipctl_init,,lfeatures,lflen*u8
gossipctl_init,,num_wireaddrs,u16 gossipctl_init,,num_wireaddrs,u16
gossipctl_init,,wireaddrs,num_wireaddrs*struct wireaddr gossipctl_init,,wireaddrs,num_wireaddrs*struct wireaddr
gossipctl_init,,listen_announce,num_wireaddrs*enum addr_listen_announce
gossipctl_init,,rgb,3*u8 gossipctl_init,,rgb,3*u8
gossipctl_init,,alias,32*u8 gossipctl_init,,alias,32*u8
gossipctl_init,,update_channel_interval,u32 gossipctl_init,,update_channel_interval,u32
@ -20,8 +21,8 @@ gossipctl_init,,reconnect,bool
# Activate the gossip daemon, so others can connect. # Activate the gossip daemon, so others can connect.
gossipctl_activate,3025 gossipctl_activate,3025
# If non-zero, port to listen on. # Do we listen?
gossipctl_activate,,port,u16 gossipctl_activate,,listen,bool
# Gossipd->master, I am ready. # Gossipd->master, I am ready.
gossipctl_activate_reply,3125 gossipctl_activate_reply,3125

Can't render this file because it has a wrong number of fields in line 6.

6
lightningd/gossip_control.c

@ -206,7 +206,8 @@ void gossip_init(struct lightningd *ld)
tmpctx, ld->config.broadcast_interval, tmpctx, ld->config.broadcast_interval,
&get_chainparams(ld)->genesis_blockhash, &ld->id, &get_chainparams(ld)->genesis_blockhash, &ld->id,
get_offered_global_features(tmpctx), get_offered_global_features(tmpctx),
get_offered_local_features(tmpctx), ld->wireaddrs, ld->rgb, get_offered_local_features(tmpctx), ld->wireaddrs,
ld->listen_announce, ld->rgb,
ld->alias, ld->config.channel_update_interval, ld->reconnect); ld->alias, ld->config.channel_update_interval, ld->reconnect);
subd_send_msg(ld->gossip, msg); subd_send_msg(ld->gossip, msg);
} }
@ -222,8 +223,7 @@ static void gossip_activate_done(struct subd *gossip UNUSED,
void gossip_activate(struct lightningd *ld) void gossip_activate(struct lightningd *ld)
{ {
const u8 *msg = towire_gossipctl_activate(NULL, const u8 *msg = towire_gossipctl_activate(NULL, ld->listen);
ld->listen ? ld->portnum : 0);
subd_req(ld->gossip, ld->gossip, take(msg), -1, 0, subd_req(ld->gossip, ld->gossip, take(msg), -1, 0,
gossip_activate_done, NULL); gossip_activate_done, NULL);

25
lightningd/jsonrpc.c

@ -149,12 +149,31 @@ 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 && cmd->ld->portnum) { if (cmd->ld->listen) {
bool have_listen_no_announce = false;
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 */
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->wireaddrs); i++) {
json_add_address(response, NULL, cmd->ld->wireaddrs+i); if (cmd->ld->listen_announce[i] & ADDR_ANNOUNCE)
json_add_address(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) {
json_array_start(response, "listen-only");
for (size_t i = 0; i < tal_count(cmd->ld->wireaddrs); i++) {
if (cmd->ld->listen_announce[i] == ADDR_LISTEN)
json_add_address(response, NULL,
cmd->ld->wireaddrs+i);
}
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));

2
lightningd/lightningd.c

@ -70,8 +70,10 @@ static struct lightningd *new_lightningd(const tal_t *ctx)
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, 0); ld->wireaddrs = tal_arr(ld, struct wireaddr, 0);
ld->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->reconnect = true; ld->reconnect = true;
timers_init(&ld->timers, time_mono()); timers_init(&ld->timers, time_mono());
ld->topology = new_topology(ld, ld->log); ld->topology = new_topology(ld, ld->log);

7
lightningd/lightningd.h

@ -117,8 +117,13 @@ struct lightningd {
/* Do we want to listen for other peers? */ /* Do we want to listen for other peers? */
bool listen; bool listen;
/* Addresses to announce to the network (tal_count()) */ /* Do we want to guess addresses to listen and announce? */
bool autolisten;
/* Addresses to bind/announce to the network (tal_count()) */
struct wireaddr *wireaddrs; struct wireaddr *wireaddrs;
/* And the bitset for each, whether to listen, announce or both */
enum addr_listen_announce *listen_announce;
/* Bearer of all my secrets. */ /* Bearer of all my secrets. */
int hsm_fd; int hsm_fd;

34
lightningd/netaddress.c

@ -228,9 +228,12 @@ static bool get_local_sockname(struct lightningd *ld,
return true; return true;
} }
/* Return a wireaddr without port filled in */ /* Return 0 if not available, or whether it's listenable-only or announceable.
static bool guess_one_address(struct lightningd *ld, * If it's listenable only, will set wireaddr to all-zero address for universal
struct wireaddr *addr, u16 portnum, * binding. */
static enum addr_listen_announce guess_one_address(struct lightningd *ld,
struct wireaddr *addr,
u16 portnum,
enum wire_addr_type type) enum wire_addr_type type)
{ {
addr->type = type; addr->type = type;
@ -245,7 +248,7 @@ static bool guess_one_address(struct lightningd *ld,
sin.sin_addr.s_addr = 0x08080808; sin.sin_addr.s_addr = 0x08080808;
sin.sin_family = AF_INET; sin.sin_family = AF_INET;
if (!get_local_sockname(ld, AF_INET, &sin, sizeof(sin))) if (!get_local_sockname(ld, AF_INET, &sin, sizeof(sin)))
return false; return 0;
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; break;
@ -260,25 +263,27 @@ static bool guess_one_address(struct lightningd *ld,
sin6.sin6_family = AF_INET6; sin6.sin6_family = AF_INET6;
memcpy(sin6.sin6_addr.s6_addr, pchGoogle, sizeof(pchGoogle)); memcpy(sin6.sin6_addr.s6_addr, pchGoogle, sizeof(pchGoogle));
if (!get_local_sockname(ld, AF_INET6, &sin6, sizeof(sin6))) if (!get_local_sockname(ld, AF_INET6, &sin6, sizeof(sin6)))
return false; return 0;
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; break;
} }
case ADDR_TYPE_PADDING: case ADDR_TYPE_PADDING:
log_debug(ld->log, "Padding address, ignoring"); log_debug(ld->log, "Padding address, ignoring");
return false; return 0;
} }
if (!IsRoutable(addr)) { if (!IsRoutable(addr)) {
log_debug(ld->log, "Address %s is not routable", log_debug(ld->log, "Address %s is not routable",
type_to_string(tmpctx, struct wireaddr, addr)); type_to_string(tmpctx, struct wireaddr, addr));
return false; /* This corresponds to INADDR_ANY or in6addr_any */
memset(addr->addr, 0, addr->addrlen);
return ADDR_LISTEN;
} }
log_debug(ld->log, "Public address %s", log_debug(ld->log, "Public address %s",
type_to_string(tmpctx, struct wireaddr, addr)); type_to_string(tmpctx, struct wireaddr, addr));
return true; return ADDR_LISTEN_AND_ANNOUNCE;
} }
void guess_addresses(struct lightningd *ld) void guess_addresses(struct lightningd *ld)
@ -289,10 +294,19 @@ void guess_addresses(struct lightningd *ld)
/* We allocate an extra, then remove if it's not needed. */ /* We allocate an extra, then remove if it's not needed. */
tal_resize(&ld->wireaddrs, n+1); tal_resize(&ld->wireaddrs, n+1);
if (guess_one_address(ld, &ld->wireaddrs[n], ld->portnum, ADDR_TYPE_IPV4)) { tal_resize(&ld->listen_announce, n+1);
/* We do IPv6 first: on Linux, that binds to IPv4 too. */
ld->listen_announce[n] = guess_one_address(ld, &ld->wireaddrs[n],
ld->portnum, ADDR_TYPE_IPV6);
if (ld->listen_announce[n] != 0) {
n++; n++;
tal_resize(&ld->wireaddrs, n+1); tal_resize(&ld->wireaddrs, n+1);
tal_resize(&ld->listen_announce, n+1);
} }
if (!guess_one_address(ld, &ld->wireaddrs[n], ld->portnum, ADDR_TYPE_IPV6)) ld->listen_announce[n] = guess_one_address(ld, &ld->wireaddrs[n],
ld->portnum, ADDR_TYPE_IPV4);
if (ld->listen_announce[n] == 0) {
tal_resize(&ld->wireaddrs, n); tal_resize(&ld->wireaddrs, n);
tal_resize(&ld->listen_announce, n);
}
} }

98
lightningd/options.c

@ -102,11 +102,15 @@ static char *opt_set_u32(const char *arg, u32 *u)
return NULL; 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; char *endp;
unsigned long l; unsigned long l;
log_broken(ld->log, "--port has been deprecated, use --autolisten=0 or --addr=:<port>");
if (!deprecated_apis)
return "--port is deprecated";
assert(arg != NULL); assert(arg != NULL);
/* This is how the manpage says to do it. Yech. */ /* This is how the manpage says to do it. Yech. */
@ -114,9 +118,13 @@ static char *opt_set_u16(const char *arg, u16 *u)
l = strtoul(arg, &endp, 0); l = strtoul(arg, &endp, 0);
if (*endp || !arg[0]) if (*endp || !arg[0])
return tal_fmt(NULL, "'%s' is not a number", arg); return tal_fmt(NULL, "'%s' is not a number", arg);
*u = l; ld->portnum = l;
if (errno || *u != l) if (errno || ld->portnum != l)
return tal_fmt(NULL, "'%s' is out of range", arg); return tal_fmt(NULL, "'%s' is out of range", arg);
if (ld->portnum == 0)
ld->autolisten = false;
return NULL; return NULL;
} }
@ -138,7 +146,9 @@ static char *opt_set_s32(const char *arg, s32 *u)
return NULL; return NULL;
} }
static char *opt_add_addr(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->wireaddrs);
char const *err_msg; char const *err_msg;
@ -146,6 +156,8 @@ static char *opt_add_addr(const char *arg, struct lightningd *ld)
assert(arg != NULL); assert(arg != NULL);
tal_resize(&ld->wireaddrs, n+1); tal_resize(&ld->wireaddrs, n+1);
tal_resize(&ld->listen_announce, n+1);
ld->listen_announce[n] = ala;
if (!parse_wireaddr(arg, &ld->wireaddrs[n], ld->portnum, &err_msg)) { 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); return tal_fmt(NULL, "Unable to parse IP address '%s': %s", arg, err_msg);
@ -155,6 +167,21 @@ static char *opt_add_addr(const char *arg, struct lightningd *ld)
} }
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) static char *opt_add_ipaddr(const char *arg, struct lightningd *ld)
{ {
log_broken(ld->log, "--ipaddr has been deprecated, use --addr"); log_broken(ld->log, "--ipaddr has been deprecated, use --addr");
@ -177,11 +204,6 @@ static void opt_show_s32(char buf[OPT_SHOW_LEN], const s32 *u)
snprintf(buf, OPT_SHOW_LEN, "%"PRIi32, *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) static char *opt_set_network(const char *arg, struct lightningd *ld)
{ {
assert(arg != NULL); assert(arg != NULL);
@ -339,9 +361,19 @@ static void config_register_opts(struct lightningd *ld)
ld, opt_hidden); ld, opt_hidden);
opt_register_arg("--addr", opt_add_addr, NULL, opt_register_arg("--addr", opt_add_addr, NULL,
ld, ld,
"Set the IP address (v4 or v6) to listen on and announce to the network for incoming connections"); "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 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, 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, opt_register_early_arg("--network", opt_set_network, opt_show_network,
ld, ld,
@ -649,8 +681,8 @@ void register_opts(struct lightningd *ld)
/* --port needs to be an early arg to force it being parsed /* --port needs to be an early arg to force it being parsed
* before --ipaddr which may depend on it */ * before --ipaddr which may depend on it */
opt_register_early_arg("--port", opt_set_u16, opt_show_u16, &ld->portnum, opt_register_early_arg("--port", opt_set_port, NULL, ld,
"Port to bind to (0 means don't listen)"); opt_hidden);
opt_register_arg("--bitcoin-datadir", opt_set_talstr, NULL, opt_register_arg("--bitcoin-datadir", opt_set_talstr, NULL,
&ld->topology->bitcoind->datadir, &ld->topology->bitcoind->datadir,
"-datadir arg for bitcoin-cli"); "-datadir arg for bitcoin-cli");
@ -778,11 +810,11 @@ void handle_opts(struct lightningd *ld, int argc, char *argv[])
check_config(ld); check_config(ld);
if (ld->portnum && ld->listen && tal_count(ld->wireaddrs) == 0) if (ld->listen && ld->autolisten)
guess_addresses(ld); guess_addresses(ld);
else else
log_debug(ld->log, "Not guessing addresses: %s", log_debug(ld->log, "Not guessing addresses: %s",
(ld->portnum && ld->listen) ? "manually set" : "port set to zero"); !ld->listen ? "--offline" : "--autolisten=0");
} }
/* FIXME: This is a hack! Expose somehow in ccan/opt.*/ /* FIXME: This is a hack! Expose somehow in ccan/opt.*/
@ -801,6 +833,21 @@ static const char *next_name(const char *names, unsigned *len)
return first_name(names + 1, len); return first_name(names + 1, len);
} }
static void json_add_opt_addrs(struct json_result *response,
const char *name0,
const struct wireaddr *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(name0, wireaddrs+i));
}
}
static void add_config(struct lightningd *ld, static void add_config(struct lightningd *ld,
struct json_result *response, struct json_result *response,
const struct opt_table *opt, const struct opt_table *opt,
@ -870,16 +917,25 @@ static void add_config(struct lightningd *ld,
topo->override_fee_rate[0], topo->override_fee_rate[0],
topo->override_fee_rate[1], topo->override_fee_rate[1],
topo->override_fee_rate[2]); 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) { } else if (opt->cb_arg == (void *)opt_add_ipaddr) {
/* 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) {
/* This is a bit weird, we can have multiple args */ json_add_opt_addrs(response, name0,
for (size_t i = 0; i < tal_count(ld->wireaddrs); i++) { ld->wireaddrs, ld->listen_announce,
json_add_string(response, ADDR_LISTEN_AND_ANNOUNCE);
name0, return;
fmt_wireaddr(name0, } else if (opt->cb_arg == (void *)opt_add_bind_addr) {
ld->wireaddrs+i)); json_add_opt_addrs(response, name0,
} ld->wireaddrs, ld->listen_announce,
ADDR_LISTEN);
return;
} else if (opt->cb_arg == (void *)opt_add_announce_addr) {
json_add_opt_addrs(response, name0,
ld->wireaddrs, ld->listen_announce,
ADDR_ANNOUNCE);
return; return;
#if DEVELOPER #if DEVELOPER
} else if (strstarts(name, "dev-")) { } else if (strstarts(name, "dev-")) {

4
tests/test_gossip.py

@ -16,8 +16,8 @@ def test_gossip_pruning(node_factory, bitcoind):
opts = {'channel-update-interval': 5} opts = {'channel-update-interval': 5}
l1, l2, l3 = node_factory.get_nodes(3, opts) l1, l2, l3 = node_factory.get_nodes(3, opts)
l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
l2.rpc.connect(l3.info['id'], 'localhost', l3.info['port']) l2.rpc.connect(l3.info['id'], 'localhost', l3.port)
scid1 = l1.fund_channel(l2, 10**6) scid1 = l1.fund_channel(l2, 10**6)
scid2 = l2.fund_channel(l3, 10**6) scid2 = l2.fund_channel(l3, 10**6)

1
tests/test_lightningd.py

@ -4288,7 +4288,6 @@ class LightningDTests(BaseLightningDTests):
# See utils.py # See utils.py
assert configs['bitcoin-datadir'] == bitcoind.bitcoin_dir assert configs['bitcoin-datadir'] == bitcoind.bitcoin_dir
assert configs['lightning-dir'] == l1.daemon.lightning_dir assert configs['lightning-dir'] == l1.daemon.lightning_dir
assert configs['port'] == l1.port
assert configs['allow-deprecated-apis'] is False assert configs['allow-deprecated-apis'] is False
assert configs['override-fee-rates'] == '15000/7500/1000' assert configs['override-fee-rates'] == '15000/7500/1000'
assert configs['network'] == 'regtest' assert configs['network'] == 'regtest'

5
tests/utils.py

@ -261,7 +261,7 @@ class LightningD(TailableProc):
opts = { opts = {
'bitcoin-datadir': bitcoin_dir, 'bitcoin-datadir': bitcoin_dir,
'lightning-dir': lightning_dir, 'lightning-dir': lightning_dir,
'port': port, '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',
@ -369,7 +369,8 @@ class LightningNode(object):
def start(self): def start(self):
self.daemon.start() self.daemon.start()
self.port = self.rpc.getinfo()['port'] # This shortcut is sufficient for our simple tests.
self.port = self.rpc.getinfo()['address'][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

Loading…
Cancel
Save