From 9b589fb5ba4277f201352faabdc4f6aad44fc663 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 11 Oct 2017 20:31:50 +1030 Subject: [PATCH] common/wire_error: helpers to create/parse WIRE_ERROR messages. Signed-off-by: Rusty Russell --- common/Makefile | 1 + common/wire_error.c | 93 +++++++++++++++++++++++++++++++++++++++++++++ common/wire_error.h | 50 ++++++++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 common/wire_error.c create mode 100644 common/wire_error.h diff --git a/common/Makefile b/common/Makefile index 07d701f00..9ea159cb8 100644 --- a/common/Makefile +++ b/common/Makefile @@ -32,6 +32,7 @@ COMMON_SRC := \ common/utils.c \ common/utxo.c \ common/version.c \ + common/wire_error.c \ common/withdraw_tx.c COMMON_HEADERS_NOGEN := $(COMMON_SRC:.c=.h) common/overflows.h common/htlc.h diff --git a/common/wire_error.c b/common/wire_error.c new file mode 100644 index 000000000..e0c1d21b6 --- /dev/null +++ b/common/wire_error.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include +#include +#include + +u8 *towire_errorfmtv(const tal_t *ctx, + const struct channel_id *channel, + const char *fmt, + va_list ap) +{ + /* BOLT #1: + * + * The channel is referred to by `channel_id` unless `channel_id` is + * zero (ie. all bytes zero), in which case it refers to all + * channels. */ + static const struct channel_id all_channels; + char *estr; + u8 *msg; + + estr = tal_vfmt(ctx, fmt, ap); + /* We need tal_len to work, so we use copy. */ + msg = towire_error(ctx, channel ? channel : &all_channels, + (u8 *)tal_dup_arr(estr, char, estr, strlen(estr), 0)); + tal_free(estr); + va_end(ap); + + return msg; +} + +u8 *towire_errorfmt(const tal_t *ctx, + const struct channel_id *channel, + const char *fmt, ...) +{ + va_list ap; + u8 *msg; + + va_start(ap, fmt); + msg = towire_errorfmtv(ctx, channel, fmt, ap); + va_end(ap); + + return msg; +} + +bool is_all_channels(const struct channel_id *channel_id) +{ + /* BOLT #1: + * + * A node receiving `error` MUST fail the channel referred to by the + * message, or if `channel_id` is zero, it MUST fail all channels and + * MUST close the connection. If no existing channel is referred to + * by the message, the receiver MUST ignore the message. + */ + return memeqzero(channel_id, sizeof(*channel_id)); +} + +char *sanitize_error(const tal_t *ctx, const u8 *errmsg, + struct channel_id *channel_id) +{ + struct channel_id dummy; + u8 *data; + size_t i; + + if (!channel_id) + channel_id = &dummy; + + if (!fromwire_error(ctx, errmsg, NULL, channel_id, &data)) + return tal_fmt(ctx, "Invalid ERROR message '%s'", + tal_hex(ctx, errmsg)); + + /* BOLT #1: + * + * A receiving node SHOULD only print out `data` verbatim if the + * string is composed solely of printable ASCII characters. For + * reference, the printable character set includes byte values 32 + * through 127 inclusive. + */ + for (i = 0; i < tal_len(data); i++) { + if (data[i] < 32 || data[i] > 127) { + /* Convert to hex, minus NUL term */ + data = (u8 *)tal_hex(ctx, data); + tal_resize(&data, tal_len(data)-1); + break; + } + } + + return tal_fmt(ctx, "channel %s: %.*s", + is_all_channels(channel_id) + ? "ALL" + : type_to_string(ctx, struct channel_id, channel_id), + (int)tal_len(data), (char *)data); +} diff --git a/common/wire_error.h b/common/wire_error.h new file mode 100644 index 000000000..78a4e388f --- /dev/null +++ b/common/wire_error.h @@ -0,0 +1,50 @@ +#ifndef LIGHTNING_COMMON_WIRE_ERROR_H +#define LIGHTNING_COMMON_WIRE_ERROR_H +#include "config.h" +#include +#include +#include +#include + +struct channel_id; + +/** + * towire_errorfmt - helper to turn string into WIRE_ERROR. + * + * @ctx: context to allocate from + * @channel: specific channel to complain about, or NULL for all. + * @fmt: format for error. + */ +u8 *towire_errorfmt(const tal_t *ctx, + const struct channel_id *channel, + const char *fmt, ...) PRINTF_FMT(3,4); + +/** + * towire_errorfmtv - helper to turn string into WIRE_ERROR. + * + * @ctx: context to allocate from + * @channel: specific channel to complain about, or NULL for all. + * @fmt: format for error. + * @ap: accumulated varargs. + */ +u8 *towire_errorfmtv(const tal_t *ctx, + const struct channel_id *channel, + const char *fmt, + va_list ap); + +/** + * is_all_channels - True if channel_id is all zeroes. + */ +bool is_all_channels(const struct channel_id *channel_id); + +/** + * sanitize_error - extract and sanitize contents of WIRE_ERROR. + * + * @ctx: context to allocate from + * @errmsg: the wire_error + * @channel: (out) channel it's referrring to, or NULL if don't care. + */ +char *sanitize_error(const tal_t *ctx, const u8 *errmsg, + struct channel_id *channel_id); + +#endif /* LIGHTNING_COMMON_WIRE_ERROR_H */