/* Simple tool to route gossip from a peer. */ #include #include #include #include #include #include #include #include #include #include #include #define io_write_ simple_write #define io_read_ simple_read #define io_close simple_close static struct io_plan *simple_write(struct io_conn *conn, const void *data, size_t len, struct io_plan *(*next)(struct io_conn *, void *), void *arg); static struct io_plan *simple_read(struct io_conn *conn, void *data, size_t len, struct io_plan *(*next)(struct io_conn *, void *), void *next_arg); static struct io_plan *simple_close(struct io_conn *conn) { return NULL; } #include "../connectd/handshake.c" /* This makes the handshake prototypes work. */ struct io_conn { int fd; }; static struct secret notsosecret; static bool initial_sync = false; static unsigned long max_messages = -1UL; /* Empty stubs to make us compile */ void status_peer_io(enum log_level iodir, const u8 *p) { } void status_fmt(enum log_level level, const char *fmt, ...) { } #if DEVELOPER void dev_sabotage_fd(int fd) { abort(); } void dev_blackhole_fd(int fd) { abort(); } enum dev_disconnect dev_disconnect(int pkt_type) { return DEV_DISCONNECT_NORMAL; } #endif void peer_failed_connection_lost(void) { exit(0); } struct secret *hsm_do_ecdh(const tal_t *ctx, const struct pubkey *point) { struct secret *ss = tal(ctx, struct secret); if (secp256k1_ecdh(secp256k1_ctx, ss->data, &point->pubkey, notsosecret.data) != 1) return tal_free(ss); return ss; } /* We don't want to discard *any* messages. */ bool is_unknown_msg_discardable(const u8 *cursor) { return false; } static struct io_plan *simple_write(struct io_conn *conn, const void *data, size_t len, struct io_plan *(*next)(struct io_conn *, void *), void *arg) { if (!write_all(conn->fd, data, len)) err(1, "Writing data"); return next(conn, arg); } static struct io_plan *simple_read(struct io_conn *conn, void *data, size_t len, struct io_plan *(*next)(struct io_conn *, void *), void *next_arg) { if (!read_all(conn->fd, data, len)) err(1, "Reading data"); return next(conn, next_arg); } static struct io_plan *handshake_success(struct io_conn *conn, const struct pubkey *them, const struct wireaddr_internal *addr, const struct crypto_state *orig_cs, char **args) { u8 *msg; struct crypto_state cs = *orig_cs; u8 *localfeatures; if (initial_sync) { localfeatures = tal(conn, u8); localfeatures[0] = (1 << 3); } else localfeatures = NULL; msg = towire_init(NULL, NULL, localfeatures); sync_crypto_write(&cs, conn->fd, take(msg)); /* Ignore their init message. */ tal_free(sync_crypto_read(NULL, &cs, conn->fd)); /* Did they ask us to send any messages? Do so now. */ while (*args) { u8 *m = tal_hexdata(NULL, *args, strlen(*args)); if (!m) errx(1, "Invalid hexdata '%s'", *args); sync_crypto_write(&cs, conn->fd, take(m)); args++; } /* Now write out whatever we get. */ while ((msg = sync_crypto_read(NULL, &cs, conn->fd)) != NULL) { be16 len = cpu_to_be16(tal_bytelen(msg)); if (!write_all(STDOUT_FILENO, &len, sizeof(len)) || !write_all(STDOUT_FILENO, msg, tal_bytelen(msg))) err(1, "Writing out msg"); tal_free(msg); if (--max_messages == 0) exit(0); } err(1, "Reading msg"); } int main(int argc, char *argv[]) { struct io_conn *conn = tal(NULL, struct io_conn); struct wireaddr_internal addr; int af = -1; struct pubkey us, them; const char *err_msg; const char *at; struct addrinfo *ai = NULL; setup_locale(); secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); opt_register_noarg("--initial-sync", opt_set_bool, &initial_sync, "Stream complete gossip history at start"); opt_register_arg("--max-messages", opt_set_ulongval, opt_show_ulongval, &max_messages, "Terminate after reading this many messages (> 0)"); opt_register_noarg("--help|-h", opt_usage_and_exit, "id@addr[:port] [hex-msg-tosend...]\n" "Connect to a lightning peer and relay gossip messages from it", "Print this message."); opt_parse(&argc, argv, opt_log_stderr_exit); if (argc < 2) opt_usage_exit_fail("Need an id@addr to connect to"); at = strchr(argv[1], '@'); if (!at) opt_usage_exit_fail("Need id@addr"); if (!pubkey_from_hexstr(argv[1], at - argv[1], &them)) opt_usage_exit_fail("Invalid id %.*s", (int)(at - argv[1]), argv[1]); if (!parse_wireaddr_internal(at+1, &addr, DEFAULT_PORT, NULL, true, false, &err_msg)) opt_usage_exit_fail("%s '%s'", err_msg, argv[1]); switch (addr.itype) { case ADDR_INTERNAL_SOCKNAME: af = AF_LOCAL; ai = wireaddr_internal_to_addrinfo(conn, &addr); break; case ADDR_INTERNAL_ALLPROTO: case ADDR_INTERNAL_AUTOTOR: case ADDR_INTERNAL_FORPROXY: opt_usage_exit_fail("Don't support proxy use"); case ADDR_INTERNAL_WIREADDR: switch (addr.u.wireaddr.type) { case ADDR_TYPE_TOR_V2: case ADDR_TYPE_TOR_V3: opt_usage_exit_fail("Don't support proxy use"); break; case ADDR_TYPE_IPV4: af = AF_INET; break; case ADDR_TYPE_IPV6: af = AF_INET6; break; } ai = wireaddr_to_addrinfo(tmpctx, &addr.u.wireaddr); } if (af == -1 || ai == NULL) err(1, "Initializing socket"); conn->fd = socket(af, SOCK_STREAM, 0); if (conn->fd < 0) err(1, "Creating socket"); memset(¬sosecret, 0x42, sizeof(notsosecret)); if (!pubkey_from_secret(¬sosecret, &us)) errx(1, "Creating pubkey"); if (connect(conn->fd, ai->ai_addr, ai->ai_addrlen) != 0) err(1, "Connecting to %s", at+1); initiator_handshake(conn, &us, &them, &addr, handshake_success, argv+2); exit(0); }