gossipd: send updated node_annoucement remote_addr

This is the cheapest algo I came up with that simply checks that the
same `remote_addr` has been report by two different peers. Can be
improved in many ways:

 - Check by connecting to a radonm peers in the network
 - Check for more than two confirmations or a certain fraction
 - ...

Changelog-Added: Send updated node_annoucement when two peers report the same remote_addr.
This commit is contained in:
Michael Schmoock 2022-02-23 19:11:03 +01:00 committed by Rusty Russell
parent 28b4e57974
commit 67fdc6f8ad
15 changed files with 116 additions and 62 deletions

View File

@ -1,6 +1,7 @@
/* Routines to make our own gossip messages. Not as in "we're the gossip
* generation, man!" */
#include "config.h"
#include <ccan/asort/asort.h>
#include <ccan/cast/cast.h>
#include <ccan/mem/mem.h>
#include <common/daemon_conn.h>
@ -19,6 +20,15 @@
#include <hsmd/hsmd_wiregen.h>
#include <wire/wire_sync.h>
static bool wireaddr_arr_contains(const struct wireaddr *was,
const struct wireaddr *wa)
{
for (size_t i = 0; i < tal_count(was); i++)
if (wireaddr_eq(&was[i], wa))
return true;
return false;
}
/* Create a node_announcement with the given signature. It may be NULL in the
* case we need to create a provisional announcement for the HSM to sign.
* This is called twice: once with the dummy signature to get it signed and a
@ -30,16 +40,39 @@ static u8 *create_node_announcement(const tal_t *ctx, struct daemon *daemon,
u32 timestamp,
const struct lease_rates *rates)
{
struct wireaddr *was;
u8 *addresses = tal_arr(tmpctx, u8, 0);
u8 *announcement;
struct tlv_node_ann_tlvs *na_tlv;
size_t i;
/* add all announceable addresses */
was = tal_arr(tmpctx, struct wireaddr, 0);
for (i = 0; i < tal_count(daemon->announceable); i++)
tal_arr_expand(&was, daemon->announceable[i]);
/* add reported `remote_addr` v4 and v6 of our self */
if (daemon->remote_addr_v4 != NULL &&
!wireaddr_arr_contains(was, daemon->remote_addr_v4))
tal_arr_expand(&was, *daemon->remote_addr_v4);
if (daemon->remote_addr_v6 != NULL &&
!wireaddr_arr_contains(was, daemon->remote_addr_v6))
tal_arr_expand(&was, *daemon->remote_addr_v6);
/* Sort by address type again, as we added dynamic remote_addr v4/v6. */
/* BOLT #7:
*
* The origin node:
*...
* - MUST place address descriptors in ascending order.
*/
asort(was, tal_count(was), wireaddr_cmp_type, NULL);
if (!sig)
sig = talz(tmpctx, secp256k1_ecdsa_signature);
for (i = 0; i < tal_count(daemon->announceable); i++)
towire_wireaddr(&addresses, &daemon->announceable[i]);
for (i = 0; i < tal_count(was); i++)
towire_wireaddr(&addresses, &was[i]);
na_tlv = tlv_node_ann_tlvs_new(tmpctx);
na_tlv->option_will_fund = cast_const(struct lease_rates *, rates);

View File

