From 608bacd6f34be6d235a99707449c677a181f98a0 Mon Sep 17 00:00:00 2001 From: Christian Decker Date: Wed, 7 Sep 2016 17:16:17 +0200 Subject: [PATCH] routing: Refactoring IRC announcements. Moving all IRC related functionality from routing.c into its own module so that we can replace it later. --- daemon/Makefile | 1 + daemon/irc_announce.c | 154 ++++++++++++++++++++++++++++++++++++++++++ daemon/irc_announce.h | 9 +++ daemon/lightningd.c | 1 + daemon/lightningd.h | 1 - daemon/routing.c | 145 +-------------------------------------- daemon/routing.h | 4 -- 7 files changed, 166 insertions(+), 149 deletions(-) create mode 100644 daemon/irc_announce.c create mode 100644 daemon/irc_announce.h diff --git a/daemon/Makefile b/daemon/Makefile index 4f780e2336b9..60f5cca3fb30 100644 --- a/daemon/Makefile +++ b/daemon/Makefile @@ -26,6 +26,7 @@ DAEMON_SRC := \ daemon/feechange.c \ daemon/htlc.c \ daemon/invoice.c \ + daemon/irc_announce.c \ daemon/jsonrpc.c \ daemon/lightningd.c \ daemon/netaddr.c \ diff --git a/daemon/irc_announce.c b/daemon/irc_announce.c new file mode 100644 index 000000000000..20501d9df3e7 --- /dev/null +++ b/daemon/irc_announce.c @@ -0,0 +1,154 @@ +#include "bitcoin/privkey.h" +#include "bitcoin/signature.h" +#include "daemon/chaintopology.h" +#include "daemon/irc_announce.h" +#include "daemon/lightningd.h" +#include "daemon/log.h" +#include "daemon/peer.h" +#include "daemon/routing.h" +#include "daemon/secrets.h" +#include "daemon/timeout.h" +#include "utils.h" + +#include +#include + +static bool announce_channel(const tal_t *ctx, struct ircstate *state, struct peer *p) +{ + char txid[65]; + int siglen; + u8 der[72]; + struct signature sig; + struct privmsg *msg = talz(ctx, struct privmsg); + struct txlocator *loc = locate_tx(ctx, state->dstate, &p->anchor.txid); + if (loc == NULL) + return false; + + bitcoin_txid_to_hex(&p->anchor.txid, txid, sizeof(txid)); + msg->channel = "#lightning-nodes"; + msg->msg = tal_fmt( + msg, "CHAN %s %s %s %d %d %d %d %d", + pubkey_to_hexstr(msg, state->dstate->secpctx, &state->dstate->id), + pubkey_to_hexstr(msg, state->dstate->secpctx, p->id), + txid, + loc->blkheight, + loc->index, + state->dstate->config.fee_base, + state->dstate->config.fee_per_satoshi, + p->remote.locktime.locktime + ); + + privkey_sign(state->dstate, msg->msg, strlen(msg->msg), &sig); + siglen = signature_to_der(state->dstate->secpctx, der, &sig); + msg->msg = tal_fmt(msg, "%s %s", tal_hexstr(ctx, der, siglen), msg->msg); + + irc_send_msg(state, msg); + return true; +} + +static void announce_channels(struct ircstate *state) +{ + tal_t *ctx = tal(state, tal_t); + struct peer *p; + + list_for_each(&state->dstate->peers, p, list) { + + if (!state_is_normal(p->state)) + continue; + announce_channel(ctx, state, p); + } + tal_free(ctx); + + new_reltimer(state->dstate, state, time_from_sec(60), announce_channels, state); +} + +/* Reconnect to IRC server upon disconnection. */ +static void handle_irc_disconnect(struct ircstate *state) +{ + new_reltimer(state->dstate, state, state->reconnect_timeout, irc_connect, state); +} + +/* + * Handle an incoming message by checking if it is a channel + * announcement, parse it and add the channel to the topology if yes. + * + * The format for a valid announcement is: + * CHAN + * + */ +static void handle_irc_privmsg(struct ircstate *istate, const struct privmsg *msg) +{ + int blkheight; + char **splits = tal_strsplit(msg, msg->msg + 1, " ", STR_NO_EMPTY); + + if (tal_count(splits) != 11 || !streq(splits[1], "CHAN")) + return; + + int siglen = hex_data_size(strlen(splits[0])); + u8 *der = tal_hexdata(msg, splits[0], strlen(splits[0])); + if (der == NULL) + return; + + struct signature sig; + struct sha256_double hash; + char *content = strchr(msg->msg, ' ') + 1; + if (!signature_from_der(istate->dstate->secpctx, der, siglen, &sig)) + return; + + sha256_double(&hash, content, strlen(content)); + splits++; + + struct pubkey *pk1 = talz(msg, struct pubkey); + struct pubkey *pk2 = talz(msg, struct pubkey); + struct sha256_double *txid = talz(msg, struct sha256_double); + int index; + + bool ok = true; + ok &= pubkey_from_hexstr(istate->dstate->secpctx, splits[1], strlen(splits[1]), pk1); + ok &= pubkey_from_hexstr(istate->dstate->secpctx, splits[2], strlen(splits[2]), pk2); + ok &= bitcoin_txid_from_hex(splits[3], strlen(splits[3]), txid); + blkheight = atoi(splits[4]); + index = atoi(splits[5]); + if (!ok || index < 0 || blkheight < 0) { + log_debug(istate->dstate->base_log, "Unable to parse channel announcent."); + return; + } + + if(!check_signed_hash(istate->dstate->secpctx, &hash, &sig, pk1)){ + log_debug(istate->log, + "Ignoring announcement from %s, signature check failed.", + splits[1]); + return; + } + + /* + * FIXME Check in topology that the tx is in the block and + * that the endpoints match. + */ + + add_connection(istate->dstate, pk1, pk2, atoi(splits[6]), + atoi(splits[7]), atoi(splits[8]), 6); +} + +void setup_irc_connection(struct lightningd_state *dstate) +{ + // Register callback + irc_privmsg_cb = *handle_irc_privmsg; + irc_disconnect_cb = *handle_irc_disconnect; + + struct ircstate *state = talz(dstate, struct ircstate); + state->dstate = dstate; + state->server = "irc.freenode.net"; + state->reconnect_timeout = time_from_sec(15); + state->log = new_log(state, state->dstate->log_record, "%s:irc", + log_prefix(state->dstate->base_log)); + + /* Truncate nick at 13 bytes, would be imposed by freenode anyway */ + state->nick = tal_fmt( + state, + "N%.12s", + pubkey_to_hexstr(state, dstate->secpctx, &dstate->id) + 1); + + irc_connect(state); + announce_channels(state); +} diff --git a/daemon/irc_announce.h b/daemon/irc_announce.h new file mode 100644 index 000000000000..bce649771a5f --- /dev/null +++ b/daemon/irc_announce.h @@ -0,0 +1,9 @@ +#ifndef LIGHTNING_DAEMON_IRC_ANNOUNCE_H +#define LIGHTNING_DAEMON_IRC_ANNOUNCE_H +#include "config.h" +#include "irc.h" + +// Main entrypoint for the lightning daemon +void setup_irc_connection(struct lightningd_state *dstate); + +#endif /* LIGHTNING_DAEMON_IRC_ANNOUNCE_H */ diff --git a/daemon/lightningd.c b/daemon/lightningd.c index 7c3d86a65719..fef17f629e62 100644 --- a/daemon/lightningd.c +++ b/daemon/lightningd.c @@ -3,6 +3,7 @@ #include "configdir.h" #include "controlled_time.h" #include "db.h" +#include "irc_announce.h" #include "jsonrpc.h" #include "lightningd.h" #include "log.h" diff --git a/daemon/lightningd.h b/daemon/lightningd.h index 9526971c6a3b..dc8f8d1624c6 100644 --- a/daemon/lightningd.h +++ b/daemon/lightningd.h @@ -2,7 +2,6 @@ #define LIGHTNING_DAEMON_LIGHTNING_H #include "config.h" #include "bitcoin/pubkey.h" -#include "routing.h" #include "watch.h" #include #include diff --git a/daemon/routing.c b/daemon/routing.c index 1c5dbbc44b00..b497d715a28e 100644 --- a/daemon/routing.c +++ b/daemon/routing.c @@ -1,21 +1,14 @@ #include "jsonrpc.h" -#include "bitcoin/block.h" -#include "chaintopology.h" -#include "daemon/secrets.h" #include "lightningd.h" #include "log.h" #include "overflows.h" #include "peer.h" #include "pseudorand.h" #include "routing.h" -#include "timeout.h" -#include "utils.h" #include #include #include -#include #include -#include #include /* 365.25 * 24 * 60 / 10 */ @@ -490,146 +483,10 @@ static void json_routefail(struct command *cmd, command_success(cmd, null_response(cmd)); } + const struct json_command dev_routefail_command = { "dev-routefail", json_routefail, "FAIL htlcs that we can't route if {enable}", "Returns an empty result on success" }; - -static void announce_channels(struct ircstate *state) -{ - tal_t *ctx = tal(state, tal_t); - char txid[65]; - struct peer *p; - - list_for_each(&state->dstate->peers, p, list) { - - if (!state_is_normal(p->state)) - continue; - - struct txlocator *loc = locate_tx(ctx, state->dstate, &p->anchor.txid); - if (loc == NULL) - continue; - - bitcoin_txid_to_hex(&p->anchor.txid, txid, sizeof(txid)); - struct privmsg *msg = talz(state, struct privmsg); - msg->channel = "#lightning-nodes"; - msg->msg = tal_fmt( - msg, "CHAN %s %s %s %d %d %d %d %d", - pubkey_to_hexstr(msg, state->dstate->secpctx, &state->dstate->id), - pubkey_to_hexstr(msg, state->dstate->secpctx, p->id), - txid, - loc->blkheight, - loc->index, - state->dstate->config.fee_base, - state->dstate->config.fee_per_satoshi, - p->remote.locktime.locktime - ); - - struct signature sig; - u8 der[72]; - - memset(der, 0, sizeof(der)); - privkey_sign(state->dstate, msg->msg, strlen(msg->msg), &sig); - int numbytes = signature_to_der(state->dstate->secpctx, der, &sig); - msg->msg = tal_fmt(msg, "%s %s", tal_hexstr(ctx, der, numbytes), msg->msg); - - irc_send_msg(state, msg); - tal_free(loc); - } - tal_free(ctx); - - new_reltimer(state->dstate, state, time_from_sec(60), announce_channels, state); -} - -/* Reconnect to IRC server upon disconnection. */ -static void handle_irc_disconnect(struct ircstate *state) -{ - new_reltimer(state->dstate, state, state->reconnect_timeout, irc_connect, state); -} - -/* - * Handle an incoming message by checking if it is a channel - * announcement, parse it and add the channel to the topology if yes. - * - * The format for a valid announcement is: - * CHAN - * - */ -static void handle_irc_privmsg(struct ircstate *istate, const struct privmsg *msg) -{ - int blkheight; - char **splits = tal_strsplit(msg, msg->msg + 1, " ", STR_NO_EMPTY); - - if (tal_count(splits) != 11 || !streq(splits[1], "CHAN")) - return; - - int siglen = hex_data_size(strlen(splits[0])); - u8 *der = tal_hexdata(msg, splits[0], strlen(splits[0])); - if (der == NULL) - return; - - struct signature sig; - struct sha256_double hash; - char *content = strchr(msg->msg, ' ') + 1; - if (!signature_from_der(istate->dstate->secpctx, der, siglen, &sig)) - return; - - sha256_double(&hash, content, strlen(content)); - splits++; - - struct pubkey *pk1 = talz(msg, struct pubkey); - struct pubkey *pk2 = talz(msg, struct pubkey); - struct sha256_double *txid = talz(msg, struct sha256_double); - int index; - - bool ok = true; - ok &= pubkey_from_hexstr(istate->dstate->secpctx, splits[1], strlen(splits[1]), pk1); - ok &= pubkey_from_hexstr(istate->dstate->secpctx, splits[2], strlen(splits[2]), pk2); - ok &= bitcoin_txid_from_hex(splits[3], strlen(splits[3]), txid); - blkheight = atoi(splits[4]); - index = atoi(splits[5]); - if (!ok || index < 0 || blkheight < 0) { - log_debug(istate->dstate->base_log, "Unable to parse channel announcent."); - return; - } - - if(!check_signed_hash(istate->dstate->secpctx, &hash, &sig, pk1)){ - log_debug(istate->log, - "Ignoring announcement from %s, signature check failed.", - splits[1]); - return; - } - - /* - * FIXME Check in topology that the tx is in the block and - * that the endpoints match. - */ - - add_connection(istate->dstate, pk1, pk2, atoi(splits[6]), - atoi(splits[7]), atoi(splits[8]), 6); -} - -void setup_irc_connection(struct lightningd_state *dstate) -{ - // Register callback - irc_privmsg_cb = *handle_irc_privmsg; - irc_disconnect_cb = *handle_irc_disconnect; - - struct ircstate *state = talz(dstate, struct ircstate); - state->dstate = dstate; - state->server = "irc.freenode.net"; - state->reconnect_timeout = time_from_sec(15); - state->log = new_log(state, state->dstate->log_record, "%s:irc", - log_prefix(state->dstate->base_log)); - - /* Truncate nick at 13 bytes, would be imposed by freenode anyway */ - state->nick = tal_fmt( - state, - "N%.12s", - pubkey_to_hexstr(state, dstate->secpctx, &dstate->id) + 1); - - irc_connect(state); - announce_channels(state); -} diff --git a/daemon/routing.h b/daemon/routing.h index 5a3fc8790bff..faeede0615a2 100644 --- a/daemon/routing.h +++ b/daemon/routing.h @@ -2,7 +2,6 @@ #define LIGHTNING_DAEMON_ROUTING_H #include "config.h" #include "bitcoin/pubkey.h" -#include "irc.h" #define ROUTING_MAX_HOPS 20 @@ -68,7 +67,4 @@ struct node_map *empty_node_map(struct lightningd_state *dstate); char *opt_add_route(const char *arg, struct lightningd_state *dstate); -// Main entrypoint for the lightning daemon -void setup_irc_connection(struct lightningd_state *dstate); - #endif /* LIGHTNING_DAEMON_ROUTING_H */