Browse Source

channeld: handle onion messages.

We do most of the decoding here, and just hand the results to lightningd.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
travis-debug
Rusty Russell 5 years ago
parent
commit
dd690553b8
  1. 17
      channeld/channel_wire.csv
  2. 146
      channeld/channeld.c
  3. 7
      lightningd/channel_control.c
  4. 1
      tools/generate-wire.py

17
channeld/channel_wire.csv

@ -208,3 +208,20 @@ msgdata,channel_send_error,reason,wirestring,
# Tell master channeld has sent the error message.
msgtype,channel_send_error_reply,1108
# Tell lightningd we got a onion message (for us, or to fwd)
msgtype,got_onionmsg_to_us,1142
msgdata,got_onionmsg_to_us,reply_blinding,?pubkey,
msgdata,got_onionmsg_to_us,reply_path_len,u16,
msgdata,got_onionmsg_to_us,reply_path,onionmsg_path,reply_path_len
msgtype,got_onionmsg_forward,1143
msgdata,got_onionmsg_forward,next_scid,?short_channel_id,
msgdata,got_onionmsg_forward,next_node_id,?node_id,
msgdata,got_onionmsg_forward,next_blinding,?pubkey,
msgdata,got_onionmsg_forward,next_onion,u8,1366
# Lightningd tells us to send a onion message.
msgtype,send_onionmsg,1040
msgdata,send_onionmsg,onion,u8,1366
msgdata,send_onionmsg,blinding,?pubkey,

Can't render this file because it has a wrong number of fields in line 9.

146
channeld/channeld.c

