diff --git a/daemon/routing.c b/daemon/routing.c index b8460504c..f1d90ea8d 100644 --- a/daemon/routing.c +++ b/daemon/routing.c @@ -78,6 +78,7 @@ struct node *new_node(struct routing_state *rstate, n->alias = NULL; n->hostname = NULL; n->node_announcement = NULL; + n->last_timestamp = 0; node_map_add(rstate->nodes, n); tal_add_destructor(n, destroy_node); diff --git a/lightningd/channel/channel.c b/lightningd/channel/channel.c index 48be0c9be..266fcce7d 100644 --- a/lightningd/channel/channel.c +++ b/lightningd/channel/channel.c @@ -305,6 +305,9 @@ static void handle_peer_announcement_signatures(struct peer *peer, const u8 *msg if (peer->funding_locked[LOCAL] && peer->have_sigs[LOCAL]) { send_channel_announcement(peer); send_channel_update(peer, false); + /* Tell the master that we just announced the channel, + * so it may announce the node */ + daemon_conn_send(&peer->master, take(towire_channel_announced(msg))); } } @@ -1105,6 +1108,9 @@ static void handle_funding_announce_depth(struct peer *peer, const u8 *msg) if (peer->have_sigs[REMOTE]) { send_channel_announcement(peer); send_channel_update(peer, false); + /* Tell the master that we just announced the channel, + * so it may announce the node */ + daemon_conn_send(&peer->master, take(towire_channel_announced(msg))); } } @@ -1326,6 +1332,7 @@ static struct io_plan *req_in(struct io_conn *conn, struct daemon_conn *master) case WIRE_CHANNEL_MALFORMED_HTLC: case WIRE_CHANNEL_PING_REPLY: case WIRE_CHANNEL_PEER_BAD_MESSAGE: + case WIRE_CHANNEL_ANNOUNCED: break; } status_failed(WIRE_CHANNEL_BAD_COMMAND, "%u %s", t, diff --git a/lightningd/channel/channel_wire.csv b/lightningd/channel/channel_wire.csv index 9c31a6b84..4ecaf657c 100644 --- a/lightningd/channel/channel_wire.csv +++ b/lightningd/channel/channel_wire.csv @@ -117,3 +117,5 @@ channel_ping,0,len,u16 channel_ping_reply,111 channel_ping_reply,0,totlen,u16 +# Channeld tells the master that the channel has been announced +channel_announced,12 \ No newline at end of file diff --git a/lightningd/gossip/gossip.c b/lightningd/gossip/gossip.c index a4dbbbabb..d60b9bdef 100644 --- a/lightningd/gossip/gossip.c +++ b/lightningd/gossip/gossip.c @@ -660,6 +660,15 @@ static struct io_plan *resolve_channel_req(struct io_conn *conn, return daemon_conn_read_next(conn, &daemon->master); } +static void handle_forwarded_msg(struct io_conn *conn, struct daemon *daemon, const u8 *msg) +{ + u8 *payload; + if (!fromwire_gossip_forwarded_msg(msg, msg, NULL, &payload)) { + status_trace("Malformed forwarded message: %s", tal_hex(trc, msg)); + return; + } + handle_gossip_msg(daemon->rstate, payload); +} static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master) { struct daemon *daemon = container_of(master, struct daemon, master); @@ -692,6 +701,9 @@ static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master case WIRE_GOSSIP_RESOLVE_CHANNEL_REQUEST: return resolve_channel_req(conn, daemon, daemon->master.msg_in); + case WIRE_GOSSIP_FORWARDED_MSG: + handle_forwarded_msg(conn, daemon, daemon->master.msg_in); + return daemon_conn_read_next(conn, &daemon->master); case WIRE_GOSSIPCTL_RELEASE_PEER_REPLY: case WIRE_GOSSIP_GETNODES_REPLY: case WIRE_GOSSIP_GETROUTE_REPLY: diff --git a/lightningd/gossip/gossip_wire.csv b/lightningd/gossip/gossip_wire.csv index 66656c1c7..4b44384bb 100644 --- a/lightningd/gossip/gossip_wire.csv +++ b/lightningd/gossip/gossip_wire.csv @@ -98,3 +98,9 @@ gossip_resolve_channel_request,0,channel_id,struct short_channel_id gossip_resolve_channel_reply,109 gossip_resolve_channel_reply,0,num_keys,u16 gossip_resolve_channel_reply,0,keys,num_keys*struct pubkey + +# The main daemon forward some gossip message to gossipd, allows injecting +# arbitrary gossip messages. +gossip_forwarded_msg,10 +gossip_forwarded_msg,0,msglen,2 +gossip_forwarded_msg,2,msg,msglen diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 776d854a0..a7e7c4b7c 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -148,6 +148,7 @@ static int gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) case WIRE_GOSSIP_GETCHANNELS_REQUEST: case WIRE_GOSSIP_PING: case WIRE_GOSSIP_RESOLVE_CHANNEL_REQUEST: + case WIRE_GOSSIP_FORWARDED_MSG: /* This is a reply, so never gets through to here. */ case WIRE_GOSSIPCTL_RELEASE_PEER_REPLY: case WIRE_GOSSIP_GETNODES_REPLY: diff --git a/lightningd/hsm/hsm.c b/lightningd/hsm/hsm.c index 0298b1374..490dd149c 100644 --- a/lightningd/hsm/hsm.c +++ b/lightningd/hsm/hsm.c @@ -511,6 +511,37 @@ static void sign_funding_tx(struct daemon_conn *master, const u8 *msg) tal_free(tmpctx); } +static void sign_node_announcement(struct daemon_conn *master, const u8 *msg) +{ + /* 2 bytes msg type + 64 bytes signature */ + size_t offset = 66; + struct sha256_double hash; + struct privkey node_pkey; + secp256k1_ecdsa_signature sig; + u8 *reply; + u8 *ann; + + if (!fromwire_hsmctl_node_announcement_sig_req(msg, msg, NULL, &ann)) { + status_trace("Failed to parse node_announcement_sig_req: %s", + tal_hex(trc, msg)); + return; + } + + if (tal_len(ann) < offset) { + status_trace("Node announcement too short: %s", tal_hex(trc, msg)); + return; + } + + /* FIXME(cdecker) Check the node announcement's content */ + node_key(&node_pkey, NULL); + sha256_double(&hash, ann + offset, tal_len(ann) - offset); + + sign_hash(&node_pkey, &hash, &sig); + + reply = towire_hsmctl_node_announcement_sig_reply(msg, &sig); + daemon_conn_send(master, take(reply)); +} + static struct io_plan *control_received_req(struct io_conn *conn, struct daemon_conn *master) { @@ -533,6 +564,10 @@ static struct io_plan *control_received_req(struct io_conn *conn, sign_funding_tx(master, master->msg_in); return daemon_conn_read_next(conn, master); + case WIRE_HSMCTL_NODE_ANNOUNCEMENT_SIG_REQ: + sign_node_announcement(master, master->msg_in); + return daemon_conn_read_next(conn, master); + case WIRE_HSMCTL_INIT_REPLY: case WIRE_HSMCTL_HSMFD_ECDH_FD_REPLY: case WIRE_HSMCTL_HSMFD_CHANNELD_REPLY: @@ -543,6 +578,7 @@ static struct io_plan *control_received_req(struct io_conn *conn, case WIRE_HSMSTATUS_FD_FAILED: case WIRE_HSMSTATUS_KEY_FAILED: case WIRE_HSMSTATUS_CLIENT_BAD_REQUEST: + case WIRE_HSMCTL_NODE_ANNOUNCEMENT_SIG_REPLY: break; } diff --git a/lightningd/hsm/hsm_wire.csv b/lightningd/hsm/hsm_wire.csv index aefe3aeb6..4ce802f46 100644 --- a/lightningd/hsm/hsm_wire.csv +++ b/lightningd/hsm/hsm_wire.csv @@ -50,3 +50,11 @@ hsmctl_hsmfd_channeld,0,unique_id,8 # Empty reply, just an fd hsmctl_hsmfd_channeld_reply,105 + +# Master asks the HSM to sign a node_announcement +hsmctl_node_announcement_sig_req,6 +hsmctl_node_announcement_sig_req,0,annlen,2 +hsmctl_node_announcement_sig_req,2,announcement,annlen*u8 + +hsmctl_node_announcement_sig_reply,106 +hsmctl_node_announcement_sig_reply,0,signature,secp256k1_ecdsa_signature diff --git a/lightningd/hsm_control.c b/lightningd/hsm_control.c index 95b0d03a8..5d021383b 100644 --- a/lightningd/hsm_control.c +++ b/lightningd/hsm_control.c @@ -73,12 +73,14 @@ static int hsm_msg(struct subd *hsm, const u8 *msg, const int *fds) case WIRE_HSMCTL_HSMFD_ECDH: case WIRE_HSMCTL_HSMFD_CHANNELD: case WIRE_HSMCTL_SIGN_FUNDING: + case WIRE_HSMCTL_NODE_ANNOUNCEMENT_SIG_REQ: /* Replies should be paired to individual requests. */ case WIRE_HSMCTL_INIT_REPLY: case WIRE_HSMCTL_HSMFD_CHANNELD_REPLY: case WIRE_HSMCTL_HSMFD_ECDH_FD_REPLY: case WIRE_HSMCTL_SIGN_FUNDING_REPLY: + case WIRE_HSMCTL_NODE_ANNOUNCEMENT_SIG_REPLY: errx(1, "HSM gave invalid message %s", hsm_wire_type_name(t)); } return 0; diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 01b90c0b5..cc9bb2edd 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1249,6 +1249,67 @@ static int peer_failed_malformed_htlc(struct peer *peer, const u8 *msg) return 0; } +/* 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. */ +static u8 *create_node_announcement(const tal_t *ctx, struct lightningd *ld, + secp256k1_ecdsa_signature *sig) +{ + u32 timestamp = time_now().ts.tv_sec; + u8 rgb[3] = {0x77, 0x88, 0x99}; + u8 alias[32]; + u8 *features = NULL; + u8 *addresses = NULL; + u8 *announcement; + if (!sig) { + sig = tal(ctx, secp256k1_ecdsa_signature); + memset(sig, 0, sizeof(*sig)); + } + memset(alias, 0, sizeof(alias)); + announcement = + towire_node_announcement(ctx, sig, timestamp, &ld->dstate.id, rgb, + alias, features, addresses); + return announcement; +} + +/* We got the signature for out provisional node_announcement back + * from the HSM, create the real announcement and forward it to + * gossipd so it can take care of forwarding it. */ +static bool send_node_announcement_got_sig(struct subd *hsm, const u8 *msg, + const int *fds, + struct lightningd *ld) +{ + tal_t *tmpctx = tal_tmpctx(hsm); + secp256k1_ecdsa_signature sig; + u8 *announcement, *wrappedmsg; + if (!fromwire_hsmctl_node_announcement_sig_reply(msg, NULL, &sig)) { + log_debug(ld->log, + "HSM returned an invalid node_announcement sig"); + return false; + } + announcement = create_node_announcement(tmpctx, ld, &sig); + wrappedmsg = towire_gossip_forwarded_msg(tmpctx, announcement); + subd_send_msg(ld->gossip, take(wrappedmsg)); + tal_free(tmpctx); + return true; +} + +/* We were informed by channeld that it announced the channel and sent + * an update, so we can now start sending a node_announcement. The + * first step is to build the provisional announcement and ask the HSM + * to sign it. */ +static void peer_channel_announced(struct peer *peer, const u8 *msg) +{ + struct lightningd *ld = peer->ld; + tal_t *tmpctx = tal_tmpctx(ld); + u8 *req; + req = towire_hsmctl_node_announcement_sig_req( + tmpctx, create_node_announcement(tmpctx, ld, NULL)); + subd_req(ld, ld->hsm, take(req), -1, 0, + send_node_announcement_got_sig, ld); + tal_free(tmpctx); +} + static int channel_msg(struct subd *sd, const u8 *msg, const int *unused) { enum channel_wire_type t = fromwire_peektype(msg); @@ -1268,6 +1329,9 @@ static int channel_msg(struct subd *sd, const u8 *msg, const int *unused) return peer_failed_htlc(sd->peer, msg); case WIRE_CHANNEL_MALFORMED_HTLC: return peer_failed_malformed_htlc(sd->peer, msg); + case WIRE_CHANNEL_ANNOUNCED: + peer_channel_announced(sd->peer, msg); + break; /* We never see fatal ones. */ case WIRE_CHANNEL_BAD_COMMAND: