diff --git a/daemon/p2p_announce.c b/daemon/p2p_announce.c index 88a76f09b..7dc445a1f 100644 --- a/daemon/p2p_announce.c +++ b/daemon/p2p_announce.c @@ -9,6 +9,7 @@ #include "utils.h" #include +#include #include #include #include @@ -35,32 +36,104 @@ u8 ipv4prefix[] = { 0x00, 0x00, 0xFF, 0xFF }; -/* Read an IP from `srcip` and convert it into the dotted - * notation. Handles both IPv4 and IPv6 addresses and converts - * accordingly. We differentiate the two by using the RFC 4291 - * IPv4-mapped IPv6 format */ -static char* read_ip(const tal_t *ctx, const struct ipv6 *srcip) +/* BOLT #7: + * + * The following `address descriptor` types are defined: + * + * 1. `0`: padding. data = none (length 0). + * 1. `1`: IPv4. data = `[4:ipv4-addr][2:port]` (length 6) + * 2. `2`: IPv6. data = `[16:ipv6-addr][2:port]` (length 18) + */ + +/* FIXME: Don't just take first one, depends whether we have IPv6 ourselves */ +/* Returns false iff it was malformed */ +static bool read_ip(const tal_t *ctx, const u8 *addresses, char **hostname, + int *port) { + size_t len = tal_count(addresses); + const u8 *p = addresses; char tempaddr[INET6_ADDRSTRLEN]; - - if (memcmp(srcip, ipv4prefix, sizeof(ipv4prefix)) == 0) { - inet_ntop(AF_INET, srcip + 12, tempaddr, sizeof(tempaddr)); - }else{ - inet_ntop(AF_INET6, srcip, tempaddr, sizeof(tempaddr)); + be16 portnum; + + *hostname = NULL; + while (len) { + u8 type = *p; + p++; + len--; + + switch (type) { + case 0: + break; + case 1: + /* BOLT #7: + * + * The receiving node SHOULD fail the connection if + * `addrlen` is insufficient to hold the address + * descriptors of the known types. + */ + if (len < 6) + return false; + inet_ntop(AF_INET, p, tempaddr, sizeof(tempaddr)); + memcpy(&portnum, p + 4, sizeof(portnum)); + *hostname = tal_strdup(ctx, tempaddr); + return true; + case 2: + if (len < 18) + return false; + inet_ntop(AF_INET6, p, tempaddr, sizeof(tempaddr)); + memcpy(&portnum, p + 16, sizeof(portnum)); + *hostname = tal_strdup(ctx, tempaddr); + return true; + default: + /* BOLT #7: + * + * The receiving node SHOULD ignore the first `address + * descriptor` which does not match the types defined + * above. + */ + return true; + } } - return tal_strdup(ctx, tempaddr); + + /* Not a fatal error. */ + return true; } -/* Serialize the IP address in `srcip` into a 16 byte - * representation. It handles both IPv6 and IPv4 addresses, prefixing - * IPv4 addresses with the prefix described in RFC 4291. */ -static void write_ip(struct ipv6 *dstip, char *srcip) +/* BOLT #7: + * + * The creating node SHOULD fill `addresses` with an address descriptor for + * each public network address which expects incoming connections, and MUST + * set `addrlen` to the number of bytes in `addresses`. Non-zero typed + * address descriptors MUST be placed in ascending order; any number of + * zero-typed address descriptors MAY be placed anywhere, but SHOULD only be + * used for aligning fields following `addresses`. + * + * The creating node MUST NOT create a type 1 or type 2 address descriptor + * with `port` equal to zero, and SHOULD ensure `ipv4-addr` and `ipv6-addr` + * are routable addresses. The creating node MUST NOT include more than one + * `address descriptor` of the same type. + */ +/* FIXME: handle case where we have both ipv6 and ipv4 addresses! */ +static u8 *write_ip(const tal_t *ctx, const char *srcip, int port) { + u8 *address; + be16 portnum = cpu_to_be16(port); + + if (!port) + return tal_arr(ctx, u8, 0); + if (!strchr(srcip, ':')) { - memcpy(dstip, ipv4prefix, sizeof(ipv4prefix)); - inet_pton(AF_INET, srcip, dstip); + address = tal_arr(ctx, u8, 7); + address[0] = 1; + inet_pton(AF_INET, srcip, address+1); + memcpy(address + 5, &portnum, sizeof(portnum)); + return address; } else { - inet_pton(AF_INET6, srcip, dstip); + address = tal_arr(ctx, u8, 18); + address[0] = 2; + inet_pton(AF_INET6, srcip, address+1); + memcpy(address + 17, &portnum, sizeof(portnum)); + return address; } } @@ -276,18 +349,17 @@ void handle_node_announcement( struct node *node; struct signature signature; u32 timestamp; - struct ipv6 ipv6; - u16 port; struct pubkey node_id; u8 rgb_color[3]; u8 alias[32]; - u8 *features; + u8 *features, *addresses; const tal_t *tmpctx = tal_tmpctx(peer); serialized = tal_dup_arr(tmpctx, u8, node_ann, len, 0); if (!fromwire_node_announcement(tmpctx, serialized, NULL, - &signature, ×tamp, &ipv6, &port, - &node_id, rgb_color, alias, &features)) { + &signature, ×tamp, + &node_id, rgb_color, alias, &features, + &addresses)) { tal_free(tmpctx); return; } @@ -320,8 +392,11 @@ void handle_node_announcement( node->last_timestamp = timestamp; node->hostname = tal_free(node->hostname); - node->hostname = read_ip(node, &ipv6); - node->port = port; + if (!read_ip(node, addresses, &node->hostname, &node->port)) { + /* FIXME: SHOULD fail connection here. */ + tal_free(serialized); + return; + } memcpy(node->rgb_color, rgb_color, 3); u8 *tag = tal_arr(tmpctx, u8, 0); @@ -379,11 +454,11 @@ static void broadcast_node_announcement(struct lightningd_state *dstate) { u8 *serialized; struct signature signature; - struct ipv6 ipv6; static const u8 rgb_color[3]; static const u8 alias[32]; u32 timestamp = time_now().ts.tv_sec; const tal_t *tmpctx = tal_tmpctx(dstate); + u8 *address; /* Are we listening for incoming connections at all? */ if (!dstate->external_ip || !dstate->portnum) { @@ -394,19 +469,19 @@ static void broadcast_node_announcement(struct lightningd_state *dstate) /* Avoid triggering memcheck */ memset(&signature, 0, sizeof(signature)); - write_ip(&ipv6, dstate->external_ip); + address = write_ip(tmpctx, dstate->external_ip, dstate->portnum); serialized = towire_node_announcement(tmpctx, &signature, timestamp, - &ipv6, dstate->portnum, &dstate->id, rgb_color, alias, - 0, NULL); + 0, NULL, + tal_count(address), address); privkey_sign(dstate, serialized + 66, tal_count(serialized) - 66, &signature); serialized = towire_node_announcement(tmpctx, &signature, timestamp, - &ipv6, dstate->portnum, &dstate->id, rgb_color, alias, - 0, NULL); + 0, NULL, + tal_count(address), address); broadcast(dstate, WIRE_NODE_ANNOUNCEMENT, serialized, NULL); tal_free(tmpctx); } diff --git a/daemon/routing.h b/daemon/routing.h index aac61b0d6..042a2931e 100644 --- a/daemon/routing.h +++ b/daemon/routing.h @@ -41,7 +41,7 @@ struct node_connection { struct node { struct pubkey id; - /* IP/Hostname and port of this node */ + /* IP/Hostname and port of this node (may be NULL) */ char *hostname; int port; diff --git a/wire/gen_peer_wire_csv b/wire/gen_peer_wire_csv index e64eaf3c5..a3b08a937 100644 --- a/wire/gen_peer_wire_csv +++ b/wire/gen_peer_wire_csv @@ -104,13 +104,13 @@ channel_announcement,398,features,len node_announcement,257 node_announcement,0,signature,64 node_announcement,64,timestamp,4 -node_announcement,68,ipv6,16 -node_announcement,84,port,2 -node_announcement,86,node-id,33 -node_announcement,119,rgb-color,3 -node_announcement,122,alias,32 -node_announcement,154,len,2 -node_announcement,156,features,len +node_announcement,68,node-id,33 +node_announcement,101,rgb-color,3 +node_announcement,104,alias,32 +node_announcement,136,flen,2 +node_announcement,138,features,flen +node_announcement,138+flen,addrlen,2 +node_announcement,140+flen,addresses,addrlen channel_update,258 channel_update,0,signature,64 channel_update,64,channel-id,8 diff --git a/wire/test/run-peer-wire.c b/wire/test/run-peer-wire.c index 92831da44..252d2ccb5 100644 --- a/wire/test/run-peer-wire.c +++ b/wire/test/run-peer-wire.c @@ -158,13 +158,13 @@ struct msg_commit_sig { struct msg_node_announcement { struct signature signature; u32 timestamp; - struct ipv6 ipv6; - u16 port; struct pubkey node_id; u8 rgb_color[3]; u8 alias[32]; u16 len; u8 *features; + u16 alen; + u8 *addresses; }; struct msg_open_channel { struct channel_id temporary_channel_id; @@ -348,12 +348,11 @@ static void *towire_struct_node_announcement(const tal_t *ctx, return towire_node_announcement(ctx, &s->signature, s->timestamp, - &s->ipv6, - s->port, &s->node_id, s->rgb_color, s->alias, - s->len, s->features); + s->len, s->features, + s->alen, s->addresses); } static struct msg_node_announcement *fromwire_struct_node_announcement(const tal_t *ctx, const void *p, size_t *plen) @@ -362,14 +361,13 @@ static struct msg_node_announcement *fromwire_struct_node_announcement(const tal if (!fromwire_node_announcement(s, p, plen, &s->signature, &s->timestamp, - &s->ipv6, - &s->port, &s->node_id, s->rgb_color, s->alias, - &s->features)) + &s->features, &s->addresses)) return tal_free(s); s->len = tal_count(s->features); + s->alen = tal_count(s->addresses); return s; } @@ -816,7 +814,8 @@ static bool node_announcement_eq(const struct msg_node_announcement *a, const struct msg_node_announcement *b) { return eq_with(a, b, alias) - && eq_var(a, b, len, features); + && eq_var(a, b, len, features) + && eq_var(a, b, alen, addresses); } /* Try flipping each bit, try running short. */ @@ -1056,6 +1055,9 @@ int main(void) na.len = 2; na.features = tal_arr(ctx, u8, 2); memset(na.features, 2, 2); + na.alen = 2; + na.addresses = tal_arr(ctx, u8, 2); + memset(na.addresses, 2, 2); msg = towire_struct_node_announcement(ctx, &na); len = tal_count(msg);