@ -13,6 +13,7 @@
#include <bitcoin/chainparams.h>
#include <bitcoin/privkey.h>
#include <bitcoin/script.h>
#include <ccan/array_size/array_size.h>
#include <ccan/cast/cast.h>
#include <ccan/container_of/container_of.h>
#include <ccan/crypto/hkdf_sha256/hkdf_sha256.h>
@ -1621,6 +1622,138 @@ static bool channeld_handle_custommsg(const u8 *msg)
#endif
}
#if EXPERIMENTAL_FEATURES
/* Peer sends onion msg. */
static void handle_onion_message(struct peer *peer, const u8 *msg)
{
enum onion_type badreason;
struct onionpacket op;
struct secret ss;
struct route_step *rs;
u8 onion[TOTAL_PACKET_SIZE];
const u8 *cursor;
size_t max, maxlen;
struct tlv_onionmsg_payload *om;
const struct short_channel_id *next_scid;
struct node_id *next_node;
struct tlv_onion_message_tlvs *tlvs = tlv_onion_message_tlvs_new(msg);
if (!fromwire_onion_message(msg, onion, tlvs))
peer_failed(peer->pps,
&peer->channel_id,
"Bad onion_message %s", tal_hex(peer, msg));
if (tlvs->blinding) {
status_broken("FIXME: Handle blinding!");
return;
}
/* We unwrap the onion now. */
badreason = parse_onionpacket(onion, TOTAL_PACKET_SIZE, &op);
if (badreason != 0) {
status_debug("onion msg: can't parse onionpacket: %s",
onion_type_name(badreason));
return;
}
/* Because wire takes struct pubkey. */
msg = hsm_req(tmpctx, towire_hsm_ecdh_req(tmpctx, &op.ephemeralkey));
if (!fromwire_hsm_ecdh_resp(msg, &ss))
status_failed(STATUS_FAIL_HSM_IO, "Reading ecdh response");
/* We make sure we can parse onion packet, so we know if shared secret
* is actually valid (this checks hmac). */
rs = process_onionpacket(tmpctx, &op, &ss, NULL, 0, false);
if (!rs) {
status_debug("onion msg: can't process onionpacket ss=%s",
type_to_string(tmpctx, struct secret, &ss));
return;
}
/* The raw payload is prepended with length in the TLV world. */
cursor = rs->raw_payload;
max = tal_bytelen(rs->raw_payload);
maxlen = fromwire_bigsize(&cursor, &max);
if (!cursor) {
status_debug("onion msg: Invalid hop payload %s",
tal_hex(tmpctx, rs->raw_payload));
return;
}
if (maxlen > max) {
status_debug("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_debug("onion msg: invalid onionmsg_payload %s",
tal_hex(tmpctx, rs->raw_payload));
return;
}
if (om->next_short_channel_id)
next_scid = &om->next_short_channel_id->short_channel_id;
else
next_scid = NULL;
if (om->next_node_id) {
next_node = tal(msg, struct node_id);
node_id_from_pubkey(next_node, &om->next_node_id->node_id);
} else
next_node = NULL;
if (om->enctlv) {
status_broken("FIXME: Handle enctlv!");
return;
}
if (rs->nextcase == ONION_END) {
/* FIXME: Handle reply_path */
/* payload may not be valid, so we hand it pre-decrypted to lightningd */
wire_sync_write(MASTER_FD,
take(towire_got_onionmsg_to_us(NULL,
NULL,
NULL)));
} else {
/* This *MUST* have instructions on where to go next. */
if (!next_scid && !next_node) {
status_debug("onion msg: no next field in %s",
tal_hex(tmpctx, rs->raw_payload));
return;
}
wire_sync_write(MASTER_FD,
take(towire_got_onionmsg_forward(NULL,
next_scid,
next_node,
NULL,
serialize_onionpacket(tmpctx, rs->next))));
}
}
/* We send onion msg. */
static void send_onionmsg(struct peer *peer, const u8 *msg)
{
u8 onion_routing_packet[TOTAL_PACKET_SIZE];
struct pubkey *blinding;
struct tlv_onion_message_tlvs *tlvs = tlv_onion_message_tlvs_new(msg);
if (!fromwire_send_onionmsg(msg, msg, onion_routing_packet, &blinding))
master_badmsg(WIRE_SEND_ONIONMSG, msg);
if (blinding) {
tlvs->blinding = tal(tlvs,
struct tlv_onion_message_tlvs_blinding);
tlvs->blinding->blinding = *blinding;
}
sync_crypto_write(peer->pps,
take(towire_onion_message(NULL,
onion_routing_packet,
tlvs)));
}
#endif /* EXPERIMENTAL_FEATURES */
static void peer_in(struct peer *peer, const u8 *msg)
{
enum wire_type type = fromwire_peektype(msg);
@ -1694,7 +1827,8 @@ static void peer_in(struct peer *peer, const u8 *msg)
return;
#if EXPERIMENTAL_FEATURES
case WIRE_ONION_MESSAGE:
break;
handle_onion_message(peer, msg);
return;
#endif
case WIRE_INIT:
@ -2684,6 +2818,14 @@ static void req_in(struct peer *peer, const u8 *msg)
case WIRE_CHANNEL_SEND_ERROR:
handle_send_error(peer, msg);
return;
#if EXPERIMENTAL_FEATURES
case WIRE_SEND_ONIONMSG:
send_onionmsg(peer, msg);
return;
#else
case WIRE_SEND_ONIONMSG:
break;
#endif /* !EXPERIMENTAL_FEATURES */
#if DEVELOPER
case WIRE_CHANNEL_DEV_REENABLE_COMMIT:
handle_dev_reenable_commit(peer);
@ -2711,6 +2853,8 @@ static void req_in(struct peer *peer, const u8 *msg)
case WIRE_CHANNEL_FAIL_FALLEN_BEHIND:
case WIRE_CHANNEL_DEV_MEMLEAK_REPLY:
case WIRE_CHANNEL_SEND_ERROR_REPLY:
case WIRE_GOT_ONIONMSG_TO_US:
case WIRE_GOT_ONIONMSG_FORWARD:
break;
}

7
lightningd/channel_control.c

@ -319,6 +319,10 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds)
case WIRE_CHANNEL_SEND_ERROR_REPLY:
handle_error_channel(sd->channel, msg);
break;
case WIRE_GOT_ONIONMSG_TO_US:
case WIRE_GOT_ONIONMSG_FORWARD:
/* FIXME */
break;
/* And we never get these from channeld. */
case WIRE_CHANNEL_INIT:
@ -334,7 +338,8 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds)
case WIRE_CHANNEL_FEERATES:
case WIRE_CHANNEL_SPECIFIC_FEERATES:
case WIRE_CHANNEL_DEV_MEMLEAK:
/* Replies go to requests. */
case WIRE_SEND_ONIONMSG:
/* Replies go to requests. */
case WIRE_CHANNEL_OFFER_HTLC_REPLY:
case WIRE_CHANNEL_DEV_REENABLE_COMMIT_REPLY:
case WIRE_CHANNEL_DEV_MEMLEAK_REPLY:

1
tools/generate-wire.py

@ -226,6 +226,7 @@ class Type(FieldSet):
'onionreply',
'witscript',
'feature_set',
'onionmsg_path',
]
# Some BOLT types are re-typed based on their field name

Loading…
Cancel
Save