Browse Source

gossipd, channeld: handle onion messages in gossipd so we don't need a channel.

The previous onion_message code required a confirmed, not-shutting-down
channel, not just a connection.  That's overkill; plus before widespread
adoption we will want to connect directly as a last resort.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa
Rusty Russell 4 years ago
parent
commit
9d57612415
  1. 242
      channeld/channeld.c
  2. 20
      channeld/channeld_wire.csv
  3. 162
      channeld/channeld_wiregen.c
  4. 21
      channeld/channeld_wiregen.h
  5. 5
      gossipd/Makefile
  6. 279
      gossipd/gossipd.c
  7. 21
      gossipd/gossipd_wire.csv
  8. 164
      gossipd/gossipd_wiregen.c
  9. 21
      gossipd/gossipd_wiregen.h
  10. 12
      lightningd/channel.c
  11. 2
      lightningd/channel.h
  12. 13
      lightningd/channel_control.c
  13. 16
      lightningd/gossip_control.c
  14. 101
      lightningd/onion_message.c
  15. 6
      lightningd/onion_message.h
  16. 4
      wire/peer_wire.c

242
channeld/channeld.c

@ -51,7 +51,6 @@
#include <common/psbt_internal.h> #include <common/psbt_internal.h>
#include <common/psbt_open.h> #include <common/psbt_open.h>
#include <common/read_peer_msg.h> #include <common/read_peer_msg.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>
@ -65,7 +64,6 @@
#include <hsmd/hsmd_wiregen.h> #include <hsmd/hsmd_wiregen.h>
#include <inttypes.h> #include <inttypes.h>
#include <secp256k1.h> #include <secp256k1.h>
#include <sodium/crypto_aead_chacha20poly1305.h>
#include <stdio.h> #include <stdio.h>
#if EXPERIMENTAL_FEATURES #if EXPERIMENTAL_FEATURES
#include <wire/bolt12_exp_wiregen.h> #include <wire/bolt12_exp_wiregen.h>
@ -1805,230 +1803,6 @@ static bool channeld_handle_custommsg(const u8 *msg)
} }
#if EXPERIMENTAL_FEATURES #if EXPERIMENTAL_FEATURES
/* Peer sends onion msg. */
static void handle_onion_message(struct peer *peer, const u8 *msg)
{
enum onion_wire badreason;
struct onionpacket *op;
struct secret ss, *blinding_ss;
struct pubkey *blinding_in;
struct route_step *rs;
u8 onion[TOTAL_PACKET_SIZE(ROUTING_INFO_SIZE)];
const u8 *cursor;
size_t max, maxlen;
struct tlv_onionmsg_payload *om;
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));
/* We unwrap the onion now. */
op = parse_onionpacket(tmpctx, onion, TOTAL_PACKET_SIZE(ROUTING_INFO_SIZE), &badreason);
if (badreason != 0) {
status_debug("onion msg: can't parse onionpacket: %s",
onion_wire_name(badreason));
return;
}
if (tlvs->blinding) {
struct secret hmac;
/* E(i) */
blinding_in = tal_dup(msg, struct pubkey, tlvs->blinding);
status_debug("blinding in = %s",
type_to_string(tmpctx, struct pubkey, blinding_in));
blinding_ss = tal(msg, struct secret);
ecdh(blinding_in, blinding_ss);
/* b(i) = HMAC256("blinded_node_id", ss(i)) * k(i) */
subkey_from_hmac("blinded_node_id", blinding_ss, &hmac);
/* We instead tweak the *ephemeral* key from the onion and use
* our normal privkey: since hsmd knows only how to ECDH with
* our real key */
if (secp256k1_ec_pubkey_tweak_mul(secp256k1_ctx,
&op->ephemeralkey.pubkey,
hmac.data) != 1) {
status_debug("onion msg: can't tweak pubkey");
return;
}
} else {
blinding_ss = NULL;
blinding_in = NULL;
}
ecdh(&op->ephemeralkey, &ss);
/* 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 we weren't given a blinding factor, tlv can provide one. */
if (om->blinding && !blinding_ss) {
/* E(i) */
blinding_in = tal_dup(msg, struct pubkey, om->blinding);
blinding_ss = tal(msg, struct secret);
ecdh(blinding_in, blinding_ss);
}
if (om->enctlv) {
const unsigned char npub[crypto_aead_chacha20poly1305_ietf_NPUBBYTES] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
u8 *dec;
struct secret rho;
int ret;
if (!blinding_ss) {
status_debug("enctlv but no blinding?");
return;
}
/* We need this to decrypt enctlv */
subkey_from_hmac("rho", blinding_ss, &rho);
/* Overrides next_scid / next_node */
if (tal_bytelen(om->enctlv)
< crypto_aead_chacha20poly1305_ietf_ABYTES) {
status_debug("enctlv too short for mac");
return;
}
dec = tal_arr(msg, u8,
tal_bytelen(om->enctlv)
- crypto_aead_chacha20poly1305_ietf_ABYTES);
ret = crypto_aead_chacha20poly1305_ietf_decrypt(dec, NULL,
NULL,
om->enctlv,
tal_bytelen(om->enctlv),
NULL, 0,
npub,
rho.data);
if (ret != 0)
errx(1, "Failed to decrypt enctlv field");
status_debug("enctlv -> %s", tal_hex(tmpctx, dec));
/* Replace onionmsg with one from enctlv */
cursor = dec;
maxlen = tal_bytelen(dec);
om = tlv_onionmsg_payload_new(msg);
if (!fromwire_onionmsg_payload(&cursor, &maxlen, om)) {
status_debug("onion msg: invalid enctlv onionmsg_payload %s",
tal_hex(tmpctx, dec));
return;
}
} else if (blinding_ss && rs->nextcase != ONION_END) {
status_debug("Onion had %s, but not enctlv?",
tlvs->blinding ? "blinding" : "om blinding");
return;
}
if (rs->nextcase == ONION_END) {
struct pubkey *blinding;
const struct onionmsg_path **path;
u8 *omsg;
if (om->reply_path) {
blinding = &om->reply_path->blinding;
path = cast_const2(const struct onionmsg_path **,
om->reply_path->path);
} else {
blinding = NULL;
path = NULL;
}
/* We re-marshall here by policy, before handing to lightningd */
omsg = tal_arr(tmpctx, u8, 0);
towire_tlvstream_raw(&omsg, om->fields);
wire_sync_write(MASTER_FD,
take(towire_got_onionmsg_to_us(NULL,
blinding_in,
blinding,
path,
omsg)));
} else {
struct pubkey *next_blinding;
struct node_id *next_node;
/* This *MUST* have instructions on where to go next. */
if (!om->next_short_channel_id && !om->next_node_id) {
status_debug("onion msg: no next field in %s",
tal_hex(tmpctx, rs->raw_payload));
return;
}
if (blinding_ss) {
/* E(i-1) = H(E(i) || ss(i)) * E(i) */
struct sha256 h;
blinding_hash_e_and_ss(blinding_in, blinding_ss, &h);
next_blinding = tal(msg, struct pubkey);
blinding_next_pubkey(blinding_in, &h, next_blinding);
} else
next_blinding = NULL;
if (om->next_node_id) {
next_node = tal(tmpctx, struct node_id);
node_id_from_pubkey(next_node, om->next_node_id);
} else
next_node = NULL;
wire_sync_write(MASTER_FD,
take(towire_got_onionmsg_forward(NULL,
om->next_short_channel_id,
next_node,
next_blinding,
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(ROUTING_INFO_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_dup(tlvs, struct pubkey, blinding);
sync_crypto_write(peer->pps,
take(towire_onion_message(NULL,
onion_routing_packet,
tlvs)));
}
static void handle_send_tx_sigs(struct peer *peer, const u8 *msg) static void handle_send_tx_sigs(struct peer *peer, const u8 *msg)
{ {
struct wally_psbt *psbt; struct wally_psbt *psbt;
@ -2278,9 +2052,6 @@ static void peer_in(struct peer *peer, const u8 *msg)
handle_peer_shutdown(peer, msg); handle_peer_shutdown(peer, msg);
return; return;
#if EXPERIMENTAL_FEATURES #if EXPERIMENTAL_FEATURES
case WIRE_ONION_MESSAGE:
handle_onion_message(peer, msg);
return;
case WIRE_TX_SIGNATURES: case WIRE_TX_SIGNATURES:
handle_tx_sigs(peer, msg); handle_tx_sigs(peer, msg);
return; return;
@ -2323,6 +2094,9 @@ static void peer_in(struct peer *peer, const u8 *msg)
case WIRE_PING: case WIRE_PING:
case WIRE_PONG: case WIRE_PONG:
case WIRE_ERROR: case WIRE_ERROR:
#if EXPERIMENTAL_FEATURES
case WIRE_ONION_MESSAGE:
#endif
abort(); abort();
} }
@ -3361,14 +3135,6 @@ static void req_in(struct peer *peer, const u8 *msg)
case WIRE_CHANNELD_SEND_TX_SIGS: case WIRE_CHANNELD_SEND_TX_SIGS:
break; break;
#endif /* !EXPERIMENTAL_FEATURES */ #endif /* !EXPERIMENTAL_FEATURES */
#if EXPERIMENTAL_FEATURES
case WIRE_SEND_ONIONMSG:
send_onionmsg(peer, msg);
return;
#else
case WIRE_SEND_ONIONMSG:
break;
#endif /* !EXPERIMENTAL_FEATURES */
#if DEVELOPER #if DEVELOPER
case WIRE_CHANNELD_DEV_REENABLE_COMMIT: case WIRE_CHANNELD_DEV_REENABLE_COMMIT:
handle_dev_reenable_commit(peer); handle_dev_reenable_commit(peer);
@ -3397,8 +3163,6 @@ static void req_in(struct peer *peer, const u8 *msg)
case WIRE_CHANNELD_FAIL_FALLEN_BEHIND: case WIRE_CHANNELD_FAIL_FALLEN_BEHIND:
case WIRE_CHANNELD_DEV_MEMLEAK_REPLY: case WIRE_CHANNELD_DEV_MEMLEAK_REPLY:
case WIRE_CHANNELD_SEND_ERROR_REPLY: case WIRE_CHANNELD_SEND_ERROR_REPLY:
case WIRE_GOT_ONIONMSG_TO_US:
case WIRE_GOT_ONIONMSG_FORWARD:
break; break;
} }

20
channeld/channeld_wire.csv

@ -224,23 +224,3 @@ msgdata,channeld_send_error,reason,wirestring,
# Tell master channeld has sent the error message. # Tell master channeld has sent the error message.
msgtype,channeld_send_error_reply,1108 msgtype,channeld_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,blinding_in,?pubkey,
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
msgdata,got_onionmsg_to_us,rawmsg_len,u16,
msgdata,got_onionmsg_to_us,rawmsg,u8,rawmsg_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 12.

162
channeld/channeld_wiregen.c

@ -48,9 +48,6 @@ const char *channeld_wire_name(int e)
case WIRE_CHANNELD_GOT_ANNOUNCEMENT: return "WIRE_CHANNELD_GOT_ANNOUNCEMENT"; case WIRE_CHANNELD_GOT_ANNOUNCEMENT: return "WIRE_CHANNELD_GOT_ANNOUNCEMENT";
case WIRE_CHANNELD_SEND_ERROR: return "WIRE_CHANNELD_SEND_ERROR"; case WIRE_CHANNELD_SEND_ERROR: return "WIRE_CHANNELD_SEND_ERROR";
case WIRE_CHANNELD_SEND_ERROR_REPLY: return "WIRE_CHANNELD_SEND_ERROR_REPLY"; case WIRE_CHANNELD_SEND_ERROR_REPLY: return "WIRE_CHANNELD_SEND_ERROR_REPLY";
case WIRE_GOT_ONIONMSG_TO_US: return "WIRE_GOT_ONIONMSG_TO_US";
case WIRE_GOT_ONIONMSG_FORWARD: return "WIRE_GOT_ONIONMSG_FORWARD";
case WIRE_SEND_ONIONMSG: return "WIRE_SEND_ONIONMSG";
} }
snprintf(invalidbuf, sizeof(invalidbuf), "INVALID %i", e); snprintf(invalidbuf, sizeof(invalidbuf), "INVALID %i", e);
@ -88,9 +85,6 @@ bool channeld_wire_is_defined(u16 type)
case WIRE_CHANNELD_GOT_ANNOUNCEMENT:; case WIRE_CHANNELD_GOT_ANNOUNCEMENT:;
case WIRE_CHANNELD_SEND_ERROR:; case WIRE_CHANNELD_SEND_ERROR:;
case WIRE_CHANNELD_SEND_ERROR_REPLY:; case WIRE_CHANNELD_SEND_ERROR_REPLY:;
case WIRE_GOT_ONIONMSG_TO_US:;
case WIRE_GOT_ONIONMSG_FORWARD:;
case WIRE_SEND_ONIONMSG:;
return true; return true;
} }
return false; return false;
@ -1102,158 +1096,4 @@ bool fromwire_channeld_send_error_reply(const void *p)
return false; return false;
return cursor != NULL; return cursor != NULL;
} }
// SHA256STAMP:58b780dc0bd7296e837407e362f2364f70104199c6a6b01382bb9278696688ae
/* WIRE: GOT_ONIONMSG_TO_US */
/* Tell lightningd we got a onion message (for us */
u8 *towire_got_onionmsg_to_us(const tal_t *ctx, const struct pubkey *blinding_in, const struct pubkey *reply_blinding, const struct onionmsg_path **reply_path, const u8 *rawmsg)
{
u16 reply_path_len = tal_count(reply_path);
u16 rawmsg_len = tal_count(rawmsg);
u8 *p = tal_arr(ctx, u8, 0);
towire_u16(&p, WIRE_GOT_ONIONMSG_TO_US);
if (!blinding_in)
towire_bool(&p, false);
else {
towire_bool(&p, true);
towire_pubkey(&p, blinding_in);
}
if (!reply_blinding)
towire_bool(&p, false);
else {
towire_bool(&p, true);
towire_pubkey(&p, reply_blinding);
}
towire_u16(&p, reply_path_len);
for (size_t i = 0; i < reply_path_len; i++)
towire_onionmsg_path(&p, reply_path[i]);
towire_u16(&p, rawmsg_len);
towire_u8_array(&p, rawmsg, rawmsg_len);
return memcheck(p, tal_count(p));
}
bool fromwire_got_onionmsg_to_us(const tal_t *ctx, const void *p, struct pubkey **blinding_in, struct pubkey **reply_blinding, struct onionmsg_path ***reply_path, u8 **rawmsg)
{
u16 reply_path_len;
u16 rawmsg_len;
const u8 *cursor = p;
size_t plen = tal_count(p);
if (fromwire_u16(&cursor, &plen) != WIRE_GOT_ONIONMSG_TO_US)
return false;
if (!fromwire_bool(&cursor, &plen))
*blinding_in = NULL;
else {
*blinding_in = tal(ctx, struct pubkey);
fromwire_pubkey(&cursor, &plen, *blinding_in);
}
if (!fromwire_bool(&cursor, &plen))
*reply_blinding = NULL;
else {
*reply_blinding = tal(ctx, struct pubkey);
fromwire_pubkey(&cursor, &plen, *reply_blinding);
}
reply_path_len = fromwire_u16(&cursor, &plen);
// 2nd case reply_path
*reply_path = reply_path_len ? tal_arr(ctx, struct onionmsg_path *, reply_path_len) : NULL;
for (size_t i = 0; i < reply_path_len; i++)
(*reply_path)[i] = fromwire_onionmsg_path(*reply_path, &cursor, &plen);
rawmsg_len = fromwire_u16(&cursor, &plen);
// 2nd case rawmsg
*rawmsg = rawmsg_len ? tal_arr(ctx, u8, rawmsg_len) : NULL;
fromwire_u8_array(&cursor, &plen, *rawmsg, rawmsg_len);
return cursor != NULL;
}
/* WIRE: GOT_ONIONMSG_FORWARD */
u8 *towire_got_onionmsg_forward(const tal_t *ctx, const struct short_channel_id *next_scid, const struct node_id *next_node_id, const struct pubkey *next_blinding, const u8 next_onion[1366])
{
u8 *p = tal_arr(ctx, u8, 0);
towire_u16(&p, WIRE_GOT_ONIONMSG_FORWARD);
if (!next_scid)
towire_bool(&p, false);
else {
towire_bool(&p, true);
towire_short_channel_id(&p, next_scid);
}
if (!next_node_id)
towire_bool(&p, false);
else {
towire_bool(&p, true);
towire_node_id(&p, next_node_id);
}
if (!next_blinding)
towire_bool(&p, false);
else {
towire_bool(&p, true);
towire_pubkey(&p, next_blinding);
}
towire_u8_array(&p, next_onion, 1366);
return memcheck(p, tal_count(p));
}
bool fromwire_got_onionmsg_forward(const tal_t *ctx, const void *p, struct short_channel_id **next_scid, struct node_id **next_node_id, struct pubkey **next_blinding, u8 next_onion[1366])
{
const u8 *cursor = p;
size_t plen = tal_count(p);
if (fromwire_u16(&cursor, &plen) != WIRE_GOT_ONIONMSG_FORWARD)
return false;
if (!fromwire_bool(&cursor, &plen))
*next_scid = NULL;
else {
*next_scid = tal(ctx, struct short_channel_id);
fromwire_short_channel_id(&cursor, &plen, *next_scid);
}
if (!fromwire_bool(&cursor, &plen))
*next_node_id = NULL;
else {
*next_node_id = tal(ctx, struct node_id);
fromwire_node_id(&cursor, &plen, *next_node_id);
}
if (!fromwire_bool(&cursor, &plen))
*next_blinding = NULL;
else {
*next_blinding = tal(ctx, struct pubkey);
fromwire_pubkey(&cursor, &plen, *next_blinding);
}
fromwire_u8_array(&cursor, &plen, next_onion, 1366);
return cursor != NULL;
}
/* WIRE: SEND_ONIONMSG */
/* Lightningd tells us to send a onion message. */
u8 *towire_send_onionmsg(const tal_t *ctx, const u8 onion[1366], const struct pubkey *blinding)
{
u8 *p = tal_arr(ctx, u8, 0);
towire_u16(&p, WIRE_SEND_ONIONMSG);
towire_u8_array(&p, onion, 1366);
if (!blinding)
towire_bool(&p, false);
else {
towire_bool(&p, true);
towire_pubkey(&p, blinding);
}
return memcheck(p, tal_count(p));
}
bool fromwire_send_onionmsg(const tal_t *ctx, const void *p, u8 onion[1366], struct pubkey **blinding)
{
const u8 *cursor = p;
size_t plen = tal_count(p);
if (fromwire_u16(&cursor, &plen) != WIRE_SEND_ONIONMSG)
return false;
fromwire_u8_array(&cursor, &plen, onion, 1366);
if (!fromwire_bool(&cursor, &plen))
*blinding = NULL;
else {
*blinding = tal(ctx, struct pubkey);
fromwire_pubkey(&cursor, &plen, *blinding);
}
return cursor != NULL;
}
// SHA256STAMP:564860d28225780e0746b0f9e6944d691a342d12bd9d0400bb962577fab64067

