From d40fea774b4c571439da9055642c6db8fd9d152f Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Mon, 25 Jul 2011 21:30:43 +0000 Subject: [PATCH] Import dht-0.21. This has blacklisting support. --- third-party/dht/CHANGES | 4 ++ third-party/dht/README | 6 ++ third-party/dht/dht-example.c | 8 +++ third-party/dht/dht.c | 129 ++++++++++++++++++++-------------- third-party/dht/dht.h | 1 + 5 files changed, 95 insertions(+), 53 deletions(-) diff --git a/third-party/dht/CHANGES b/third-party/dht/CHANGES index b5b0dc893..0c69ac4de 100644 --- a/third-party/dht/CHANGES +++ b/third-party/dht/CHANGES @@ -1,3 +1,7 @@ +25 July 2011: dht-0.21 + + * Blacklisting support. + 7 July 2011: dht-0.20 * Fix compilation on systems that have memmem but don't define HAVE_MEMMEM. diff --git a/third-party/dht/README b/third-party/dht/README index ba4e6e177..5252a9453 100644 --- a/third-party/dht/README +++ b/third-party/dht/README @@ -157,6 +157,12 @@ of the search. In the case of DHT_EVENT_VALUES, data is a list of nodes in ``compact'' format -- 6 or 18 bytes per node. Its length in bytes is in data_len. +* dht_blacklisted + +This is a function that takes an IP address and returns true if this +address should be silently ignored. Do not use this feature unless you +really must -- Kademlia supposes transitive reachability. + * dht_hash This should compute a reasonably strong cryptographic hash of the passed diff --git a/third-party/dht/dht-example.c b/third-party/dht/dht-example.c index d05dcab4b..dc69e2b43 100644 --- a/third-party/dht/dht-example.c +++ b/third-party/dht/dht-example.c @@ -409,6 +409,14 @@ main(int argc, char **argv) exit(1); } +/* Functions called by the DHT. */ + +int +dht_blacklisted(const struct sockaddr *sa, int salen) +{ + return 0; +} + /* We need to provide a reasonably strong cryptographic hashing function. Here's how we'd do it if we had RSA's MD5 code. */ #if 0 diff --git a/third-party/dht/dht.c b/third-party/dht/dht.c index e96b31b03..8295b9cb4 100644 --- a/third-party/dht/dht.c +++ b/third-party/dht/dht.c @@ -212,6 +212,8 @@ struct storage { struct storage *next; }; +static void flush_search_node(struct search_node *n, struct search *sr); + static int send_ping(const struct sockaddr *sa, int salen, const unsigned char *tid, int tid_len); static int send_pong(const struct sockaddr *sa, int salen, @@ -636,6 +638,68 @@ send_cached_ping(struct bucket *b) return rc; } +/* Called whenever we send a request to a node, increases the ping count + and, if that reaches 3, sends a ping to a new candidate. */ +static void +pinged(struct node *n, struct bucket *b) +{ + n->pinged++; + n->pinged_time = now.tv_sec; + if(n->pinged >= 3) + send_cached_ping(b ? b : find_bucket(n->id, n->ss.ss_family)); +} + +/* The internal blacklist is an LRU cache of nodes that have sent + incorrect messages. */ +static void +blacklist_node(const unsigned char *id, const struct sockaddr *sa, int salen) +{ + int i; + + debugf("Blacklisting broken node.\n"); + + if(id) { + struct node *n; + struct search *sr; + /* Make the node easy to discard. */ + n = find_node(id, sa->sa_family); + if(n) { + n->pinged = 3; + pinged(n, NULL); + } + /* Discard it from any searches in progress. */ + sr = searches; + while(sr) { + for(i = 0; i < sr->numnodes; i++) + if(id_cmp(sr->nodes[i].id, id) == 0) + flush_search_node(&sr->nodes[i], sr); + sr = sr->next; + } + } + /* And make sure we don't hear from it again. */ + memcpy(&blacklist[next_blacklisted], sa, salen); + next_blacklisted = (next_blacklisted + 1) % DHT_MAX_BLACKLISTED; +} + +static int +node_blacklisted(const struct sockaddr *sa, int salen) +{ + int i; + + if(salen > sizeof(struct sockaddr_storage)) + abort(); + + if(dht_blacklisted(sa, salen)) + return 1; + + for(i = 0; i < DHT_MAX_BLACKLISTED; i++) { + if(memcmp(&blacklist[i], sa, salen) == 0) + return 1; + } + + return 0; +} + /* Split a bucket into two equal parts. */ static struct bucket * split_bucket(struct bucket *b) @@ -674,16 +738,6 @@ split_bucket(struct bucket *b) return b; } -/* Called whenever we send a request to a node. */ -static void -pinged(struct node *n, struct bucket *b) -{ - n->pinged++; - n->pinged_time = now.tv_sec; - if(n->pinged >= 3) - send_cached_ping(b ? b : find_bucket(n->id, n->ss.ss_family)); -} - /* We just learnt about a node, not necessarily a new one. Confirm is 1 if the node sent a message, 2 if it sent us a reply. */ static struct node * @@ -700,7 +754,7 @@ new_node(const unsigned char *id, const struct sockaddr *sa, int salen, if(id_cmp(id, myid) == 0) return NULL; - if(is_martian(sa)) + if(is_martian(sa) || node_blacklisted(sa, salen)) return NULL; mybucket = in_bucket(myid, b); @@ -1328,37 +1382,6 @@ expire_storage(void) return 1; } -/* We've just found out that a node is buggy. */ -static void -broken_node(const unsigned char *id, const struct sockaddr *sa, int salen) -{ - int i; - - debugf("Blacklisting broken node.\n"); - - if(id) { - struct node *n; - struct search *sr; - /* Make the node easy to discard. */ - n = find_node(id, sa->sa_family); - if(n) { - n->pinged = 3; - pinged(n, NULL); - } - /* Discard it from any searches in progress. */ - sr = searches; - while(sr) { - for(i = 0; i < sr->numnodes; i++) - if(id_cmp(sr->nodes[i].id, id) == 0) - flush_search_node(&sr->nodes[i], sr); - sr = sr->next; - } - } - /* And make sure we don't hear from it again. */ - memcpy(&blacklist[next_blacklisted], sa, salen); - next_blacklisted = (next_blacklisted + 1) % DHT_MAX_BLACKLISTED; -} - static int rotate_secrets(void) { @@ -1846,8 +1869,6 @@ dht_periodic(const void *buf, size_t buflen, time_t *tosleep, dht_callback *callback, void *closure) { - int i; - gettimeofday(&now, NULL); if(buflen > 0) { @@ -1865,15 +1886,11 @@ dht_periodic(const void *buf, size_t buflen, if(is_martian(from)) goto dontread; - for(i = 0; i < DHT_MAX_BLACKLISTED; i++) { - if(memcmp(&blacklist[i], from, fromlen) == 0) { - debugf("Received packet from blacklisted node.\n"); - goto dontread; - } + if(node_blacklisted(from, fromlen)) { + debugf("Received packet from blacklisted node.\n"); + goto dontread; } - /* See parse_message. */ - if(((char*)buf)[buflen] != '\0') { debugf("Unterminated message.\n"); errno = EINVAL; @@ -1915,7 +1932,7 @@ dht_periodic(const void *buf, size_t buflen, /* This is really annoying, as it means that we will time-out all our searches that go through this node. Kill it. */ - broken_node(id, from, fromlen); + blacklist_node(id, from, fromlen); goto dontread; } if(tid_match(tid, "pn", NULL)) { @@ -1933,7 +1950,7 @@ dht_periodic(const void *buf, size_t buflen, gp ? " for get_peers" : ""); if(nodes_len % 26 != 0 || nodes6_len % 38 != 0) { debugf("Unexpected length for node info!\n"); - broken_node(id, from, fromlen); + blacklist_node(id, from, fromlen); } else if(gp && sr == NULL) { debugf("Unknown search!\n"); new_node(id, from, fromlen, 1); @@ -2300,6 +2317,12 @@ dht_send(const void *buf, size_t len, int flags, if(salen == 0) abort(); + if(node_blacklisted(sa, salen)) { + debugf("Attempting to send to blacklisted node.\n"); + errno = EPERM; + return -1; + } + if(sa->sa_family == AF_INET) s = dht_socket; else if(sa->sa_family == AF_INET6) diff --git a/third-party/dht/dht.h b/third-party/dht/dht.h index 2f76e5678..f88e46b29 100644 --- a/third-party/dht/dht.h +++ b/third-party/dht/dht.h @@ -50,6 +50,7 @@ int dht_get_nodes(struct sockaddr_in *sin, int *num, int dht_uninit(void); /* This must be provided by the user. */ +int dht_blacklisted(const struct sockaddr *sa, int salen); void dht_hash(void *hash_return, int hash_size, const void *v1, int len1, const void *v2, int len2,