mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-03 18:57:06 +01:00
connectd: handle onion messages.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
50eccb6a12
commit
8782d39476
15 changed files with 827 additions and 978 deletions
|
@ -7,6 +7,7 @@ CONNECTD_HEADERS := connectd/connectd_wiregen.h \
|
||||||
connectd/handshake.h \
|
connectd/handshake.h \
|
||||||
connectd/multiplex.h \
|
connectd/multiplex.h \
|
||||||
connectd/netaddress.h \
|
connectd/netaddress.h \
|
||||||
|
connectd/onion_message.h \
|
||||||
connectd/tor_autoservice.h \
|
connectd/tor_autoservice.h \
|
||||||
connectd/tor.h
|
connectd/tor.h
|
||||||
|
|
||||||
|
@ -41,6 +42,8 @@ CONNECTD_COMMON_OBJS := \
|
||||||
common/bech32_util.o \
|
common/bech32_util.o \
|
||||||
common/bigsize.o \
|
common/bigsize.o \
|
||||||
common/bip32.o \
|
common/bip32.o \
|
||||||
|
common/blinding.o \
|
||||||
|
common/blindedpath.o \
|
||||||
common/channel_id.o \
|
common/channel_id.o \
|
||||||
common/cryptomsg.o \
|
common/cryptomsg.o \
|
||||||
common/daemon.o \
|
common/daemon.o \
|
||||||
|
@ -49,6 +52,7 @@ CONNECTD_COMMON_OBJS := \
|
||||||
common/dev_disconnect.o \
|
common/dev_disconnect.o \
|
||||||
common/ecdh_hsmd.o \
|
common/ecdh_hsmd.o \
|
||||||
common/features.o \
|
common/features.o \
|
||||||
|
common/hmac.o \
|
||||||
common/status_wiregen.o \
|
common/status_wiregen.o \
|
||||||
common/gossip_store.o \
|
common/gossip_store.o \
|
||||||
common/gossip_rcvd_filter.o \
|
common/gossip_rcvd_filter.o \
|
||||||
|
@ -56,12 +60,14 @@ CONNECTD_COMMON_OBJS := \
|
||||||
common/memleak.o \
|
common/memleak.o \
|
||||||
common/msg_queue.o \
|
common/msg_queue.o \
|
||||||
common/node_id.o \
|
common/node_id.o \
|
||||||
|
common/onion.o \
|
||||||
common/onionreply.o \
|
common/onionreply.o \
|
||||||
common/ping.o \
|
common/ping.o \
|
||||||
common/per_peer_state.o \
|
common/per_peer_state.o \
|
||||||
common/psbt_open.o \
|
common/psbt_open.o \
|
||||||
common/pseudorand.o \
|
common/pseudorand.o \
|
||||||
common/setup.o \
|
common/setup.o \
|
||||||
|
common/sphinx.o \
|
||||||
common/status.o \
|
common/status.o \
|
||||||
common/status_wire.o \
|
common/status_wire.o \
|
||||||
common/subdaemon.o \
|
common/subdaemon.o \
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include <connectd/handshake.h>
|
#include <connectd/handshake.h>
|
||||||
#include <connectd/multiplex.h>
|
#include <connectd/multiplex.h>
|
||||||
#include <connectd/netaddress.h>
|
#include <connectd/netaddress.h>
|
||||||
|
#include <connectd/onion_message.h>
|
||||||
#include <connectd/peer_exchange_initmsg.h>
|
#include <connectd/peer_exchange_initmsg.h>
|
||||||
#include <connectd/tor.h>
|
#include <connectd/tor.h>
|
||||||
#include <connectd/tor_autoservice.h>
|
#include <connectd/tor_autoservice.h>
|
||||||
|
@ -1970,6 +1971,10 @@ static struct io_plan *recv_req(struct io_conn *conn,
|
||||||
send_manual_ping(daemon, msg);
|
send_manual_ping(daemon, msg);
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
case WIRE_CONNECTD_SEND_ONIONMSG:
|
||||||
|
onionmsg_req(daemon, msg);
|
||||||
|
goto out;
|
||||||
|
|
||||||
case WIRE_CONNECTD_DEV_MEMLEAK:
|
case WIRE_CONNECTD_DEV_MEMLEAK:
|
||||||
#if DEVELOPER
|
#if DEVELOPER
|
||||||
dev_connect_memleak(daemon, msg);
|
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_CONNECT_FAILED:
|
||||||
case WIRE_CONNECTD_DEV_MEMLEAK_REPLY:
|
case WIRE_CONNECTD_DEV_MEMLEAK_REPLY:
|
||||||
case WIRE_CONNECTD_PING_REPLY:
|
case WIRE_CONNECTD_PING_REPLY:
|
||||||
|
case WIRE_CONNECTD_GOT_ONIONMSG_TO_US:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <common/features.h>
|
#include <common/features.h>
|
||||||
#include <common/node_id.h>
|
#include <common/node_id.h>
|
||||||
#include <common/wireaddr.h>
|
#include <common/wireaddr.h>
|
||||||
|
#include <wire/onion_wire.h>
|
||||||
|
|
||||||
msgtype,connectd_init,2000
|
msgtype,connectd_init,2000
|
||||||
msgdata,connectd_init,chainparams,chainparams,
|
msgdata,connectd_init,chainparams,chainparams,
|
||||||
|
@ -94,3 +95,24 @@ msgtype,connectd_ping_reply,2130
|
||||||
msgdata,connectd_ping_reply,sent,bool,
|
msgdata,connectd_ping_reply,sent,bool,
|
||||||
# 0 == no pong expected, otherwise length of pong.
|
# 0 == no pong expected, otherwise length of pong.
|
||||||
msgdata,connectd_ping_reply,totlen,u16,
|
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,
|
||||||
|
|
||||||
|
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <connectd/connectd_gossipd_wiregen.h>
|
#include <connectd/connectd_gossipd_wiregen.h>
|
||||||
#include <connectd/connectd_wiregen.h>
|
#include <connectd/connectd_wiregen.h>
|
||||||
#include <connectd/multiplex.h>
|
#include <connectd/multiplex.h>
|
||||||
|
#include <connectd/onion_message.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
@ -488,6 +489,12 @@ static bool handle_message_locally(struct peer *peer, const u8 *msg)
|
||||||
} else if (type == WIRE_PONG) {
|
} else if (type == WIRE_PONG) {
|
||||||
handle_pong_in(peer, msg);
|
handle_pong_in(peer, msg);
|
||||||
return true;
|
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? */
|
/* Do we want to divert to gossipd? */
|
||||||
|
|
345
connectd/onion_message.c
Normal file
345
connectd/onion_message.c
Normal file
|
@ -0,0 +1,345 @@
|
||||||
|
/*~ This contains all the code to handle onion messages. */
|
||||||
|
#include "config.h"
|
||||||
|
#include <ccan/cast/cast.h>
|
||||||
|
#include <common/blindedpath.h>
|
||||||
|
#include <common/blinding.h>
|
||||||
|
#include <common/daemon_conn.h>
|
||||||
|
#include <common/ecdh_hsmd.h>
|
||||||
|
#include <common/features.h>
|
||||||
|
#include <common/sphinx.h>
|
||||||
|
#include <common/status.h>
|
||||||
|
#include <common/type_to_string.h>
|
||||||
|
#include <common/wire_error.h>
|
||||||
|
#include <connectd/connectd.h>
|
||||||
|
#include <connectd/connectd_wiregen.h>
|
||||||
|
#include <connectd/multiplex.h>
|
||||||
|
#include <connectd/onion_message.h>
|
||||||
|
#include <wire/peer_wire.h>
|
||||||
|
|
||||||
|
/* 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))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
15
connectd/onion_message.h
Normal file
15
connectd/onion_message.h
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef LIGHTNING_CONNECTD_ONION_MESSAGE_H
|
||||||
|
#define LIGHTNING_CONNECTD_ONION_MESSAGE_H
|
||||||
|
#include "config.h"
|
||||||
|
#include <ccan/short_types/short_types.h>
|
||||||
|
|
||||||
|
/* 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 */
|
408
connectd/test/run-onion_message.c
Normal file
408
connectd/test/run-onion_message.c
Normal file
|
@ -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 <ccan/str/hex/hex.h>
|
||||||
|
#include <ccan/tal/str/str.h>
|
||||||
|
#include <common/blinding.h>
|
||||||
|
#include <common/channel_type.h>
|
||||||
|
#include <common/ecdh.h>
|
||||||
|
#include <common/json_stream.h>
|
||||||
|
#include <common/onion.h>
|
||||||
|
#include <common/onionreply.h>
|
||||||
|
#include <common/setup.h>
|
||||||
|
#include <secp256k1_ecdh.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
|
@ -34,8 +34,6 @@ GOSSIPD_COMMON_OBJS := \
|
||||||
common/bech32_util.o \
|
common/bech32_util.o \
|
||||||
common/bigsize.o \
|
common/bigsize.o \
|
||||||
common/bip32.o \
|
common/bip32.o \
|
||||||
common/blinding.o \
|
|
||||||
common/blindedpath.o \
|
|
||||||
common/channel_id.o \
|
common/channel_id.o \
|
||||||
common/cryptomsg.o \
|
common/cryptomsg.o \
|
||||||
common/daemon.o \
|
common/daemon.o \
|
||||||
|
@ -45,7 +43,6 @@ GOSSIPD_COMMON_OBJS := \
|
||||||
common/dev_disconnect.o \
|
common/dev_disconnect.o \
|
||||||
common/ecdh_hsmd.o \
|
common/ecdh_hsmd.o \
|
||||||
common/features.o \
|
common/features.o \
|
||||||
common/hmac.o \
|
|
||||||
common/status_wiregen.o \
|
common/status_wiregen.o \
|
||||||
common/gossip_rcvd_filter.o \
|
common/gossip_rcvd_filter.o \
|
||||||
common/key_derive.o \
|
common/key_derive.o \
|
||||||
|
@ -53,8 +50,6 @@ GOSSIPD_COMMON_OBJS := \
|
||||||
common/memleak.o \
|
common/memleak.o \
|
||||||
common/msg_queue.o \
|
common/msg_queue.o \
|
||||||
common/node_id.o \
|
common/node_id.o \
|
||||||
common/onion.o \
|
|
||||||
common/onionreply.o \
|
|
||||||
common/per_peer_state.o \
|
common/per_peer_state.o \
|
||||||
common/ping.o \
|
common/ping.o \
|
||||||
common/psbt_open.o \
|
common/psbt_open.o \
|
||||||
|
@ -62,7 +57,6 @@ GOSSIPD_COMMON_OBJS := \
|
||||||
common/private_channel_announcement.o \
|
common/private_channel_announcement.o \
|
||||||
common/random_select.o \
|
common/random_select.o \
|
||||||
common/setup.o \
|
common/setup.o \
|
||||||
common/sphinx.o \
|
|
||||||
common/status.o \
|
common/status.o \
|
||||||
common/status_wire.o \
|
common/status_wire.o \
|
||||||
common/subdaemon.o \
|
common/subdaemon.o \
|
||||||
|
|
|
@ -13,15 +13,12 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <ccan/cast/cast.h>
|
#include <ccan/cast/cast.h>
|
||||||
#include <ccan/tal/str/str.h>
|
#include <ccan/tal/str/str.h>
|
||||||
#include <common/blindedpath.h>
|
|
||||||
#include <common/blinding.h>
|
|
||||||
#include <common/daemon_conn.h>
|
#include <common/daemon_conn.h>
|
||||||
#include <common/ecdh_hsmd.h>
|
#include <common/ecdh_hsmd.h>
|
||||||
#include <common/lease_rates.h>
|
#include <common/lease_rates.h>
|
||||||
#include <common/memleak.h>
|
#include <common/memleak.h>
|
||||||
#include <common/private_channel_announcement.h>
|
#include <common/private_channel_announcement.h>
|
||||||
#include <common/pseudorand.h>
|
#include <common/pseudorand.h>
|
||||||
#include <common/sphinx.h>
|
|
||||||
#include <common/status.h>
|
#include <common/status.h>
|
||||||
#include <common/subdaemon.h>
|
#include <common/subdaemon.h>
|
||||||
#include <common/timeout.h>
|
#include <common/timeout.h>
|
||||||
|
@ -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
|
/*~ 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
|
* gossip, or a request for information. We deliberately use non-overlapping
|
||||||
* message types so we can distinguish them. */
|
* 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,
|
const u8 *msg,
|
||||||
struct peer *peer)
|
struct peer *peer)
|
||||||
{
|
{
|
||||||
const u8 *err;
|
|
||||||
|
|
||||||
/* These are messages relayed from peer */
|
/* These are messages relayed from peer */
|
||||||
switch ((enum peer_wire)fromwire_peektype(msg)) {
|
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) */
|
/* These are not sent by peer (connectd sends us gossip msgs) */
|
||||||
case WIRE_CHANNEL_ANNOUNCEMENT:
|
case WIRE_CHANNEL_ANNOUNCEMENT:
|
||||||
case WIRE_CHANNEL_UPDATE:
|
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_ACCEPT_CHANNEL2:
|
||||||
case WIRE_INIT_RBF:
|
case WIRE_INIT_RBF:
|
||||||
case WIRE_ACK_RBF:
|
case WIRE_ACK_RBF:
|
||||||
|
case WIRE_OBS2_ONION_MESSAGE:
|
||||||
|
case WIRE_ONION_MESSAGE:
|
||||||
#if EXPERIMENTAL_FEATURES
|
#if EXPERIMENTAL_FEATURES
|
||||||
case WIRE_STFU:
|
case WIRE_STFU:
|
||||||
#endif
|
#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",
|
status_peer_broken(&peer->id, "unexpected cmd of type %i",
|
||||||
fromwire_peektype(msg));
|
fromwire_peektype(msg));
|
||||||
return io_close(conn);
|
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
|
/*~ 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:
|
case WIRE_REPLY_SHORT_CHANNEL_IDS_END:
|
||||||
err = handle_reply_short_channel_ids_end(peer, msg);
|
err = handle_reply_short_channel_ids_end(peer, msg);
|
||||||
goto handled_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()) */
|
/* These are non-gossip messages (!is_msg_for_gossipd()) */
|
||||||
case WIRE_WARNING:
|
case WIRE_WARNING:
|
||||||
|
@ -932,6 +587,8 @@ static void handle_recv_gossip(struct daemon *daemon, const u8 *outermsg)
|
||||||
case WIRE_ACCEPT_CHANNEL2:
|
case WIRE_ACCEPT_CHANNEL2:
|
||||||
case WIRE_INIT_RBF:
|
case WIRE_INIT_RBF:
|
||||||
case WIRE_ACK_RBF:
|
case WIRE_ACK_RBF:
|
||||||
|
case WIRE_OBS2_ONION_MESSAGE:
|
||||||
|
case WIRE_ONION_MESSAGE:
|
||||||
#if EXPERIMENTAL_FEATURES
|
#if EXPERIMENTAL_FEATURES
|
||||||
case WIRE_STFU:
|
case WIRE_STFU:
|
||||||
#endif
|
#endif
|
||||||
|
@ -1464,16 +1121,11 @@ static struct io_plan *recv_req(struct io_conn *conn,
|
||||||
break;
|
break;
|
||||||
#endif /* !DEVELOPER */
|
#endif /* !DEVELOPER */
|
||||||
|
|
||||||
case WIRE_GOSSIPD_SEND_ONIONMSG:
|
|
||||||
onionmsg_req(daemon, msg);
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
/* We send these, we don't receive them */
|
/* We send these, we don't receive them */
|
||||||
case WIRE_GOSSIPD_INIT_REPLY:
|
case WIRE_GOSSIPD_INIT_REPLY:
|
||||||
case WIRE_GOSSIPD_GET_TXOUT:
|
case WIRE_GOSSIPD_GET_TXOUT:
|
||||||
case WIRE_GOSSIPD_DEV_MEMLEAK_REPLY:
|
case WIRE_GOSSIPD_DEV_MEMLEAK_REPLY:
|
||||||
case WIRE_GOSSIPD_DEV_COMPACT_STORE_REPLY:
|
case WIRE_GOSSIPD_DEV_COMPACT_STORE_REPLY:
|
||||||
case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US:
|
|
||||||
case WIRE_GOSSIPD_ADDGOSSIP_REPLY:
|
case WIRE_GOSSIPD_ADDGOSSIP_REPLY:
|
||||||
case WIRE_GOSSIPD_NEW_BLOCKHEIGHT_REPLY:
|
case WIRE_GOSSIPD_NEW_BLOCKHEIGHT_REPLY:
|
||||||
case WIRE_GOSSIPD_GET_ADDRS_REPLY:
|
case WIRE_GOSSIPD_GET_ADDRS_REPLY:
|
||||||
|
|
|
@ -69,25 +69,6 @@ msgdata,gossipd_new_blockheight,blockheight,u32,
|
||||||
# gossipd: got it!
|
# gossipd: got it!
|
||||||
msgtype,gossipd_new_blockheight_reply,3126
|
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)
|
# Lightningd tells us to inject a gossip message (for addgossip RPC)
|
||||||
msgtype,gossipd_addgossip,3044
|
msgtype,gossipd_addgossip,3044
|
||||||
msgdata,gossipd_addgossip,len,u16,
|
msgdata,gossipd_addgossip,len,u16,
|
||||||
|
|
|
|
@ -1,588 +0,0 @@
|
||||||
#include "config.h"
|
|
||||||
int unused_main(int argc, char *argv[]);
|
|
||||||
#define main unused_main
|
|
||||||
#include "../gossipd.c"
|
|
||||||
#undef main
|
|
||||||
#include <ccan/str/hex/hex.h>
|
|
||||||
#include <common/blinding.h>
|
|
||||||
#include <common/channel_type.h>
|
|
||||||
#include <common/ecdh.h>
|
|
||||||
#include <common/json_stream.h>
|
|
||||||
#include <common/onion.h>
|
|
||||||
#include <common/onionreply.h>
|
|
||||||
#include <common/setup.h>
|
|
||||||
#include <secp256k1_ecdh.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <lightningd/hsm_control.h>
|
#include <lightningd/hsm_control.h>
|
||||||
#include <lightningd/jsonrpc.h>
|
#include <lightningd/jsonrpc.h>
|
||||||
#include <lightningd/lightningd.h>
|
#include <lightningd/lightningd.h>
|
||||||
|
#include <lightningd/onion_message.h>
|
||||||
#include <lightningd/opening_common.h>
|
#include <lightningd/opening_common.h>
|
||||||
#include <lightningd/peer_control.h>
|
#include <lightningd/peer_control.h>
|
||||||
|
|
||||||
|
@ -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_DEV_MEMLEAK:
|
||||||
case WIRE_CONNECTD_PEER_FINAL_MSG:
|
case WIRE_CONNECTD_PEER_FINAL_MSG:
|
||||||
case WIRE_CONNECTD_PING:
|
case WIRE_CONNECTD_PING:
|
||||||
|
case WIRE_CONNECTD_SEND_ONIONMSG:
|
||||||
/* This is a reply, so never gets through to here. */
|
/* This is a reply, so never gets through to here. */
|
||||||
case WIRE_CONNECTD_INIT_REPLY:
|
case WIRE_CONNECTD_INIT_REPLY:
|
||||||
case WIRE_CONNECTD_ACTIVATE_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:
|
case WIRE_CONNECTD_CONNECT_FAILED:
|
||||||
connect_failed(connectd->ld, msg);
|
connect_failed(connectd->ld, msg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case WIRE_CONNECTD_GOT_ONIONMSG_TO_US:
|
||||||
|
handle_onionmsg_to_us(connectd->ld, msg);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
#include <lightningd/hsm_control.h>
|
#include <lightningd/hsm_control.h>
|
||||||
#include <lightningd/jsonrpc.h>
|
#include <lightningd/jsonrpc.h>
|
||||||
#include <lightningd/lightningd.h>
|
#include <lightningd/lightningd.h>
|
||||||
#include <lightningd/onion_message.h>
|
|
||||||
#include <lightningd/peer_control.h>
|
#include <lightningd/peer_control.h>
|
||||||
#include <lightningd/subd.h>
|
#include <lightningd/subd.h>
|
||||||
|
|
||||||
|
@ -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_COMPACT_STORE:
|
||||||
case WIRE_GOSSIPD_DEV_SET_TIME:
|
case WIRE_GOSSIPD_DEV_SET_TIME:
|
||||||
case WIRE_GOSSIPD_NEW_BLOCKHEIGHT:
|
case WIRE_GOSSIPD_NEW_BLOCKHEIGHT:
|
||||||
case WIRE_GOSSIPD_SEND_ONIONMSG:
|
|
||||||
case WIRE_GOSSIPD_ADDGOSSIP:
|
case WIRE_GOSSIPD_ADDGOSSIP:
|
||||||
case WIRE_GOSSIPD_GET_ADDRS:
|
case WIRE_GOSSIPD_GET_ADDRS:
|
||||||
case WIRE_GOSSIPD_USED_LOCAL_CHANNEL_UPDATE:
|
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:
|
case WIRE_GOSSIPD_GET_ADDRS_REPLY:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US:
|
|
||||||
handle_onionmsg_to_us(gossip->ld, msg);
|
|
||||||
break;
|
|
||||||
case WIRE_GOSSIPD_GET_TXOUT:
|
case WIRE_GOSSIPD_GET_TXOUT:
|
||||||
get_txout(gossip, msg);
|
get_txout(gossip, msg);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <common/json_tok.h>
|
#include <common/json_tok.h>
|
||||||
#include <common/param.h>
|
#include <common/param.h>
|
||||||
#include <common/type_to_string.h>
|
#include <common/type_to_string.h>
|
||||||
#include <gossipd/gossipd_wiregen.h>
|
#include <connectd/connectd_wiregen.h>
|
||||||
#include <lightningd/channel.h>
|
#include <lightningd/channel.h>
|
||||||
#include <lightningd/json.h>
|
#include <lightningd/json.h>
|
||||||
#include <lightningd/onion_message.h>
|
#include <lightningd/onion_message.h>
|
||||||
|
@ -150,7 +150,7 @@ void handle_onionmsg_to_us(struct lightningd *ld, const u8 *msg)
|
||||||
payload = tal(tmpctx, struct onion_message_hook_payload);
|
payload = tal(tmpctx, struct onion_message_hook_payload);
|
||||||
payload->our_alias = tal(payload, struct pubkey);
|
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,
|
&obs2,
|
||||||
payload->our_alias,
|
payload->our_alias,
|
||||||
&self_id,
|
&self_id,
|
||||||
|
@ -198,7 +198,7 @@ void handle_onionmsg_to_us(struct lightningd *ld, const u8 *msg)
|
||||||
}
|
}
|
||||||
tal_free(submsg);
|
tal_free(submsg);
|
||||||
|
|
||||||
/* Make sure gossipd gets this right. */
|
/* Make sure connectd gets this right. */
|
||||||
if (payload->reply_path
|
if (payload->reply_path
|
||||||
&& (!payload->reply_blinding || !payload->reply_first_node)) {
|
&& (!payload->reply_blinding || !payload->reply_first_node)) {
|
||||||
log_broken(ld->log,
|
log_broken(ld->log,
|
||||||
|
@ -277,7 +277,7 @@ static struct command_result *json_sendonionmessage2(struct command *cmd,
|
||||||
return command_fail(cmd, LIGHTNINGD,
|
return command_fail(cmd, LIGHTNINGD,
|
||||||
"experimental-onion-messages not enabled");
|
"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. */
|
* can't be reached. */
|
||||||
if (!peer_by_id(cmd->ld, first_id))
|
if (!peer_by_id(cmd->ld, first_id))
|
||||||
return command_fail(cmd, LIGHTNINGD, "Unknown first peer");
|
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,
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||||
"Creating onion failed (tlvs too long?)");
|
"Creating onion failed (tlvs too long?)");
|
||||||
|
|
||||||
subd_send_msg(cmd->ld->gossip,
|
subd_send_msg(cmd->ld->connectd,
|
||||||
take(towire_gossipd_send_onionmsg(NULL, obs2, first_id,
|
take(towire_connectd_send_onionmsg(NULL, obs2, first_id,
|
||||||
serialize_onionpacket(tmpctx, op),
|
serialize_onionpacket(tmpctx, op),
|
||||||
blinding)));
|
blinding)));
|
||||||
|
|
||||||
|
|
|
@ -65,8 +65,6 @@ bool is_msg_for_gossipd(const u8 *cursor)
|
||||||
case WIRE_REPLY_SHORT_CHANNEL_IDS_END:
|
case WIRE_REPLY_SHORT_CHANNEL_IDS_END:
|
||||||
case WIRE_QUERY_CHANNEL_RANGE:
|
case WIRE_QUERY_CHANNEL_RANGE:
|
||||||
case WIRE_REPLY_CHANNEL_RANGE:
|
case WIRE_REPLY_CHANNEL_RANGE:
|
||||||
case WIRE_OBS2_ONION_MESSAGE:
|
|
||||||
case WIRE_ONION_MESSAGE:
|
|
||||||
return true;
|
return true;
|
||||||
case WIRE_WARNING:
|
case WIRE_WARNING:
|
||||||
case WIRE_INIT:
|
case WIRE_INIT:
|
||||||
|
@ -101,6 +99,8 @@ bool is_msg_for_gossipd(const u8 *cursor)
|
||||||
case WIRE_ACCEPT_CHANNEL2:
|
case WIRE_ACCEPT_CHANNEL2:
|
||||||
case WIRE_INIT_RBF:
|
case WIRE_INIT_RBF:
|
||||||
case WIRE_ACK_RBF:
|
case WIRE_ACK_RBF:
|
||||||
|
case WIRE_OBS2_ONION_MESSAGE:
|
||||||
|
case WIRE_ONION_MESSAGE:
|
||||||
#if EXPERIMENTAL_FEATURES
|
#if EXPERIMENTAL_FEATURES
|
||||||
case WIRE_STFU:
|
case WIRE_STFU:
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Reference in a new issue