Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 52 additions & 3 deletions channeld/channeld.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
#include <inttypes.h>
#include <secp256k1.h>
#include <stdio.h>
#include <wire/gen_common_wire.h>
#include <wire/gen_onion_wire.h>
#include <wire/peer_wire.h>
#include <wire/wire.h>
Expand Down Expand Up @@ -1817,6 +1818,27 @@ static void handle_peer_shutdown(struct peer *peer, const u8 *shutdown)
billboard_update(peer);
}

/* Try to handle a custommsg Returns true if it was a custom message and has
* been handled, false if the message was not handled.
*/
static bool channeld_handle_custommsg(const u8 *msg)
{
#if DEVELOPER
enum wire_type type = fromwire_peektype(msg);
if (type % 2 == 1 && !wire_type_is_defined(type)) {
/* The message is not part of the messages we know how to
* handle. Assuming this is a custommsg, we just forward it to the
* master. */
wire_sync_write(MASTER_FD, take(towire_custommsg_in(NULL, msg)));
return true;
} else {
return false;
}
#else
return false;
#endif
}

static void peer_in(struct peer *peer, const u8 *msg)
{
enum wire_type type = fromwire_peektype(msg);
Expand All @@ -1829,6 +1851,9 @@ static void peer_in(struct peer *peer, const u8 *msg)
return;
}

if (channeld_handle_custommsg(msg))
return;

/* Since LND seems to send errors which aren't actually fatal events,
* we treat errors here as soft. */
if (handle_peer_gossip_or_error(peer->pps, &peer->channel_id, true, msg))
Expand Down Expand Up @@ -2329,9 +2354,10 @@ static void peer_reconnect(struct peer *peer,
do {
clean_tmpctx();
msg = sync_crypto_read(tmpctx, peer->pps);
} while (handle_peer_gossip_or_error(peer->pps, &peer->channel_id, true,
msg)
|| capture_premature_msg(&premature_msgs, msg));
} while (channeld_handle_custommsg(msg) ||
handle_peer_gossip_or_error(peer->pps, &peer->channel_id, true,
msg) ||
capture_premature_msg(&premature_msgs, msg));

if (peer->channel->option_static_remotekey) {
struct pubkey ignore;
Expand Down Expand Up @@ -2851,6 +2877,14 @@ static void handle_dev_memleak(struct peer *peer, const u8 *msg)
take(towire_channel_dev_memleak_reply(NULL,
found_leak)));
}

/* We were told to send a custommsg to the peer by `lightningd`. All the
* verification is done on the side of `lightningd` so we should be good to
* just forward it here. */
static void channeld_send_custommsg(struct peer *peer, const u8 *msg)
{
sync_crypto_write(peer->pps, take(msg));
}
#endif /* DEVELOPER */

static void req_in(struct peer *peer, const u8 *msg)
Expand Down Expand Up @@ -2911,6 +2945,21 @@ static void req_in(struct peer *peer, const u8 *msg)
case WIRE_CHANNEL_SEND_ERROR_REPLY:
break;
}

/* Now handle common messages. */
switch ((enum common_wire_type)t) {
#if DEVELOPER
case WIRE_CUSTOMMSG_OUT:
channeld_send_custommsg(peer, msg);
return;
#else
case WIRE_CUSTOMMSG_OUT:
#endif
/* We send these. */
case WIRE_CUSTOMMSG_IN:
break;
}

master_badmsg(-1, msg);
}

