Skip to content

Implement BEP-42: DHT Security extension #43

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
227 changes: 224 additions & 3 deletions dht.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ struct peer {
#define DHT_SEARCH_RETRANSMIT 10
#endif

#ifndef DHT_BEP42_ENFORCE
#define DHT_BEP42_ENFORCE 0
#endif

struct storage {
unsigned char id[20];
int numpeers, maxpeers;
Expand Down Expand Up @@ -293,6 +297,8 @@ struct parsed_message {
unsigned char values6[PARSE_VALUES6_LEN];
unsigned short values6_len;
unsigned short want;
unsigned char ip[18];
unsigned short ip_len;
};

static int parse_message(const unsigned char *buf, int buflen,
Expand All @@ -315,6 +321,9 @@ static int have_v = 0;
static unsigned char my_v[9];
static unsigned char secret[8];
static unsigned char oldsecret[8];
static struct sockaddr_storage my_addr;
static int my_addr_len;
static unsigned int my_addr_votes = 0;

static struct bucket *buckets = NULL;
static struct bucket *buckets6 = NULL;
Expand All @@ -341,6 +350,126 @@ static time_t expire_stuff_time;
static time_t token_bucket_time;
static int token_bucket_tokens;

static const uint32_t crc32c_table[256] = {
0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
};

static uint32_t
crc32c(const unsigned char *data, size_t len)
{
uint32_t crc = 0xffffffff;

while (len--)
crc = crc32c_table[(crc ^ *data++) & 0xff] ^ (crc >> 8);

return crc ^ 0xffffffff;
}

static uint32_t
compute_prefix(const unsigned char *id, const struct sockaddr *sa)
{
unsigned char buf[8];
const unsigned char *ip;
uint32_t crc = 0;

if(sa->sa_family == AF_INET) {
struct sockaddr_in *sin = (struct sockaddr_in*)sa;
ip = (unsigned char*)&sin->sin_addr;
buf[0] = (ip[0] & 0x3) | (id[19] & 0x7) << 5;
buf[1] = ip[1] & 0xf;
buf[2] = ip[2] & 0x3f;
buf[3] = ip[3] & 0xff;
crc = crc32c(buf, 4);
} else if(sa->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa;
ip = (unsigned char*)&sin6->sin6_addr;
buf[0] = (ip[0] & 0x1) | (id[19] & 0x7) << 5;
buf[1] = ip[1] & 0x3;
buf[2] = ip[2] & 0x7;
buf[3] = ip[3] & 0xf;
buf[4] = ip[4] & 0x1f;
buf[5] = ip[5] & 0x3f;
buf[6] = ip[6] & 0x7f;
buf[7] = ip[7] & 0xff;
crc = crc32c(buf, 8);
}

return crc;
}

static int
is_prefix_valid(const unsigned char *id, const struct sockaddr *sa)
{
uint32_t prefix = compute_prefix(id, sa);

return id[0] == (prefix >> 24) &&
id[1] == ((prefix >> 16) & 0xff) &&
(id[2] & 0xf8) == ((prefix >> 8) & 0xf8);
}

FILE *dht_debug = NULL;

#ifdef __GNUC__
Expand Down Expand Up @@ -2077,6 +2206,40 @@ dht_periodic(const void *buf, size_t buflen,

switch(message) {
case REPLY:
if(m.ip_len == 6 || m.ip_len == 18) {
struct sockaddr_storage ss;
int sslen;
if (m.ip_len == 6) {
struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
sin->sin_family = AF_INET;
memcpy(&sin->sin_addr, m.ip, 4);
memcpy(&sin->sin_port, m.ip + 4, 2);
sslen = sizeof(*sin);
} else if (m.ip_len == 18) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
sin6->sin6_family = AF_INET6;
memcpy(&sin6->sin6_addr, m.ip, 16);
memcpy(&sin6->sin6_port, m.ip + 16, 2);
sslen = sizeof(*sin6);
}
if (!my_addr_votes) {
memcpy(&my_addr, &ss, sslen);
my_addr_len = sslen;
my_addr_votes++;
} else if (my_addr_len == sslen &&
!memcmp(&my_addr, &ss, sslen)) {
if (my_addr_votes == 10) {
uint32_t prefix = compute_prefix(myid,
(struct sockaddr *)&my_addr);
myid[0] = prefix >> 24;
myid[1] = (prefix >> 16) & 0xff;
myid[2] = ((prefix >> 8) & 0xf8) | (myid[2] & 0x7);
my_addr_votes = 0;
} else
my_addr_votes++;
} else
my_addr_votes--;
}
if(m.tid_len != 4) {
debugf("Broken node truncates transaction ids: ");
debug_printable(buf, buflen);
Expand Down Expand Up @@ -2150,7 +2313,11 @@ dht_periodic(const void *buf, size_t buflen,
another request. */
search_send_get_peers(sr, NULL);
}
#if DHT_BEP42_ENFORCE > 0
if(sr && is_prefix_valid(m.id, from)) {
#else
if(sr) {
#endif
insert_search_node(m.id, from, fromlen, sr,
1, m.token, m.token_len);
if(m.values_len > 0 || m.values6_len > 0) {
Expand Down Expand Up @@ -2532,7 +2699,21 @@ send_pong(const struct sockaddr *sa, int salen,
{
char buf[512];
int i = 0, rc;
rc = snprintf(buf + i, 512 - i, "d1:rd2:id20:"); INC(i, rc, 512);
rc = snprintf(buf + i, 512 - i, "d2:ip"); INC(i, rc, 512);
if (sa->sa_family == AF_INET) {
struct sockaddr_in *sin = (struct sockaddr_in*)sa;
rc = snprintf(buf + i, 512 - i, "6:"); INC(i, rc, 512);
COPY(buf, i, &sin->sin_addr, 4, 512);
COPY(buf, i, &sin->sin_port, 2, 512);
} else if (sa->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa;
rc = snprintf(buf + i, 512 - i, "18:"); INC(i, rc, 512);
COPY(buf, i, &sin6->sin6_addr, 16, 512);
COPY(buf, i, &sin6->sin6_port, 2, 512);
} else {
abort();
}
rc = snprintf(buf + i, 512 - i, "1:rd2:id20:"); INC(i, rc, 512);
COPY(buf, i, myid, 20, 512);
rc = snprintf(buf + i, 512 - i, "e1:t%d:", tid_len); INC(i, rc, 512);
COPY(buf, i, tid, tid_len, 512);
Expand Down Expand Up @@ -2585,7 +2766,21 @@ send_nodes_peers(const struct sockaddr *sa, int salen,
char buf[2048];
int i = 0, rc, j0, j, k, len;

rc = snprintf(buf + i, 2048 - i, "d1:rd2:id20:"); INC(i, rc, 2048);
rc = snprintf(buf + i, 2048 - i, "d2:ip"); INC(i, rc, 2048);
if (sa->sa_family == AF_INET) {
struct sockaddr_in *sin = (struct sockaddr_in*)sa;
rc = snprintf(buf + i, 2048 - i, "6:"); INC(i, rc, 2048);
COPY(buf, i, &sin->sin_addr, 4, 2048);
COPY(buf, i, &sin->sin_port, 2, 2048);
} else if (sa->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa;
rc = snprintf(buf + i, 2048 - i, "18:"); INC(i, rc, 2048);
COPY(buf, i, &sin6->sin6_addr, 16, 2048);
COPY(buf, i, &sin6->sin6_port, 2, 2048);
} else {
abort();
}
rc = snprintf(buf + i, 2048 - i, "1:rd2:id20:"); INC(i, rc, 2048);
COPY(buf, i, myid, 20, 2048);
if(nodes_len > 0) {
rc = snprintf(buf + i, 2048 - i, "5:nodes%d:", nodes_len);
Expand Down Expand Up @@ -2815,7 +3010,21 @@ send_peer_announced(const struct sockaddr *sa, int salen,
char buf[512];
int i = 0, rc;

rc = snprintf(buf + i, 512 - i, "d1:rd2:id20:"); INC(i, rc, 512);
rc = snprintf(buf + i, 512 - i, "d2:ip"); INC(i, rc, 512);
if (sa->sa_family == AF_INET) {
struct sockaddr_in *sin = (struct sockaddr_in*)sa;
rc = snprintf(buf + i, 512 - i, "6:"); INC(i, rc, 512);
COPY(buf, i, &sin->sin_addr, 4, 512);
COPY(buf, i, &sin->sin_port, 2, 512);
} else if (sa->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa;
rc = snprintf(buf + i, 512 - i, "18:"); INC(i, rc, 512);
COPY(buf, i, &sin6->sin6_addr, 16, 512);
COPY(buf, i, &sin6->sin6_port, 2, 512);
} else {
abort();
}
rc = snprintf(buf + i, 512 - i, "1:rd2:id20:"); INC(i, rc, 512);
COPY(buf, i, myid, 20, 512);
rc = snprintf(buf + i, 512 - i, "e1:t%d:", tid_len);
INC(i, rc, 512);
Expand Down Expand Up @@ -3042,6 +3251,18 @@ parse_message(const unsigned char *buf, int buflen,
debugf("eek... unexpected end for want.\n");
}

p = dht_memmem(buf, buflen, "2:ip", 4);
if(p) {
long l;
char *q;
l = strtol((char*)p + 4, &q, 10);
if(q && *q == ':' && l > 0 && l <= 18) {
CHECK(q + 1, l);
memcpy(m->ip, q + 1, l);
m->ip_len = l;
}
}

#undef CHECK

if(dht_memmem(buf, buflen, "1:y1:r", 6))
Expand Down