@ -24,6 +24,7 @@
#include <common/timeout.h>
#include <common/type_to_string.h>
#include <common/wire_error.h>
#include <common/wireaddr.h>
#include <connectd/connectd_gossipd_wiregen.h>
#include <errno.h>
#include <gossipd/gossip_generation.h>
@ -341,6 +342,53 @@ static void handle_local_private_channel(struct daemon *daemon, const u8 *msg)
}
}
/* lightningd tells us it has dicovered and verified new `remote_addr`.
* We can use this to update our node announcement. */
static void handle_remote_addr(struct daemon *daemon, const u8 *msg)
{
struct wireaddr remote_addr;
if (!fromwire_gossipd_remote_addr(msg, &remote_addr))
master_badmsg(WIRE_GOSSIPD_REMOTE_ADDR, msg);
/* current best guess is that we use DEFAULT_PORT on public internet */
remote_addr.port = DEFAULT_PORT;
switch (remote_addr.type) {
case ADDR_TYPE_IPV4:
if (daemon->remote_addr_v4 != NULL &&
wireaddr_eq_without_port(daemon->remote_addr_v4,
&remote_addr))
break;
tal_free(daemon->remote_addr_v4);
daemon->remote_addr_v4 = tal_dup(daemon, struct wireaddr,
&remote_addr);
goto update_node_annoucement;
case ADDR_TYPE_IPV6:
if (daemon->remote_addr_v6 != NULL &&
wireaddr_eq_without_port(daemon->remote_addr_v6,
&remote_addr))
break;
tal_free(daemon->remote_addr_v6);
daemon->remote_addr_v6 = tal_dup(daemon, struct wireaddr,
&remote_addr);
goto update_node_annoucement;
/* ignore all other cases */
case ADDR_TYPE_TOR_V2_REMOVED:
case ADDR_TYPE_TOR_V3:
case ADDR_TYPE_DNS:
case ADDR_TYPE_WEBSOCKET:
break;
}
return;
update_node_annoucement:
status_debug("Update our node_announcement for discovered address: %s",
fmt_wireaddr(tmpctx, &remote_addr));
maybe_send_own_node_announce(daemon, false);
}
/*~ This is where connectd tells us about a new peer we might want to
* gossip with. */
static void connectd_new_peer(struct daemon *daemon, const u8 *msg)
@ -993,6 +1041,10 @@ static struct io_plan *recv_req(struct io_conn *conn,
case WIRE_GOSSIPD_LOCAL_PRIVATE_CHANNEL:
handle_local_private_channel(daemon, msg);
goto done;
case WIRE_GOSSIPD_REMOTE_ADDR:
handle_remote_addr(daemon, msg);
goto done;
#if DEVELOPER
case WIRE_GOSSIPD_DEV_SET_MAX_SCIDS_ENCODE_SIZE:
dev_set_max_scids_encode_size(daemon, msg);
@ -1062,6 +1114,8 @@ int main(int argc, char *argv[])
daemon->node_announce_regen_timer = NULL;
daemon->current_blockheight = 0; /* i.e. unknown */
daemon->rates = NULL;
daemon->remote_addr_v4 = NULL;
daemon->remote_addr_v6 = NULL;
list_head_init(&daemon->deferred_updates);
/* Tell the ecdh() function how to talk to hsmd */

View File

@ -47,6 +47,10 @@ struct daemon {
/* What addresses we can actually announce. */
struct wireaddr *announceable;
/* verified remote_addr as reported by recent peers */
struct wireaddr *remote_addr_v4;
struct wireaddr *remote_addr_v6;
/* Timer until we can send an updated node_announcement */
struct oneshot *node_announce_timer;

View File

@ -125,3 +125,7 @@ msgdata,gossipd_local_private_channel,features,u8,len
# Tell gossipd we used the channel update (in case it was deferred)
msgtype,gossipd_used_local_channel_update,3052
msgdata,gossipd_used_local_channel_update,scid,short_channel_id,
# Tell gossipd we have discovered a new remote_addr
msgtype,gossipd_remote_addr,3009
msgdata,gossipd_remote_addr,remote_addr,wireaddr,

1 #include <common/cryptomsg.h>
125
126
127
128
129
130
131

View File

@ -9,6 +9,7 @@ GOSSIPD_TEST_PROGRAMS := $(GOSSIPD_TEST_OBJS:.o=)
GOSSIPD_TEST_COMMON_OBJS := \
common/amount.o \
common/autodata.o \
common/base32.o \
common/coin_mvt.o \
common/bigsize.o \
common/blindedpath.o \
@ -25,6 +26,7 @@ GOSSIPD_TEST_COMMON_OBJS := \
common/sphinx.o \
common/type_to_string.o \
common/utils.o \
common/wireaddr.o \
gossipd/gossip_store_wiregen.o \
wire/peer$(EXP)_wiregen.o \
wire/onion$(EXP)_wiregen.o \

View File

@ -62,15 +62,6 @@ bool cupdate_different(struct gossip_store *gs UNNEEDED,
/* Generated stub for ecdh */
void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED)
{ fprintf(stderr, "ecdh called!\n"); abort(); }
/* Generated stub for fmt_wireaddr_without_port */
char *fmt_wireaddr_without_port(const tal_t *ctx UNNEEDED, const struct wireaddr *a UNNEEDED)
{ fprintf(stderr, "fmt_wireaddr_without_port called!\n"); abort(); }
/* Generated stub for fromwire_wireaddr */
bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED)
{ fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); }
/* Generated stub for fromwire_wireaddr_array */
struct wireaddr *fromwire_wireaddr_array(const tal_t *ctx UNNEEDED, const u8 *ser UNNEEDED)
{ fprintf(stderr, "fromwire_wireaddr_array called!\n"); abort(); }
/* Generated stub for gossip_store_add */
u64 gossip_store_add(struct gossip_store *gs UNNEEDED, const u8 *gossip_msg UNNEEDED,
u32 timestamp UNNEEDED, bool push UNNEEDED, const u8 *addendum UNNEEDED)
@ -157,9 +148,6 @@ void status_fmt(enum log_level level UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "status_fmt called!\n"); abort(); }
/* Generated stub for towire_wireaddr */
void towire_wireaddr(u8 **pptr UNNEEDED, const struct wireaddr *addr UNNEEDED)
{ fprintf(stderr, "towire_wireaddr called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */
int main(int argc, char *argv[])

View File

@ -33,9 +33,6 @@ void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED)
/* Generated stub for find_peer */
struct peer *find_peer(struct daemon *daemon UNNEEDED, const struct node_id *id UNNEEDED)
{ fprintf(stderr, "find_peer called!\n"); abort(); }
/* Generated stub for fmt_wireaddr_without_port */
char *fmt_wireaddr_without_port(const tal_t *ctx UNNEEDED, const struct wireaddr *a UNNEEDED)
{ fprintf(stderr, "fmt_wireaddr_without_port called!\n"); abort(); }
/* Generated stub for force_node_announce_rexmit */
void force_node_announce_rexmit(struct routing_state *rstate UNNEEDED, struct node *node UNNEEDED)
{ fprintf(stderr, "force_node_announce_rexmit called!\n"); abort(); }
@ -51,9 +48,6 @@ bool fromwire_hsmd_cupdate_sig_reply(const tal_t *ctx UNNEEDED, const void *p UN
/* Generated stub for fromwire_hsmd_node_announcement_sig_reply */
bool fromwire_hsmd_node_announcement_sig_reply(const void *p UNNEEDED, secp256k1_ecdsa_signature *signature UNNEEDED)
{ fprintf(stderr, "fromwire_hsmd_node_announcement_sig_reply called!\n"); abort(); }
/* Generated stub for fromwire_wireaddr */
bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED)
{ fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); }
/* Generated stub for get_node */
struct node *get_node(struct routing_state *rstate UNNEEDED,
const struct node_id *id UNNEEDED)
@ -121,9 +115,6 @@ u8 *towire_hsmd_cupdate_sig_req(const tal_t *ctx UNNEEDED, const u8 *cu UNNEEDED
/* Generated stub for towire_hsmd_node_announcement_sig_req */
u8 *towire_hsmd_node_announcement_sig_req(const tal_t *ctx UNNEEDED, const u8 *announcement UNNEEDED)
{ fprintf(stderr, "towire_hsmd_node_announcement_sig_req called!\n"); abort(); }
/* Generated stub for towire_wireaddr */
void towire_wireaddr(u8 **pptr UNNEEDED, const struct wireaddr *addr UNNEEDED)
{ fprintf(stderr, "towire_wireaddr called!\n"); abort(); }
/* Generated stub for wire_sync_read */
u8 *wire_sync_read(const tal_t *ctx UNNEEDED, int fd UNNEEDED)
{ fprintf(stderr, "wire_sync_read called!\n"); abort(); }

View File

@ -51,9 +51,6 @@ void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED)
/* Generated stub for find_peer */
struct peer *find_peer(struct daemon *daemon UNNEEDED, const struct node_id *id UNNEEDED)
{ fprintf(stderr, "find_peer called!\n"); abort(); }
/* Generated stub for fmt_wireaddr_without_port */
char *fmt_wireaddr_without_port(const tal_t *ctx UNNEEDED, const struct wireaddr *a UNNEEDED)
{ fprintf(stderr, "fmt_wireaddr_without_port called!\n"); abort(); }
/* Generated stub for force_node_announce_rexmit */
void force_node_announce_rexmit(struct routing_state *rstate UNNEEDED, struct node *node UNNEEDED)
{ fprintf(stderr, "force_node_announce_rexmit called!\n"); abort(); }
@ -72,9 +69,6 @@ bool fromwire_hsmd_cupdate_sig_reply(const tal_t *ctx UNNEEDED, const void *p UN
/* Generated stub for fromwire_hsmd_node_announcement_sig_reply */
bool fromwire_hsmd_node_announcement_sig_reply(const void *p UNNEEDED, secp256k1_ecdsa_signature *signature UNNEEDED)
{ fprintf(stderr, "fromwire_hsmd_node_announcement_sig_reply called!\n"); abort(); }
/* Generated stub for fromwire_wireaddr */
bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED)
{ fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); }
/* Generated stub for get_node */
struct node *get_node(struct routing_state *rstate UNNEEDED,
const struct node_id *id UNNEEDED)
@ -159,9 +153,6 @@ u8 *towire_warningfmt(const tal_t *ctx UNNEEDED,
const struct channel_id *channel UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "towire_warningfmt called!\n"); abort(); }
/* Generated stub for towire_wireaddr */
void towire_wireaddr(u8 **pptr UNNEEDED, const struct wireaddr *addr UNNEEDED)
{ fprintf(stderr, "towire_wireaddr called!\n"); abort(); }
/* Generated stub for wire_sync_read */
u8 *wire_sync_read(const tal_t *ctx UNNEEDED, int fd UNNEEDED)
{ fprintf(stderr, "wire_sync_read called!\n"); abort(); }

