mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 01:43:36 +01:00
lightningd: add routine to directly inject an onion message.
Unlike "sendonionmessage" which instructs us to send to a peer, this process it locally (presumably, it contains the next hop). This is useful because it allows us to process an onion message which starts with us (a legal case for a blinded path supplied by someone else!). It also opens the door to bolt12 self-pay. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
ba82592196
commit
b5f921ce0a
@ -2174,6 +2174,10 @@ static struct io_plan *recv_req(struct io_conn *conn,
|
||||
set_custommsgs(daemon, msg);
|
||||
goto out;
|
||||
|
||||
case WIRE_CONNECTD_INJECT_ONIONMSG:
|
||||
inject_onionmsg_req(daemon, msg);
|
||||
goto out;
|
||||
|
||||
case WIRE_CONNECTD_DEV_MEMLEAK:
|
||||
if (daemon->developer) {
|
||||
dev_connect_memleak(daemon, msg);
|
||||
@ -2216,6 +2220,7 @@ static struct io_plan *recv_req(struct io_conn *conn,
|
||||
case WIRE_CONNECTD_CUSTOMMSG_IN:
|
||||
case WIRE_CONNECTD_PEER_DISCONNECT_DONE:
|
||||
case WIRE_CONNECTD_START_SHUTDOWN_REPLY:
|
||||
case WIRE_CONNECTD_INJECT_ONIONMSG_REPLY:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -144,6 +144,16 @@ msgdata,connectd_send_onionmsg,onion_len,u16,
|
||||
msgdata,connectd_send_onionmsg,onion,u8,onion_len
|
||||
msgdata,connectd_send_onionmsg,blinding,pubkey,
|
||||
|
||||
# Lightningd tells us to digest an onion message.
|
||||
msgtype,connectd_inject_onionmsg,2042
|
||||
msgdata,connectd_inject_onionmsg,blinding,pubkey,
|
||||
msgdata,connectd_inject_onionmsg,onion_len,u16,
|
||||
msgdata,connectd_inject_onionmsg,onion,u8,onion_len
|
||||
|
||||
# Reply. If error isn't empty, something went wrong.
|
||||
msgtype,connectd_inject_onionmsg_reply,2142
|
||||
msgdata,connectd_inject_onionmsg_reply,err,wirestring,
|
||||
|
||||
# A custom message that we got from a peer and don't know how to handle, so we
|
||||
# forward it to the master for further handling.
|
||||
msgtype,connectd_custommsg_in,2110
|
||||
|
|
@ -1,6 +1,7 @@
|
||||
/*~ This contains all the code to handle onion messages. */
|
||||
#include "config.h"
|
||||
#include <ccan/cast/cast.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/blindedpath.h>
|
||||
#include <common/blinding.h>
|
||||
#include <common/daemon_conn.h>
|
||||
@ -35,12 +36,11 @@ void onionmsg_req(struct daemon *daemon, const u8 *msg)
|
||||
}
|
||||
}
|
||||
|
||||
/* Peer sends an onion msg. */
|
||||
void handle_onion_message(struct daemon *daemon,
|
||||
struct peer *peer, const u8 *msg)
|
||||
static const char *handle_onion(const tal_t *ctx,
|
||||
struct daemon *daemon,
|
||||
const struct pubkey *blinding,
|
||||
const u8 *onion)
|
||||
{
|
||||
struct pubkey blinding;
|
||||
u8 *onion;
|
||||
u8 *next_onion_msg;
|
||||
struct pubkey next_node;
|
||||
struct tlv_onionmsg_tlv *final_om;
|
||||
@ -48,26 +48,12 @@ void handle_onion_message(struct daemon *daemon,
|
||||
struct secret *final_path_id;
|
||||
const char *err;
|
||||
|
||||
/* 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)) {
|
||||
inject_peer_msg(peer,
|
||||
towire_warningfmt(NULL, NULL,
|
||||
"Bad onion_message"));
|
||||
return;
|
||||
}
|
||||
|
||||
err = onion_message_parse(tmpctx, onion, &blinding,
|
||||
err = onion_message_parse(tmpctx, onion, blinding,
|
||||
&daemon->mykey,
|
||||
&next_onion_msg, &next_node,
|
||||
&final_om, &final_alias, &final_path_id);
|
||||
if (err) {
|
||||
status_peer_debug(&peer->id, "%s", err);
|
||||
return;
|
||||
return tal_steal(ctx, err);
|
||||
}
|
||||
|
||||
if (final_om) {
|
||||
@ -91,12 +77,50 @@ void handle_onion_message(struct daemon *daemon,
|
||||
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",
|
||||
fmt_pubkey(tmpctx, &next_node));
|
||||
return;
|
||||
return tal_fmt(ctx, "onion msg: unknown next peer %s",
|
||||
fmt_pubkey(tmpctx, &next_node));
|
||||
}
|
||||
inject_peer_msg(next_peer, take(next_onion_msg));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Peer sends an onion msg, or (if peer NULL) lightningd injects one. */
|
||||
void handle_onion_message(struct daemon *daemon,
|
||||
struct peer *peer, const u8 *msg)
|
||||
{
|
||||
struct pubkey blinding;
|
||||
u8 *onion;
|
||||
|
||||
/* 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)) {
|
||||
inject_peer_msg(peer,
|
||||
towire_warningfmt(NULL, NULL,
|
||||
"Bad onion_message"));
|
||||
return;
|
||||
}
|
||||
|
||||
handle_onion(tmpctx, daemon, &blinding, onion);
|
||||
}
|
||||
|
||||
void inject_onionmsg_req(struct daemon *daemon, const u8 *msg)
|
||||
{
|
||||
u8 *onionmsg;
|
||||
struct pubkey blinding;
|
||||
const char *err;
|
||||
|
||||
if (!fromwire_connectd_inject_onionmsg(msg, msg, &blinding, &onionmsg))
|
||||
master_badmsg(WIRE_CONNECTD_INJECT_ONIONMSG, msg);
|
||||
|
||||
err = handle_onion(tmpctx, daemon, &blinding, onionmsg);
|
||||
daemon_conn_send(daemon->master,
|
||||
take(towire_connectd_inject_onionmsg_reply(NULL, err ? err : "")));
|
||||
}
|
||||
|
||||
|
||||
|
@ -3,11 +3,14 @@
|
||||
#include "config.h"
|
||||
#include <ccan/short_types/short_types.h>
|
||||
|
||||
/* Onion message comes in from peer */
|
||||
/* Onion message comes in from peer. */
|
||||
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);
|
||||
|
||||
/* Lightning tells us unwrap onion message as if from peer */
|
||||
void inject_onionmsg_req(struct daemon *daemon, const u8 *msg);
|
||||
|
||||
#endif /* LIGHTNING_CONNECTD_ONION_MESSAGE_H */
|
||||
|
@ -608,6 +608,7 @@ static unsigned connectd_msg(struct subd *connectd, const u8 *msg, const int *fd
|
||||
case WIRE_CONNECTD_PEER_CONNECT_SUBD:
|
||||
case WIRE_CONNECTD_PING:
|
||||
case WIRE_CONNECTD_SEND_ONIONMSG:
|
||||
case WIRE_CONNECTD_INJECT_ONIONMSG:
|
||||
case WIRE_CONNECTD_CUSTOMMSG_OUT:
|
||||
case WIRE_CONNECTD_START_SHUTDOWN:
|
||||
case WIRE_CONNECTD_SET_CUSTOMMSGS:
|
||||
@ -619,6 +620,7 @@ static unsigned connectd_msg(struct subd *connectd, const u8 *msg, const int *fd
|
||||
case WIRE_CONNECTD_DEV_MEMLEAK_REPLY:
|
||||
case WIRE_CONNECTD_PING_REPLY:
|
||||
case WIRE_CONNECTD_START_SHUTDOWN_REPLY:
|
||||
case WIRE_CONNECTD_INJECT_ONIONMSG_REPLY:
|
||||
break;
|
||||
|
||||
case WIRE_CONNECTD_PEER_CONNECTED:
|
||||
|
@ -249,3 +249,82 @@ static const struct json_command sendonionmessage_command = {
|
||||
"Send message to {first_id}, using {blinding}, encoded over {hops} (id, tlv)"
|
||||
};
|
||||
AUTODATA(json_command, &sendonionmessage_command);
|
||||
|
||||
static void inject_onionmsg_reply(struct subd *connectd,
|
||||
const u8 *reply,
|
||||
const int *fds UNUSED,
|
||||
struct command *cmd)
|
||||
{
|
||||
char *err;
|
||||
|
||||
if (!fromwire_connectd_inject_onionmsg_reply(cmd, reply, &err)) {
|
||||
log_broken(connectd->ld->log, "bad onionmsg_reply: %s",
|
||||
tal_hex(tmpctx, reply));
|
||||
return;
|
||||
}
|
||||
|
||||
if (strlen(err) == 0)
|
||||
was_pending(command_success(cmd, json_stream_success(cmd)));
|
||||
else
|
||||
was_pending(command_fail(cmd, LIGHTNINGD, "%s", err));
|
||||
}
|
||||
|
||||
static struct command_result *json_injectonionmessage(struct command *cmd,
|
||||
const char *buffer,
|
||||
const jsmntok_t *obj UNNEEDED,
|
||||
const jsmntok_t *params)
|
||||
{
|
||||
struct onion_hop *hops;
|
||||
struct pubkey *blinding;
|
||||
struct sphinx_path *sphinx_path;
|
||||
struct onionpacket *op;
|
||||
struct secret *path_secrets;
|
||||
size_t onion_size;
|
||||
|
||||
if (!param_check(cmd, buffer, params,
|
||||
p_req("blinding", param_pubkey, &blinding),
|
||||
p_req("hops", param_onion_hops, &hops),
|
||||
NULL))
|
||||
return command_param_failed();
|
||||
|
||||
if (!feature_offered(cmd->ld->our_features->bits[NODE_ANNOUNCE_FEATURE],
|
||||
OPT_ONION_MESSAGES))
|
||||
return command_fail(cmd, LIGHTNINGD,
|
||||
"experimental-onion-messages not enabled");
|
||||
|
||||
/* Create an onion which encodes this. */
|
||||
sphinx_path = sphinx_path_new(cmd, NULL);
|
||||
for (size_t i = 0; i < tal_count(hops); i++)
|
||||
sphinx_add_hop(sphinx_path, &hops[i].node, hops[i].tlv);
|
||||
|
||||
/* BOLT-onion-message #4:
|
||||
* - SHOULD set `onion_message_packet` `len` to 1366 or 32834.
|
||||
*/
|
||||
if (sphinx_path_payloads_size(sphinx_path) <= ROUTING_INFO_SIZE)
|
||||
onion_size = ROUTING_INFO_SIZE;
|
||||
else
|
||||
onion_size = 32768; /* VERSION_SIZE + HMAC_SIZE + PUBKEY_SIZE == 66 */
|
||||
|
||||
op = create_onionpacket(tmpctx, sphinx_path, onion_size, &path_secrets);
|
||||
if (!op)
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"Creating onion failed (tlvs too long?)");
|
||||
|
||||
if (command_check_only(cmd))
|
||||
return command_check_done(cmd);
|
||||
|
||||
subd_req(cmd, cmd->ld->connectd,
|
||||
take(towire_connectd_inject_onionmsg(NULL,
|
||||
blinding,
|
||||
serialize_onionpacket(tmpctx, op))),
|
||||
-1, 0, inject_onionmsg_reply, cmd);
|
||||
return command_still_pending(cmd);
|
||||
}
|
||||
|
||||
static const struct json_command injectonionmessage_command = {
|
||||
"injectonionmessage",
|
||||
"utility",
|
||||
json_injectonionmessage,
|
||||
"Unwrap using {blinding}, encoded over {hops} (id, tlv)"
|
||||
};
|
||||
AUTODATA(json_command, &injectonionmessage_command);
|
||||
|
Loading…
Reference in New Issue
Block a user