21
channeld/channeld_wiregen.h

@ -74,11 +74,6 @@ enum channeld_wire {
WIRE_CHANNELD_SEND_ERROR = 1008, WIRE_CHANNELD_SEND_ERROR = 1008,
/* Tell master channeld has sent the error message. */ /* Tell master channeld has sent the error message. */
WIRE_CHANNELD_SEND_ERROR_REPLY = 1108, WIRE_CHANNELD_SEND_ERROR_REPLY = 1108,
/* Tell lightningd we got a onion message (for us */
WIRE_GOT_ONIONMSG_TO_US = 1142,
WIRE_GOT_ONIONMSG_FORWARD = 1143,
/* Lightningd tells us to send a onion message. */
WIRE_SEND_ONIONMSG = 1040,
}; };
const char *channeld_wire_name(int e); const char *channeld_wire_name(int e);
@ -230,20 +225,6 @@ bool fromwire_channeld_send_error(const tal_t *ctx, const void *p, wirestring **
u8 *towire_channeld_send_error_reply(const tal_t *ctx); u8 *towire_channeld_send_error_reply(const tal_t *ctx);
bool fromwire_channeld_send_error_reply(const void *p); bool fromwire_channeld_send_error_reply(const void *p);
/* WIRE: GOT_ONIONMSG_TO_US */
/* Tell lightningd we got a onion message (for us */
u8 *towire_got_onionmsg_to_us(const tal_t *ctx, const struct pubkey *blinding_in, const struct pubkey *reply_blinding, const struct onionmsg_path **reply_path, const u8 *rawmsg);
bool fromwire_got_onionmsg_to_us(const tal_t *ctx, const void *p, struct pubkey **blinding_in, struct pubkey **reply_blinding, struct onionmsg_path ***reply_path, u8 **rawmsg);
/* WIRE: GOT_ONIONMSG_FORWARD */
u8 *towire_got_onionmsg_forward(const tal_t *ctx, const struct short_channel_id *next_scid, const struct node_id *next_node_id, const struct pubkey *next_blinding, const u8 next_onion[1366]);
bool fromwire_got_onionmsg_forward(const tal_t *ctx, const void *p, struct short_channel_id **next_scid, struct node_id **next_node_id, struct pubkey **next_blinding, u8 next_onion[1366]);
/* WIRE: SEND_ONIONMSG */
/* Lightningd tells us to send a onion message. */
u8 *towire_send_onionmsg(const tal_t *ctx, const u8 onion[1366], const struct pubkey *blinding);
bool fromwire_send_onionmsg(const tal_t *ctx, const void *p, u8 onion[1366], struct pubkey **blinding);
#endif /* LIGHTNING_CHANNELD_CHANNELD_WIREGEN_H */ #endif /* LIGHTNING_CHANNELD_CHANNELD_WIREGEN_H */
// SHA256STAMP:564860d28225780e0746b0f9e6944d691a342d12bd9d0400bb962577fab64067 // SHA256STAMP:58b780dc0bd7296e837407e362f2364f70104199c6a6b01382bb9278696688ae

5
gossipd/Makefile

@ -33,6 +33,7 @@ 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/channel_id.o \ common/channel_id.o \
common/crypto_state.o \ common/crypto_state.o \
common/cryptomsg.o \ common/cryptomsg.o \
@ -41,13 +42,16 @@ GOSSIPD_COMMON_OBJS := \
common/decode_array.o \ common/decode_array.o \
common/derive_basepoints.o \ common/derive_basepoints.o \
common/dev_disconnect.o \ common/dev_disconnect.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 \
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/per_peer_state.o \ common/per_peer_state.o \
common/ping.o \ common/ping.o \
@ -56,6 +60,7 @@ 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 \

279
gossipd/gossipd.c

@ -27,12 +27,15 @@
#include <ccan/tal/str/str.h> #include <ccan/tal/str/str.h>
#include <common/bech32.h> #include <common/bech32.h>
#include <common/bech32_util.h> #include <common/bech32_util.h>
#include <common/blinding.h>
#include <common/cryptomsg.h> #include <common/cryptomsg.h>
#include <common/daemon_conn.h> #include <common/daemon_conn.h>
#include <common/ecdh_hsmd.h>
#include <common/features.h> #include <common/features.h>
#include <common/memleak.h> #include <common/memleak.h>
#include <common/ping.h> #include <common/ping.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>
@ -58,12 +61,16 @@
#include <netdb.h> #include <netdb.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <secp256k1_ecdh.h> #include <secp256k1_ecdh.h>
#include <sodium/crypto_aead_chacha20poly1305.h>
#include <sodium/randombytes.h> #include <sodium/randombytes.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/un.h> #include <sys/un.h>
#include <unistd.h> #include <unistd.h>
#if EXPERIMENTAL_FEATURES
#include <wire/bolt12_exp_wiregen.h>
#endif
#include <wire/wire_io.h> #include <wire/wire_io.h>
#include <wire/wire_sync.h> #include <wire/wire_sync.h>
@ -428,6 +435,263 @@ static bool handle_local_channel_announcement(struct daemon *daemon,
return true; return true;
} }
#if EXPERIMENTAL_FEATURES
/* Peer sends onion msg. */
static u8 *handle_onion_message(struct peer *peer, const u8 *msg)
{
enum onion_wire badreason;
struct onionpacket *op;
struct secret ss, *blinding_ss;
struct pubkey *blinding_in;
struct route_step *rs;
u8 onion[TOTAL_PACKET_SIZE(ROUTING_INFO_SIZE)];
const u8 *cursor;
size_t max, maxlen;
struct tlv_onionmsg_payload *om;
struct tlv_onion_message_tlvs *tlvs = tlv_onion_message_tlvs_new(msg);
/* FIXME: ratelimit! */
if (!fromwire_onion_message(msg, onion, tlvs))
return towire_errorfmt(peer, NULL, "Bad onion_message");
/* We unwrap the onion now. */
op = parse_onionpacket(tmpctx, onion, TOTAL_PACKET_SIZE(ROUTING_INFO_SIZE), &badreason);
if (!op) {
status_debug("peer %s: onion msg: can't parse onionpacket: %s",
type_to_string(tmpctx, struct node_id, &peer->id),
onion_wire_name(badreason));
return NULL;
}
if (tlvs->blinding) {
struct secret hmac;
/* E(i) */
blinding_in = tal_dup(msg, struct pubkey, tlvs->blinding);
status_debug("peer %s: blinding in = %s",
type_to_string(tmpctx, struct node_id, &peer->id),
type_to_string(tmpctx, struct pubkey, blinding_in));
blinding_ss = tal(msg, struct secret);
ecdh(blinding_in, blinding_ss);
/* b(i) = HMAC256("blinded_node_id", ss(i)) * k(i) */
subkey_from_hmac("blinded_node_id", blinding_ss, &hmac);
/* We instead tweak the *ephemeral* key from the onion and use
* our normal privkey: since hsmd knows only how to ECDH with
* our real key */
if (secp256k1_ec_pubkey_tweak_mul(secp256k1_ctx,
&op->ephemeralkey.pubkey,
hmac.data) != 1) {
status_debug("peer %s: onion msg: can't tweak pubkey",
type_to_string(tmpctx, struct node_id, &peer->id));
return NULL;
}
} else {
blinding_ss = NULL;
blinding_in = NULL;
}
ecdh(&op->ephemeralkey, &ss);
/* 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("peer %s: onion msg: can't process onionpacket ss=%s",
type_to_string(tmpctx, struct node_id, &peer->id),
type_to_string(tmpctx, struct secret, &ss));
return NULL;
}
/* 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("peer %s: onion msg: Invalid hop payload %s",
type_to_string(tmpctx, struct node_id, &peer->id),
tal_hex(tmpctx, rs->raw_payload));
return NULL;
}
if (maxlen > max) {
status_debug("peer %s: onion msg: overlong hop payload %s",
type_to_string(tmpctx, struct node_id, &peer->id),
tal_hex(tmpctx, rs->raw_payload));
return NULL;
}
om = tlv_onionmsg_payload_new(msg);
if (!fromwire_onionmsg_payload(&cursor, &maxlen, om)) {
status_debug("peer %s: onion msg: invalid onionmsg_payload %s",
type_to_string(tmpctx, struct node_id, &peer->id),
tal_hex(tmpctx, rs->raw_payload));
return NULL;
}
/* If we weren't given a blinding factor, tlv can provide one. */
if (om->blinding && !blinding_ss) {
/* E(i) */
blinding_in = tal_dup(msg, struct pubkey, om->blinding);
blinding_ss = tal(msg, struct secret);
ecdh(blinding_in, blinding_ss);
}
if (om->enctlv) {
const unsigned char npub[crypto_aead_chacha20poly1305_ietf_NPUBBYTES] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
u8 *dec;
struct secret rho;
int ret;
if (!blinding_ss) {
status_debug("peer %s: enctlv but no blinding?",
type_to_string(tmpctx, struct node_id, &peer->id));
return NULL;
}
/* We need this to decrypt enctlv */
subkey_from_hmac("rho", blinding_ss, &rho);
/* Overrides next_scid / next_node */
if (tal_bytelen(om->enctlv)
< crypto_aead_chacha20poly1305_ietf_ABYTES) {
status_debug("peer %s: enctlv too short for mac",
type_to_string(tmpctx, struct node_id, &peer->id));
return NULL;
}
dec = tal_arr(msg, u8,
tal_bytelen(om->enctlv)
- crypto_aead_chacha20poly1305_ietf_ABYTES);
ret = crypto_aead_chacha20poly1305_ietf_decrypt(dec, NULL,
NULL,
om->enctlv,
tal_bytelen(om->enctlv),
NULL, 0,
npub,
rho.data);
if (ret != 0) {
status_debug("peer %s: Failed to decrypt enctlv field",
type_to_string(tmpctx, struct node_id, &peer->id));
return NULL;
}
status_debug("peer %s: enctlv -> %s",
type_to_string(tmpctx, struct node_id, &peer->id),
tal_hex(tmpctx, dec));
/* Replace onionmsg with one from enctlv */
cursor = dec;
maxlen = tal_bytelen(dec);
om = tlv_onionmsg_payload_new(msg);
if (!fromwire_onionmsg_payload(&cursor, &maxlen, om)) {
status_debug("peer %s: onion msg: invalid enctlv onionmsg_payload %s",
type_to_string(tmpctx, struct node_id, &peer->id),
tal_hex(tmpctx, dec));
return NULL;
}
} else if (blinding_ss && rs->nextcase != ONION_END) {
status_debug("peer %s: Onion had %s, but not enctlv?",
type_to_string(tmpctx, struct node_id, &peer->id),
tlvs->blinding ? "blinding" : "om blinding");
return NULL;
}
if (rs->nextcase == ONION_END) {
struct pubkey *blinding;
const struct onionmsg_path **path;
u8 *omsg;
if (om->reply_path) {
blinding = &om->reply_path->blinding;
path = cast_const2(const struct onionmsg_path **,
om->reply_path->path);
} else {
blinding = NULL;
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,
blinding_in,
blinding,
path,
omsg)));
} else {
struct pubkey *next_blinding;
struct node_id *next_node;
/* This *MUST* have instructions on where to go next. */
if (!om->next_short_channel_id && !om->next_node_id) {
status_debug("peer %s: onion msg: no next field in %s",
type_to_string(tmpctx, struct node_id, &peer->id),
tal_hex(tmpctx, rs->raw_payload));
return NULL;
}
if (blinding_ss) {
/* E(i-1) = H(E(i) || ss(i)) * E(i) */
struct sha256 h;
blinding_hash_e_and_ss(blinding_in, blinding_ss, &h);
next_blinding = tal(msg, struct pubkey);
blinding_next_pubkey(blinding_in, &h, next_blinding);
} else
next_blinding = NULL;
if (om->next_node_id) {
next_node = tal(tmpctx, struct node_id);
node_id_from_pubkey(next_node, om->next_node_id);
} else
next_node = NULL;
daemon_conn_send(peer->daemon->master,
take(towire_gossipd_got_onionmsg_forward(NULL,
om->next_short_channel_id,
next_node,
next_blinding,
serialize_onionpacket(tmpctx, rs->next))));
}
return NULL;
}
/* We send onion msg. */
static struct io_plan *onionmsg_req(struct io_conn *conn, struct daemon *daemon,
const u8 *msg)
{
struct node_id id;
u8 onion_routing_packet[TOTAL_PACKET_SIZE(ROUTING_INFO_SIZE)];
struct pubkey *blinding;
struct peer *peer;
if (!fromwire_gossipd_send_onionmsg(msg, msg, &id, onion_routing_packet,
&blinding))
master_badmsg(WIRE_GOSSIPD_SEND_ONIONMSG, msg);
/* Even if lightningd were to check for valid ids, there's a race
* where it might vanish before we read this command; cleaner to
* handle it here with 'sent' = false. */
peer = find_peer(daemon, &id);
if (peer) {
struct tlv_onion_message_tlvs *tlvs;
tlvs = tlv_onion_message_tlvs_new(msg);
if (blinding)
tlvs->blinding = tal_dup(tlvs, struct pubkey, blinding);
queue_peer_msg(peer,
take(towire_onion_message(NULL,
onion_routing_packet,
tlvs)));
}
return daemon_conn_read_next(conn, daemon->master);
}
#endif /* EXPERIMENTAL_FEATURES */
/*~ 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. */
@ -467,6 +731,11 @@ static struct io_plan *peer_msg_in(struct io_conn *conn,
case WIRE_PONG: case WIRE_PONG:
err = handle_pong(peer, msg); err = handle_pong(peer, msg);
goto handled_relay; goto handled_relay;
#if EXPERIMENTAL_FEATURES
case WIRE_ONION_MESSAGE:
err = handle_onion_message(peer, msg);
goto handled_relay;
#endif
/* These are non-gossip messages (!is_msg_for_gossipd()) */ /* These are non-gossip messages (!is_msg_for_gossipd()) */
case WIRE_INIT: case WIRE_INIT:
@ -489,7 +758,6 @@ static struct io_plan *peer_msg_in(struct io_conn *conn,
case WIRE_ANNOUNCEMENT_SIGNATURES: case WIRE_ANNOUNCEMENT_SIGNATURES:
case WIRE_GOSSIP_TIMESTAMP_FILTER: case WIRE_GOSSIP_TIMESTAMP_FILTER:
#if EXPERIMENTAL_FEATURES #if EXPERIMENTAL_FEATURES
case WIRE_ONION_MESSAGE:
case WIRE_TX_ADD_INPUT: case WIRE_TX_ADD_INPUT:
case WIRE_TX_REMOVE_INPUT: case WIRE_TX_REMOVE_INPUT:
case WIRE_TX_ADD_OUTPUT: case WIRE_TX_ADD_OUTPUT:
@ -1662,6 +1930,10 @@ static struct io_plan *recv_req(struct io_conn *conn,
break; break;
#endif /* !DEVELOPER */ #endif /* !DEVELOPER */
case WIRE_GOSSIPD_SEND_ONIONMSG:
#if EXPERIMENTAL_FEATURES
return onionmsg_req(conn, daemon, msg);
#endif
/* We send these, we don't receive them */ /* We send these, we don't receive them */
case WIRE_GOSSIPD_GETNODES_REPLY: case WIRE_GOSSIPD_GETNODES_REPLY:
case WIRE_GOSSIPD_GETROUTE_REPLY: case WIRE_GOSSIPD_GETROUTE_REPLY:
@ -1672,6 +1944,8 @@ static struct io_plan *recv_req(struct io_conn *conn,
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_GOT_ONIONMSG_FORWARD:
break; break;
} }
@ -1703,6 +1977,9 @@ int main(int argc, char *argv[])
daemon->node_announce_timer = NULL; daemon->node_announce_timer = NULL;
daemon->current_blockheight = 0; /* i.e. unknown */ daemon->current_blockheight = 0; /* i.e. unknown */
/* Tell the ecdh() function how to talk to hsmd */
ecdh_hsmd_setup(HSM_FD, status_failed);
/* Note the use of time_mono() here. That's a monotonic clock, which /* Note the use of time_mono() here. That's a monotonic clock, which
* is really useful: it can only be used to measure relative events * is really useful: it can only be used to measure relative events
* (there's no correspondence to time-since-Ken-grew-a-beard or * (there's no correspondence to time-since-Ken-grew-a-beard or

21
gossipd/gossipd_wire.csv

@ -138,3 +138,24 @@ msgdata,gossipd_get_incoming_channels_reply,private_deadends,bool,num_private
# master -> gossipd: blockheight increased. # master -> gossipd: blockheight increased.
msgtype,gossipd_new_blockheight,3026 msgtype,gossipd_new_blockheight,3026
msgdata,gossipd_new_blockheight,blockheight,u32, msgdata,gossipd_new_blockheight,blockheight,u32,
# Tell lightningd we got a onion message (for us, or to fwd)
msgtype,gossipd_got_onionmsg_to_us,3142
msgdata,gossipd_got_onionmsg_to_us,blinding_in,?pubkey,
msgdata,gossipd_got_onionmsg_to_us,reply_blinding,?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
msgtype,gossipd_got_onionmsg_forward,3143
msgdata,gossipd_got_onionmsg_forward,next_scid,?short_channel_id,
msgdata,gossipd_got_onionmsg_forward,next_node_id,?node_id,
msgdata,gossipd_got_onionmsg_forward,next_blinding,?pubkey,
msgdata,gossipd_got_onionmsg_forward,next_onion,u8,1366
# Lightningd tells us to send a onion message.
msgtype,gossipd_send_onionmsg,3040
msgdata,gossipd_send_onionmsg,id,node_id,
msgdata,gossipd_send_onionmsg,onion,u8,1366
msgdata,gossipd_send_onionmsg,blinding,?pubkey,

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

164
gossipd/gossipd_wiregen.c

@ -46,6 +46,9 @@ const char *gossipd_wire_name(int e)
case WIRE_GOSSIPD_GET_INCOMING_CHANNELS: return "WIRE_GOSSIPD_GET_INCOMING_CHANNELS"; case WIRE_GOSSIPD_GET_INCOMING_CHANNELS: return "WIRE_GOSSIPD_GET_INCOMING_CHANNELS";
case WIRE_GOSSIPD_GET_INCOMING_CHANNELS_REPLY: return "WIRE_GOSSIPD_GET_INCOMING_CHANNELS_REPLY"; case WIRE_GOSSIPD_GET_INCOMING_CHANNELS_REPLY: return "WIRE_GOSSIPD_GET_INCOMING_CHANNELS_REPLY";
case WIRE_GOSSIPD_NEW_BLOCKHEIGHT: return "WIRE_GOSSIPD_NEW_BLOCKHEIGHT"; case WIRE_GOSSIPD_NEW_BLOCKHEIGHT: return "WIRE_GOSSIPD_NEW_BLOCKHEIGHT";
case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US: return "WIRE_GOSSIPD_GOT_ONIONMSG_TO_US";
case WIRE_GOSSIPD_GOT_ONIONMSG_FORWARD: return "WIRE_GOSSIPD_GOT_ONIONMSG_FORWARD";
case WIRE_GOSSIPD_SEND_ONIONMSG: return "WIRE_GOSSIPD_SEND_ONIONMSG";
} }
snprintf(invalidbuf, sizeof(invalidbuf), "INVALID %i", e); snprintf(invalidbuf, sizeof(invalidbuf), "INVALID %i", e);
@ -81,6 +84,9 @@ bool gossipd_wire_is_defined(u16 type)
case WIRE_GOSSIPD_GET_INCOMING_CHANNELS:; case WIRE_GOSSIPD_GET_INCOMING_CHANNELS:;
case WIRE_GOSSIPD_GET_INCOMING_CHANNELS_REPLY:; case WIRE_GOSSIPD_GET_INCOMING_CHANNELS_REPLY:;
case WIRE_GOSSIPD_NEW_BLOCKHEIGHT:; case WIRE_GOSSIPD_NEW_BLOCKHEIGHT:;
case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US:;
case WIRE_GOSSIPD_GOT_ONIONMSG_FORWARD:;
case WIRE_GOSSIPD_SEND_ONIONMSG:;
return true; return true;
} }
return false; return false;
@ -857,4 +863,160 @@ bool fromwire_gossipd_new_blockheight(const void *p, u32 *blockheight)
*blockheight = fromwire_u32(&cursor, &plen); *blockheight = fromwire_u32(&cursor, &plen);
return cursor != NULL; return cursor != NULL;
} }
// SHA256STAMP:ae8bf4f19cc3dd086b9a20b8bc034d93d8ef066e901279de09fe2fd189f1344b
/* WIRE: GOSSIPD_GOT_ONIONMSG_TO_US */
/* Tell lightningd we got a onion message (for us */
u8 *towire_gossipd_got_onionmsg_to_us(const tal_t *ctx, const struct pubkey *blinding_in, const struct pubkey *reply_blinding, const struct onionmsg_path **reply_path, const u8 *rawmsg)
{
u16 reply_path_len = tal_count(reply_path);
u16 rawmsg_len = tal_count(rawmsg);
u8 *p = tal_arr(ctx, u8, 0);
towire_u16(&p, WIRE_GOSSIPD_GOT_ONIONMSG_TO_US);
if (!blinding_in)
towire_bool(&p, false);
else {
towire_bool(&p, true);
towire_pubkey(&p, blinding_in);
}
if (!reply_blinding)
towire_bool(&p, false);
else {
towire_bool(&p, true);
towire_pubkey(&p, reply_blinding);
}
towire_u16(&p, reply_path_len);
for (size_t i = 0; i < reply_path_len; i++)
towire_onionmsg_path(&p, reply_path[i]);
towire_u16(&p, rawmsg_len);
towire_u8_array(&p, rawmsg, rawmsg_len);
return memcheck(p, tal_count(p));
}
bool fromwire_gossipd_got_onionmsg_to_us(const tal_t *ctx, const void *p, struct pubkey **blinding_in, struct pubkey **reply_blinding, struct onionmsg_path ***reply_path, u8 **rawmsg)
{
u16 reply_path_len;
u16 rawmsg_len;
const u8 *cursor = p;
size_t plen = tal_count(p);
if (fromwire_u16(&cursor, &plen) != WIRE_GOSSIPD_GOT_ONIONMSG_TO_US)
return false;
if (!fromwire_bool(&cursor, &plen))
*blinding_in = NULL;
else {
*blinding_in = tal(ctx, struct pubkey);
fromwire_pubkey(&cursor, &plen, *blinding_in);
}
if (!fromwire_bool(&cursor, &plen))
*reply_blinding = NULL;
else {
*reply_blinding = tal(ctx, struct pubkey);
fromwire_pubkey(&cursor, &plen, *reply_blinding);
}
reply_path_len = fromwire_u16(&cursor, &plen);
// 2nd case reply_path
*reply_path = reply_path_len ? tal_arr(ctx, struct onionmsg_path *, reply_path_len) : NULL;
for (size_t i = 0; i < reply_path_len; i++)
(*reply_path)[i] = fromwire_onionmsg_path(*reply_path, &cursor, &plen);
rawmsg_len = fromwire_u16(&cursor, &plen);
// 2nd case rawmsg
*rawmsg = rawmsg_len ? tal_arr(ctx, u8, rawmsg_len) : NULL;
fromwire_u8_array(&cursor, &plen, *rawmsg, rawmsg_len);
return cursor != NULL;
}
/* WIRE: GOSSIPD_GOT_ONIONMSG_FORWARD */
u8 *towire_gossipd_got_onionmsg_forward(const tal_t *ctx, const struct short_channel_id *next_scid, const struct node_id *next_node_id, const struct pubkey *next_blinding, const u8 next_onion[1366])
{
u8 *p = tal_arr(ctx, u8, 0);
towire_u16(&p, WIRE_GOSSIPD_GOT_ONIONMSG_FORWARD);
if (!next_scid)
towire_bool(&p, false);
else {
towire_bool(&p, true);
towire_short_channel_id(&p, next_scid);
}
if (!next_node_id)
towire_bool(&p, false);
else {
towire_bool(&p, true);
towire_node_id(&p, next_node_id);
}
if (!next_blinding)
towire_bool(&p, false);
else {
towire_bool(&p, true);
towire_pubkey(&p, next_blinding);
}
towire_u8_array(&p, next_onion, 1366);
return memcheck(p, tal_count(p));
}
bool fromwire_gossipd_got_onionmsg_forward(const tal_t *ctx, const void *p, struct short_channel_id **next_scid, struct node_id **next_node_id, struct pubkey **next_blinding, u8 next_onion[1366])
{
const u8 *cursor = p;
size_t plen = tal_count(p);
if (fromwire_u16(&cursor, &plen) != WIRE_GOSSIPD_GOT_ONIONMSG_FORWARD)
return false;
if (!fromwire_bool(&cursor, &plen))
*next_scid = NULL;
else {
*next_scid = tal(ctx, struct short_channel_id);
fromwire_short_channel_id(&cursor, &plen, *next_scid);
}
if (!fromwire_bool(&cursor, &plen))
*next_node_id = NULL;
else {
*next_node_id = tal(ctx, struct node_id);
fromwire_node_id(&cursor, &plen, *next_node_id);
}
if (!fromwire_bool(&cursor, &plen))
*next_blinding = NULL;
else {
*next_blinding = tal(ctx, struct pubkey);
fromwire_pubkey(&cursor, &plen, *next_blinding);
}
fromwire_u8_array(&cursor, &plen, next_onion, 1366);
return cursor != NULL;
}
/* WIRE: GOSSIPD_SEND_ONIONMSG */
/* Lightningd tells us to send a onion message. */
u8 *towire_gossipd_send_onionmsg(const tal_t *ctx, const struct node_id *id, const u8 onion[1366], const struct pubkey *blinding)
{
u8 *p = tal_arr(ctx, u8, 0);
towire_u16(&p, WIRE_GOSSIPD_SEND_ONIONMSG);
towire_node_id(&p, id);
towire_u8_array(&p, onion, 1366);
if (!blinding)
towire_bool(&p, false);
else {
towire_bool(&p, true);
towire_pubkey(&p, blinding);
}
return memcheck(p, tal_count(p));
}
bool fromwire_gossipd_send_onionmsg(const tal_t *ctx, const void *p, struct node_id *id, u8 onion[1366], struct pubkey **blinding)
{
const u8 *cursor = p;
size_t plen = tal_count(p);
if (fromwire_u16(&cursor, &plen) != WIRE_GOSSIPD_SEND_ONIONMSG)
return false;
fromwire_node_id(&cursor, &plen, id);
fromwire_u8_array(&cursor, &plen, onion, 1366);
if (!fromwire_bool(&cursor, &plen))
*blinding = NULL;
else {
*blinding = tal(ctx, struct pubkey);
fromwire_pubkey(&cursor, &plen, *blinding);
}
return cursor != NULL;
}
// SHA256STAMP:45335ac4c553938ed7c2d63344d80465eca1ff70ab8ec750e3d0305f81acdad5

21
gossipd/gossipd_wiregen.h

@ -60,6 +60,11 @@ enum gossipd_wire {
WIRE_GOSSIPD_GET_INCOMING_CHANNELS_REPLY = 3125, WIRE_GOSSIPD_GET_INCOMING_CHANNELS_REPLY = 3125,
/* master -> gossipd: blockheight increased. */ /* master -> gossipd: blockheight increased. */
WIRE_GOSSIPD_NEW_BLOCKHEIGHT = 3026, WIRE_GOSSIPD_NEW_BLOCKHEIGHT = 3026,
/* Tell lightningd we got a onion message (for us */
WIRE_GOSSIPD_GOT_ONIONMSG_TO_US = 3142,
WIRE_GOSSIPD_GOT_ONIONMSG_FORWARD = 3143,
/* Lightningd tells us to send a onion message. */
WIRE_GOSSIPD_SEND_ONIONMSG = 3040,
}; };
const char *gossipd_wire_name(int e); const char *gossipd_wire_name(int e);
@ -197,6 +202,20 @@ bool fromwire_gossipd_get_incoming_channels_reply(const tal_t *ctx, const void *
u8 *towire_gossipd_new_blockheight(const tal_t *ctx, u32 blockheight); u8 *towire_gossipd_new_blockheight(const tal_t *ctx, u32 blockheight);
bool fromwire_gossipd_new_blockheight(const void *p, u32 *blockheight); bool fromwire_gossipd_new_blockheight(const void *p, u32 *blockheight);
/* WIRE: GOSSIPD_GOT_ONIONMSG_TO_US */
/* Tell lightningd we got a onion message (for us */
u8 *towire_gossipd_got_onionmsg_to_us(const tal_t *ctx, const struct pubkey *blinding_in, const struct pubkey *reply_blinding, const struct onionmsg_path **reply_path, const u8 *rawmsg);
bool fromwire_gossipd_got_onionmsg_to_us(const tal_t *ctx, const void *p, struct pubkey **blinding_in, struct pubkey **reply_blinding, struct onionmsg_path ***reply_path, u8 **rawmsg);
/* WIRE: GOSSIPD_GOT_ONIONMSG_FORWARD */
u8 *towire_gossipd_got_onionmsg_forward(const tal_t *ctx, const struct short_channel_id *next_scid, const struct node_id *next_node_id, const struct pubkey *next_blinding, const u8 next_onion[1366]);
bool fromwire_gossipd_got_onionmsg_forward(const tal_t *ctx, const void *p, struct short_channel_id **next_scid, struct node_id **next_node_id, struct pubkey **next_blinding, u8 next_onion[1366]);
/* WIRE: GOSSIPD_SEND_ONIONMSG */
/* Lightningd tells us to send a onion message. */
u8 *towire_gossipd_send_onionmsg(const tal_t *ctx, const struct node_id *id, const u8 onion[1366], const struct pubkey *blinding);
bool fromwire_gossipd_send_onionmsg(const tal_t *ctx, const void *p, struct node_id *id, u8 onion[1366], struct pubkey **blinding);
#endif /* LIGHTNING_GOSSIPD_GOSSIPD_WIREGEN_H */ #endif /* LIGHTNING_GOSSIPD_GOSSIPD_WIREGEN_H */
// SHA256STAMP:ae8bf4f19cc3dd086b9a20b8bc034d93d8ef066e901279de09fe2fd189f1344b // SHA256STAMP:45335ac4c553938ed7c2d63344d80465eca1ff70ab8ec750e3d0305f81acdad5

12
lightningd/channel.c

@ -355,13 +355,21 @@ struct channel *active_channel_by_id(struct lightningd *ld,
struct channel *active_channel_by_scid(struct lightningd *ld, struct channel *active_channel_by_scid(struct lightningd *ld,
const struct short_channel_id *scid) const struct short_channel_id *scid)
{
struct channel *chan = any_channel_by_scid(ld, scid);
if (chan && !channel_active(chan))
chan = NULL;
return chan;
}
struct channel *any_channel_by_scid(struct lightningd *ld,
const struct short_channel_id *scid)
{ {
struct peer *p; struct peer *p;
struct channel *chan; struct channel *chan;
list_for_each(&ld->peers, p, list) { list_for_each(&ld->peers, p, list) {
list_for_each(&p->channels, chan, list) { list_for_each(&p->channels, chan, list) {
if (channel_active(chan) if (chan->scid
&& chan->scid
&& short_channel_id_eq(scid, chan->scid)) && short_channel_id_eq(scid, chan->scid))
return chan; return chan;
} }

2
lightningd/channel.h

@ -263,6 +263,8 @@ struct channel *channel_by_dbid(struct lightningd *ld, const u64 dbid);
struct channel *active_channel_by_scid(struct lightningd *ld, struct channel *active_channel_by_scid(struct lightningd *ld,
const struct short_channel_id *scid); const struct short_channel_id *scid);
struct channel *any_channel_by_scid(struct lightningd *ld,
const struct short_channel_id *scid);
/* Get channel by channel_id, optionally returning uncommitted_channel. */ /* Get channel by channel_id, optionally returning uncommitted_channel. */
struct channel *channel_by_cid(struct lightningd *ld, struct channel *channel_by_cid(struct lightningd *ld,

13
lightningd/channel_control.c

@ -26,7 +26,6 @@
#include <lightningd/lightningd.h> #include <lightningd/lightningd.h>
#include <lightningd/log.h> #include <lightningd/log.h>
#include <lightningd/notification.h> #include <lightningd/notification.h>
#include <lightningd/onion_message.h>
#include <lightningd/peer_control.h> #include <lightningd/peer_control.h>
#include <lightningd/subd.h> #include <lightningd/subd.h>
#include <wire/common_wiregen.h> #include <wire/common_wiregen.h>
@ -522,17 +521,6 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds)
case WIRE_CHANNELD_SEND_ERROR_REPLY: case WIRE_CHANNELD_SEND_ERROR_REPLY:
handle_error_channel(sd->channel, msg); handle_error_channel(sd->channel, msg);
break; break;
#if EXPERIMENTAL_FEATURES
case WIRE_GOT_ONIONMSG_TO_US:
handle_onionmsg_to_us(sd->channel, msg);
break;
case WIRE_GOT_ONIONMSG_FORWARD:
handle_onionmsg_forward(sd->channel, msg);
break;
#else
case WIRE_GOT_ONIONMSG_TO_US:
case WIRE_GOT_ONIONMSG_FORWARD:
#endif
/* And we never get these from channeld. */ /* And we never get these from channeld. */
case WIRE_CHANNELD_INIT: case WIRE_CHANNELD_INIT:
case WIRE_CHANNELD_SEND_TX_SIGS: case WIRE_CHANNELD_SEND_TX_SIGS:
@ -548,7 +536,6 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds)
case WIRE_CHANNELD_FEERATES: case WIRE_CHANNELD_FEERATES:
case WIRE_CHANNELD_SPECIFIC_FEERATES: case WIRE_CHANNELD_SPECIFIC_FEERATES:
case WIRE_CHANNELD_DEV_MEMLEAK: case WIRE_CHANNELD_DEV_MEMLEAK:
case WIRE_SEND_ONIONMSG:
/* Replies go to requests. */ /* Replies go to requests. */
case WIRE_CHANNELD_OFFER_HTLC_REPLY: case WIRE_CHANNELD_OFFER_HTLC_REPLY:
case WIRE_CHANNELD_DEV_REENABLE_COMMIT_REPLY: case WIRE_CHANNELD_DEV_REENABLE_COMMIT_REPLY:

16
lightningd/gossip_control.c

@ -29,6 +29,7 @@
#include <lightningd/json.h> #include <lightningd/json.h>
#include <lightningd/jsonrpc.h> #include <lightningd/jsonrpc.h>
#include <lightningd/log.h> #include <lightningd/log.h>
#include <lightningd/onion_message.h>
#include <lightningd/options.h> #include <lightningd/options.h>
#include <lightningd/ping.h> #include <lightningd/ping.h>
#include <sodium/randombytes.h> #include <sodium/randombytes.h>
@ -149,6 +150,7 @@ 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:
/* This is a reply, so never gets through to here. */ /* This is a reply, so never gets through to here. */
case WIRE_GOSSIPD_GETNODES_REPLY: case WIRE_GOSSIPD_GETNODES_REPLY:
case WIRE_GOSSIPD_GETROUTE_REPLY: case WIRE_GOSSIPD_GETROUTE_REPLY:
@ -159,6 +161,18 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds)
case WIRE_GOSSIPD_GET_STRIPPED_CUPDATE_REPLY: case WIRE_GOSSIPD_GET_STRIPPED_CUPDATE_REPLY:
break; break;
#if EXPERIMENTAL_FEATURES
case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US:
handle_onionmsg_to_us(gossip->ld, msg);
break;
case WIRE_GOSSIPD_GOT_ONIONMSG_FORWARD:
handle_onionmsg_forward(gossip->ld, msg);
break;
#else
case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US:
case WIRE_GOSSIPD_GOT_ONIONMSG_FORWARD:
break;
#endif
case WIRE_GOSSIPD_PING_REPLY: case WIRE_GOSSIPD_PING_REPLY:
ping_reply(gossip, msg); ping_reply(gossip, msg);
break; break;
@ -193,7 +207,7 @@ void gossip_init(struct lightningd *ld, int connectd_fd)
u8 *msg; u8 *msg;
int hsmfd; int hsmfd;
hsmfd = hsm_get_global_fd(ld, HSM_CAP_SIGN_GOSSIP); hsmfd = hsm_get_global_fd(ld, HSM_CAP_ECDH|HSM_CAP_SIGN_GOSSIP);
ld->gossip = new_global_subd(ld, "lightning_gossipd", ld->gossip = new_global_subd(ld, "lightning_gossipd",
gossipd_wire_name, gossip_msg, gossipd_wire_name, gossip_msg,

101
lightningd/onion_message.c

@ -1,6 +1,5 @@
#include <channeld/channeld_wiregen.h>
#include <common/json_helpers.h> #include <common/json_helpers.h>
#include <lightningd/channel.h> #include <gossipd/gossipd_wiregen.h>
#include <lightningd/lightningd.h> #include <lightningd/lightningd.h>
#include <lightningd/onion_message.h> #include <lightningd/onion_message.h>
#include <lightningd/peer_control.h> #include <lightningd/peer_control.h>
@ -88,40 +87,8 @@ REGISTER_PLUGIN_HOOK(onion_message_blinded,
onion_message_serialize, onion_message_serialize,
struct onion_message_hook_payload *); struct onion_message_hook_payload *);
/* Returns false if we can't tell it */ void handle_onionmsg_to_us(struct lightningd *ld, const u8 *msg)
static bool make_peer_send(struct lightningd *ld,
struct channel *dst, const u8 *msg TAKES)
{ {
/* Take ownership of msg (noop if it's taken) */
msg = tal_dup_talarr(tmpctx, u8, msg);
if (!dst) {
log_debug(ld->log, "Can't send %s: no channel",
channeld_wire_name(fromwire_peektype(msg)));
return false;
}
if (!dst->owner) {
log_debug(ld->log, "Can't send %s: not connected",
channeld_wire_name(fromwire_peektype(msg)));
return false;
}
/* FIXME: We should allow this for closingd too, and we should
* allow incoming via openingd!. */
if (!streq(dst->owner->name, "channeld")) {
log_debug(ld->log, "Can't send %s: owned by %s",
channeld_wire_name(fromwire_peektype(msg)),
dst->owner->name);
return false;
}
subd_send_msg(dst->owner, take(msg));
return true;
}
void handle_onionmsg_to_us(struct channel *channel, const u8 *msg)
{
struct lightningd *ld = channel->peer->ld;
struct onion_message_hook_payload *payload; struct onion_message_hook_payload *payload;
u8 *submsg; u8 *submsg;
size_t submsglen; size_t submsglen;
@ -129,30 +96,30 @@ void handle_onionmsg_to_us(struct channel *channel, const u8 *msg)
payload = tal(ld, struct onion_message_hook_payload); payload = tal(ld, struct onion_message_hook_payload);
payload->om = tlv_onionmsg_payload_new(payload); payload->om = tlv_onionmsg_payload_new(payload);
if (!fromwire_got_onionmsg_to_us(payload, msg, if (!fromwire_gossipd_got_onionmsg_to_us(payload, msg,
&payload->blinding_in, &payload->blinding_in,
&payload->reply_blinding, &payload->reply_blinding,
&payload->reply_path, &payload->reply_path,
&submsg)) { &submsg)) {
channel_internal_error(channel, "bad got_onionmsg_tous: %s", log_broken(ld->log, "bad got_onionmsg_tous: %s",
tal_hex(tmpctx, msg)); tal_hex(tmpctx, msg));
return; return;
} }
submsglen = tal_bytelen(submsg); submsglen = tal_bytelen(submsg);
if (!fromwire_onionmsg_payload(cast_const2(const u8 **, &submsg), if (!fromwire_onionmsg_payload(cast_const2(const u8 **, &submsg),
&submsglen, payload->om)) { &submsglen, payload->om)) {
channel_internal_error(channel, "bad got_onionmsg_tous om: %s", log_broken(ld->log, "bad got_onionmsg_tous om: %s",
tal_hex(tmpctx, msg)); tal_hex(tmpctx, msg));
return; return;
} }
if (payload->reply_path && !payload->reply_blinding) { if (payload->reply_path && !payload->reply_blinding) {
log_broken(channel->log, log_broken(ld->log,
"No reply blinding, ignoring reply path"); "No reply blinding, ignoring reply path");
payload->reply_path = tal_free(payload->reply_path); payload->reply_path = tal_free(payload->reply_path);
} }
log_debug(channel->log, "Got onionmsg%s%s", log_debug(ld->log, "Got onionmsg%s%s",
payload->reply_blinding ? " reply_blinding": "", payload->reply_blinding ? " reply_blinding": "",
payload->reply_path ? " reply_path": ""); payload->reply_path ? " reply_path": "");
@ -162,35 +129,40 @@ void handle_onionmsg_to_us(struct channel *channel, const u8 *msg)
plugin_hook_call_onion_message(ld, payload); plugin_hook_call_onion_message(ld, payload);
} }
void handle_onionmsg_forward(struct channel *channel, const u8 *msg) void handle_onionmsg_forward(struct lightningd *ld, const u8 *msg)
{ {
struct lightningd *ld = channel->peer->ld;
struct short_channel_id *next_scid; struct short_channel_id *next_scid;
struct node_id *next_node; struct node_id *next_node;
struct pubkey *next_blinding; struct pubkey *next_blinding;
u8 onion[TOTAL_PACKET_SIZE(ROUTING_INFO_SIZE)]; u8 onion[TOTAL_PACKET_SIZE(ROUTING_INFO_SIZE)];
struct channel *outchan;
if (!fromwire_got_onionmsg_forward(msg, msg, &next_scid, &next_node, if (!fromwire_gossipd_got_onionmsg_forward(msg, msg, &next_scid,
&next_node,
&next_blinding, onion)) { &next_blinding, onion)) {
channel_internal_error(channel, "bad got_onionmsg_forward: %s", log_broken(ld->log, "bad got_onionmsg_forward: %s",
tal_hex(tmpctx, msg)); tal_hex(tmpctx, msg));
return; return;
} }
if (next_scid) if (next_scid) {
outchan = active_channel_by_scid(ld, next_scid); struct channel *outchan = any_channel_by_scid(ld, next_scid);
else if (next_node) { if (outchan)
struct peer *p = peer_by_id(ld, next_node); next_node = &outchan->peer->id;
if (p) }
outchan = peer_active_channel(p);
else
outchan = NULL;
} else
outchan = NULL;
make_peer_send(ld, outchan, if (!next_node) {
take(towire_send_onionmsg(NULL, onion, next_blinding))); log_debug(ld->log, "Cannot forward onionmsg to %s",
next_scid ? type_to_string(tmpctx,
struct short_channel_id,
next_scid)
: "unspecified dest");
} else {
subd_send_msg(ld->gossip,
take(towire_gossipd_send_onionmsg(NULL,
next_node,
onion,
next_blinding)));
}
} }
struct hop { struct hop {
@ -421,7 +393,6 @@ static struct command_result *json_send_onion_message(struct command *cmd,
struct sphinx_path *sphinx_path; struct sphinx_path *sphinx_path;
struct onionpacket *op; struct onionpacket *op;
struct secret *path_secrets; struct secret *path_secrets;
struct channel *first_hop;
struct node_id first_id; struct node_id first_id;
if (!param(cmd, buffer, params, if (!param(cmd, buffer, params,
@ -430,10 +401,11 @@ static struct command_result *json_send_onion_message(struct command *cmd,
NULL)) NULL))
return command_param_failed(); return command_param_failed();
/* FIXME: Allow sending to non-channel peers! */
node_id_from_pubkey(&first_id, &hops[0].id); node_id_from_pubkey(&first_id, &hops[0].id);
first_hop = active_channel_by_id(cmd->ld, &first_id, NULL);
if (!first_hop) /* Sanity check first; gossipd doesn't bother telling us if peer
* can't be reached. */
if (!peer_by_id(cmd->ld, &first_id))
return command_fail(cmd, LIGHTNINGD, "Unknown first peer"); return command_fail(cmd, LIGHTNINGD, "Unknown first peer");
/* Create an onion which encodes this. */ /* Create an onion which encodes this. */
@ -452,11 +424,10 @@ static struct command_result *json_send_onion_message(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?)");
if (!make_peer_send(cmd->ld, first_hop, subd_send_msg(cmd->ld->gossip,
take(towire_send_onionmsg(NULL, take(towire_gossipd_send_onionmsg(NULL, &first_id,
serialize_onionpacket(tmpctx, op), serialize_onionpacket(tmpctx, op),
NULL)))) NULL)));
return command_fail(cmd, LIGHTNINGD, "First peer not ready");
return command_success(cmd, json_stream_success(cmd)); return command_success(cmd, json_stream_success(cmd));
} }

6
lightningd/onion_message.h

@ -3,9 +3,9 @@
#include "config.h" #include "config.h"
#include <ccan/short_types/short_types.h> #include <ccan/short_types/short_types.h>
struct channel; struct lightningd;
void handle_onionmsg_to_us(struct channel *channel, const u8 *msg); void handle_onionmsg_to_us(struct lightningd *ld, const u8 *msg);
void handle_onionmsg_forward(struct channel *channel, const u8 *msg); void handle_onionmsg_forward(struct lightningd *ld, const u8 *msg);
#endif /* LIGHTNING_LIGHTNINGD_ONION_MESSAGE_H */ #endif /* LIGHTNING_LIGHTNINGD_ONION_MESSAGE_H */

4
wire/peer_wire.c

@ -62,6 +62,9 @@ bool is_msg_for_gossipd(const u8 *cursor)
case WIRE_REPLY_CHANNEL_RANGE: case WIRE_REPLY_CHANNEL_RANGE:
case WIRE_PING: case WIRE_PING:
case WIRE_PONG: case WIRE_PONG:
#if EXPERIMENTAL_FEATURES
case WIRE_ONION_MESSAGE:
#endif
return true; return true;
case WIRE_INIT: case WIRE_INIT:
case WIRE_ERROR: case WIRE_ERROR:
@ -83,7 +86,6 @@ bool is_msg_for_gossipd(const u8 *cursor)
case WIRE_ANNOUNCEMENT_SIGNATURES: case WIRE_ANNOUNCEMENT_SIGNATURES:
case WIRE_GOSSIP_TIMESTAMP_FILTER: case WIRE_GOSSIP_TIMESTAMP_FILTER:
#if EXPERIMENTAL_FEATURES #if EXPERIMENTAL_FEATURES
case WIRE_ONION_MESSAGE:
case WIRE_TX_ADD_INPUT: case WIRE_TX_ADD_INPUT:
case WIRE_TX_REMOVE_INPUT: case WIRE_TX_REMOVE_INPUT:
case WIRE_TX_ADD_OUTPUT: case WIRE_TX_ADD_OUTPUT:

Loading…
Cancel
Save