From 0bffd788d4364d95808d3866088d9928b51ed4fe Mon Sep 17 00:00:00 2001 From: Javed Khan Date: Sun, 2 Aug 2020 22:25:14 +0530 Subject: [PATCH 01/11] pool: handle both clearnet and brontide peers --- src/addr.c | 8 +++- src/addrmgr.c | 2 +- src/pool.c | 127 +++++++++++++++++++++++++++++--------------------- src/pool.h | 2 +- 4 files changed, 83 insertions(+), 56 deletions(-) diff --git a/src/addr.c b/src/addr.c index 9fac9a5a..bcca56f0 100644 --- a/src/addr.c +++ b/src/addr.c @@ -396,8 +396,8 @@ hsk_addr_from_string(hsk_addr_t *addr, const char *src, uint16_t port) { } sin_port = (uint16_t)word; - } else if (!port && port_s) { - return false; + } else if (!port) { + sin_port = at ? HSK_BRONTIDE_PORT : HSK_PORT; } uint8_t sin_addr[16]; @@ -940,7 +940,11 @@ hsk_addr_print(const hsk_addr_t *addr, const char *prefix) { char host[HSK_MAX_HOST]; assert(hsk_addr_to_string(addr, host, HSK_MAX_HOST, HSK_BRONTIDE_PORT)); + char b32[54]; + hsk_base32_encode(addr->key, 33, b32, false); + printf("%saddr\n", prefix); + printf("%skey=%s\n", prefix, b32); printf("%s type=%d\n", prefix, addr->type); printf("%s host=%s\n", prefix, host); } diff --git a/src/addrmgr.c b/src/addrmgr.c index 950863ba..929e3a09 100644 --- a/src/addrmgr.c +++ b/src/addrmgr.c @@ -57,7 +57,7 @@ hsk_addrman_init(hsk_addrman_t *am, const hsk_timedata_t *td) { const char **seed; for (seed = hsk_seeds; *seed; seed++) { hsk_addr_t addr; - assert(hsk_addr_from_string(&addr, *seed, HSK_BRONTIDE_PORT)); + assert(hsk_addr_from_string(&addr, *seed, 0)); assert(hsk_addrman_add_addr(am, &addr)); } diff --git a/src/pool.c b/src/pool.c index 5d239d97..5b7b5edb 100644 --- a/src/pool.c +++ b/src/pool.c @@ -53,7 +53,7 @@ typedef struct hsk_write_data_s { */ static hsk_peer_t * -hsk_peer_alloc(hsk_pool_t *pool); +hsk_peer_alloc(hsk_pool_t *pool, bool encrypted); static void hsk_peer_free(hsk_peer_t *peer); @@ -266,10 +266,7 @@ hsk_pool_set_seeds(hsk_pool_t *pool, const char *seeds) { memcpy(&seed[0], &seeds[start], size); seed[size] = '\0'; - if (!hsk_addr_from_string(&addr, seed, HSK_BRONTIDE_PORT)) - return false; - - if (!hsk_addr_has_key(&addr)) + if (!hsk_addr_from_string(&addr, seed, 0)) return false; if (!hsk_addrman_add_addr(&pool->am, &addr)) @@ -385,12 +382,12 @@ hsk_pool_refill(hsk_pool_t *pool) { break; } - if (!hsk_ec_verify_pubkey(pool->ec, addr.key)) { + if (hsk_addr_has_key(&addr) && !hsk_ec_verify_pubkey(pool->ec, addr.key)) { hsk_addrman_remove_addr(&pool->am, &addr); continue; } - hsk_peer_t *peer = hsk_peer_alloc(pool); + hsk_peer_t *peer = hsk_peer_alloc(pool, hsk_addr_has_key(&addr)); if (!peer) { hsk_pool_log(pool, "could not allocate peer\n"); @@ -782,7 +779,7 @@ hsk_pool_timer(hsk_pool_t *pool) { */ static int -hsk_peer_init(hsk_peer_t *peer, hsk_pool_t *pool) { +hsk_peer_init(hsk_peer_t *peer, hsk_pool_t *pool, bool encrypted) { if (!peer || !pool) return HSK_EBADARGS; @@ -793,13 +790,17 @@ hsk_peer_init(hsk_peer_t *peer, hsk_pool_t *pool) { peer->loop = pool->loop; // peer->socket; - hsk_brontide_init(&peer->brontide, pool->ec); - peer->brontide.connect_cb = after_brontide_connect; - peer->brontide.connect_arg = (void *)peer; - peer->brontide.write_cb = brontide_do_write; - peer->brontide.write_arg = (void *)peer; - peer->brontide.read_cb = after_brontide_read; - peer->brontide.read_arg = (void *)peer; + peer->brontide = NULL; + if (encrypted) { + peer->brontide = malloc(sizeof(hsk_brontide_t)); + hsk_brontide_init(peer->brontide, pool->ec); + peer->brontide->connect_cb = after_brontide_connect; + peer->brontide->connect_arg = (void *)peer; + peer->brontide->write_cb = brontide_do_write; + peer->brontide->write_arg = (void *)peer; + peer->brontide->read_cb = after_brontide_read; + peer->brontide->read_arg = (void *)peer; + } peer->id = pool->peer_id++; memset(peer->host, 0, sizeof(peer->host)); @@ -846,7 +847,8 @@ hsk_peer_uninit(hsk_peer_t *peer) { if (!peer) return; - hsk_brontide_uninit(&peer->brontide); + if (peer->brontide != NULL) + hsk_brontide_uninit(peer->brontide); hsk_map_uninit(&peer->names); @@ -857,13 +859,13 @@ hsk_peer_uninit(hsk_peer_t *peer) { } static hsk_peer_t * -hsk_peer_alloc(hsk_pool_t *pool) { +hsk_peer_alloc(hsk_pool_t *pool, bool encrypted) { hsk_peer_t *peer = malloc(sizeof(hsk_peer_t)); if (!peer) return NULL; - if (hsk_peer_init(peer, pool) != HSK_SUCCESS) { + if (hsk_peer_init(peer, pool, encrypted) != HSK_SUCCESS) { hsk_peer_free(peer); return NULL; } @@ -908,7 +910,8 @@ hsk_peer_open(hsk_peer_t *peer, const hsk_addr_t *addr) { assert(hsk_addr_to_sa(addr, sa)); - assert(hsk_brontide_connect(&peer->brontide, pool->key, addr->key) == 0); + if (peer->brontide != NULL) + assert(hsk_brontide_connect(peer->brontide, pool->key, addr->key) == 0); if (uv_tcp_connect(conn, &peer->socket, sa, on_connect) != 0) { free(conn); @@ -926,7 +929,8 @@ hsk_peer_close(hsk_peer_t *peer) { case HSK_STATE_DISCONNECTING: return HSK_SUCCESS; case HSK_STATE_HANDSHAKE: - hsk_brontide_destroy(&peer->brontide); + if (peer->brontide != NULL) + hsk_brontide_destroy(peer->brontide); case HSK_STATE_READING: assert(uv_read_stop((uv_stream_t *)&peer->socket) == 0); case HSK_STATE_CONNECTED: @@ -1032,21 +1036,6 @@ hsk_peer_remove(hsk_peer_t *peer) { assert(hsk_map_del(&pool->peers, &peer->addr)); } -static int -hsk_peer_write( - hsk_peer_t *peer, - uint8_t *data, - size_t data_len, - bool should_free -) { - if (peer->state != HSK_STATE_HANDSHAKE) - return HSK_SUCCESS; - - assert(should_free); - - return hsk_brontide_write(&peer->brontide, data, data_len); -} - static int hsk_peer_write_raw( hsk_peer_t *peer, @@ -1113,6 +1102,27 @@ hsk_peer_write_raw( return rc; } +static int +hsk_peer_write( + hsk_peer_t *peer, + uint8_t *data, + size_t data_len, + bool should_free +) { + if (peer->state != HSK_STATE_HANDSHAKE) + return HSK_SUCCESS; + + assert(should_free); + + int rc; + if (peer->brontide != NULL) { + rc = hsk_brontide_write(peer->brontide, data, data_len); + } else { + rc = hsk_peer_write_raw(peer, data, data_len, true); + } + return rc; +} + static int hsk_peer_send(hsk_peer_t *peer, const hsk_msg_t *msg) { int msg_size = hsk_msg_size(msg); @@ -1336,7 +1346,7 @@ hsk_peer_handle_addr(hsk_peer_t *peer, hsk_addr_msg_t *msg) { if (addr->addr.port == 0) continue; - if (!hsk_addr_has_key(&addr->addr)) + if (hsk_addr_has_key(&addr->addr)) continue; hsk_addrman_add_na(&pool->am, addr); @@ -1697,13 +1707,19 @@ on_connect(uv_connect_t *conn, int status) { peer->state = HSK_STATE_READING; peer->conn_time = hsk_now(); - int r = hsk_brontide_on_connect(&peer->brontide); + if (peer->brontide != NULL) { + int r = hsk_brontide_on_connect(peer->brontide); - if (r != HSK_SUCCESS) { - hsk_peer_log(peer, "brontide_on_connect failed: %s\n", hsk_strerror(r)); - hsk_peer_destroy(peer); + if (r != HSK_SUCCESS) { + hsk_peer_log(peer, "brontide_on_connect failed: %s\n", hsk_strerror(r)); + hsk_peer_destroy(peer); + return; + } return; } + + peer->state = HSK_STATE_HANDSHAKE; + hsk_peer_send_version(peer); } static void @@ -1749,24 +1765,31 @@ after_read(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { if (!peer) return; + if (peer->brontide != NULL) { + int r = hsk_brontide_on_read( + peer->brontide, + (uint8_t *)buf->base, + (size_t)nread + ); + if (r != HSK_SUCCESS) { + hsk_peer_log(peer, "brontide_on_read failed: %s\n", hsk_strerror(r)); + hsk_peer_destroy(peer); + return; + } + } else { + hsk_peer_on_read( + peer, + (uint8_t *)buf->base, + (size_t)nread + ); + } + if (nread < 0) { if (nread != UV_EOF) hsk_peer_log(peer, "read error: %s\n", uv_strerror(nread)); hsk_peer_destroy(peer); return; } - - int r = hsk_brontide_on_read( - &peer->brontide, - (uint8_t *)buf->base, - (size_t)nread - ); - - if (r != HSK_SUCCESS) { - hsk_peer_log(peer, "brontide_on_read failed: %s\n", hsk_strerror(r)); - hsk_peer_destroy(peer); - return; - } } static void diff --git a/src/pool.h b/src/pool.h index 7407e116..644dc252 100644 --- a/src/pool.h +++ b/src/pool.h @@ -56,7 +56,7 @@ typedef struct hsk_peer_s { hsk_chain_t *chain; uv_loop_t *loop; uv_tcp_t socket; - hsk_brontide_t brontide; + hsk_brontide_t *brontide; uint64_t id; char host[HSK_MAX_HOST]; hsk_addr_t addr; From 41e1147030bf8bda8e0fd2ace14d6e9b624318b9 Mon Sep 17 00:00:00 2001 From: Matthew Zipkin Date: Fri, 21 Aug 2020 14:06:50 -0400 Subject: [PATCH 02/11] pool: send getaddr after handshake to discover more peers --- src/pool.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/pool.c b/src/pool.c index 5b7b5edb..f88f1055 100644 --- a/src/pool.c +++ b/src/pool.c @@ -91,6 +91,9 @@ hsk_peer_send_ping(hsk_peer_t *peer, uint64_t nonce); static int hsk_peer_send_getheaders(hsk_peer_t *peer, const uint8_t *stop); +static int +hsk_peer_send_getaddr(hsk_peer_t *peer); + static int hsk_peer_send_getproof( hsk_peer_t *peer, @@ -1213,6 +1216,13 @@ hsk_peer_send_sendheaders(hsk_peer_t *peer) { return hsk_peer_send(peer, (hsk_msg_t *)&msg); } +static int +hsk_peer_send_getaddr(hsk_peer_t *peer) { + hsk_peer_log(peer, "sending getaddr\n"); + hsk_version_msg_t msg = { .cmd = HSK_MSG_GETADDR }; + return hsk_peer_send(peer, (hsk_msg_t *)&msg); +} + static int hsk_peer_send_getheaders(hsk_peer_t *peer, const uint8_t *stop) { hsk_peer_log(peer, "sending getheaders\n"); @@ -1265,6 +1275,13 @@ hsk_peer_handle_version(hsk_peer_t *peer, const hsk_version_msg_t *msg) { if (rc != HSK_SUCCESS) return rc; + // Discover more peers + rc = hsk_peer_send_getaddr(peer); + + if (rc != HSK_SUCCESS) + return rc; + + // Start syncing return hsk_peer_send_getheaders(peer, NULL); } From 5d990e11c81fe60e2bad3f8cc192a904b3112bc2 Mon Sep 17 00:00:00 2001 From: Matthew Zipkin Date: Mon, 24 Aug 2020 10:07:38 -0400 Subject: [PATCH 03/11] pool: break infinite failure loop on invalid message header --- src/pool.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pool.c b/src/pool.c index f88f1055..49615bc6 100644 --- a/src/pool.c +++ b/src/pool.c @@ -1585,7 +1585,10 @@ hsk_peer_on_read(hsk_peer_t *peer, const uint8_t *data, size_t data_len) { memcpy(peer->msg + peer->msg_pos, data, need); data += need; data_len -= need; - hsk_peer_parse(peer, peer->msg, peer->msg_len); + if (hsk_peer_parse(peer, peer->msg, peer->msg_len) != 0) { + hsk_peer_destroy(peer); + return; + } } memcpy(peer->msg + peer->msg_pos, data, data_len); From 21e5578a315b31e5fca3c287c4c499ab5c328efc Mon Sep 17 00:00:00 2001 From: Javed Khan Date: Mon, 24 Aug 2020 21:56:08 +0530 Subject: [PATCH 04/11] addr: parse non standard ports --- src/addr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/addr.c b/src/addr.c index bcca56f0..a5a94471 100644 --- a/src/addr.c +++ b/src/addr.c @@ -375,7 +375,7 @@ hsk_addr_from_string(hsk_addr_t *addr, const char *src, uint16_t port) { uint16_t sin_port = port; - if (port && port_s) { + if (port_s) { int i = 0; uint32_t word = 0; char *s = port_s; @@ -398,6 +398,8 @@ hsk_addr_from_string(hsk_addr_t *addr, const char *src, uint16_t port) { sin_port = (uint16_t)word; } else if (!port) { sin_port = at ? HSK_BRONTIDE_PORT : HSK_PORT; + } else { + sin_port = port; } uint8_t sin_addr[16]; From 7d82c2140864a10ae69467c92420d328c55a511b Mon Sep 17 00:00:00 2001 From: Matthew Zipkin Date: Tue, 25 Aug 2020 09:54:34 -0400 Subject: [PATCH 05/11] pool: ignore duplicate or otherwise bad seeds during daemon init --- src/pool.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/pool.c b/src/pool.c index 49615bc6..94469628 100644 --- a/src/pool.c +++ b/src/pool.c @@ -263,17 +263,23 @@ hsk_pool_set_seeds(hsk_pool_t *pool, const char *seeds) { continue; } - if (size >= HSK_MAX_HOST) - return false; + if (size >= HSK_MAX_HOST) { + hsk_pool_log(pool, "seed address exceeds maximum length allowed.\n"); + continue; + } memcpy(&seed[0], &seeds[start], size); seed[size] = '\0'; - if (!hsk_addr_from_string(&addr, seed, 0)) - return false; + if (!hsk_addr_from_string(&addr, seed, 0)) { + hsk_pool_log(pool, "could not parse seed from string: %s\n", seed); + continue; + } - if (!hsk_addrman_add_addr(&pool->am, &addr)) - return false; + if (!hsk_addrman_add_addr(&pool->am, &addr)) { + hsk_pool_log(pool, "could not add seed: %s\n", seed); + continue; + } start = i + 1; } From 9b0fc01d50c1d90a4b97c8218806dc2b6d4bbc9c Mon Sep 17 00:00:00 2001 From: Matthew Zipkin Date: Thu, 17 Sep 2020 14:47:39 -0400 Subject: [PATCH 06/11] pool: remove unused member in hsk_peer_s --- src/pool.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pool.h b/src/pool.h index 644dc252..cd859e56 100644 --- a/src/pool.h +++ b/src/pool.h @@ -60,7 +60,6 @@ typedef struct hsk_peer_s { uint64_t id; char host[HSK_MAX_HOST]; hsk_addr_t addr; - uint16_t port; int state; uint8_t read_buffer[HSK_BUFFER_SIZE]; int headers; From ca076fd4b5997641449c1f065d638cbf7741ebb8 Mon Sep 17 00:00:00 2001 From: Matthew Zipkin Date: Thu, 17 Sep 2020 14:48:46 -0400 Subject: [PATCH 07/11] addr: use local instead of static tmp --- src/addr.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/addr.c b/src/addr.c index a5a94471..2b559666 100644 --- a/src/addr.c +++ b/src/addr.c @@ -448,8 +448,7 @@ hsk_addr_to_string( if (!port) port = fb; - // XXX Not thread safe. - static char tmp[HSK_MAX_HOST]; + char tmp[HSK_MAX_HOST]; if (af == AF_INET6) { assert(len + need < HSK_MAX_HOST); @@ -489,8 +488,7 @@ hsk_addr_to_full( char b32[54]; hsk_base32_encode(addr->key, 33, b32, false); - // XXX Not thread safe. - static char tmp[HSK_MAX_HOST]; + char tmp[HSK_MAX_HOST]; sprintf(tmp, "%s@%s", b32, dst); strcpy(dst, tmp); @@ -517,8 +515,7 @@ hsk_addr_to_at(const hsk_addr_t *addr, char *dst, size_t dst_len, uint16_t fb) { if (!port) port = fb; - // XXX Not thread safe. - static char tmp[HSK_MAX_HOST]; + char tmp[HSK_MAX_HOST]; sprintf(tmp, "%s@%u", dst, port); strcpy(dst, tmp); } From 71b05263e56820f3ec0b42812d3a6c9821629d32 Mon Sep 17 00:00:00 2001 From: Matthew Zipkin Date: Fri, 18 Sep 2020 17:43:21 -0400 Subject: [PATCH 08/11] pool: call hsk_pool_refill once per pool loop without blocking --- src/pool.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pool.c b/src/pool.c index 94469628..1cc5f5cc 100644 --- a/src/pool.c +++ b/src/pool.c @@ -383,17 +383,17 @@ hsk_pool_getaddr(hsk_pool_t *pool, hsk_addr_t *addr) { static int hsk_pool_refill(hsk_pool_t *pool) { - while (pool->size < pool->max_size) { + if (pool->size < pool->max_size) { hsk_addr_t addr; if (!hsk_pool_getaddr(pool, &addr)) { hsk_pool_debug(pool, "could not find suitable addr\n"); - break; + return HSK_SUCCESS; } if (hsk_addr_has_key(&addr) && !hsk_ec_verify_pubkey(pool->ec, addr.key)) { hsk_addrman_remove_addr(&pool->am, &addr); - continue; + return HSK_SUCCESS; } hsk_peer_t *peer = hsk_peer_alloc(pool, hsk_addr_has_key(&addr)); From ce0fa697792a86acb59c2e914a3516907187421d Mon Sep 17 00:00:00 2001 From: Matthew Zipkin Date: Fri, 18 Sep 2020 18:12:01 -0400 Subject: [PATCH 09/11] pool: log pool size and count of peers with completed handshake --- src/pool.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/pool.c b/src/pool.c index 1cc5f5cc..fbda81c2 100644 --- a/src/pool.c +++ b/src/pool.c @@ -929,6 +929,16 @@ hsk_peer_open(hsk_peer_t *peer, const hsk_addr_t *addr) { peer->state = HSK_STATE_CONNECTING; + + hsk_peer_t *peerIter, *next; + uint64_t active = 0; + for (peerIter = pool->head; peerIter; peerIter = next) { + next = peerIter->next; + if (peerIter->state == HSK_STATE_HANDSHAKE) + active++; + } + hsk_pool_log(pool, "size: %d active: %d\n", pool->size, active); + return HSK_SUCCESS; } From 60a3796e4bb3b976c4d56d8abb1dbd332fec9c67 Mon Sep 17 00:00:00 2001 From: Matthew Zipkin Date: Sun, 20 Sep 2020 23:48:04 -0400 Subject: [PATCH 10/11] pool: ignore duplicate block errors from chain Fixes a regression caused by 7d82c2140864a10ae69467c92420d328c55a511b that would destory peers that sent duplicate blocks (which is very common thing for multiple peers to do!) --- src/pool.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pool.c b/src/pool.c index fbda81c2..af7009d8 100644 --- a/src/pool.c +++ b/src/pool.c @@ -1449,7 +1449,10 @@ hsk_peer_handle_headers(hsk_peer_t *peer, const hsk_headers_msg_t *msg) { if (rc != HSK_SUCCESS) { hsk_peer_log(peer, "failed adding block: %s\n", hsk_strerror(rc)); - return rc; + if (rc == HSK_EDUPLICATE) + return HSK_SUCCESS; + else + return rc; } peer->headers += 1; From 522f0b93a03f3908ea1ade752c63c4ee045e28a6 Mon Sep 17 00:00:00 2001 From: Matthew Zipkin Date: Sun, 20 Sep 2020 23:53:17 -0400 Subject: [PATCH 11/11] pool: set state to CONNECTING before initializing tcp handle This garuntees that if hsk_peer_open() fails, that hsk_peer_close() will call uv_close() before freeing the peer, preventing a race condition where libuv tries to free the connection handle after the peer has been destroyed. --- src/pool.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/pool.c b/src/pool.c index af7009d8..818ca49a 100644 --- a/src/pool.c +++ b/src/pool.c @@ -896,6 +896,8 @@ hsk_peer_open(hsk_peer_t *peer, const hsk_addr_t *addr) { assert(peer && addr); assert(peer->pool && peer->loop && peer->state == HSK_STATE_DISCONNECTED); + peer->state = HSK_STATE_CONNECTING; + hsk_pool_t *pool = (hsk_pool_t *)peer->pool; uv_loop_t *loop = pool->loop; @@ -927,9 +929,6 @@ hsk_peer_open(hsk_peer_t *peer, const hsk_addr_t *addr) { return HSK_EFAILURE; } - peer->state = HSK_STATE_CONNECTING; - - hsk_peer_t *peerIter, *next; uint64_t active = 0; for (peerIter = pool->head; peerIter; peerIter = next) {