diff --git a/connectd/Makefile b/connectd/Makefile index 779a354a8..8b1ea8907 100644 --- a/connectd/Makefile +++ b/connectd/Makefile @@ -7,6 +7,7 @@ CONNECTD_HEADERS := connectd/connectd_wiregen.h \ connectd/handshake.h \ connectd/multiplex.h \ connectd/netaddress.h \ + connectd/onion_message.h \ connectd/tor_autoservice.h \ connectd/tor.h @@ -41,6 +42,8 @@ CONNECTD_COMMON_OBJS := \ common/bech32_util.o \ common/bigsize.o \ common/bip32.o \ + common/blinding.o \ + common/blindedpath.o \ common/channel_id.o \ common/cryptomsg.o \ common/daemon.o \ @@ -49,6 +52,7 @@ CONNECTD_COMMON_OBJS := \ common/dev_disconnect.o \ common/ecdh_hsmd.o \ common/features.o \ + common/hmac.o \ common/status_wiregen.o \ common/gossip_store.o \ common/gossip_rcvd_filter.o \ @@ -56,12 +60,14 @@ CONNECTD_COMMON_OBJS := \ common/memleak.o \ common/msg_queue.o \ common/node_id.o \ + common/onion.o \ common/onionreply.o \ common/ping.o \ common/per_peer_state.o \ common/psbt_open.o \ common/pseudorand.o \ common/setup.o \ + common/sphinx.o \ common/status.o \ common/status_wire.o \ common/subdaemon.o \ diff --git a/connectd/connectd.c b/connectd/connectd.c index 1d9bdfe29..b8343f6c6 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -1970,6 +1971,10 @@ static struct io_plan *recv_req(struct io_conn *conn, send_manual_ping(daemon, msg); goto out; + case WIRE_CONNECTD_SEND_ONIONMSG: + onionmsg_req(daemon, msg); + goto out; + case WIRE_CONNECTD_DEV_MEMLEAK: #if DEVELOPER dev_connect_memleak(daemon, msg); @@ -1983,6 +1988,7 @@ static struct io_plan *recv_req(struct io_conn *conn, case WIRE_CONNECTD_CONNECT_FAILED: case WIRE_CONNECTD_DEV_MEMLEAK_REPLY: case WIRE_CONNECTD_PING_REPLY: + case WIRE_CONNECTD_GOT_ONIONMSG_TO_US: break; } diff --git a/connectd/connectd_wire.csv b/connectd/connectd_wire.csv index b3f8f5b17..52dae09d0 100644 --- a/connectd/connectd_wire.csv +++ b/connectd/connectd_wire.csv @@ -3,6 +3,7 @@ #include #include #include +#include msgtype,connectd_init,2000 msgdata,connectd_init,chainparams,chainparams, @@ -94,3 +95,24 @@ msgtype,connectd_ping_reply,2130 msgdata,connectd_ping_reply,sent,bool, # 0 == no pong expected, otherwise length of pong. msgdata,connectd_ping_reply,totlen,u16, + +# We tell lightningd we got an onionmsg +msgtype,connectd_got_onionmsg_to_us,2145 +msgdata,connectd_got_onionmsg_to_us,obs2,bool, +msgdata,connectd_got_onionmsg_to_us,node_alias,pubkey, +msgdata,connectd_got_onionmsg_to_us,self_id,?secret, +msgdata,connectd_got_onionmsg_to_us,reply_blinding,?pubkey, +msgdata,connectd_got_onionmsg_to_us,reply_first_node,?pubkey, +msgdata,connectd_got_onionmsg_to_us,reply_path_len,u16, +msgdata,connectd_got_onionmsg_to_us,reply_path,onionmsg_path,reply_path_len +msgdata,connectd_got_onionmsg_to_us,rawmsg_len,u16, +msgdata,connectd_got_onionmsg_to_us,rawmsg,u8,rawmsg_len + +# Lightningd tells us to send an onion message. +msgtype,connectd_send_onionmsg,2041 +msgdata,connectd_send_onionmsg,obs2,bool, +msgdata,connectd_send_onionmsg,id,node_id, +msgdata,connectd_send_onionmsg,onion_len,u16, +msgdata,connectd_send_onionmsg,onion,u8,onion_len +msgdata,connectd_send_onionmsg,blinding,pubkey, + diff --git a/connectd/multiplex.c b/connectd/multiplex.c index 18010471a..8637d01ff 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -488,6 +489,12 @@ static bool handle_message_locally(struct peer *peer, const u8 *msg) } else if (type == WIRE_PONG) { handle_pong_in(peer, msg); return true; + } else if (type == WIRE_OBS2_ONION_MESSAGE) { + handle_obs2_onion_message(peer->daemon, peer, msg); + return true; + } else if (type == WIRE_ONION_MESSAGE) { + handle_onion_message(peer->daemon, peer, msg); + return true; } /* Do we want to divert to gossipd? */ diff --git a/connectd/onion_message.c b/connectd/onion_message.c new file mode 100644 index 000000000..f19594899 --- /dev/null +++ b/connectd/onion_message.c @@ -0,0 +1,345 @@ +/*~ This contains all the code to handle onion messages. */ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Peer sends obsolete onion msg. */ +void handle_obs2_onion_message(struct daemon *daemon, + struct peer *peer, const u8 *msg) +{ + enum onion_wire badreason; + struct onionpacket *op; + struct pubkey blinding, ephemeral; + struct route_step *rs; + u8 *onion; + struct tlv_obs2_onionmsg_payload *om; + struct secret ss, onion_ss; + const u8 *cursor; + size_t max, maxlen; + + /* Ignore unless explicitly turned on. */ + if (!feature_offered(daemon->our_features->bits[NODE_ANNOUNCE_FEATURE], + OPT_ONION_MESSAGES)) + return; + + /* FIXME: ratelimit! */ + if (!fromwire_obs2_onion_message(msg, msg, &blinding, &onion)) { + queue_peer_msg(peer, + towire_warningfmt(NULL, NULL, + "Bad onion_message")); + return; + } + + /* We unwrap the onion now. */ + op = parse_onionpacket(tmpctx, onion, tal_bytelen(onion), &badreason); + if (!op) { + status_peer_debug(&peer->id, "onion msg: can't parse onionpacket: %s", + onion_wire_name(badreason)); + return; + } + + ephemeral = op->ephemeralkey; + if (!unblind_onion(&blinding, ecdh, &ephemeral, &ss)) { + status_peer_debug(&peer->id, "onion msg: can't unblind onionpacket"); + return; + } + + /* Now get onion shared secret and parse it. */ + ecdh(&ephemeral, &onion_ss); + rs = process_onionpacket(tmpctx, op, &onion_ss, NULL, 0, false); + if (!rs) { + status_peer_debug(&peer->id, + "onion msg: can't process onionpacket ss=%s", + type_to_string(tmpctx, struct secret, &onion_ss)); + return; + } + + /* The raw payload is prepended with length in the modern onion. */ + cursor = rs->raw_payload; + max = tal_bytelen(rs->raw_payload); + maxlen = fromwire_bigsize(&cursor, &max); + if (!cursor) { + status_peer_debug(&peer->id, "onion msg: Invalid hop payload %s", + tal_hex(tmpctx, rs->raw_payload)); + return; + } + if (maxlen > max) { + status_peer_debug(&peer->id, "onion msg: overlong hop payload %s", + tal_hex(tmpctx, rs->raw_payload)); + return; + } + + om = tlv_obs2_onionmsg_payload_new(msg); + if (!fromwire_obs2_onionmsg_payload(&cursor, &maxlen, om)) { + status_peer_debug(&peer->id, "onion msg: invalid onionmsg_payload %s", + tal_hex(tmpctx, rs->raw_payload)); + return; + } + + if (rs->nextcase == ONION_END) { + struct pubkey *reply_blinding, *first_node_id, me, alias; + const struct onionmsg_path **reply_path; + struct secret *self_id; + u8 *omsg; + + if (!pubkey_from_node_id(&me, &daemon->id)) { + status_broken("Failed to convert own id"); + return; + } + + /* Final enctlv is actually optional */ + if (!om->enctlv) { + alias = me; + self_id = NULL; + } else if (!decrypt_obs2_final_enctlv(tmpctx, &blinding, &ss, + om->enctlv, &me, &alias, + &self_id)) { + status_peer_debug(&peer->id, + "onion msg: failed to decrypt enctlv" + " %s", tal_hex(tmpctx, om->enctlv)); + return; + } + + if (om->reply_path) { + first_node_id = &om->reply_path->first_node_id; + reply_blinding = &om->reply_path->blinding; + reply_path = cast_const2(const struct onionmsg_path **, + om->reply_path->path); + } else { + first_node_id = NULL; + reply_blinding = NULL; + reply_path = NULL; + } + + /* We re-marshall here by policy, before handing to lightningd */ + omsg = tal_arr(tmpctx, u8, 0); + towire_tlvstream_raw(&omsg, om->fields); + daemon_conn_send(daemon->master, + take(towire_connectd_got_onionmsg_to_us(NULL, + true, /* obs2 */ + &alias, self_id, + reply_blinding, + first_node_id, + reply_path, + omsg))); + } else { + struct pubkey next_node, next_blinding; + struct peer *next_peer; + struct node_id next_node_id; + + /* This fails as expected if no enctlv. */ + if (!decrypt_obs2_enctlv(&blinding, &ss, om->enctlv, &next_node, + &next_blinding)) { + status_peer_debug(&peer->id, + "onion msg: invalid enctlv %s", + tal_hex(tmpctx, om->enctlv)); + return; + } + + /* Even though lightningd checks for valid ids, there's a race + * where it might vanish before we read this command. */ + node_id_from_pubkey(&next_node_id, &next_node); + next_peer = peer_htable_get(&daemon->peers, &next_node_id); + if (!next_peer) { + status_peer_debug(&peer->id, + "onion msg: unknown next peer %s", + type_to_string(tmpctx, + struct pubkey, + &next_node)); + return; + } + queue_peer_msg(next_peer, + take(towire_obs2_onion_message(NULL, + &next_blinding, + serialize_onionpacket(tmpctx, rs->next)))); + } +} + +void onionmsg_req(struct daemon *daemon, const u8 *msg) +{ + struct node_id id; + u8 *onionmsg; + struct pubkey blinding; + struct peer *peer; + bool obs2; + + if (!fromwire_connectd_send_onionmsg(msg, msg, &obs2, &id, &onionmsg, &blinding)) + master_badmsg(WIRE_CONNECTD_SEND_ONIONMSG, msg); + + /* Even though lightningd checks for valid ids, there's a race + * where it might vanish before we read this command. */ + peer = peer_htable_get(&daemon->peers, &id); + if (peer) { + u8 *omsg; + if (obs2) + omsg = towire_obs2_onion_message(NULL, &blinding, onionmsg); + else + omsg = towire_onion_message(NULL, &blinding, onionmsg); + queue_peer_msg(peer, take(omsg)); + } +} + +/* Peer sends an onion msg. */ +void handle_onion_message(struct daemon *daemon, + struct peer *peer, const u8 *msg) +{ + enum onion_wire badreason; + struct onionpacket *op; + struct pubkey blinding, ephemeral; + struct route_step *rs; + u8 *onion; + struct tlv_onionmsg_payload *om; + struct secret ss, onion_ss; + const u8 *cursor; + size_t max, maxlen; + + /* Ignore unless explicitly turned on. */ + if (!feature_offered(daemon->our_features->bits[NODE_ANNOUNCE_FEATURE], + OPT_ONION_MESSAGES)) + return; + + /* FIXME: ratelimit! */ + if (!fromwire_onion_message(msg, msg, &blinding, &onion)) { + queue_peer_msg(peer, + towire_warningfmt(NULL, NULL, + "Bad onion_message")); + return; + } + + /* We unwrap the onion now. */ + op = parse_onionpacket(tmpctx, onion, tal_bytelen(onion), &badreason); + if (!op) { + status_peer_debug(&peer->id, "onion msg: can't parse onionpacket: %s", + onion_wire_name(badreason)); + return; + } + + ephemeral = op->ephemeralkey; + if (!unblind_onion(&blinding, ecdh, &ephemeral, &ss)) { + status_peer_debug(&peer->id, "onion msg: can't unblind onionpacket"); + return; + } + + /* Now get onion shared secret and parse it. */ + ecdh(&ephemeral, &onion_ss); + rs = process_onionpacket(tmpctx, op, &onion_ss, NULL, 0, false); + if (!rs) { + status_peer_debug(&peer->id, + "onion msg: can't process onionpacket ss=%s", + type_to_string(tmpctx, struct secret, &onion_ss)); + return; + } + + /* The raw payload is prepended with length in the modern onion. */ + cursor = rs->raw_payload; + max = tal_bytelen(rs->raw_payload); + maxlen = fromwire_bigsize(&cursor, &max); + if (!cursor) { + status_peer_debug(&peer->id, "onion msg: Invalid hop payload %s", + tal_hex(tmpctx, rs->raw_payload)); + return; + } + if (maxlen > max) { + status_peer_debug(&peer->id, "onion msg: overlong hop payload %s", + tal_hex(tmpctx, rs->raw_payload)); + return; + } + + om = tlv_onionmsg_payload_new(msg); + if (!fromwire_onionmsg_payload(&cursor, &maxlen, om)) { + status_peer_debug(&peer->id, "onion msg: invalid onionmsg_payload %s", + tal_hex(tmpctx, rs->raw_payload)); + return; + } + + if (rs->nextcase == ONION_END) { + struct pubkey *reply_blinding, *first_node_id, me, alias; + const struct onionmsg_path **reply_path; + struct secret *self_id; + u8 *omsg; + + if (!pubkey_from_node_id(&me, &daemon->id)) { + status_broken("Failed to convert own id"); + return; + } + + /* Final enctlv is actually optional */ + if (!om->encrypted_data_tlv) { + alias = me; + self_id = NULL; + } else if (!decrypt_final_enctlv(tmpctx, &blinding, &ss, + om->encrypted_data_tlv, &me, &alias, + &self_id)) { + status_peer_debug(&peer->id, + "onion msg: failed to decrypt enctlv" + " %s", tal_hex(tmpctx, om->encrypted_data_tlv)); + return; + } + + if (om->reply_path) { + first_node_id = &om->reply_path->first_node_id; + reply_blinding = &om->reply_path->blinding; + reply_path = cast_const2(const struct onionmsg_path **, + om->reply_path->path); + } else { + first_node_id = NULL; + reply_blinding = NULL; + reply_path = NULL; + } + + /* We re-marshall here by policy, before handing to lightningd */ + omsg = tal_arr(tmpctx, u8, 0); + towire_tlvstream_raw(&omsg, om->fields); + daemon_conn_send(daemon->master, + take(towire_connectd_got_onionmsg_to_us(NULL, + false, /* !obs2 */ + &alias, self_id, + reply_blinding, + first_node_id, + reply_path, + omsg))); + } else { + struct pubkey next_node, next_blinding; + struct peer *next_peer; + struct node_id next_node_id; + + /* This fails as expected if no enctlv. */ + if (!decrypt_enctlv(&blinding, &ss, om->encrypted_data_tlv, &next_node, + &next_blinding)) { + status_peer_debug(&peer->id, + "onion msg: invalid enctlv %s", + tal_hex(tmpctx, om->encrypted_data_tlv)); + return; + } + + /* FIXME: Handle short_channel_id! */ + node_id_from_pubkey(&next_node_id, &next_node); + next_peer = peer_htable_get(&daemon->peers, &next_node_id); + if (!next_peer) { + status_peer_debug(&peer->id, + "onion msg: unknown next peer %s", + type_to_string(tmpctx, + struct pubkey, + &next_node)); + return; + } + queue_peer_msg(next_peer, + take(towire_onion_message(NULL, + &next_blinding, + serialize_onionpacket(tmpctx, rs->next)))); + } +} + diff --git a/connectd/onion_message.h b/connectd/onion_message.h new file mode 100644 index 000000000..22fc9bb8b --- /dev/null +++ b/connectd/onion_message.h @@ -0,0 +1,15 @@ +#ifndef LIGHTNING_CONNECTD_ONION_MESSAGE_H +#define LIGHTNING_CONNECTD_ONION_MESSAGE_H +#include "config.h" +#include + +/* Various messages come in from peer */ +void handle_obs2_onion_message(struct daemon *daemon, + struct peer *peer, const u8 *msg); +void handle_onion_message(struct daemon *daemon, + struct peer *peer, const u8 *msg); + +/* Lightningd tells us to send an onion message */ +void onionmsg_req(struct daemon *daemon, const u8 *msg); + +#endif /* LIGHTNING_CONNECTD_ONION_MESSAGE_H */ diff --git a/connectd/test/run-onion_message.c b/connectd/test/run-onion_message.c new file mode 100644 index 000000000..8533d718f --- /dev/null +++ b/connectd/test/run-onion_message.c @@ -0,0 +1,408 @@ +#include "config.h" +#include "../onion_message.c" +#include "common/blindedpath.c" +#include "common/blinding.c" +#include "common/bigsize.c" +#include "common/hmac.c" +#include "common/onion.c" +#include "common/sphinx.c" +#include "wire/fromwire.c" +#if EXPERIMENTAL_FEATURES +#include "wire/peer_exp_wiregen.c" +#include "wire/onion_exp_wiregen.c" +#else +#include "wire/peer_wiregen.c" +#include "wire/onion_wiregen.c" +#endif +#include "wire/tlvstream.c" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* AUTOGENERATED MOCKS START */ +/* Generated stub for amount_asset_is_main */ +bool amount_asset_is_main(struct amount_asset *asset UNNEEDED) +{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); } +/* Generated stub for amount_asset_to_sat */ +struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED) +{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); } +/* Generated stub for amount_msat */ +struct amount_msat amount_msat(u64 millisatoshis UNNEEDED) +{ fprintf(stderr, "amount_msat called!\n"); abort(); } +/* Generated stub for amount_msat_eq */ +bool amount_msat_eq(struct amount_msat a UNNEEDED, struct amount_msat b UNNEEDED) +{ fprintf(stderr, "amount_msat_eq called!\n"); abort(); } +/* Generated stub for amount_sat */ +struct amount_sat amount_sat(u64 satoshis UNNEEDED) +{ fprintf(stderr, "amount_sat called!\n"); abort(); } +/* Generated stub for amount_sat_add */ + bool amount_sat_add(struct amount_sat *val UNNEEDED, + struct amount_sat a UNNEEDED, + struct amount_sat b UNNEEDED) +{ fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_eq */ +bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) +{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); } +/* Generated stub for amount_sat_greater_eq */ +bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) +{ fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_sub */ + bool amount_sat_sub(struct amount_sat *val UNNEEDED, + struct amount_sat a UNNEEDED, + struct amount_sat b UNNEEDED) +{ fprintf(stderr, "amount_sat_sub called!\n"); abort(); } +/* Generated stub for amount_sat_to_asset */ +struct amount_asset amount_sat_to_asset(struct amount_sat *sat UNNEEDED, const u8 *asset UNNEEDED) +{ fprintf(stderr, "amount_sat_to_asset called!\n"); abort(); } +/* Generated stub for amount_tx_fee */ +struct amount_sat amount_tx_fee(u32 fee_per_kw UNNEEDED, size_t weight UNNEEDED) +{ fprintf(stderr, "amount_tx_fee called!\n"); abort(); } +/* Generated stub for daemon_conn_send */ +void daemon_conn_send(struct daemon_conn *dc UNNEEDED, const u8 *msg UNNEEDED) +{ fprintf(stderr, "daemon_conn_send called!\n"); abort(); } +/* Generated stub for ecdh */ +void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED) +{ fprintf(stderr, "ecdh called!\n"); abort(); } +/* Generated stub for fromwire_amount_msat */ +struct amount_msat fromwire_amount_msat(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_amount_msat called!\n"); abort(); } +/* Generated stub for fromwire_amount_sat */ +struct amount_sat fromwire_amount_sat(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_amount_sat called!\n"); abort(); } +/* Generated stub for fromwire_channel_id */ +bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, + struct channel_id *channel_id UNNEEDED) +{ fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } +/* Generated stub for fromwire_connectd_send_onionmsg */ +bool fromwire_connectd_send_onionmsg(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, bool *obs2 UNNEEDED, struct node_id *id UNNEEDED, u8 **onion UNNEEDED, struct pubkey *blinding UNNEEDED) +{ fprintf(stderr, "fromwire_connectd_send_onionmsg called!\n"); abort(); } +/* Generated stub for fromwire_node_id */ +void fromwire_node_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct node_id *id UNNEEDED) +{ fprintf(stderr, "fromwire_node_id called!\n"); abort(); } +/* Generated stub for master_badmsg */ +void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg) +{ fprintf(stderr, "master_badmsg called!\n"); abort(); } +/* Generated stub for new_onionreply */ +struct onionreply *new_onionreply(const tal_t *ctx UNNEEDED, const u8 *contents TAKES UNNEEDED) +{ fprintf(stderr, "new_onionreply called!\n"); abort(); } +/* Generated stub for node_id_from_pubkey */ +void node_id_from_pubkey(struct node_id *id UNNEEDED, const struct pubkey *key UNNEEDED) +{ fprintf(stderr, "node_id_from_pubkey called!\n"); abort(); } +/* Generated stub for pubkey_from_node_id */ +bool pubkey_from_node_id(struct pubkey *key UNNEEDED, const struct node_id *id UNNEEDED) +{ fprintf(stderr, "pubkey_from_node_id called!\n"); abort(); } +/* Generated stub for queue_peer_msg */ +void queue_peer_msg(struct peer *peer UNNEEDED, const u8 *msg TAKES UNNEEDED) +{ fprintf(stderr, "queue_peer_msg called!\n"); abort(); } +/* Generated stub for status_fmt */ +void status_fmt(enum log_level level UNNEEDED, + const struct node_id *peer UNNEEDED, + const char *fmt UNNEEDED, ...) + +{ fprintf(stderr, "status_fmt called!\n"); abort(); } +/* Generated stub for towire */ +void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) +{ fprintf(stderr, "towire called!\n"); abort(); } +/* Generated stub for towire_amount_msat */ +void towire_amount_msat(u8 **pptr UNNEEDED, const struct amount_msat msat UNNEEDED) +{ fprintf(stderr, "towire_amount_msat called!\n"); abort(); } +/* Generated stub for towire_amount_sat */ +void towire_amount_sat(u8 **pptr UNNEEDED, const struct amount_sat sat UNNEEDED) +{ fprintf(stderr, "towire_amount_sat called!\n"); abort(); } +/* Generated stub for towire_bool */ +void towire_bool(u8 **pptr UNNEEDED, bool v UNNEEDED) +{ fprintf(stderr, "towire_bool called!\n"); abort(); } +/* Generated stub for towire_channel_id */ +void towire_channel_id(u8 **pptr UNNEEDED, const struct channel_id *channel_id UNNEEDED) +{ fprintf(stderr, "towire_channel_id called!\n"); abort(); } +/* Generated stub for towire_connectd_got_onionmsg_to_us */ +u8 *towire_connectd_got_onionmsg_to_us(const tal_t *ctx UNNEEDED, bool obs2 UNNEEDED, const struct pubkey *node_alias UNNEEDED, const struct secret *self_id UNNEEDED, const struct pubkey *reply_blinding UNNEEDED, const struct pubkey *reply_first_node UNNEEDED, const struct onionmsg_path **reply_path UNNEEDED, const u8 *rawmsg UNNEEDED) +{ fprintf(stderr, "towire_connectd_got_onionmsg_to_us called!\n"); abort(); } +/* Generated stub for towire_node_id */ +void towire_node_id(u8 **pptr UNNEEDED, const struct node_id *id UNNEEDED) +{ fprintf(stderr, "towire_node_id called!\n"); abort(); } +/* Generated stub for towire_pad */ +void towire_pad(u8 **pptr UNNEEDED, size_t num UNNEEDED) +{ fprintf(stderr, "towire_pad called!\n"); abort(); } +/* Generated stub for towire_secp256k1_ecdsa_signature */ +void towire_secp256k1_ecdsa_signature(u8 **pptr UNNEEDED, + const secp256k1_ecdsa_signature *signature UNNEEDED) +{ fprintf(stderr, "towire_secp256k1_ecdsa_signature called!\n"); abort(); } +/* Generated stub for towire_sha256 */ +void towire_sha256(u8 **pptr UNNEEDED, const struct sha256 *sha256 UNNEEDED) +{ fprintf(stderr, "towire_sha256 called!\n"); abort(); } +/* Generated stub for towire_tu32 */ +void towire_tu32(u8 **pptr UNNEEDED, u32 v UNNEEDED) +{ fprintf(stderr, "towire_tu32 called!\n"); abort(); } +/* Generated stub for towire_tu64 */ +void towire_tu64(u8 **pptr UNNEEDED, u64 v UNNEEDED) +{ fprintf(stderr, "towire_tu64 called!\n"); abort(); } +/* Generated stub for towire_u16 */ +void towire_u16(u8 **pptr UNNEEDED, u16 v UNNEEDED) +{ fprintf(stderr, "towire_u16 called!\n"); abort(); } +/* Generated stub for towire_u32 */ +void towire_u32(u8 **pptr UNNEEDED, u32 v UNNEEDED) +{ fprintf(stderr, "towire_u32 called!\n"); abort(); } +/* Generated stub for towire_u64 */ +void towire_u64(u8 **pptr UNNEEDED, u64 v UNNEEDED) +{ fprintf(stderr, "towire_u64 called!\n"); abort(); } +/* Generated stub for towire_u8 */ +void towire_u8(u8 **pptr UNNEEDED, u8 v UNNEEDED) +{ fprintf(stderr, "towire_u8 called!\n"); abort(); } +/* Generated stub for towire_u8_array */ +void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNEEDED) +{ fprintf(stderr, "towire_u8_array called!\n"); abort(); } +/* Generated stub for towire_warningfmt */ +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(); } +/* AUTOGENERATED MOCKS END */ + +/* Updated each time, as we pretend to be Alice, Bob, Carol */ +static const struct privkey *mykey; + +static void test_ecdh(const struct pubkey *point, struct secret *ss) +{ + if (secp256k1_ecdh(secp256k1_ctx, ss->data, &point->pubkey, + mykey->secret.data, NULL, NULL) != 1) + abort(); +} + +static void json_strfield(const char *name, const char *val) +{ + printf("\t\"%s\": \"%s\",\n", name, val); +} + +static void json_onionmsg_payload(const struct tlv_obs2_onionmsg_payload *om) +{ + if (om->reply_path) { + printf("\t\"reply_path\": {\n"); + json_strfield("first_node_id", + type_to_string(tmpctx, struct pubkey, + &om->reply_path->first_node_id)); + json_strfield("blinding", + type_to_string(tmpctx, struct pubkey, + &om->reply_path->blinding)); + printf("\t\"path\": [\n"); + for (size_t i = 0; i < tal_count(om->reply_path->path); i++) { + json_strfield("node_id", + type_to_string(tmpctx, struct pubkey, + &om->reply_path->path[i]->node_id)); + json_strfield("encrypted_recipient_data", + tal_hex(tmpctx, + om->reply_path->path[i]->encrypted_recipient_data)); + } + printf("]}\n"); + } + if (om->invoice) + json_strfield("invoice", tal_hex(tmpctx, om->invoice)); + if (om->invoice_request) + json_strfield("invoice_request", + tal_hex(tmpctx, om->invoice_request)); + if (om->invoice_error) + json_strfield("invoice_error", + tal_hex(tmpctx, om->invoice_error)); +} + +/* Return next onion (and updates blinding), or NULL */ +static u8 *json_test(const char *testname, + const u8 *data, + const struct privkey *me, + const struct privkey *blinding_priv, + struct pubkey *blinding) +{ + struct pubkey my_id, next_node; + struct secret ss, onion_ss; + struct pubkey ephemeral; + struct route_step *rs; + const u8 *cursor; + size_t max, maxlen; + struct onionpacket *op; + struct tlv_obs2_onionmsg_payload *om; + + op = parse_onionpacket(tmpctx, data, tal_bytelen(data), NULL); + assert(op); + + pubkey_from_privkey(me, &my_id); + printf("{"); + json_strfield("test name", testname); + json_strfield("reader_privkey", + type_to_string(tmpctx, struct privkey, me)); + json_strfield("reader_id", + type_to_string(tmpctx, struct pubkey, &my_id)); + + if (blinding_priv) + json_strfield("blinding_privkey", + type_to_string(tmpctx, struct privkey, + blinding_priv)); + json_strfield("blinding", + type_to_string(tmpctx, struct pubkey, blinding)); + printf("\"onionmsg\": {\n"); + json_strfield("raw", tal_hex(tmpctx, data)); + json_strfield("version", tal_fmt(tmpctx, "%i", op->version)); + json_strfield("public_key", + type_to_string(tmpctx, struct pubkey, &op->ephemeralkey)); + json_strfield("hop_payloads", + tal_hex(tmpctx, op->routinginfo)); + json_strfield("hmac", + tal_hexstr(tmpctx, &op->hmac, sizeof(op->hmac))); + printf("},\n"); + + ephemeral = op->ephemeralkey; + + /* Set this for test_ecdh */ + mykey = me; + assert(unblind_onion(blinding, test_ecdh, &ephemeral, &ss)); + json_strfield("ECDH shared secret", + type_to_string(tmpctx, struct secret, &ss)); + /* Reproduce internal calc from unblind_onion */ + { + struct secret hmac; + subkey_from_hmac("blinded_node_id", &ss, &hmac); + json_strfield("HMAC256(\\\"blinded_node_id\\\", ss(i)) * k(i)", + type_to_string(tmpctx, struct secret, &hmac)); + } + json_strfield("Tweaked onion pubkey", + type_to_string(tmpctx, struct pubkey, &ephemeral)); + + /* Now get onion shared secret and parse it. */ + test_ecdh(&ephemeral, &onion_ss); + json_strfield("onion shared secret", + type_to_string(tmpctx, struct secret, &onion_ss)); + rs = process_onionpacket(tmpctx, op, &onion_ss, NULL, 0, false); + assert(rs); + + printf("\"onion contents\": {\n"); + json_strfield("raw", tal_hex(tmpctx, rs->raw_payload)); + + cursor = rs->raw_payload; + max = tal_bytelen(rs->raw_payload); + maxlen = fromwire_bigsize(&cursor, &max); + json_strfield("length", tal_fmt(tmpctx, "%zu", maxlen)); + json_strfield("rawtlv", tal_hexstr(tmpctx, cursor, maxlen)); + json_strfield("hmac", tal_hexstr(tmpctx, rs->next->hmac.bytes, + sizeof(rs->next->hmac.bytes))); + om = tlv_obs2_onionmsg_payload_new(tmpctx); + assert(fromwire_obs2_onionmsg_payload(&cursor, &maxlen, om)); + + json_onionmsg_payload(om); + + /* We expect one of these. */ + assert(om->enctlv); + + printf("\t\"encrypted_data_tlv\": {\n"); + json_strfield("raw", tal_hex(tmpctx, om->enctlv)); + + if (rs->nextcase == ONION_END) { + struct secret *self_id; + struct pubkey alias; + assert(decrypt_obs2_final_enctlv(tmpctx, + blinding, &ss, + om->enctlv, + &my_id, &alias, &self_id)); + if (self_id) { + json_strfield("self_id", + type_to_string(tmpctx, struct secret, + self_id)); + } + printf("}\n"); + return NULL; + } else { + assert(decrypt_obs2_enctlv(blinding, &ss, om->enctlv, &next_node, + blinding)); + json_strfield("next_node", + type_to_string(tmpctx, struct pubkey, &next_node)); + json_strfield("next_blinding", + type_to_string(tmpctx, struct pubkey, + blinding)); + printf("}"); + printf("},\n"); + return serialize_onionpacket(tmpctx, rs->next); + } +} + +int main(int argc, char *argv[]) +{ + struct onionpacket *op; + u8 *data; + struct privkey alice, bob, carol, dave, blinding_priv; + struct pubkey alice_id, bob_id, carol_id, dave_id; + struct pubkey blinding; + + common_setup(argv[0]); + + memset(&alice, 'A', sizeof(alice)); + memset(&bob, 'B', sizeof(bob)); + memset(&carol, 'C', sizeof(carol)); + memset(&dave, 'D', sizeof(dave)); + pubkey_from_privkey(&alice, &alice_id); + pubkey_from_privkey(&bob, &bob_id); + pubkey_from_privkey(&carol, &carol_id); + pubkey_from_privkey(&dave, &dave_id); + + /* ThomasH sends via email: + * + * { + * "version":0, + * "public_key": + * "0256b328b30c8bf5839e24058747879408bdb36241dc9c2e7c619faa12b2920967", + * "hop_payloads": + * "37df67dcefdb678725cb8074d3224dfe235ba3f22f71ac8a2c9d1398b1175295b1dd3f14c02d698021e8a8856637306c6f195e01494eb8dc636b4462367533a84786b8592e580086cdf0f1c58b77eb68703a2fb82ecc2e91307a25b6d5e4045174551b1c867264d3905e4f05b2e5bcfed7e7276660bf7e956bce5afa395e7e4c15883b856bc93dd9d6a968838ef51314d38dd41e5ab84b8846dca3c61d87e55780e7a7da336a965a4652263413cdef41daa68f7bb7cd4d566c19a1c4eece369c47e604575f38e7a246a985c3441b60ae33c564395bb7a4bbe28325ccdb07503285dacf90b5e09f4e455fb42459741f9d497000298b99f1e70adc28f59a1be85a96952f27b6a6c5d6a08822b4f5cae05daa6c2ce2f8ca5fdd4e8f0df46b94791b3159fe8eace11bcf8d58be425b49ce2b47c007affefd5cea785c1996ad805f8c8c5ca79f15ab26e2bd4080b1d74328e7ce5bd2a579c71a6bd25f33f2ce475a2cfbe67ed1f4eb8fbd86920f41d573488abe059166aabbc3be187c435423ead6a5473994e0246efe76e419893aa2d7566b2645f3496d97585de9c92b8c5a5226398cc459ce84abc02fe2b45b5ecaf21961730d4a34bbe6fdfe720e71e3d81a494c01080d8039360d534c6ee5a3c47a1874e526969add9126b30d9192f85ba45bcfd7029cc7560f0e25e14b5deaa805360c4967705e85325ac055922863470f5397e8404022488caebf9204acd6cb02a11088aebf7e497b4ff1172f0a9c6bf980914cc4eb42fc78b457add549abf1134f84922b217502938b42d10b35079f44c5168d4c3e9fe7ca8094ef72ed73ef84f1d3530b6b3545f9f4f013e7e8cbcf2619f57754a7380ce6a9532ee14c55990faa43df6c09530a314b5f4ce597f5ec9b776e8597ce258ac47dac43bd3ac9e52788ff3a66b7dc07cd1bc3e6d197339d85fa8d3d6c3054dd1a5e416c714b544de6eb55209e40e3cac412a51748370160d2d73b6d97abd62f7bae70df27cd199c511fa693019c5717d471e934906b98cd974fda4dd1cb5e2d721044a0be2bdf24d0971e09f2f39488fe389fc5230699b4df7cec7447e5be4ea49bd7c3fe1a5ec7358510dc1dd9c1a8da68c0863188d80549e49f7c00f57d2009b2427b2aed1569603fc247734039469f9fdf3ddd3a22fa95c5d8066a468327a02b474c9915419af82c8edc67686984767fe7885207c6820f6c2e57cb8fd0bcb9981ebc8065c74e970a5d593c3b73ee25a0877ca096a9f7edfee6d43bd817c7d415fea9abb6f206c61aa36942df9318762a76b9da26d0d41a0ae9eee042a175f82dc134bf6f2d46a218db358d6852940e6e30df4a58ac6cb409e7ce99afe1e3f42768bd617af4d0a235d0ba0dd5075f9cc091784395d30e7e42d4e006db21bea9b45d1f122b75c051e84e2281573ef54ebad053218fff0cc28ea89a06adc218d4134f407654990592e75462f5ee4a463c1e46425222d48761162da8049613cafd7ecc52ff8024e9d58512b958e3a3d12dede84e1441247700bca0f992875349448b430683c756438fd4e91f3d44f3cf624ed21f3c63cf92615ecc201d0cd3159b1b3fccd8f29d2daba9ac5ba87b1dd2f83323a2b2d3176b803ce9c7bdc4bae615925eb22a213df1eeb2f8ff95586536caf042d565984aacf1425a120a5d8d7a9cbb70bf4852e116b89ff5b198d672220af2be4246372e7c3836cf50d732212a3e3346ff92873ace57fa687b2b1aab3e8dc6cb9f93f865d998cff0a1680d9012a9597c90a070e525f66226cc287814f4ac4157b15a0b25aa110946cd69fd404fafd5656669bfd1d9e509eabc004c5a", + * "hmac": "564bb85911bea8f90d306f4acdafa1c0887619ac72606b11e6b2765734d810ac" + * } + */ + op = tal(tmpctx, struct onionpacket); + op->version = 0; + assert(pubkey_from_hexstr("0256b328b30c8bf5839e24058747879408bdb36241dc9c2e7c619faa12b2920967", strlen("0256b328b30c8bf5839e24058747879408bdb36241dc9c2e7c619faa12b2920967"), &op->ephemeralkey)); + assert(hex_decode("564bb85911bea8f90d306f4acdafa1c0887619ac72606b11e6b2765734d810ac", + strlen("564bb85911bea8f90d306f4acdafa1c0887619ac72606b11e6b2765734d810ac"), + &op->hmac, sizeof(op->hmac))); + op->routinginfo = tal_hexdata(op, "37df67dcefdb678725cb8074d3224dfe235ba3f22f71ac8a2c9d1398b1175295b1dd3f14c02d698021e8a8856637306c6f195e01494eb8dc636b4462367533a84786b8592e580086cdf0f1c58b77eb68703a2fb82ecc2e91307a25b6d5e4045174551b1c867264d3905e4f05b2e5bcfed7e7276660bf7e956bce5afa395e7e4c15883b856bc93dd9d6a968838ef51314d38dd41e5ab84b8846dca3c61d87e55780e7a7da336a965a4652263413cdef41daa68f7bb7cd4d566c19a1c4eece369c47e604575f38e7a246a985c3441b60ae33c564395bb7a4bbe28325ccdb07503285dacf90b5e09f4e455fb42459741f9d497000298b99f1e70adc28f59a1be85a96952f27b6a6c5d6a08822b4f5cae05daa6c2ce2f8ca5fdd4e8f0df46b94791b3159fe8eace11bcf8d58be425b49ce2b47c007affefd5cea785c1996ad805f8c8c5ca79f15ab26e2bd4080b1d74328e7ce5bd2a579c71a6bd25f33f2ce475a2cfbe67ed1f4eb8fbd86920f41d573488abe059166aabbc3be187c435423ead6a5473994e0246efe76e419893aa2d7566b2645f3496d97585de9c92b8c5a5226398cc459ce84abc02fe2b45b5ecaf21961730d4a34bbe6fdfe720e71e3d81a494c01080d8039360d534c6ee5a3c47a1874e526969add9126b30d9192f85ba45bcfd7029cc7560f0e25e14b5deaa805360c4967705e85325ac055922863470f5397e8404022488caebf9204acd6cb02a11088aebf7e497b4ff1172f0a9c6bf980914cc4eb42fc78b457add549abf1134f84922b217502938b42d10b35079f44c5168d4c3e9fe7ca8094ef72ed73ef84f1d3530b6b3545f9f4f013e7e8cbcf2619f57754a7380ce6a9532ee14c55990faa43df6c09530a314b5f4ce597f5ec9b776e8597ce258ac47dac43bd3ac9e52788ff3a66b7dc07cd1bc3e6d197339d85fa8d3d6c3054dd1a5e416c714b544de6eb55209e40e3cac412a51748370160d2d73b6d97abd62f7bae70df27cd199c511fa693019c5717d471e934906b98cd974fda4dd1cb5e2d721044a0be2bdf24d0971e09f2f39488fe389fc5230699b4df7cec7447e5be4ea49bd7c3fe1a5ec7358510dc1dd9c1a8da68c0863188d80549e49f7c00f57d2009b2427b2aed1569603fc247734039469f9fdf3ddd3a22fa95c5d8066a468327a02b474c9915419af82c8edc67686984767fe7885207c6820f6c2e57cb8fd0bcb9981ebc8065c74e970a5d593c3b73ee25a0877ca096a9f7edfee6d43bd817c7d415fea9abb6f206c61aa36942df9318762a76b9da26d0d41a0ae9eee042a175f82dc134bf6f2d46a218db358d6852940e6e30df4a58ac6cb409e7ce99afe1e3f42768bd617af4d0a235d0ba0dd5075f9cc091784395d30e7e42d4e006db21bea9b45d1f122b75c051e84e2281573ef54ebad053218fff0cc28ea89a06adc218d4134f407654990592e75462f5ee4a463c1e46425222d48761162da8049613cafd7ecc52ff8024e9d58512b958e3a3d12dede84e1441247700bca0f992875349448b430683c756438fd4e91f3d44f3cf624ed21f3c63cf92615ecc201d0cd3159b1b3fccd8f29d2daba9ac5ba87b1dd2f83323a2b2d3176b803ce9c7bdc4bae615925eb22a213df1eeb2f8ff95586536caf042d565984aacf1425a120a5d8d7a9cbb70bf4852e116b89ff5b198d672220af2be4246372e7c3836cf50d732212a3e3346ff92873ace57fa687b2b1aab3e8dc6cb9f93f865d998cff0a1680d9012a9597c90a070e525f66226cc287814f4ac4157b15a0b25aa110946cd69fd404fafd5656669bfd1d9e509eabc004c5a", + strlen("37df67dcefdb678725cb8074d3224dfe235ba3f22f71ac8a2c9d1398b1175295b1dd3f14c02d698021e8a8856637306c6f195e01494eb8dc636b4462367533a84786b8592e580086cdf0f1c58b77eb68703a2fb82ecc2e91307a25b6d5e4045174551b1c867264d3905e4f05b2e5bcfed7e7276660bf7e956bce5afa395e7e4c15883b856bc93dd9d6a968838ef51314d38dd41e5ab84b8846dca3c61d87e55780e7a7da336a965a4652263413cdef41daa68f7bb7cd4d566c19a1c4eece369c47e604575f38e7a246a985c3441b60ae33c564395bb7a4bbe28325ccdb07503285dacf90b5e09f4e455fb42459741f9d497000298b99f1e70adc28f59a1be85a96952f27b6a6c5d6a08822b4f5cae05daa6c2ce2f8ca5fdd4e8f0df46b94791b3159fe8eace11bcf8d58be425b49ce2b47c007affefd5cea785c1996ad805f8c8c5ca79f15ab26e2bd4080b1d74328e7ce5bd2a579c71a6bd25f33f2ce475a2cfbe67ed1f4eb8fbd86920f41d573488abe059166aabbc3be187c435423ead6a5473994e0246efe76e419893aa2d7566b2645f3496d97585de9c92b8c5a5226398cc459ce84abc02fe2b45b5ecaf21961730d4a34bbe6fdfe720e71e3d81a494c01080d8039360d534c6ee5a3c47a1874e526969add9126b30d9192f85ba45bcfd7029cc7560f0e25e14b5deaa805360c4967705e85325ac055922863470f5397e8404022488caebf9204acd6cb02a11088aebf7e497b4ff1172f0a9c6bf980914cc4eb42fc78b457add549abf1134f84922b217502938b42d10b35079f44c5168d4c3e9fe7ca8094ef72ed73ef84f1d3530b6b3545f9f4f013e7e8cbcf2619f57754a7380ce6a9532ee14c55990faa43df6c09530a314b5f4ce597f5ec9b776e8597ce258ac47dac43bd3ac9e52788ff3a66b7dc07cd1bc3e6d197339d85fa8d3d6c3054dd1a5e416c714b544de6eb55209e40e3cac412a51748370160d2d73b6d97abd62f7bae70df27cd199c511fa693019c5717d471e934906b98cd974fda4dd1cb5e2d721044a0be2bdf24d0971e09f2f39488fe389fc5230699b4df7cec7447e5be4ea49bd7c3fe1a5ec7358510dc1dd9c1a8da68c0863188d80549e49f7c00f57d2009b2427b2aed1569603fc247734039469f9fdf3ddd3a22fa95c5d8066a468327a02b474c9915419af82c8edc67686984767fe7885207c6820f6c2e57cb8fd0bcb9981ebc8065c74e970a5d593c3b73ee25a0877ca096a9f7edfee6d43bd817c7d415fea9abb6f206c61aa36942df9318762a76b9da26d0d41a0ae9eee042a175f82dc134bf6f2d46a218db358d6852940e6e30df4a58ac6cb409e7ce99afe1e3f42768bd617af4d0a235d0ba0dd5075f9cc091784395d30e7e42d4e006db21bea9b45d1f122b75c051e84e2281573ef54ebad053218fff0cc28ea89a06adc218d4134f407654990592e75462f5ee4a463c1e46425222d48761162da8049613cafd7ecc52ff8024e9d58512b958e3a3d12dede84e1441247700bca0f992875349448b430683c756438fd4e91f3d44f3cf624ed21f3c63cf92615ecc201d0cd3159b1b3fccd8f29d2daba9ac5ba87b1dd2f83323a2b2d3176b803ce9c7bdc4bae615925eb22a213df1eeb2f8ff95586536caf042d565984aacf1425a120a5d8d7a9cbb70bf4852e116b89ff5b198d672220af2be4246372e7c3836cf50d732212a3e3346ff92873ace57fa687b2b1aab3e8dc6cb9f93f865d998cff0a1680d9012a9597c90a070e525f66226cc287814f4ac4157b15a0b25aa110946cd69fd404fafd5656669bfd1d9e509eabc004c5a")); + + data = serialize_onionpacket(tmpctx, op); + printf("[\n"); + + memset(&blinding_priv, 5, sizeof(blinding_priv)); + pubkey_from_privkey(&blinding_priv, &blinding); + + data = json_test("onion message for Alice", + data, + &alice, + &blinding_priv, + &blinding); + + data = json_test("onion message for Bob", + data, + &bob, + NULL, + &blinding); + + data = json_test("onion message for Carol", + data, + &carol, + NULL, + &blinding); + + data = json_test("onion message for Dave", + data, + &dave, + NULL, + &blinding); + + assert(!data); + printf("]\n"); + + common_shutdown(); + return 0; +} diff --git a/gossipd/Makefile b/gossipd/Makefile index 13c8eada0..6fbb6a7e4 100644 --- a/gossipd/Makefile +++ b/gossipd/Makefile @@ -34,8 +34,6 @@ GOSSIPD_COMMON_OBJS := \ common/bech32_util.o \ common/bigsize.o \ common/bip32.o \ - common/blinding.o \ - common/blindedpath.o \ common/channel_id.o \ common/cryptomsg.o \ common/daemon.o \ @@ -45,7 +43,6 @@ GOSSIPD_COMMON_OBJS := \ common/dev_disconnect.o \ common/ecdh_hsmd.o \ common/features.o \ - common/hmac.o \ common/status_wiregen.o \ common/gossip_rcvd_filter.o \ common/key_derive.o \ @@ -53,8 +50,6 @@ GOSSIPD_COMMON_OBJS := \ common/memleak.o \ common/msg_queue.o \ common/node_id.o \ - common/onion.o \ - common/onionreply.o \ common/per_peer_state.o \ common/ping.o \ common/psbt_open.o \ @@ -62,7 +57,6 @@ GOSSIPD_COMMON_OBJS := \ common/private_channel_announcement.o \ common/random_select.o \ common/setup.o \ - common/sphinx.o \ common/status.o \ common/status_wire.o \ common/subdaemon.o \ diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 0e8153ffa..d7797c068 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -13,15 +13,12 @@ #include "config.h" #include #include -#include -#include #include #include #include #include #include #include -#include #include #include #include @@ -350,327 +347,6 @@ static void handle_local_private_channel(struct daemon *daemon, const u8 *msg) } } -/* Peer sends obsolete onion msg. */ -static u8 *handle_obs2_onion_message(struct peer *peer, const u8 *msg) -{ - enum onion_wire badreason; - struct onionpacket *op; - struct pubkey blinding, ephemeral; - struct route_step *rs; - u8 *onion; - struct tlv_obs2_onionmsg_payload *om; - struct secret ss, onion_ss; - const u8 *cursor; - size_t max, maxlen; - - /* Ignore unless explicitly turned on. */ - if (!feature_offered(peer->daemon->our_features->bits[NODE_ANNOUNCE_FEATURE], - OPT_ONION_MESSAGES)) - return NULL; - - /* FIXME: ratelimit! */ - if (!fromwire_obs2_onion_message(msg, msg, &blinding, &onion)) - return towire_warningfmt(peer, NULL, "Bad onion_message"); - - /* We unwrap the onion now. */ - op = parse_onionpacket(tmpctx, onion, tal_bytelen(onion), &badreason); - if (!op) { - status_peer_debug(&peer->id, "onion msg: can't parse onionpacket: %s", - onion_wire_name(badreason)); - return NULL; - } - - ephemeral = op->ephemeralkey; - if (!unblind_onion(&blinding, ecdh, &ephemeral, &ss)) { - status_peer_debug(&peer->id, "onion msg: can't unblind onionpacket"); - return NULL; - } - - /* Now get onion shared secret and parse it. */ - ecdh(&ephemeral, &onion_ss); - rs = process_onionpacket(tmpctx, op, &onion_ss, NULL, 0, false); - if (!rs) { - status_peer_debug(&peer->id, - "onion msg: can't process onionpacket ss=%s", - type_to_string(tmpctx, struct secret, &onion_ss)); - return NULL; - } - - /* The raw payload is prepended with length in the modern onion. */ - cursor = rs->raw_payload; - max = tal_bytelen(rs->raw_payload); - maxlen = fromwire_bigsize(&cursor, &max); - if (!cursor) { - status_peer_debug(&peer->id, "onion msg: Invalid hop payload %s", - tal_hex(tmpctx, rs->raw_payload)); - return NULL; - } - if (maxlen > max) { - status_peer_debug(&peer->id, "onion msg: overlong hop payload %s", - tal_hex(tmpctx, rs->raw_payload)); - return NULL; - } - - om = tlv_obs2_onionmsg_payload_new(msg); - if (!fromwire_obs2_onionmsg_payload(&cursor, &maxlen, om)) { - status_peer_debug(&peer->id, "onion msg: invalid onionmsg_payload %s", - tal_hex(tmpctx, rs->raw_payload)); - return NULL; - } - - if (rs->nextcase == ONION_END) { - struct pubkey *reply_blinding, *first_node_id, me, alias; - const struct onionmsg_path **reply_path; - struct secret *self_id; - u8 *omsg; - - if (!pubkey_from_node_id(&me, &peer->daemon->id)) { - status_broken("Failed to convert own id"); - return NULL; - } - - /* Final enctlv is actually optional */ - if (!om->enctlv) { - alias = me; - self_id = NULL; - } else if (!decrypt_obs2_final_enctlv(tmpctx, &blinding, &ss, - om->enctlv, &me, &alias, - &self_id)) { - status_peer_debug(&peer->id, - "onion msg: failed to decrypt enctlv" - " %s", tal_hex(tmpctx, om->enctlv)); - return NULL; - } - - if (om->reply_path) { - first_node_id = &om->reply_path->first_node_id; - reply_blinding = &om->reply_path->blinding; - reply_path = cast_const2(const struct onionmsg_path **, - om->reply_path->path); - } else { - first_node_id = NULL; - reply_blinding = NULL; - reply_path = NULL; - } - - /* We re-marshall here by policy, before handing to lightningd */ - omsg = tal_arr(tmpctx, u8, 0); - towire_tlvstream_raw(&omsg, om->fields); - daemon_conn_send(peer->daemon->master, - take(towire_gossipd_got_onionmsg_to_us(NULL, - true, /* obs2 */ - &alias, self_id, - reply_blinding, - first_node_id, - reply_path, - omsg))); - } else { - struct pubkey next_node, next_blinding; - struct peer *next_peer; - struct node_id next_node_id; - - /* This fails as expected if no enctlv. */ - if (!decrypt_obs2_enctlv(&blinding, &ss, om->enctlv, &next_node, - &next_blinding)) { - status_peer_debug(&peer->id, - "onion msg: invalid enctlv %s", - tal_hex(tmpctx, om->enctlv)); - return NULL; - } - - /* Even though lightningd checks for valid ids, there's a race - * where it might vanish before we read this command. */ - node_id_from_pubkey(&next_node_id, &next_node); - next_peer = find_peer(peer->daemon, &next_node_id); - if (!next_peer) { - status_peer_debug(&peer->id, - "onion msg: unknown next peer %s", - type_to_string(tmpctx, - struct pubkey, - &next_node)); - return NULL; - } - queue_peer_msg(next_peer, - take(towire_obs2_onion_message(NULL, - &next_blinding, - serialize_onionpacket(tmpctx, rs->next)))); - } - - return NULL; -} - -static void onionmsg_req(struct daemon *daemon, const u8 *msg) -{ - struct node_id id; - u8 *onionmsg; - struct pubkey blinding; - struct peer *peer; - bool obs2; - - if (!fromwire_gossipd_send_onionmsg(msg, msg, &obs2, &id, &onionmsg, &blinding)) - master_badmsg(WIRE_GOSSIPD_SEND_ONIONMSG, msg); - - /* Even though lightningd checks for valid ids, there's a race - * where it might vanish before we read this command. */ - peer = find_peer(daemon, &id); - if (peer) { - u8 *omsg; - if (obs2) - omsg = towire_obs2_onion_message(NULL, &blinding, onionmsg); - else - omsg = towire_onion_message(NULL, &blinding, onionmsg); - queue_peer_msg(peer, take(omsg)); - } -} - -/* Peer sends an onion msg. */ -static u8 *handle_onion_message(struct peer *peer, const u8 *msg) -{ - enum onion_wire badreason; - struct onionpacket *op; - struct pubkey blinding, ephemeral; - struct route_step *rs; - u8 *onion; - struct tlv_onionmsg_payload *om; - struct secret ss, onion_ss; - const u8 *cursor; - size_t max, maxlen; - - /* Ignore unless explicitly turned on. */ - if (!feature_offered(peer->daemon->our_features->bits[NODE_ANNOUNCE_FEATURE], - OPT_ONION_MESSAGES)) - return NULL; - - /* FIXME: ratelimit! */ - if (!fromwire_onion_message(msg, msg, &blinding, &onion)) - return towire_warningfmt(peer, NULL, "Bad onion_message"); - - /* We unwrap the onion now. */ - op = parse_onionpacket(tmpctx, onion, tal_bytelen(onion), &badreason); - if (!op) { - status_peer_debug(&peer->id, "onion msg: can't parse onionpacket: %s", - onion_wire_name(badreason)); - return NULL; - } - - ephemeral = op->ephemeralkey; - if (!unblind_onion(&blinding, ecdh, &ephemeral, &ss)) { - status_peer_debug(&peer->id, "onion msg: can't unblind onionpacket"); - return NULL; - } - - /* Now get onion shared secret and parse it. */ - ecdh(&ephemeral, &onion_ss); - rs = process_onionpacket(tmpctx, op, &onion_ss, NULL, 0, false); - if (!rs) { - status_peer_debug(&peer->id, - "onion msg: can't process onionpacket ss=%s", - type_to_string(tmpctx, struct secret, &onion_ss)); - return NULL; - } - - /* The raw payload is prepended with length in the modern onion. */ - cursor = rs->raw_payload; - max = tal_bytelen(rs->raw_payload); - maxlen = fromwire_bigsize(&cursor, &max); - if (!cursor) { - status_peer_debug(&peer->id, "onion msg: Invalid hop payload %s", - tal_hex(tmpctx, rs->raw_payload)); - return NULL; - } - if (maxlen > max) { - status_peer_debug(&peer->id, "onion msg: overlong hop payload %s", - tal_hex(tmpctx, rs->raw_payload)); - return NULL; - } - - om = tlv_onionmsg_payload_new(msg); - if (!fromwire_onionmsg_payload(&cursor, &maxlen, om)) { - status_peer_debug(&peer->id, "onion msg: invalid onionmsg_payload %s", - tal_hex(tmpctx, rs->raw_payload)); - return NULL; - } - - if (rs->nextcase == ONION_END) { - struct pubkey *reply_blinding, *first_node_id, me, alias; - const struct onionmsg_path **reply_path; - struct secret *self_id; - u8 *omsg; - - if (!pubkey_from_node_id(&me, &peer->daemon->id)) { - status_broken("Failed to convert own id"); - return NULL; - } - - /* Final enctlv is actually optional */ - if (!om->encrypted_data_tlv) { - alias = me; - self_id = NULL; - } else if (!decrypt_final_enctlv(tmpctx, &blinding, &ss, - om->encrypted_data_tlv, &me, &alias, - &self_id)) { - status_peer_debug(&peer->id, - "onion msg: failed to decrypt enctlv" - " %s", tal_hex(tmpctx, om->encrypted_data_tlv)); - return NULL; - } - - if (om->reply_path) { - first_node_id = &om->reply_path->first_node_id; - reply_blinding = &om->reply_path->blinding; - reply_path = cast_const2(const struct onionmsg_path **, - om->reply_path->path); - } else { - first_node_id = NULL; - reply_blinding = NULL; - reply_path = NULL; - } - - /* We re-marshall here by policy, before handing to lightningd */ - omsg = tal_arr(tmpctx, u8, 0); - towire_tlvstream_raw(&omsg, om->fields); - daemon_conn_send(peer->daemon->master, - take(towire_gossipd_got_onionmsg_to_us(NULL, - false, /* !obs2 */ - &alias, self_id, - reply_blinding, - first_node_id, - reply_path, - omsg))); - } else { - struct pubkey next_node, next_blinding; - struct peer *next_peer; - struct node_id next_node_id; - - /* This fails as expected if no enctlv. */ - if (!decrypt_enctlv(&blinding, &ss, om->encrypted_data_tlv, &next_node, - &next_blinding)) { - status_peer_debug(&peer->id, - "onion msg: invalid enctlv %s", - tal_hex(tmpctx, om->encrypted_data_tlv)); - return NULL; - } - - /* FIXME: Handle short_channel_id! */ - node_id_from_pubkey(&next_node_id, &next_node); - next_peer = find_peer(peer->daemon, &next_node_id); - if (!next_peer) { - status_peer_debug(&peer->id, - "onion msg: unknown next peer %s", - type_to_string(tmpctx, - struct pubkey, - &next_node)); - return NULL; - } - queue_peer_msg(next_peer, - take(towire_onion_message(NULL, - &next_blinding, - serialize_onionpacket(tmpctx, rs->next)))); - } - - return NULL; -} - /*~ This is where the per-peer daemons send us messages. It's either forwarded * gossip, or a request for information. We deliberately use non-overlapping * message types so we can distinguish them. */ @@ -678,17 +354,8 @@ static struct io_plan *peer_msg_in(struct io_conn *conn, const u8 *msg, struct peer *peer) { - const u8 *err; - /* These are messages relayed from peer */ switch ((enum peer_wire)fromwire_peektype(msg)) { - case WIRE_OBS2_ONION_MESSAGE: - err = handle_obs2_onion_message(peer, msg); - goto handled_relay; - case WIRE_ONION_MESSAGE: - err = handle_onion_message(peer, msg); - goto handled_relay; - /* These are not sent by peer (connectd sends us gossip msgs) */ case WIRE_CHANNEL_ANNOUNCEMENT: case WIRE_CHANNEL_UPDATE: @@ -730,6 +397,8 @@ static struct io_plan *peer_msg_in(struct io_conn *conn, case WIRE_ACCEPT_CHANNEL2: case WIRE_INIT_RBF: case WIRE_ACK_RBF: + case WIRE_OBS2_ONION_MESSAGE: + case WIRE_ONION_MESSAGE: #if EXPERIMENTAL_FEATURES case WIRE_STFU: #endif @@ -743,14 +412,6 @@ static struct io_plan *peer_msg_in(struct io_conn *conn, status_peer_broken(&peer->id, "unexpected cmd of type %i", fromwire_peektype(msg)); return io_close(conn); - - /* Forwarded messages may be bad, so we have error which the per-peer - * daemon will forward to the peer. */ -handled_relay: - if (err) - queue_peer_msg(peer, take(err)); - - return daemon_conn_read_next(conn, peer->dc); } /*~ This is where connectd tells us about a new peer, and we hand back an fd for @@ -891,12 +552,6 @@ static void handle_recv_gossip(struct daemon *daemon, const u8 *outermsg) case WIRE_REPLY_SHORT_CHANNEL_IDS_END: err = handle_reply_short_channel_ids_end(peer, msg); goto handled_msg; - case WIRE_OBS2_ONION_MESSAGE: - err = handle_obs2_onion_message(peer, msg); - goto handled_msg; - case WIRE_ONION_MESSAGE: - err = handle_onion_message(peer, msg); - goto handled_msg; /* These are non-gossip messages (!is_msg_for_gossipd()) */ case WIRE_WARNING: @@ -932,6 +587,8 @@ static void handle_recv_gossip(struct daemon *daemon, const u8 *outermsg) case WIRE_ACCEPT_CHANNEL2: case WIRE_INIT_RBF: case WIRE_ACK_RBF: + case WIRE_OBS2_ONION_MESSAGE: + case WIRE_ONION_MESSAGE: #if EXPERIMENTAL_FEATURES case WIRE_STFU: #endif @@ -1464,16 +1121,11 @@ static struct io_plan *recv_req(struct io_conn *conn, break; #endif /* !DEVELOPER */ - case WIRE_GOSSIPD_SEND_ONIONMSG: - onionmsg_req(daemon, msg); - goto done; - /* We send these, we don't receive them */ case WIRE_GOSSIPD_INIT_REPLY: case WIRE_GOSSIPD_GET_TXOUT: case WIRE_GOSSIPD_DEV_MEMLEAK_REPLY: case WIRE_GOSSIPD_DEV_COMPACT_STORE_REPLY: - case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US: case WIRE_GOSSIPD_ADDGOSSIP_REPLY: case WIRE_GOSSIPD_NEW_BLOCKHEIGHT_REPLY: case WIRE_GOSSIPD_GET_ADDRS_REPLY: diff --git a/gossipd/gossipd_wire.csv b/gossipd/gossipd_wire.csv index eaec7643c..e5369751e 100644 --- a/gossipd/gossipd_wire.csv +++ b/gossipd/gossipd_wire.csv @@ -69,25 +69,6 @@ msgdata,gossipd_new_blockheight,blockheight,u32, # gossipd: got it! msgtype,gossipd_new_blockheight_reply,3126 -msgtype,gossipd_got_onionmsg_to_us,3145 -msgdata,gossipd_got_onionmsg_to_us,obs2,bool, -msgdata,gossipd_got_onionmsg_to_us,node_alias,pubkey, -msgdata,gossipd_got_onionmsg_to_us,self_id,?secret, -msgdata,gossipd_got_onionmsg_to_us,reply_blinding,?pubkey, -msgdata,gossipd_got_onionmsg_to_us,reply_first_node,?pubkey, -msgdata,gossipd_got_onionmsg_to_us,reply_path_len,u16, -msgdata,gossipd_got_onionmsg_to_us,reply_path,onionmsg_path,reply_path_len -msgdata,gossipd_got_onionmsg_to_us,rawmsg_len,u16, -msgdata,gossipd_got_onionmsg_to_us,rawmsg,u8,rawmsg_len - -# Lightningd tells us to send an onion message. -msgtype,gossipd_send_onionmsg,3041 -msgdata,gossipd_send_onionmsg,obs2,bool, -msgdata,gossipd_send_onionmsg,id,node_id, -msgdata,gossipd_send_onionmsg,onion_len,u16, -msgdata,gossipd_send_onionmsg,onion,u8,onion_len -msgdata,gossipd_send_onionmsg,blinding,pubkey, - # Lightningd tells us to inject a gossip message (for addgossip RPC) msgtype,gossipd_addgossip,3044 msgdata,gossipd_addgossip,len,u16, diff --git a/gossipd/test/run-onion_message.c b/gossipd/test/run-onion_message.c deleted file mode 100644 index 13e47d554..000000000 --- a/gossipd/test/run-onion_message.c +++ /dev/null @@ -1,588 +0,0 @@ -#include "config.h" -int unused_main(int argc, char *argv[]); -#define main unused_main -#include "../gossipd.c" -#undef main -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if DEVELOPER -bool dev_suppress_gossip; - -/* Generated stub for dev_set_max_scids_encode_size */ -void dev_set_max_scids_encode_size(struct daemon *daemon UNNEEDED, - const u8 *msg UNNEEDED) -{ fprintf(stderr, "dev_set_max_scids_encode_size called!\n"); abort(); } -/* Generated stub for dump_memleak */ -bool dump_memleak(struct htable *memtable UNNEEDED, - void (*print)(const char *fmt UNNEEDED, ...)) -{ fprintf(stderr, "dump_memleak called!\n"); abort(); } -/* Generated stub for memleak_status_broken */ -void memleak_status_broken(const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "memleak_status_broken called!\n"); abort(); } -#endif - -/* AUTOGENERATED MOCKS START */ -/* Generated stub for add_to_txout_failures */ -void add_to_txout_failures(struct routing_state *rstate UNNEEDED, - const struct short_channel_id *scid UNNEEDED) -{ fprintf(stderr, "add_to_txout_failures called!\n"); abort(); } -/* Generated stub for daemon_conn_new_ */ -struct daemon_conn *daemon_conn_new_(const tal_t *ctx UNNEEDED, int fd UNNEEDED, - struct io_plan *(*recv)(struct io_conn * UNNEEDED, - const u8 * UNNEEDED, - void *) UNNEEDED, - void (*outq_empty)(void *) UNNEEDED, - void *arg UNNEEDED) -{ fprintf(stderr, "daemon_conn_new_ called!\n"); abort(); } -/* Generated stub for daemon_conn_read_next */ -struct io_plan *daemon_conn_read_next(struct io_conn *conn UNNEEDED, - struct daemon_conn *dc UNNEEDED) -{ fprintf(stderr, "daemon_conn_read_next called!\n"); abort(); } -/* Generated stub for daemon_conn_send */ -void daemon_conn_send(struct daemon_conn *dc UNNEEDED, const u8 *msg UNNEEDED) -{ fprintf(stderr, "daemon_conn_send called!\n"); abort(); } -/* Generated stub for daemon_conn_send_fd */ -void daemon_conn_send_fd(struct daemon_conn *dc UNNEEDED, int fd UNNEEDED) -{ fprintf(stderr, "daemon_conn_send_fd called!\n"); abort(); } -/* Generated stub for daemon_shutdown */ -void daemon_shutdown(void) -{ fprintf(stderr, "daemon_shutdown called!\n"); abort(); } -/* Generated stub for ecdh */ -void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED) -{ fprintf(stderr, "ecdh called!\n"); abort(); } -/* Generated stub for ecdh_hsmd_setup */ -void ecdh_hsmd_setup(int hsm_fd UNNEEDED, - void (*failed)(enum status_failreason UNNEEDED, - const char *fmt UNNEEDED, ...)) -{ fprintf(stderr, "ecdh_hsmd_setup called!\n"); abort(); } -/* Generated stub for first_chan */ -struct chan *first_chan(const struct node *node UNNEEDED, struct chan_map_iter *i UNNEEDED) -{ fprintf(stderr, "first_chan 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 free_chan */ -void free_chan(struct routing_state *rstate UNNEEDED, struct chan *chan UNNEEDED) -{ fprintf(stderr, "free_chan called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_addgossip */ -bool fromwire_gossipd_addgossip(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u8 **msg UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_addgossip called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_dev_set_time */ -bool fromwire_gossipd_dev_set_time(const void *p UNNEEDED, u32 *dev_gossip_time UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_dev_set_time called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_dev_suppress */ -bool fromwire_gossipd_dev_suppress(const void *p UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_dev_suppress called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_get_addrs */ -bool fromwire_gossipd_get_addrs(const void *p UNNEEDED, struct node_id *id UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_get_addrs called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_get_txout_reply */ -bool fromwire_gossipd_get_txout_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, struct amount_sat *satoshis UNNEEDED, u8 **outscript UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_get_txout_reply called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_init */ -bool fromwire_gossipd_init(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, const struct chainparams **chainparams UNNEEDED, struct feature_set **our_features UNNEEDED, struct node_id *id UNNEEDED, u8 rgb[3] UNNEEDED, u8 alias[32] UNNEEDED, struct wireaddr **announcable UNNEEDED, u32 **dev_gossip_time UNNEEDED, bool *dev_fast_gossip UNNEEDED, bool *dev_fast_gossip_prune UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_init called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_local_channel_announcement */ -bool fromwire_gossipd_local_channel_announcement(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, u8 **cannounce UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_local_channel_announcement called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_local_channel_close */ -bool fromwire_gossipd_local_channel_close(const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_local_channel_close called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_local_private_channel */ -bool fromwire_gossipd_local_private_channel(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, struct amount_sat *capacity UNNEEDED, struct short_channel_id *scid UNNEEDED, u8 **features UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_local_private_channel called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_new_blockheight */ -bool fromwire_gossipd_new_blockheight(const void *p UNNEEDED, u32 *blockheight UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_new_blockheight called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_new_lease_rates */ -bool fromwire_gossipd_new_lease_rates(const void *p UNNEEDED, struct lease_rates *rates UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_new_lease_rates called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_new_peer */ -bool fromwire_gossipd_new_peer(const void *p UNNEEDED, struct node_id *id UNNEEDED, bool *gossip_queries_feature UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_new_peer called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_outpoint_spent */ -bool fromwire_gossipd_outpoint_spent(const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_outpoint_spent called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_recv_gossip */ -bool fromwire_gossipd_recv_gossip(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, u8 **msg UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_recv_gossip called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_send_onionmsg */ -bool fromwire_gossipd_send_onionmsg(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, bool *obs2 UNNEEDED, struct node_id *id UNNEEDED, u8 **onion UNNEEDED, struct pubkey *blinding UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_send_onionmsg 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 get_node */ -struct node *get_node(struct routing_state *rstate UNNEEDED, - const struct node_id *id UNNEEDED) -{ fprintf(stderr, "get_node called!\n"); abort(); } -/* Generated stub for gossip_store_compact */ -bool gossip_store_compact(struct gossip_store *gs UNNEEDED) -{ fprintf(stderr, "gossip_store_compact called!\n"); abort(); } -/* Generated stub for gossip_store_get */ -const u8 *gossip_store_get(const tal_t *ctx UNNEEDED, - struct gossip_store *gs UNNEEDED, - u64 offset UNNEEDED) -{ fprintf(stderr, "gossip_store_get called!\n"); abort(); } -/* Generated stub for gossip_store_load */ -u32 gossip_store_load(struct routing_state *rstate UNNEEDED, struct gossip_store *gs UNNEEDED) -{ fprintf(stderr, "gossip_store_load called!\n"); abort(); } -/* Generated stub for gossip_time_now */ -struct timeabs gossip_time_now(const struct routing_state *rstate UNNEEDED) -{ fprintf(stderr, "gossip_time_now called!\n"); abort(); } -/* Generated stub for handle_channel_announcement */ -u8 *handle_channel_announcement(struct routing_state *rstate UNNEEDED, - const u8 *announce TAKES UNNEEDED, - u32 current_blockheight UNNEEDED, - const struct short_channel_id **scid UNNEEDED, - struct peer *peer UNNEEDED) -{ fprintf(stderr, "handle_channel_announcement called!\n"); abort(); } -/* Generated stub for handle_channel_update */ -u8 *handle_channel_update(struct routing_state *rstate UNNEEDED, const u8 *update TAKES UNNEEDED, - struct peer *peer UNNEEDED, - struct short_channel_id *unknown_scid UNNEEDED, - bool force UNNEEDED) -{ fprintf(stderr, "handle_channel_update called!\n"); abort(); } -/* Generated stub for handle_local_channel_update */ -void handle_local_channel_update(struct daemon *daemon UNNEEDED, const u8 *msg UNNEEDED) -{ fprintf(stderr, "handle_local_channel_update called!\n"); abort(); } -/* Generated stub for handle_node_announcement */ -u8 *handle_node_announcement(struct routing_state *rstate UNNEEDED, const u8 *node UNNEEDED, - struct peer *peer UNNEEDED, bool *was_unknown UNNEEDED) -{ fprintf(stderr, "handle_node_announcement called!\n"); abort(); } -/* Generated stub for handle_pending_cannouncement */ -bool handle_pending_cannouncement(struct daemon *daemon UNNEEDED, - struct routing_state *rstate UNNEEDED, - const struct short_channel_id *scid UNNEEDED, - const struct amount_sat sat UNNEEDED, - const u8 *txscript UNNEEDED) -{ fprintf(stderr, "handle_pending_cannouncement called!\n"); abort(); } -/* Generated stub for handle_query_channel_range */ -const u8 *handle_query_channel_range(struct peer *peer UNNEEDED, const u8 *msg UNNEEDED) -{ fprintf(stderr, "handle_query_channel_range called!\n"); abort(); } -/* Generated stub for handle_query_short_channel_ids */ -const u8 *handle_query_short_channel_ids(struct peer *peer UNNEEDED, const u8 *msg UNNEEDED) -{ fprintf(stderr, "handle_query_short_channel_ids called!\n"); abort(); } -/* Generated stub for handle_reply_channel_range */ -const u8 *handle_reply_channel_range(struct peer *peer UNNEEDED, const u8 *msg UNNEEDED) -{ fprintf(stderr, "handle_reply_channel_range called!\n"); abort(); } -/* Generated stub for handle_reply_short_channel_ids_end */ -const u8 *handle_reply_short_channel_ids_end(struct peer *peer UNNEEDED, const u8 *msg UNNEEDED) -{ fprintf(stderr, "handle_reply_short_channel_ids_end called!\n"); abort(); } -/* Generated stub for handle_used_local_channel_update */ -void handle_used_local_channel_update(struct daemon *daemon UNNEEDED, const u8 *msg UNNEEDED) -{ fprintf(stderr, "handle_used_local_channel_update called!\n"); abort(); } -/* Generated stub for json_add_member */ -void json_add_member(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, - bool quote UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "json_add_member called!\n"); abort(); } -/* Generated stub for json_member_direct */ -char *json_member_direct(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, size_t extra UNNEEDED) -{ fprintf(stderr, "json_member_direct called!\n"); abort(); } -/* Generated stub for json_object_end */ -void json_object_end(struct json_stream *js UNNEEDED) -{ fprintf(stderr, "json_object_end called!\n"); abort(); } -/* Generated stub for json_object_start */ -void json_object_start(struct json_stream *ks UNNEEDED, const char *fieldname UNNEEDED) -{ fprintf(stderr, "json_object_start called!\n"); abort(); } -/* Generated stub for local_disable_chan */ -void local_disable_chan(struct daemon *daemon UNNEEDED, const struct chan *chan UNNEEDED, int direction UNNEEDED) -{ fprintf(stderr, "local_disable_chan called!\n"); abort(); } -/* Generated stub for local_enable_chan */ -void local_enable_chan(struct daemon *daemon UNNEEDED, const struct chan *chan UNNEEDED, int direction UNNEEDED) -{ fprintf(stderr, "local_enable_chan called!\n"); abort(); } -/* Generated stub for master_badmsg */ -void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg) -{ fprintf(stderr, "master_badmsg called!\n"); abort(); } -/* Generated stub for maybe_send_own_node_announce */ -void maybe_send_own_node_announce(struct daemon *daemon UNNEEDED, bool startup UNNEEDED) -{ fprintf(stderr, "maybe_send_own_node_announce called!\n"); abort(); } -/* Generated stub for maybe_send_query_responses */ -void maybe_send_query_responses(struct daemon *daemon UNNEEDED) -{ fprintf(stderr, "maybe_send_query_responses called!\n"); abort(); } -/* Generated stub for memleak_find_allocations */ -struct htable *memleak_find_allocations(const tal_t *ctx UNNEEDED, - const void *exclude1 UNNEEDED, - const void *exclude2 UNNEEDED) -{ fprintf(stderr, "memleak_find_allocations called!\n"); abort(); } -/* Generated stub for memleak_remove_region */ -void memleak_remove_region(struct htable *memtable UNNEEDED, - const void *p UNNEEDED, size_t bytelen UNNEEDED) -{ fprintf(stderr, "memleak_remove_region called!\n"); abort(); } -/* Generated stub for new_onionreply */ -struct onionreply *new_onionreply(const tal_t *ctx UNNEEDED, const u8 *contents TAKES UNNEEDED) -{ fprintf(stderr, "new_onionreply called!\n"); abort(); } -/* Generated stub for new_reltimer_ */ -struct oneshot *new_reltimer_(struct timers *timers UNNEEDED, - const tal_t *ctx UNNEEDED, - struct timerel expire UNNEEDED, - void (*cb)(void *) UNNEEDED, void *arg UNNEEDED) -{ fprintf(stderr, "new_reltimer_ called!\n"); abort(); } -/* Generated stub for new_routing_state */ -struct routing_state *new_routing_state(const tal_t *ctx UNNEEDED, - const struct node_id *local_id UNNEEDED, - struct list_head *peers UNNEEDED, - struct timers *timers UNNEEDED, - const u32 *dev_gossip_time TAKES UNNEEDED, - bool dev_fast_gossip UNNEEDED, - bool dev_fast_gossip_prune UNNEEDED) -{ fprintf(stderr, "new_routing_state called!\n"); abort(); } -/* Generated stub for new_seeker */ -struct seeker *new_seeker(struct daemon *daemon UNNEEDED) -{ fprintf(stderr, "new_seeker called!\n"); abort(); } -/* Generated stub for next_chan */ -struct chan *next_chan(const struct node *node UNNEEDED, struct chan_map_iter *i UNNEEDED) -{ fprintf(stderr, "next_chan called!\n"); abort(); } -/* Generated stub for notleak_ */ -void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) -{ fprintf(stderr, "notleak_ called!\n"); abort(); } -/* Generated stub for private_channel_announcement */ -const u8 *private_channel_announcement(const tal_t *ctx UNNEEDED, - const struct short_channel_id *scid UNNEEDED, - const struct node_id *local_node_id UNNEEDED, - const struct node_id *remote_node_id UNNEEDED, - const u8 *features UNNEEDED) -{ fprintf(stderr, "private_channel_announcement called!\n"); abort(); } -/* Generated stub for query_unknown_channel */ -void query_unknown_channel(struct daemon *daemon UNNEEDED, - struct peer *peer UNNEEDED, - const struct short_channel_id *id UNNEEDED) -{ fprintf(stderr, "query_unknown_channel called!\n"); abort(); } -/* Generated stub for query_unknown_node */ -void query_unknown_node(struct seeker *seeker UNNEEDED, struct peer *peer UNNEEDED) -{ fprintf(stderr, "query_unknown_node called!\n"); abort(); } -/* Generated stub for refresh_local_channel */ -void refresh_local_channel(struct daemon *daemon UNNEEDED, - struct chan *chan UNNEEDED, int direction UNNEEDED) -{ fprintf(stderr, "refresh_local_channel called!\n"); abort(); } -/* Generated stub for remove_channel_from_store */ -void remove_channel_from_store(struct routing_state *rstate UNNEEDED, - struct chan *chan UNNEEDED) -{ fprintf(stderr, "remove_channel_from_store called!\n"); abort(); } -/* Generated stub for remove_unknown_scid */ -bool remove_unknown_scid(struct seeker *seeker UNNEEDED, - const struct short_channel_id *scid UNNEEDED, - bool found UNNEEDED) -{ fprintf(stderr, "remove_unknown_scid called!\n"); abort(); } -/* Generated stub for route_prune */ -void route_prune(struct routing_state *rstate UNNEEDED) -{ fprintf(stderr, "route_prune called!\n"); abort(); } -/* Generated stub for routing_add_private_channel */ -bool routing_add_private_channel(struct routing_state *rstate UNNEEDED, - const struct node_id *id UNNEEDED, - struct amount_sat sat UNNEEDED, - const u8 *chan_ann UNNEEDED, u64 index UNNEEDED) -{ fprintf(stderr, "routing_add_private_channel called!\n"); abort(); } -/* Generated stub for sanitize_error */ -char *sanitize_error(const tal_t *ctx UNNEEDED, const u8 *errmsg UNNEEDED, - struct channel_id *channel_id UNNEEDED) -{ fprintf(stderr, "sanitize_error called!\n"); abort(); } -/* Generated stub for seeker_setup_peer_gossip */ -void seeker_setup_peer_gossip(struct seeker *seeker UNNEEDED, struct peer *peer UNNEEDED) -{ fprintf(stderr, "seeker_setup_peer_gossip called!\n"); abort(); } -/* Generated stub for status_failed */ -void status_failed(enum status_failreason code UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "status_failed called!\n"); abort(); } -/* Generated stub for status_fmt */ -void status_fmt(enum log_level level UNNEEDED, - const struct node_id *peer UNNEEDED, - const char *fmt UNNEEDED, ...) - -{ fprintf(stderr, "status_fmt called!\n"); abort(); } -/* Generated stub for status_setup_async */ -void status_setup_async(struct daemon_conn *master UNNEEDED) -{ fprintf(stderr, "status_setup_async called!\n"); abort(); } -/* Generated stub for subdaemon_setup */ -void subdaemon_setup(int argc UNNEEDED, char *argv[]) -{ fprintf(stderr, "subdaemon_setup called!\n"); abort(); } -/* Generated stub for timer_expired */ -void timer_expired(struct timer *timer UNNEEDED) -{ fprintf(stderr, "timer_expired called!\n"); abort(); } -/* Generated stub for towire_gossipd_addgossip_reply */ -u8 *towire_gossipd_addgossip_reply(const tal_t *ctx UNNEEDED, const wirestring *err UNNEEDED) -{ fprintf(stderr, "towire_gossipd_addgossip_reply called!\n"); abort(); } -/* Generated stub for towire_gossipd_dev_compact_store_reply */ -u8 *towire_gossipd_dev_compact_store_reply(const tal_t *ctx UNNEEDED, bool success UNNEEDED) -{ fprintf(stderr, "towire_gossipd_dev_compact_store_reply called!\n"); abort(); } -/* Generated stub for towire_gossipd_dev_memleak_reply */ -u8 *towire_gossipd_dev_memleak_reply(const tal_t *ctx UNNEEDED, bool leak UNNEEDED) -{ fprintf(stderr, "towire_gossipd_dev_memleak_reply called!\n"); abort(); } -/* Generated stub for towire_gossipd_get_addrs_reply */ -u8 *towire_gossipd_get_addrs_reply(const tal_t *ctx UNNEEDED, const struct wireaddr *addrs UNNEEDED) -{ fprintf(stderr, "towire_gossipd_get_addrs_reply called!\n"); abort(); } -/* Generated stub for towire_gossipd_get_txout */ -u8 *towire_gossipd_get_txout(const tal_t *ctx UNNEEDED, const struct short_channel_id *short_channel_id UNNEEDED) -{ fprintf(stderr, "towire_gossipd_get_txout called!\n"); abort(); } -/* Generated stub for towire_gossipd_got_onionmsg_to_us */ -u8 *towire_gossipd_got_onionmsg_to_us(const tal_t *ctx UNNEEDED, bool obs2 UNNEEDED, const struct pubkey *node_alias UNNEEDED, const struct secret *self_id UNNEEDED, const struct pubkey *reply_blinding UNNEEDED, const struct pubkey *reply_first_node UNNEEDED, const struct onionmsg_path **reply_path UNNEEDED, const u8 *rawmsg UNNEEDED) -{ fprintf(stderr, "towire_gossipd_got_onionmsg_to_us called!\n"); abort(); } -/* Generated stub for towire_gossipd_init_reply */ -u8 *towire_gossipd_init_reply(const tal_t *ctx UNNEEDED) -{ fprintf(stderr, "towire_gossipd_init_reply called!\n"); abort(); } -/* Generated stub for towire_gossipd_new_blockheight_reply */ -u8 *towire_gossipd_new_blockheight_reply(const tal_t *ctx UNNEEDED) -{ fprintf(stderr, "towire_gossipd_new_blockheight_reply called!\n"); abort(); } -/* Generated stub for towire_gossipd_new_peer_reply */ -u8 *towire_gossipd_new_peer_reply(const tal_t *ctx UNNEEDED, bool success UNNEEDED) -{ fprintf(stderr, "towire_gossipd_new_peer_reply called!\n"); abort(); } -/* Generated stub for towire_gossipd_send_gossip */ -u8 *towire_gossipd_send_gossip(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, const u8 *msg UNNEEDED) -{ fprintf(stderr, "towire_gossipd_send_gossip called!\n"); abort(); } -/* Generated stub for towire_warningfmt */ -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(); } -/* AUTOGENERATED MOCKS END */ - -/* Updated each time, as we pretend to be Alice, Bob, Carol */ -static const struct privkey *mykey; - -static void test_ecdh(const struct pubkey *point, struct secret *ss) -{ - if (secp256k1_ecdh(secp256k1_ctx, ss->data, &point->pubkey, - mykey->secret.data, NULL, NULL) != 1) - abort(); -} - -static void json_strfield(const char *name, const char *val) -{ - printf("\t\"%s\": \"%s\",\n", name, val); -} - -static void json_onionmsg_payload(const struct tlv_obs2_onionmsg_payload *om) -{ - if (om->reply_path) { - printf("\t\"reply_path\": {\n"); - json_strfield("first_node_id", - type_to_string(tmpctx, struct pubkey, - &om->reply_path->first_node_id)); - json_strfield("blinding", - type_to_string(tmpctx, struct pubkey, - &om->reply_path->blinding)); - printf("\t\"path\": [\n"); - for (size_t i = 0; i < tal_count(om->reply_path->path); i++) { - json_strfield("node_id", - type_to_string(tmpctx, struct pubkey, - &om->reply_path->path[i]->node_id)); - json_strfield("encrypted_recipient_data", - tal_hex(tmpctx, - om->reply_path->path[i]->encrypted_recipient_data)); - } - printf("]}\n"); - } - if (om->invoice) - json_strfield("invoice", tal_hex(tmpctx, om->invoice)); - if (om->invoice_request) - json_strfield("invoice_request", - tal_hex(tmpctx, om->invoice_request)); - if (om->invoice_error) - json_strfield("invoice_error", - tal_hex(tmpctx, om->invoice_error)); -} - -/* Return next onion (and updates blinding), or NULL */ -static u8 *json_test(const char *testname, - const u8 *data, - const struct privkey *me, - const struct privkey *blinding_priv, - struct pubkey *blinding) -{ - struct pubkey my_id, next_node; - struct secret ss, onion_ss; - struct pubkey ephemeral; - struct route_step *rs; - const u8 *cursor; - size_t max, maxlen; - struct onionpacket *op; - struct tlv_obs2_onionmsg_payload *om; - - op = parse_onionpacket(tmpctx, data, tal_bytelen(data), NULL); - assert(op); - - pubkey_from_privkey(me, &my_id); - printf("{"); - json_strfield("test name", testname); - json_strfield("reader_privkey", - type_to_string(tmpctx, struct privkey, me)); - json_strfield("reader_id", - type_to_string(tmpctx, struct pubkey, &my_id)); - - if (blinding_priv) - json_strfield("blinding_privkey", - type_to_string(tmpctx, struct privkey, - blinding_priv)); - json_strfield("blinding", - type_to_string(tmpctx, struct pubkey, blinding)); - printf("\"onionmsg\": {\n"); - json_strfield("raw", tal_hex(tmpctx, data)); - json_strfield("version", tal_fmt(tmpctx, "%i", op->version)); - json_strfield("public_key", - type_to_string(tmpctx, struct pubkey, &op->ephemeralkey)); - json_strfield("hop_payloads", - tal_hex(tmpctx, op->routinginfo)); - json_strfield("hmac", - tal_hexstr(tmpctx, &op->hmac, sizeof(op->hmac))); - printf("},\n"); - - ephemeral = op->ephemeralkey; - - /* Set this for test_ecdh */ - mykey = me; - assert(unblind_onion(blinding, test_ecdh, &ephemeral, &ss)); - json_strfield("ECDH shared secret", - type_to_string(tmpctx, struct secret, &ss)); - /* Reproduce internal calc from unblind_onion */ - { - struct secret hmac; - subkey_from_hmac("blinded_node_id", &ss, &hmac); - json_strfield("HMAC256(\\\"blinded_node_id\\\", ss(i)) * k(i)", - type_to_string(tmpctx, struct secret, &hmac)); - } - json_strfield("Tweaked onion pubkey", - type_to_string(tmpctx, struct pubkey, &ephemeral)); - - /* Now get onion shared secret and parse it. */ - test_ecdh(&ephemeral, &onion_ss); - json_strfield("onion shared secret", - type_to_string(tmpctx, struct secret, &onion_ss)); - rs = process_onionpacket(tmpctx, op, &onion_ss, NULL, 0, false); - assert(rs); - - printf("\"onion contents\": {\n"); - json_strfield("raw", tal_hex(tmpctx, rs->raw_payload)); - - cursor = rs->raw_payload; - max = tal_bytelen(rs->raw_payload); - maxlen = fromwire_bigsize(&cursor, &max); - json_strfield("length", tal_fmt(tmpctx, "%zu", maxlen)); - json_strfield("rawtlv", tal_hexstr(tmpctx, cursor, maxlen)); - json_strfield("hmac", tal_hexstr(tmpctx, rs->next->hmac.bytes, - sizeof(rs->next->hmac.bytes))); - om = tlv_obs2_onionmsg_payload_new(tmpctx); - assert(fromwire_obs2_onionmsg_payload(&cursor, &maxlen, om)); - - json_onionmsg_payload(om); - - /* We expect one of these. */ - assert(om->enctlv); - - printf("\t\"encrypted_data_tlv\": {\n"); - json_strfield("raw", tal_hex(tmpctx, om->enctlv)); - - if (rs->nextcase == ONION_END) { - struct secret *self_id; - struct pubkey alias; - assert(decrypt_obs2_final_enctlv(tmpctx, - blinding, &ss, - om->enctlv, - &my_id, &alias, &self_id)); - if (self_id) { - json_strfield("self_id", - type_to_string(tmpctx, struct secret, - self_id)); - } - printf("}\n"); - return NULL; - } else { - assert(decrypt_obs2_enctlv(blinding, &ss, om->enctlv, &next_node, - blinding)); - json_strfield("next_node", - type_to_string(tmpctx, struct pubkey, &next_node)); - json_strfield("next_blinding", - type_to_string(tmpctx, struct pubkey, - blinding)); - printf("}"); - printf("},\n"); - return serialize_onionpacket(tmpctx, rs->next); - } -} - -int main(int argc, char *argv[]) -{ - struct onionpacket *op; - u8 *data; - struct privkey alice, bob, carol, dave, blinding_priv; - struct pubkey alice_id, bob_id, carol_id, dave_id; - struct pubkey blinding; - - common_setup(argv[0]); - - memset(&alice, 'A', sizeof(alice)); - memset(&bob, 'B', sizeof(bob)); - memset(&carol, 'C', sizeof(carol)); - memset(&dave, 'D', sizeof(dave)); - pubkey_from_privkey(&alice, &alice_id); - pubkey_from_privkey(&bob, &bob_id); - pubkey_from_privkey(&carol, &carol_id); - pubkey_from_privkey(&dave, &dave_id); - - /* ThomasH sends via email: - * - * { - * "version":0, - * "public_key": - * "0256b328b30c8bf5839e24058747879408bdb36241dc9c2e7c619faa12b2920967", - * "hop_payloads": - * "37df67dcefdb678725cb8074d3224dfe235ba3f22f71ac8a2c9d1398b1175295b1dd3f14c02d698021e8a8856637306c6f195e01494eb8dc636b4462367533a84786b8592e580086cdf0f1c58b77eb68703a2fb82ecc2e91307a25b6d5e4045174551b1c867264d3905e4f05b2e5bcfed7e7276660bf7e956bce5afa395e7e4c15883b856bc93dd9d6a968838ef51314d38dd41e5ab84b8846dca3c61d87e55780e7a7da336a965a4652263413cdef41daa68f7bb7cd4d566c19a1c4eece369c47e604575f38e7a246a985c3441b60ae33c564395bb7a4bbe28325ccdb07503285dacf90b5e09f4e455fb42459741f9d497000298b99f1e70adc28f59a1be85a96952f27b6a6c5d6a08822b4f5cae05daa6c2ce2f8ca5fdd4e8f0df46b94791b3159fe8eace11bcf8d58be425b49ce2b47c007affefd5cea785c1996ad805f8c8c5ca79f15ab26e2bd4080b1d74328e7ce5bd2a579c71a6bd25f33f2ce475a2cfbe67ed1f4eb8fbd86920f41d573488abe059166aabbc3be187c435423ead6a5473994e0246efe76e419893aa2d7566b2645f3496d97585de9c92b8c5a5226398cc459ce84abc02fe2b45b5ecaf21961730d4a34bbe6fdfe720e71e3d81a494c01080d8039360d534c6ee5a3c47a1874e526969add9126b30d9192f85ba45bcfd7029cc7560f0e25e14b5deaa805360c4967705e85325ac055922863470f5397e8404022488caebf9204acd6cb02a11088aebf7e497b4ff1172f0a9c6bf980914cc4eb42fc78b457add549abf1134f84922b217502938b42d10b35079f44c5168d4c3e9fe7ca8094ef72ed73ef84f1d3530b6b3545f9f4f013e7e8cbcf2619f57754a7380ce6a9532ee14c55990faa43df6c09530a314b5f4ce597f5ec9b776e8597ce258ac47dac43bd3ac9e52788ff3a66b7dc07cd1bc3e6d197339d85fa8d3d6c3054dd1a5e416c714b544de6eb55209e40e3cac412a51748370160d2d73b6d97abd62f7bae70df27cd199c511fa693019c5717d471e934906b98cd974fda4dd1cb5e2d721044a0be2bdf24d0971e09f2f39488fe389fc5230699b4df7cec7447e5be4ea49bd7c3fe1a5ec7358510dc1dd9c1a8da68c0863188d80549e49f7c00f57d2009b2427b2aed1569603fc247734039469f9fdf3ddd3a22fa95c5d8066a468327a02b474c9915419af82c8edc67686984767fe7885207c6820f6c2e57cb8fd0bcb9981ebc8065c74e970a5d593c3b73ee25a0877ca096a9f7edfee6d43bd817c7d415fea9abb6f206c61aa36942df9318762a76b9da26d0d41a0ae9eee042a175f82dc134bf6f2d46a218db358d6852940e6e30df4a58ac6cb409e7ce99afe1e3f42768bd617af4d0a235d0ba0dd5075f9cc091784395d30e7e42d4e006db21bea9b45d1f122b75c051e84e2281573ef54ebad053218fff0cc28ea89a06adc218d4134f407654990592e75462f5ee4a463c1e46425222d48761162da8049613cafd7ecc52ff8024e9d58512b958e3a3d12dede84e1441247700bca0f992875349448b430683c756438fd4e91f3d44f3cf624ed21f3c63cf92615ecc201d0cd3159b1b3fccd8f29d2daba9ac5ba87b1dd2f83323a2b2d3176b803ce9c7bdc4bae615925eb22a213df1eeb2f8ff95586536caf042d565984aacf1425a120a5d8d7a9cbb70bf4852e116b89ff5b198d672220af2be4246372e7c3836cf50d732212a3e3346ff92873ace57fa687b2b1aab3e8dc6cb9f93f865d998cff0a1680d9012a9597c90a070e525f66226cc287814f4ac4157b15a0b25aa110946cd69fd404fafd5656669bfd1d9e509eabc004c5a", - * "hmac": "564bb85911bea8f90d306f4acdafa1c0887619ac72606b11e6b2765734d810ac" - * } - */ - op = tal(tmpctx, struct onionpacket); - op->version = 0; - assert(pubkey_from_hexstr("0256b328b30c8bf5839e24058747879408bdb36241dc9c2e7c619faa12b2920967", strlen("0256b328b30c8bf5839e24058747879408bdb36241dc9c2e7c619faa12b2920967"), &op->ephemeralkey)); - assert(hex_decode("564bb85911bea8f90d306f4acdafa1c0887619ac72606b11e6b2765734d810ac", - strlen("564bb85911bea8f90d306f4acdafa1c0887619ac72606b11e6b2765734d810ac"), - &op->hmac, sizeof(op->hmac))); - op->routinginfo = tal_hexdata(op, "37df67dcefdb678725cb8074d3224dfe235ba3f22f71ac8a2c9d1398b1175295b1dd3f14c02d698021e8a8856637306c6f195e01494eb8dc636b4462367533a84786b8592e580086cdf0f1c58b77eb68703a2fb82ecc2e91307a25b6d5e4045174551b1c867264d3905e4f05b2e5bcfed7e7276660bf7e956bce5afa395e7e4c15883b856bc93dd9d6a968838ef51314d38dd41e5ab84b8846dca3c61d87e55780e7a7da336a965a4652263413cdef41daa68f7bb7cd4d566c19a1c4eece369c47e604575f38e7a246a985c3441b60ae33c564395bb7a4bbe28325ccdb07503285dacf90b5e09f4e455fb42459741f9d497000298b99f1e70adc28f59a1be85a96952f27b6a6c5d6a08822b4f5cae05daa6c2ce2f8ca5fdd4e8f0df46b94791b3159fe8eace11bcf8d58be425b49ce2b47c007affefd5cea785c1996ad805f8c8c5ca79f15ab26e2bd4080b1d74328e7ce5bd2a579c71a6bd25f33f2ce475a2cfbe67ed1f4eb8fbd86920f41d573488abe059166aabbc3be187c435423ead6a5473994e0246efe76e419893aa2d7566b2645f3496d97585de9c92b8c5a5226398cc459ce84abc02fe2b45b5ecaf21961730d4a34bbe6fdfe720e71e3d81a494c01080d8039360d534c6ee5a3c47a1874e526969add9126b30d9192f85ba45bcfd7029cc7560f0e25e14b5deaa805360c4967705e85325ac055922863470f5397e8404022488caebf9204acd6cb02a11088aebf7e497b4ff1172f0a9c6bf980914cc4eb42fc78b457add549abf1134f84922b217502938b42d10b35079f44c5168d4c3e9fe7ca8094ef72ed73ef84f1d3530b6b3545f9f4f013e7e8cbcf2619f57754a7380ce6a9532ee14c55990faa43df6c09530a314b5f4ce597f5ec9b776e8597ce258ac47dac43bd3ac9e52788ff3a66b7dc07cd1bc3e6d197339d85fa8d3d6c3054dd1a5e416c714b544de6eb55209e40e3cac412a51748370160d2d73b6d97abd62f7bae70df27cd199c511fa693019c5717d471e934906b98cd974fda4dd1cb5e2d721044a0be2bdf24d0971e09f2f39488fe389fc5230699b4df7cec7447e5be4ea49bd7c3fe1a5ec7358510dc1dd9c1a8da68c0863188d80549e49f7c00f57d2009b2427b2aed1569603fc247734039469f9fdf3ddd3a22fa95c5d8066a468327a02b474c9915419af82c8edc67686984767fe7885207c6820f6c2e57cb8fd0bcb9981ebc8065c74e970a5d593c3b73ee25a0877ca096a9f7edfee6d43bd817c7d415fea9abb6f206c61aa36942df9318762a76b9da26d0d41a0ae9eee042a175f82dc134bf6f2d46a218db358d6852940e6e30df4a58ac6cb409e7ce99afe1e3f42768bd617af4d0a235d0ba0dd5075f9cc091784395d30e7e42d4e006db21bea9b45d1f122b75c051e84e2281573ef54ebad053218fff0cc28ea89a06adc218d4134f407654990592e75462f5ee4a463c1e46425222d48761162da8049613cafd7ecc52ff8024e9d58512b958e3a3d12dede84e1441247700bca0f992875349448b430683c756438fd4e91f3d44f3cf624ed21f3c63cf92615ecc201d0cd3159b1b3fccd8f29d2daba9ac5ba87b1dd2f83323a2b2d3176b803ce9c7bdc4bae615925eb22a213df1eeb2f8ff95586536caf042d565984aacf1425a120a5d8d7a9cbb70bf4852e116b89ff5b198d672220af2be4246372e7c3836cf50d732212a3e3346ff92873ace57fa687b2b1aab3e8dc6cb9f93f865d998cff0a1680d9012a9597c90a070e525f66226cc287814f4ac4157b15a0b25aa110946cd69fd404fafd5656669bfd1d9e509eabc004c5a", - strlen("37df67dcefdb678725cb8074d3224dfe235ba3f22f71ac8a2c9d1398b1175295b1dd3f14c02d698021e8a8856637306c6f195e01494eb8dc636b4462367533a84786b8592e580086cdf0f1c58b77eb68703a2fb82ecc2e91307a25b6d5e4045174551b1c867264d3905e4f05b2e5bcfed7e7276660bf7e956bce5afa395e7e4c15883b856bc93dd9d6a968838ef51314d38dd41e5ab84b8846dca3c61d87e55780e7a7da336a965a4652263413cdef41daa68f7bb7cd4d566c19a1c4eece369c47e604575f38e7a246a985c3441b60ae33c564395bb7a4bbe28325ccdb07503285dacf90b5e09f4e455fb42459741f9d497000298b99f1e70adc28f59a1be85a96952f27b6a6c5d6a08822b4f5cae05daa6c2ce2f8ca5fdd4e8f0df46b94791b3159fe8eace11bcf8d58be425b49ce2b47c007affefd5cea785c1996ad805f8c8c5ca79f15ab26e2bd4080b1d74328e7ce5bd2a579c71a6bd25f33f2ce475a2cfbe67ed1f4eb8fbd86920f41d573488abe059166aabbc3be187c435423ead6a5473994e0246efe76e419893aa2d7566b2645f3496d97585de9c92b8c5a5226398cc459ce84abc02fe2b45b5ecaf21961730d4a34bbe6fdfe720e71e3d81a494c01080d8039360d534c6ee5a3c47a1874e526969add9126b30d9192f85ba45bcfd7029cc7560f0e25e14b5deaa805360c4967705e85325ac055922863470f5397e8404022488caebf9204acd6cb02a11088aebf7e497b4ff1172f0a9c6bf980914cc4eb42fc78b457add549abf1134f84922b217502938b42d10b35079f44c5168d4c3e9fe7ca8094ef72ed73ef84f1d3530b6b3545f9f4f013e7e8cbcf2619f57754a7380ce6a9532ee14c55990faa43df6c09530a314b5f4ce597f5ec9b776e8597ce258ac47dac43bd3ac9e52788ff3a66b7dc07cd1bc3e6d197339d85fa8d3d6c3054dd1a5e416c714b544de6eb55209e40e3cac412a51748370160d2d73b6d97abd62f7bae70df27cd199c511fa693019c5717d471e934906b98cd974fda4dd1cb5e2d721044a0be2bdf24d0971e09f2f39488fe389fc5230699b4df7cec7447e5be4ea49bd7c3fe1a5ec7358510dc1dd9c1a8da68c0863188d80549e49f7c00f57d2009b2427b2aed1569603fc247734039469f9fdf3ddd3a22fa95c5d8066a468327a02b474c9915419af82c8edc67686984767fe7885207c6820f6c2e57cb8fd0bcb9981ebc8065c74e970a5d593c3b73ee25a0877ca096a9f7edfee6d43bd817c7d415fea9abb6f206c61aa36942df9318762a76b9da26d0d41a0ae9eee042a175f82dc134bf6f2d46a218db358d6852940e6e30df4a58ac6cb409e7ce99afe1e3f42768bd617af4d0a235d0ba0dd5075f9cc091784395d30e7e42d4e006db21bea9b45d1f122b75c051e84e2281573ef54ebad053218fff0cc28ea89a06adc218d4134f407654990592e75462f5ee4a463c1e46425222d48761162da8049613cafd7ecc52ff8024e9d58512b958e3a3d12dede84e1441247700bca0f992875349448b430683c756438fd4e91f3d44f3cf624ed21f3c63cf92615ecc201d0cd3159b1b3fccd8f29d2daba9ac5ba87b1dd2f83323a2b2d3176b803ce9c7bdc4bae615925eb22a213df1eeb2f8ff95586536caf042d565984aacf1425a120a5d8d7a9cbb70bf4852e116b89ff5b198d672220af2be4246372e7c3836cf50d732212a3e3346ff92873ace57fa687b2b1aab3e8dc6cb9f93f865d998cff0a1680d9012a9597c90a070e525f66226cc287814f4ac4157b15a0b25aa110946cd69fd404fafd5656669bfd1d9e509eabc004c5a")); - - data = serialize_onionpacket(tmpctx, op); - printf("[\n"); - - memset(&blinding_priv, 5, sizeof(blinding_priv)); - pubkey_from_privkey(&blinding_priv, &blinding); - - data = json_test("onion message for Alice", - data, - &alice, - &blinding_priv, - &blinding); - - data = json_test("onion message for Bob", - data, - &bob, - NULL, - &blinding); - - data = json_test("onion message for Carol", - data, - &carol, - NULL, - &blinding); - - data = json_test("onion message for Dave", - data, - &dave, - NULL, - &blinding); - - assert(!data); - printf("]\n"); - - common_shutdown(); - return 0; -} diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c index ed037461a..bd56b82c1 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -364,6 +365,7 @@ static unsigned connectd_msg(struct subd *connectd, const u8 *msg, const int *fd case WIRE_CONNECTD_DEV_MEMLEAK: case WIRE_CONNECTD_PEER_FINAL_MSG: case WIRE_CONNECTD_PING: + case WIRE_CONNECTD_SEND_ONIONMSG: /* This is a reply, so never gets through to here. */ case WIRE_CONNECTD_INIT_REPLY: case WIRE_CONNECTD_ACTIVATE_REPLY: @@ -384,6 +386,10 @@ static unsigned connectd_msg(struct subd *connectd, const u8 *msg, const int *fd case WIRE_CONNECTD_CONNECT_FAILED: connect_failed(connectd->ld, msg); break; + + case WIRE_CONNECTD_GOT_ONIONMSG_TO_US: + handle_onionmsg_to_us(connectd->ld, msg); + break; } return 0; } diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index f6895fd69..7429d4db3 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -164,7 +163,6 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) case WIRE_GOSSIPD_DEV_COMPACT_STORE: case WIRE_GOSSIPD_DEV_SET_TIME: case WIRE_GOSSIPD_NEW_BLOCKHEIGHT: - case WIRE_GOSSIPD_SEND_ONIONMSG: case WIRE_GOSSIPD_ADDGOSSIP: case WIRE_GOSSIPD_GET_ADDRS: case WIRE_GOSSIPD_USED_LOCAL_CHANNEL_UPDATE: @@ -180,9 +178,6 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) case WIRE_GOSSIPD_GET_ADDRS_REPLY: break; - case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US: - handle_onionmsg_to_us(gossip->ld, msg); - break; case WIRE_GOSSIPD_GET_TXOUT: get_txout(gossip, msg); break; diff --git a/lightningd/onion_message.c b/lightningd/onion_message.c index e6e51f5eb..fec95b7ca 100644 --- a/lightningd/onion_message.c +++ b/lightningd/onion_message.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include @@ -150,7 +150,7 @@ void handle_onionmsg_to_us(struct lightningd *ld, const u8 *msg) payload = tal(tmpctx, struct onion_message_hook_payload); payload->our_alias = tal(payload, struct pubkey); - if (!fromwire_gossipd_got_onionmsg_to_us(payload, msg, + if (!fromwire_connectd_got_onionmsg_to_us(payload, msg, &obs2, payload->our_alias, &self_id, @@ -198,7 +198,7 @@ void handle_onionmsg_to_us(struct lightningd *ld, const u8 *msg) } tal_free(submsg); - /* Make sure gossipd gets this right. */ + /* Make sure connectd gets this right. */ if (payload->reply_path && (!payload->reply_blinding || !payload->reply_first_node)) { log_broken(ld->log, @@ -277,7 +277,7 @@ static struct command_result *json_sendonionmessage2(struct command *cmd, return command_fail(cmd, LIGHTNINGD, "experimental-onion-messages not enabled"); - /* Sanity check first; gossipd doesn't bother telling us if peer + /* Sanity check first; connectd doesn't bother telling us if peer * can't be reached. */ if (!peer_by_id(cmd->ld, first_id)) return command_fail(cmd, LIGHTNINGD, "Unknown first peer"); @@ -300,8 +300,8 @@ static struct command_result *json_sendonionmessage2(struct command *cmd, return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "Creating onion failed (tlvs too long?)"); - subd_send_msg(cmd->ld->gossip, - take(towire_gossipd_send_onionmsg(NULL, obs2, first_id, + subd_send_msg(cmd->ld->connectd, + take(towire_connectd_send_onionmsg(NULL, obs2, first_id, serialize_onionpacket(tmpctx, op), blinding))); diff --git a/wire/peer_wire.c b/wire/peer_wire.c index 1ed291db5..35089e48f 100644 --- a/wire/peer_wire.c +++ b/wire/peer_wire.c @@ -65,8 +65,6 @@ bool is_msg_for_gossipd(const u8 *cursor) case WIRE_REPLY_SHORT_CHANNEL_IDS_END: case WIRE_QUERY_CHANNEL_RANGE: case WIRE_REPLY_CHANNEL_RANGE: - case WIRE_OBS2_ONION_MESSAGE: - case WIRE_ONION_MESSAGE: return true; case WIRE_WARNING: case WIRE_INIT: @@ -101,6 +99,8 @@ bool is_msg_for_gossipd(const u8 *cursor) case WIRE_ACCEPT_CHANNEL2: case WIRE_INIT_RBF: case WIRE_ACK_RBF: + case WIRE_OBS2_ONION_MESSAGE: + case WIRE_ONION_MESSAGE: #if EXPERIMENTAL_FEATURES case WIRE_STFU: #endif