Skip to content

Commit

Permalink
gossipd/lightningd: use wireaddr_internal.
Browse files Browse the repository at this point in the history
This replacement is a little menial, but it explicitly catches all
the places where we allow a local socket.  The actual implementation of
opening a AF_UNIX socket is almost hidden in the patch.

The detection of "valid address" is now more complex:

	p->addr.itype != ADDR_INTERNAL_WIREADDR || p->addr.u.wireaddr.type != ADDR_TYPE_PADDING

But most places we do this, we should audit: I'm pretty sure we can't
get an invalid address any more from gossipd (they may be in db, but
we should fix that too).

Closes: ElementsProject#1323
Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell authored and cdecker committed May 7, 2018
1 parent 6b2282f commit 73cd009
Show file tree
Hide file tree
Showing 22 changed files with 249 additions and 153 deletions.
205 changes: 134 additions & 71 deletions gossipd/gossip.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#include <wire/gen_peer_wire.h>
#include <wire/wire_io.h>
Expand Down Expand Up @@ -128,7 +129,7 @@ struct daemon {

u8 alias[33];
u8 rgb[3];
struct wireaddr *wireaddrs;
struct wireaddr_internal *wireaddrs;
enum addr_listen_announce *listen_announce;

/* To make sure our node_announcement timestamps increase */
Expand All @@ -149,7 +150,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;
Expand Down Expand Up @@ -192,7 +193,7 @@ struct peer {
struct pubkey id;

/* Where it's connected to. */
struct wireaddr addr;
struct wireaddr_internal addr;

/* Feature bitmaps. */
u8 *gfeatures, *lfeatures;
Expand All @@ -214,7 +215,7 @@ struct addrhint {

struct pubkey id;
/* FIXME: use array... */
struct wireaddr addr;
struct wireaddr_internal addr;
};

/* FIXME: Reorder */
Expand Down Expand Up @@ -309,7 +310,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);
Expand Down Expand Up @@ -522,7 +523,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)
{
Expand Down Expand Up @@ -566,8 +567,12 @@ static u8 *create_node_announcement(const tal_t *ctx, struct daemon *daemon,
memset(sig, 0, sizeof(*sig));
}
for (i = 0; i < tal_count(daemon->wireaddrs); i++) {
if (daemon->listen_announce[i] & ADDR_ANNOUNCE)
towire_wireaddr(&addresses, daemon->wireaddrs+i);
if (!(daemon->listen_announce[i] & ADDR_ANNOUNCE))
continue;
/* You can only announce wiretypes! */
assert(daemon->wireaddrs[i].itype == ADDR_INTERNAL_WIREADDR);
towire_wireaddr(&addresses,
&daemon->wireaddrs[i].u.wireaddr);
}

announcement =
Expand Down Expand Up @@ -1521,7 +1526,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);

Expand All @@ -1533,10 +1538,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;
wireaddr_from_ipv6(&addr, &s6->sin6_addr, 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;
wireaddr_from_ipv4(&addr, &s4->sin_addr, 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);
Expand All @@ -1548,50 +1561,78 @@ static struct io_plan *connection_in(struct io_conn *conn, struct daemon *daemon
init_new_peer, daemon);
}

static void setup_listeners(struct daemon *daemon)
/* Returns true if it was an IPv6 wildcard (as inserted by guess_addresses) */
static bool handle_wireaddr_listen(struct daemon *daemon,
const struct wireaddr *wireaddr,
bool had_ipv6_wildcard)
{
bool had_ipv6_wildcard = false;
int fd;
struct sockaddr_in addr;
struct sockaddr_in6 addr6;

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),
!had_ipv6_wildcard);
if (fd >= 0) {
status_trace("Created IPv4 listener on port %u",
wireaddr->port);
io_new_listener(daemon, fd, connection_in, daemon);
}
return false;
case ADDR_TYPE_IPV6:
wireaddr_to_ipv6(wireaddr, &addr6);
if (memeqzero(&addr6.sin6_addr, sizeof(addr6.sin6_addr)))
had_ipv6_wildcard = true;
else
had_ipv6_wildcard = false;
fd = make_listen_fd(AF_INET6, &addr6, sizeof(addr6), true);
if (fd >= 0) {
status_trace("Created IPv6 listener on port %u",
wireaddr->port);
io_new_listener(daemon, fd, connection_in, daemon);
}
return had_ipv6_wildcard;
case ADDR_TYPE_PADDING:
break;
}
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Invalid listener wireaddress type %u", wireaddr->type);
}

static void setup_listeners(struct daemon *daemon)
{
bool had_ipv6_wildcard = false;
struct sockaddr_un addrun;
int fd;

for (size_t i = 0; i < tal_count(daemon->wireaddrs); i++) {
if (!(daemon->listen_announce[i] & ADDR_LISTEN))
continue;

switch (daemon->wireaddrs[i].type) {
case ADDR_TYPE_IPV4:
wireaddr_to_ipv4(&daemon->wireaddrs[i], &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);
}
switch (daemon->wireaddrs[i].itype) {
case ADDR_INTERNAL_SOCKNAME:
addrun.sun_family = AF_UNIX;
memcpy(addrun.sun_path, daemon->wireaddrs[i].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);
continue;
case ADDR_TYPE_IPV6:
wireaddr_to_ipv6(&daemon->wireaddrs[i], &addr6);
if (memeqzero(&addr6.sin6_addr, sizeof(addr6.sin6_addr)))
had_ipv6_wildcard = true;
fd = make_listen_fd(AF_INET6, &addr6, sizeof(addr6),
true);
if (fd >= 0) {
status_trace("Created IPv6 listener on port %u",
daemon->wireaddrs[i].port);
io_new_listener(daemon, fd, connection_in,
daemon);
}
case ADDR_INTERNAL_WIREADDR:
had_ipv6_wildcard = handle_wireaddr_listen(
daemon, &daemon->wireaddrs[i].u.wireaddr,
had_ipv6_wildcard);
continue;
case ADDR_TYPE_PADDING:
break;
}
/* Shouldn't happen. */
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Invalid listener address type %u",
daemon->wireaddrs[i].type);
daemon->wireaddrs[i].itype);
}
}

Expand Down Expand Up @@ -1686,7 +1727,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)
{
Expand Down Expand Up @@ -1751,6 +1792,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;
Expand All @@ -1759,24 +1801,32 @@ 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:
wireaddr_to_ipv4(&reach->addr, &sin);
ai.ai_family = sin.sin_family;
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;
break;
case ADDR_TYPE_IPV6:
wireaddr_to_ipv6(&reach->addr, &sin6);
ai.ai_family = sin6.sin6_family;
ai.ai_addrlen = sizeof(sin6);
ai.ai_addr = (struct sockaddr *)&sin6;
ai.ai_addr = (struct sockaddr *)&sun;
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);
}
Expand All @@ -1797,12 +1847,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;
}
}
Expand Down Expand Up @@ -1830,7 +1882,8 @@ gossip_resolve_addr(const tal_t *ctx,
* we should copy all addresses.
* For now getting first address should be fine. */
a = tal(ctx, struct addrhint);
a->addr = node->addresses[0];
a->addr.itype = ADDR_INTERNAL_WIREADDR;
a->addr.u.wireaddr = node->addresses[0];

return a;
}
Expand All @@ -1839,7 +1892,7 @@ 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);
Expand Down Expand Up @@ -1892,23 +1945,33 @@ 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);
af = -1;
switch (a->addr.itype) {
case ADDR_INTERNAL_SOCKNAME:
af = AF_LOCAL;
break;
case ADDR_TYPE_IPV6:
fd = socket(AF_INET6, SOCK_STREAM, 0);
break;
default:
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);
Expand Down Expand Up @@ -2051,7 +2114,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;
Expand Down
Loading

0 comments on commit 73cd009

Please sign in to comment.