connectd: forward onion messages by scid as well as node_id.

This is now permitted in the offers PR, so we should support it.  But
we can't just look up in the gossmap, since the "short_channel_id"
could be an alias.  So we get lightningd to tell us all scid->peer
mappings, and look up in that.

Changelog-Added: Protocol: onion messages can now be forwarded by short_channel_id.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2024-07-10 12:25:49 +09:30 committed by Vincenzo Palazzo
parent 19af516dcb
commit 621bfe370e
4 changed files with 56 additions and 32 deletions

View file

@ -40,7 +40,7 @@ static bool decrypt_final_onionmsg(const tal_t *ctx,
static bool decrypt_forwarding_onionmsg(const struct pubkey *blinding,
const struct secret *ss,
const u8 *enctlv,
struct pubkey *next_node,
struct sciddir_or_pubkey *next_node,
struct pubkey *next_blinding)
{
struct tlv_encrypted_data_tlv *encmsg;
@ -58,14 +58,27 @@ static bool decrypt_forwarding_onionmsg(const struct pubkey *blinding,
if (encmsg->path_id)
return false;
/* BOLT #4:
* - SHOULD forward the message using `onion_message` to the next peer
* indicated by `next_node_id`.
/* BOLT-offers #4:
* - if it is not the final node according to the onion encryption:
*...
* - if `next_node_id` is present:
* - the *next peer* is the peer with that node id.
* - otherwise, if `short_channel_id` is present and corresponds to an announced short_channel_id or a local alias for a channel:
* - the *next peer* is the peer at the other end of that channel.
* - otherwise:
* - MUST ignore the message.
*/
if (!encmsg->next_node_id)
if (encmsg->next_node_id)
sciddir_or_pubkey_from_pubkey(next_node, encmsg->next_node_id);
else if (encmsg->short_channel_id) {
/* This is actually scid, not sciddir, but the type is convenient! */
struct short_channel_id_dir scidd;
scidd.scid = *encmsg->short_channel_id;
scidd.dir = 0;
sciddir_or_pubkey_from_scidd(next_node, &scidd);
} else
return false;
*next_node = *encmsg->next_node_id;
blindedpath_next_blinding(encmsg, blinding, ss, next_blinding);
return true;
}
@ -76,7 +89,7 @@ const char *onion_message_parse(const tal_t *ctx,
const struct pubkey *blinding,
const struct pubkey *me,
u8 **next_onion_msg,
struct pubkey *next_node_id,
struct sciddir_or_pubkey *next_node,
struct tlv_onionmsg_tlv **final_om,
struct pubkey *final_alias,
struct secret **final_path_id)
@ -161,7 +174,7 @@ const char *onion_message_parse(const tal_t *ctx,
}
/* This fails as expected if no enctlv. */
if (!decrypt_forwarding_onionmsg(blinding, &ss, om->encrypted_recipient_data, next_node_id,
if (!decrypt_forwarding_onionmsg(blinding, &ss, om->encrypted_recipient_data, next_node,
&next_blinding)) {
return tal_fmt(ctx,
"onion_message_parse: invalid encrypted_recipient_data %s",

View file

@ -5,7 +5,7 @@
#include <common/amount.h>
struct tlv_onionmsg_tlv;
struct node_id;
struct sciddir_or_pubkey;
struct pubkey;
/**
@ -15,7 +15,7 @@ struct pubkey;
* @blinding: Blinding we were given for @onion_message_packet
* @me: my pubkey
* @next_onion_msg (out): set if we should forward, otherwise NULL.
* @next_node_id (out): set to node id to fwd to, iff *@next_onion_msg.
* @next_node (out): set to node id or scid to fwd to, iff *@next_onion_msg.
* @final_om (out): set if we're the final hop, otherwise NULL.
* @final_alias (out): our alias (if *@final_om), or our own ID
* @final_path_id (out): secret enclosed, if any (iff *@final_om).
@ -27,7 +27,7 @@ const char *onion_message_parse(const tal_t *ctx,
const struct pubkey *blinding,
const struct pubkey *me,
u8 **next_onion_msg,
struct pubkey *next_node_id,
struct sciddir_or_pubkey *next_node,
struct tlv_onionmsg_tlv **final_om,
struct pubkey *final_alias,
struct secret **final_path_id);

View file

@ -14,6 +14,7 @@ static void maybe_print(const char *fmt, ...);
#include "../hmac.c"
#include "../onion_encode.c"
#include "../onion_message_parse.c"
#include "../sciddir_or_pubkey.c"
#include "../sphinx.c"
#include "../../wire/onion_wiregen.c"
#include "../../wire/peer_wiregen.c"
@ -29,32 +30,18 @@ bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
/* 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 fromwire_sciddir_or_pubkey */
void fromwire_sciddir_or_pubkey(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
struct sciddir_or_pubkey *sciddpk UNNEEDED)
{ fprintf(stderr, "fromwire_sciddir_or_pubkey 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 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 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_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_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_sciddir_or_pubkey */
void towire_sciddir_or_pubkey(u8 **pptr UNNEEDED,
const struct sciddir_or_pubkey *sciddpk UNNEEDED)
{ fprintf(stderr, "towire_sciddir_or_pubkey called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */
static bool comma;
@ -355,7 +342,7 @@ int main(int argc, char *argv[])
json_start("hops", '[');
for (size_t i = 0; i < ARRAY_SIZE(erd); i++) {
struct pubkey next_node_id;
struct sciddir_or_pubkey next_node;
struct tlv_onionmsg_tlv *final_om;
struct pubkey final_alias;
struct secret *final_path_id;
@ -373,12 +360,13 @@ int main(int argc, char *argv[])
mykey = &privkey[i];
assert(onion_message_parse(tmpctx, onion_message_packet, &blinding_pub,
&id[i],
&onion_message, &next_node_id,
&onion_message, &next_node,
&final_om,
&final_alias,
&final_path_id) == NULL);
if (onion_message) {
json_pubkey("next_node_id", &next_node_id);
assert(next_node.is_pubkey);
json_pubkey("next_node_id", &next_node.pubkey);
} else {
const struct tlv_field *hello;
json_start("tlvs", '{');

View file

@ -42,7 +42,7 @@ static const char *handle_onion(const tal_t *ctx,
const u8 *onion)
{
u8 *next_onion_msg;
struct pubkey next_node;
struct sciddir_or_pubkey next_node;
struct tlv_onionmsg_tlv *final_om;
struct pubkey final_alias;
struct secret *final_path_id;
@ -73,12 +73,35 @@ static const char *handle_onion(const tal_t *ctx,
assert(next_onion_msg);
/* FIXME: Handle short_channel_id! */
node_id_from_pubkey(&next_node_id, &next_node);
/* BOLT-offers #4:
* - if it is not the final node according to the onion encryption:
*...
* - if `next_node_id` is present:
* - the *next peer* is the peer with that node id.
* - otherwise, if `short_channel_id` is present and corresponds to an announced short_channel_id or a local alias for a channel:
* - the *next peer* is the peer at the other end of that channel.
* - otherwise:
* - MUST ignore the message.
* - SHOULD forward the message using `onion_message` to the *next peer*.
*/
/* Since an alias is legal here, we can't simply lookup in gossmap. */
if (!next_node.is_pubkey) {
struct scid_to_node_id *scid_to_node_id;
scid_to_node_id = scid_htable_get(daemon->scid_htable, next_node.scidd.scid);
if (!scid_to_node_id) {
return tal_fmt(ctx, "onion msg: unknown next scid %s",
fmt_short_channel_id(tmpctx, next_node.scidd.scid));
}
next_node_id = scid_to_node_id->node_id;
} else {
node_id_from_pubkey(&next_node_id, &next_node.pubkey);
}
next_peer = peer_htable_get(daemon->peers, &next_node_id);
if (!next_peer) {
return tal_fmt(ctx, "onion msg: unknown next peer %s",
fmt_pubkey(tmpctx, &next_node));
fmt_sciddir_or_pubkey(tmpctx, &next_node));
}
inject_peer_msg(next_peer, take(next_onion_msg));
}