View File

@ -50,15 +50,9 @@ struct short_channel_id *decode_short_ids(const tal_t *ctx UNNEEDED, const u8 *e
/* Generated stub for ecdh */
void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED)
{ fprintf(stderr, "ecdh called!\n"); abort(); }
/* Generated stub for fmt_wireaddr_without_port */
char *fmt_wireaddr_without_port(const tal_t *ctx UNNEEDED, const struct wireaddr *a UNNEEDED)
{ fprintf(stderr, "fmt_wireaddr_without_port called!\n"); abort(); }
/* Generated stub for fromwire_gossipd_dev_set_max_scids_encode_size */
bool fromwire_gossipd_dev_set_max_scids_encode_size(const void *p UNNEEDED, u32 *max UNNEEDED)
{ fprintf(stderr, "fromwire_gossipd_dev_set_max_scids_encode_size called!\n"); abort(); }
/* Generated stub for fromwire_wireaddr */
bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED)
{ fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); }
/* Generated stub for get_cupdate_parts */
void get_cupdate_parts(const u8 *channel_update UNNEEDED,
const u8 *parts[2] UNNEEDED,
@ -110,9 +104,6 @@ u8 *towire_warningfmt(const tal_t *ctx UNNEEDED,
const struct channel_id *channel UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "towire_warningfmt called!\n"); abort(); }
/* Generated stub for towire_wireaddr */
void towire_wireaddr(u8 **pptr UNNEEDED, const struct wireaddr *addr UNNEEDED)
{ fprintf(stderr, "towire_wireaddr called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */
void status_fmt(enum log_level level UNNEEDED,

View File

@ -29,12 +29,6 @@ bool blinding_next_pubkey(const struct pubkey *pk UNNEEDED,
/* Generated stub for ecdh */
void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED)
{ fprintf(stderr, "ecdh called!\n"); abort(); }
/* Generated stub for fmt_wireaddr_without_port */
char *fmt_wireaddr_without_port(const tal_t *ctx UNNEEDED, const struct wireaddr *a UNNEEDED)
{ fprintf(stderr, "fmt_wireaddr_without_port called!\n"); abort(); }
/* Generated stub for fromwire_wireaddr */
bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED)
{ fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); }
/* Generated stub for json_add_member */
void json_add_member(struct json_stream *js UNNEEDED,
const char *fieldname UNNEEDED,
@ -96,9 +90,6 @@ void status_fmt(enum log_level level UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "status_fmt called!\n"); abort(); }
/* Generated stub for towire_wireaddr */
void towire_wireaddr(u8 **pptr UNNEEDED, const struct wireaddr *addr UNNEEDED)
{ fprintf(stderr, "towire_wireaddr called!\n"); abort(); }
/* Generated stub for would_ratelimit_cupdate */
bool would_ratelimit_cupdate(struct routing_state *rstate UNNEEDED,
const struct half_chan *hc UNNEEDED,

View File

@ -33,15 +33,6 @@ bool cupdate_different(struct gossip_store *gs UNNEEDED,
/* Generated stub for ecdh */
void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED)
{ fprintf(stderr, "ecdh called!\n"); abort(); }
/* Generated stub for fmt_wireaddr_without_port */
char *fmt_wireaddr_without_port(const tal_t *ctx UNNEEDED, const struct wireaddr *a UNNEEDED)
{ fprintf(stderr, "fmt_wireaddr_without_port called!\n"); abort(); }
/* Generated stub for fromwire_wireaddr */
bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED)
{ fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); }
/* Generated stub for fromwire_wireaddr_array */
struct wireaddr *fromwire_wireaddr_array(const tal_t *ctx UNNEEDED, const u8 *ser UNNEEDED)
{ fprintf(stderr, "fromwire_wireaddr_array called!\n"); abort(); }
/* Generated stub for gossip_store_add */
u64 gossip_store_add(struct gossip_store *gs UNNEEDED, const u8 *gossip_msg UNNEEDED,
u32 timestamp UNNEEDED, bool push UNNEEDED, const u8 *addendum UNNEEDED)
@ -127,9 +118,6 @@ u8 *towire_warningfmt(const tal_t *ctx UNNEEDED,
const struct channel_id *channel UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "towire_warningfmt called!\n"); abort(); }
/* Generated stub for towire_wireaddr */
void towire_wireaddr(u8 **pptr UNNEEDED, const struct wireaddr *addr UNNEEDED)
{ fprintf(stderr, "towire_wireaddr called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */
/* NOOP stub for gossip_store_new */

View File

@ -176,6 +176,7 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds)
case WIRE_GOSSIPD_ADDGOSSIP_REPLY:
case WIRE_GOSSIPD_NEW_BLOCKHEIGHT_REPLY:
case WIRE_GOSSIPD_GET_ADDRS_REPLY:
case WIRE_GOSSIPD_REMOTE_ADDR:
break;
case WIRE_GOSSIPD_GET_TXOUT:

View File

@ -35,6 +35,7 @@
#include <connectd/connectd_wiregen.h>
#include <errno.h>
#include <fcntl.h>
#include <gossipd/gossipd_wiregen.h>
#include <hsmd/hsmd_wiregen.h>
#include <inttypes.h>
#include <lightningd/bitcoind.h>
@ -1128,6 +1129,11 @@ static void update_remote_addr(struct lightningd *ld,
*ld->remote_addr_v4 = *remote_addr;
break;
}
/* tell gossip we have a valid update */
if (wireaddr_eq_without_port(ld->remote_addr_v4, remote_addr))
subd_send_msg(ld->gossip, towire_gossipd_remote_addr(
tmpctx,
ld->remote_addr_v4));
/* store latest values */
*ld->remote_addr_v4 = *remote_addr;
ld->remote_addr_v4_peer = peer_id;
@ -1143,6 +1149,10 @@ static void update_remote_addr(struct lightningd *ld,
*ld->remote_addr_v6 = *remote_addr;
break;
}
if (wireaddr_eq_without_port(ld->remote_addr_v6, remote_addr))
subd_send_msg(ld->gossip, towire_gossipd_remote_addr(
tmpctx,
ld->remote_addr_v6));
*ld->remote_addr_v6 = *remote_addr;
ld->remote_addr_v6_peer = peer_id;
break;

View File

@ -645,6 +645,9 @@ u8 *towire_errorfmt(const tal_t *ctx UNNEEDED,
const struct channel_id *channel UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "towire_errorfmt called!\n"); abort(); }
/* Generated stub for towire_gossipd_remote_addr */
u8 *towire_gossipd_remote_addr(const tal_t *ctx UNNEEDED, const struct wireaddr *remote_addr UNNEEDED)
{ fprintf(stderr, "towire_gossipd_remote_addr called!\n"); abort(); }
/* Generated stub for towire_hsmd_sign_bolt12 */
u8 *towire_hsmd_sign_bolt12(const tal_t *ctx UNNEEDED, const wirestring *messagename UNNEEDED, const wirestring *fieldname UNNEEDED, const struct sha256 *merkleroot UNNEEDED, const u8 *publictweak UNNEEDED)
{ fprintf(stderr, "towire_hsmd_sign_bolt12 called!\n"); abort(); }

View File

@ -749,6 +749,9 @@ u8 *towire_final_incorrect_cltv_expiry(const tal_t *ctx UNNEEDED, u32 cltv_expir
/* Generated stub for towire_final_incorrect_htlc_amount */
u8 *towire_final_incorrect_htlc_amount(const tal_t *ctx UNNEEDED, struct amount_msat incoming_htlc_amt UNNEEDED)
{ fprintf(stderr, "towire_final_incorrect_htlc_amount called!\n"); abort(); }
/* Generated stub for towire_gossipd_remote_addr */
u8 *towire_gossipd_remote_addr(const tal_t *ctx UNNEEDED, const struct wireaddr *remote_addr UNNEEDED)
{ fprintf(stderr, "towire_gossipd_remote_addr called!\n"); abort(); }
/* Generated stub for towire_hsmd_get_output_scriptpubkey */
u8 *towire_hsmd_get_output_scriptpubkey(const tal_t *ctx UNNEEDED, u64 channel_id UNNEEDED, const struct node_id *peer_id UNNEEDED, const struct pubkey *commitment_point UNNEEDED)
{ fprintf(stderr, "towire_hsmd_get_output_scriptpubkey called!\n"); abort(); }