Expand Down
7 changes: 7 additions & 0 deletions common/read_peer_msg.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <assert.h>
#include <ccan/fdpass/fdpass.h>
#include <common/crypto_sync.h>
#include <common/gossip_rcvd_filter.h>
Expand Down Expand Up @@ -155,6 +156,11 @@ bool handle_peer_gossip_or_error(struct per_peer_state *pps,
bool all_channels;
struct channel_id actual;

#if DEVELOPER
/* Any odd-typed unknown message is handled by the caller, so if we
* find one here it's an error. */
assert(!is_unknown_msg_discardable(msg));
#else
/* BOLT #1:
*
* A receiving node:
Expand All @@ -163,6 +169,7 @@ bool handle_peer_gossip_or_error(struct per_peer_state *pps,
*/
if (is_unknown_msg_discardable(msg))
goto handled;
#endif

if (handle_timestamp_filter(pps, msg))
return true;
Expand Down
1 change: 1 addition & 0 deletions doc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ MANPAGES := doc/lightning-cli.1 \
doc/lightning-decodepay.7 \
doc/lightning-delexpiredinvoice.7 \
doc/lightning-delinvoice.7 \
doc/lightning-dev-sendcustommsg.7 \
doc/lightning-disconnect.7 \
doc/lightning-fundchannel.7 \
doc/lightning-fundchannel_start.7 \
Expand Down
35 changes: 35 additions & 0 deletions doc/PLUGINS.md
Original file line number Diff line number Diff line change
Expand Up @@ -760,8 +760,43 @@ Return a custom error to the request sender:
}
```


#### `custommsg`

The `custommsg` plugin hook is the receiving counterpart to the
[`dev-sendcustommsg`][sendcustommsg] RPC method and allows plugins to handle
messages that are not handled internally. The goal of these two components is
to allow the implementation of custom protocols or prototypes on top of a
c-lightning node, without having to change the node's implementation itself.

The payload for a call follows this format:

```json
{
"peer_id": "02df5ffe895c778e10f7742a6c5b8a0cefbe9465df58b92fadeb883752c8107c8f",
"message": "1337ffffffff"
}
```

This payload would have been sent by the peer with the `node_id` matching
`peer_id`, and the message has type `0x1337` and contents `ffffffff`. Notice
that the messages are currently limited to odd-numbered types and must not
match a type that is handled internally by c-lightning. These limitations are
in place in order to avoid conflicts with the internal state tracking, and
avoiding disconnections or channel closures, since odd-numbered message can be
ignored by nodes (see ["it's ok to be odd" in the specification][oddok] for
details). The plugin must implement the parsing of the message, including the
type prefix, since c-lightning does not know how to parse the message.

The result for this hook is currently being discarded. For future uses of the
result we suggest just returning a `null`. This will ensure backward
compatibility should the semantics be changed in future.


[jsonrpc-spec]: https://www.jsonrpc.org/specification
[jsonrpc-notification-spec]: https://www.jsonrpc.org/specification#notification
[bolt4]: https://github.com/lightningnetwork/lightning-rfc/blob/master/04-onion-routing.md
[bolt4-failure-codes]: https://github.com/lightningnetwork/lightning-rfc/blob/master/04-onion-routing.md#failure-messages
[bolt2-open-channel]: https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md#the-open_channel-message
[sendcustommsg]: lightning-dev-sendcustommsg.7.html
[oddok]: https://github.com/lightningnetwork/lightning-rfc/blob/master/00-introduction.md#its-ok-to-be-odd
1 change: 1 addition & 0 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ c-lightning Documentation
lightning-decodepay <lightning-decodepay.7.md>
lightning-delexpiredinvoice <lightning-delexpiredinvoice.7.md>
lightning-delinvoice <lightning-delinvoice.7.md>
lightning-dev-sendcustommsg <lightning-dev-sendcustommsg.7.md>
lightning-disconnect <lightning-disconnect.7.md>
lightning-fundchannel <lightning-fundchannel.7.md>
lightning-fundchannel_cancel <lightning-fundchannel_cancel.7.md>
Expand Down
Empty file.
63 changes: 63 additions & 0 deletions doc/lightning-dev-sendcustommsg.7.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
lightning-dev-sendcustommsg -- Low-level interface to send protocol messages to peers
=====================================================================================

SYNOPSIS
--------

**dev-sendcustommsg** *node_id* *msg*

DESCRIPTION
-----------

The `dev-sendcustommsg` RPC method allows the user to inject a custom message
into the communication with the peer with the given `node_id`. This is
intended as a low-level interface to implement custom protocol extensions on
top, not for direct use by end-users.

The message must be a hex encoded well-formed message, including the 2-byte
type prefix, but excluding the length prefix which will be added by the RPC
method. The messages must not use even-numbered types, since these may require
synchronous handling on the receiving side, and can cause the connection to be
dropped. The message types may also not use one of the internally handled
types, since that may cause issues with the internal state tracking of
c-lightning.

The node specified by `node_id` must be a peer, i.e., it must have a direct
connection with the node receiving the RPC call, and the connection must be
established. For a method to send arbitrary messages over multiple hops,
including hops that do not understand the custom message, see the
`createonion` and `sendonion` RPC methods. Messages can only be injected if
the connection is handled by `openingd` or `channeld`. Messages cannot be
injected when the peer is handled by `onchaind` or `closingd` since these do
not have a connection, or are synchronous daemons that do not handle
spontaneous messages.

On the reveiving end a plugin may implement the `custommsg` plugin hook and
get notified about incoming messages.

RETURN VALUE
------------

The method will validate the arguments and queue the message for delivery
through the daemon that is currently handling the connection. Queuing provides
best effort guarantees and the message may not be delivered if the connection
is terminated while the message is queued. The RPC method will return as soon
as the message is queued.

If any of the above limitations is not respected the method returns an
explicit error message stating the issue.

AUTHOR
------

Christian Decker <<decker.christian@gmail.com>> is mainly responsible.

SEE ALSO
--------

lightning-createonion(7), lightning-sendonion(7)

RESOURCES
---------

Main web site: <https://github.com/ElementsProject/lightning>
14 changes: 14 additions & 0 deletions lightningd/channel_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <lightningd/log.h>
#include <lightningd/peer_control.h>
#include <lightningd/subd.h>
#include <wire/gen_common_wire.h>
#include <wire/wire_sync.h>

static void update_feerates(struct lightningd *ld, struct channel *channel)
Expand Down Expand Up @@ -319,6 +320,19 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds)
break;
}

switch ((enum common_wire_type)t) {
#if DEVELOPER
case WIRE_CUSTOMMSG_IN:
handle_custommsg_in(sd->ld, sd->node_id, msg);
break;
#else
case WIRE_CUSTOMMSG_IN:
#endif
/* We send these. */
case WIRE_CUSTOMMSG_OUT:
break;
}

return 0;
}

Expand Down
29 changes: 28 additions & 1 deletion lightningd/opening_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@
#include <lightningd/notification.h>
#include <lightningd/opening_control.h>
#include <lightningd/options.h>
#include <lightningd/peer_control.h>
#include <lightningd/plugin_hook.h>
#include <lightningd/subd.h>
#include <openingd/gen_opening_wire.h>
#include <wire/gen_common_wire.h>
#include <wire/wire.h>
#include <wire/wire_sync.h>

Expand Down Expand Up @@ -922,6 +922,20 @@ static unsigned int openingd_msg(struct subd *openingd,
case WIRE_OPENING_DEV_MEMLEAK_REPLY:
break;
}

switch ((enum common_wire_type)t) {
#if DEVELOPER
case WIRE_CUSTOMMSG_IN:
handle_custommsg_in(openingd->ld, openingd->node_id, msg);
return 0;
#else
case WIRE_CUSTOMMSG_IN:
#endif
/* We send these. */
case WIRE_CUSTOMMSG_OUT:
break;
}

log_broken(openingd->log, "Unexpected msg %s: %s",
opening_wire_type_name(t), tal_hex(tmpctx, msg));
tal_free(openingd);
Expand Down Expand Up @@ -1323,3 +1337,16 @@ void opening_dev_memleak(struct command *cmd)
opening_memleak_req_next(cmd, NULL);
}
#endif /* DEVELOPER */

struct subd *peer_get_owning_subd(struct peer *peer)
{
struct channel *channel;
channel = peer_active_channel(peer);

if (channel != NULL) {
return channel->owner;
} else if (peer->uncommitted_channel != NULL) {
return peer->uncommitted_channel->openingd;
}
return NULL;
}
3 changes: 3 additions & 0 deletions lightningd/opening_control.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define LIGHTNING_LIGHTNINGD_OPENING_CONTROL_H
#include "config.h"
#include <ccan/short_types/short_types.h>
#include <lightningd/peer_control.h>

struct channel_id;
struct crypto_state;
Expand All @@ -26,4 +27,6 @@ struct command;
void opening_dev_memleak(struct command *cmd);
#endif

struct subd *peer_get_owning_subd(struct peer *peer);

#endif /* LIGHTNING_LIGHTNINGD_OPENING_CONTROL_H */
Loading