From d5be8d26f2f6accb1b93d4ffa628960e801ecfac Mon Sep 17 00:00:00 2001 From: Rusty Russell <rusty@rustcorp.com.au> Date: Wed, 12 Apr 2017 09:10:10 -0700 Subject: [PATCH] lightningd/ping: ping support. A spec update brings ping support. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> --- lightningd/Makefile | 1 + lightningd/channel/channel.c | 21 ++++++++++++++ lightningd/gossip/gossip.c | 30 ++++++++++++++++++++ lightningd/ping.c | 53 ++++++++++++++++++++++++++++++++++++ lightningd/ping.h | 13 +++++++++ wire/gen_peer_wire_csv | 7 +++++ wire/peer_wire.c | 2 ++ 7 files changed, 127 insertions(+) create mode 100644 lightningd/ping.c create mode 100644 lightningd/ping.h diff --git a/lightningd/Makefile b/lightningd/Makefile index 2485ed108..dbc60da5e 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -51,6 +51,7 @@ LIGHTNINGD_LIB_SRC := \ lightningd/key_derive.c \ lightningd/msg_queue.c \ lightningd/peer_failed.c \ + lightningd/ping.c \ lightningd/status.c \ lightningd/utxo.c diff --git a/lightningd/channel/channel.c b/lightningd/channel/channel.c index 5365d99f6..5db314667 100644 --- a/lightningd/channel/channel.c +++ b/lightningd/channel/channel.c @@ -28,6 +28,7 @@ #include <lightningd/key_derive.h> #include <lightningd/msg_queue.h> #include <lightningd/peer_failed.h> +#include <lightningd/ping.h> #include <lightningd/status.h> #include <secp256k1.h> #include <signal.h> @@ -819,6 +820,20 @@ static void handle_peer_fail_htlc(struct peer *peer, const u8 *msg) abort(); } +static void handle_ping(struct peer *peer, const u8 *msg) +{ + u8 *pong; + + if (!check_ping_make_pong(peer, msg, &pong)) + peer_failed(io_conn_fd(peer->peer_conn), + &peer->pcs.cs, + &peer->channel_id, + WIRE_CHANNEL_PEER_BAD_MESSAGE, + "Bad ping"); + if (pong) + msg_enqueue(&peer->peer_out, take(pong)); +} + static struct io_plan *peer_in(struct io_conn *conn, struct peer *peer, u8 *msg) { enum wire_type type = fromwire_peektype(msg); @@ -868,6 +883,12 @@ static struct io_plan *peer_in(struct io_conn *conn, struct peer *peer, u8 *msg) case WIRE_UPDATE_FAIL_HTLC: handle_peer_fail_htlc(peer, msg); goto done; + case WIRE_PING: + handle_ping(peer, msg); + goto done; + + /* We don't send pings, so don't expect pongs. */ + case WIRE_PONG: case WIRE_INIT: case WIRE_ERROR: case WIRE_OPEN_CHANNEL: diff --git a/lightningd/gossip/gossip.c b/lightningd/gossip/gossip.c index 35168c68e..43d63985d 100644 --- a/lightningd/gossip/gossip.c +++ b/lightningd/gossip/gossip.c @@ -21,6 +21,7 @@ #include <lightningd/debug.h> #include <lightningd/gossip/gen_gossip_wire.h> #include <lightningd/gossip_msg.h> +#include <lightningd/ping.h> #include <lightningd/status.h> #include <secp256k1_ecdh.h> #include <sodium/randombytes.h> @@ -168,6 +169,20 @@ static void handle_gossip_msg(struct routing_state *rstate, u8 *msg) } } +static bool handle_ping(struct peer *peer, u8 *ping) +{ + u8 *pong; + + if (!check_ping_make_pong(peer, ping, &pong)) { + peer->error = "Bad ping"; + return false; + } + + if (pong) + msg_enqueue(&peer->peer_out, take(pong)); + return true; +} + static struct io_plan *peer_msgin(struct io_conn *conn, struct peer *peer, u8 *msg) { @@ -190,6 +205,21 @@ static struct io_plan *peer_msgin(struct io_conn *conn, peer->error = "Duplicate INIT message received"; return io_close(conn); + case WIRE_PING: + if (!handle_ping(peer, msg)) + return io_close(conn); + return peer_read_message(conn, &peer->pcs, peer_msgin); + + case WIRE_PONG: + /* BOLT #1: + * + * A node receiving a `pong` message MAY fail the channels if + * `byteslen` does not correspond to any `ping` + * `num_pong_bytes` value it has sent. + */ + peer->error = "Unexpected pong received"; + return io_close(conn); + case WIRE_OPEN_CHANNEL: case WIRE_ACCEPT_CHANNEL: case WIRE_FUNDING_CREATED: diff --git a/lightningd/ping.c b/lightningd/ping.c new file mode 100644 index 000000000..9a9e9ca8c --- /dev/null +++ b/lightningd/ping.c @@ -0,0 +1,53 @@ +#include <lightningd/ping.h> +#include <wire/gen_peer_wire.h> + +bool check_ping_make_pong(const tal_t *ctx, const u8 *ping, u8 **pong) +{ + u16 num_pong_bytes; + u8 *ignored; + + if (!fromwire_ping(ctx, ping, NULL, &num_pong_bytes, &ignored)) + return false; + tal_free(ignored); + + /* FIXME: */ + /* BOLT #1: + * + * A node receiving a `ping` message SHOULD fail the channels if it + * has received significantly in excess of one `ping` per 30 seconds, + */ + + /* BOLT #1: + * + * ... otherwise if `num_pong_bytes` is less than 65532 it MUST + * respond by sending a `pong` message with `byteslen` equal to + * `num_pong_bytes`, otherwise it MUST ignore the `ping`. + */ + if (num_pong_bytes < 65532) { + /* BOLT #1: + * + * A node sending `pong` or `ping` SHOULD set `ignored` to + * zeroes, but MUST NOT set `ignored` to sensitive data such + * as secrets, or portions of initialized memory. + */ + ignored = tal_arrz(ctx, u8, num_pong_bytes); + *pong = towire_pong(ctx, ignored); + tal_free(ignored); + } + return true; +} + +u8 *make_ping(const tal_t *ctx, u16 num_pong_bytes, u16 padlen) +{ + /* BOLT #1: + * + * A node sending `pong` or `ping` SHOULD set `ignored` to zeroes, but + * MUST NOT set `ignored` to sensitive data such as secrets, or + * portions of initialized memory. + */ + u8 *ping, *ignored = tal_arrz(ctx, u8, padlen); + + ping = towire_ping(ctx, num_pong_bytes, ignored); + tal_free(ignored); + return ping; +} diff --git a/lightningd/ping.h b/lightningd/ping.h new file mode 100644 index 000000000..92683493f --- /dev/null +++ b/lightningd/ping.h @@ -0,0 +1,13 @@ +#ifndef LIGHTNING_LIGHTNINGD_PING_H +#define LIGHTNING_LIGHTNINGD_PING_H +#include "config.h" +#include <ccan/short_types/short_types.h> +#include <ccan/tal/tal.h> + +/* Returns false on error, otherwise *pong set if reply needed. */ +bool check_ping_make_pong(const tal_t *ctx, const u8 *ping, u8 **pong); + +/* Make a ping packet requesting num_pong_bytes */ +u8 *make_ping(const tal_t *ctx, u16 num_pong_bytes, u16 padlen); + +#endif /* LIGHTNING_LIGHTNINGD_PING_H */ diff --git a/wire/gen_peer_wire_csv b/wire/gen_peer_wire_csv index 308fb526c..e31d8e545 100644 --- a/wire/gen_peer_wire_csv +++ b/wire/gen_peer_wire_csv @@ -7,6 +7,13 @@ error,17 error,0,channel-id,32 error,32,len,2 error,34,data,len +ping,18 +ping,0,num_pong_bytes,2 +ping,2,byteslen,2 +ping,4,ignored,byteslen +pong,19 +pong,0,byteslen,2 +pong,2,ignored,byteslen open_channel,32 open_channel,0,chain-hash,32 open_channel,32,temporary-channel-id,32 diff --git a/wire/peer_wire.c b/wire/peer_wire.c index 17a37e6cb..976fb8c3e 100644 --- a/wire/peer_wire.c +++ b/wire/peer_wire.c @@ -23,6 +23,8 @@ static bool unknown_type(enum wire_type t) case WIRE_CHANNEL_ANNOUNCEMENT: case WIRE_NODE_ANNOUNCEMENT: case WIRE_CHANNEL_UPDATE: + case WIRE_PING: + case WIRE_PONG: return false; } return true;