Import dht-0.21. This has blacklisting support.

This commit is contained in:
Juliusz Chroboczek 2011-07-25 21:30:43 +00:00
parent fe42e456b4
commit d40fea774b
5 changed files with 95 additions and 53 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

125
third-party/dht/dht.c vendored
View File

@ -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,14 +1886,10 @@ 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) {
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");
@ -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)

View File

@ -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,