Skip to content

Commit

Permalink
Use a keyed hash function instead of a CRC to lookup questions sharin…
Browse files Browse the repository at this point in the history
…g the same query id
  • Loading branch information
jedisct1 committed Jan 4, 2015
1 parent c6c544b commit a9a99af
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 51 deletions.
1 change: 1 addition & 0 deletions dnscrypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ struct context {
uint8_t crypt_publickey[crypto_box_PUBLICKEYBYTES];
uint8_t crypt_secretkey[crypto_box_SECRETKEYBYTES];
uint64_t nonce_ts_last;
unsigned char hash_key[crypto_shorthash_KEYBYTES];
};

int dnscrypt_cmp_client_nonce(const uint8_t
Expand Down
2 changes: 2 additions & 0 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,8 @@ main(int argc, const char **argv)
exit(1);
}

randombytes_buf(c.hash_key, sizeof c.hash_key);

if ((c.event_loop = event_base_new()) == NULL) {
logger(LOG_ERR, "Unable to initialize the event loop.");
exit(1);
Expand Down
60 changes: 19 additions & 41 deletions rfc1035.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,52 +170,30 @@ extract_name(struct dns_header *header, size_t plen, unsigned char **pp, char
}
}

/* CRC the question section. This is used to safely detect query
/* Hash the question section. This is used to safely detect query
retransmision and to detect answers to questions we didn't ask, which
might be poisoning attacks. Note that we decode the name rather
than CRC the raw bytes, since replies might be compressed differently.
than hash the raw bytes, since replies might be compressed differently.
We ignore case in the names for the same reason. Return all-ones
if there is not question section. */
unsigned int
questions_crc(struct dns_header *header, size_t plen, char *name)
uint64_t
questions_hash(struct dns_header *header, size_t plen, char *name, const unsigned char key[crypto_shorthash_KEYBYTES])
{
int q;
unsigned int crc = 0xffffffff;
unsigned char *p1, *p = (unsigned char *)(header+1);

for (q = ntohs(header->qdcount); q != 0; q--)
{
if (!extract_name(header, plen, &p, name, 1, 4))
return crc; /* bad packet */

for (p1 = (unsigned char *)name; *p1; p1++)
{
int i = 8;
char c = *p1;

if (c >= 'A' && c <= 'Z')
c += 'a' - 'A';

crc ^= c << 24;
while (i--)
crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
}

/* CRC the class and type as well */
for (p1 = p; p1 < p+4; p1++)
{
int i = 8;
crc ^= *p1 << 24;
while (i--)
crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
}

p += 4;
if (!CHECK_LEN(header, p, plen, 0))
return crc; /* bad packet */
}

return crc;
unsigned char qb[MAXDNAME + 4];
uint64_t hash = 0xffffffffffffffffULL;
unsigned char *p = (unsigned char *)(header+1);
size_t name_len;

if (ntohs(header->qdcount) != 1 ||
!extract_name(header, plen, &p, name, 1, 4) ||
(name_len = strlen(name)) > (sizeof qb - 4)) {
return hash;
}
memcpy(qb, name, name_len);
memcpy(qb + name_len, p, 4);
crypto_shorthash((unsigned char *) &hash, qb, name_len + 4ULL, key);

return hash;
}

static unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes)
Expand Down
3 changes: 2 additions & 1 deletion rfc1035.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@

#include "compat.h"
#include "dns-protocol.h"
#include <sodium.h>

unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
uint64_t questions_hash(struct dns_header *header, size_t plen, char *buff, const unsigned char key[crypto_shorthash_KEYBYTES]);
int extract_name(struct dns_header *header, size_t plen, unsigned char **pp, char
*name, int isExtract, int extrabytes);
int add_resource_record(struct dns_header *header, unsigned int nameoffset, unsigned char **pp,
Expand Down
16 changes: 8 additions & 8 deletions udp_request.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

#include "dnscrypt.h"

typedef struct SendtoWithRetryCtx_ {
Expand Down Expand Up @@ -349,7 +350,7 @@ client_to_proxy_cb(evutil_socket_t client_proxy_handle, short ev_flags,
}

udp_request->id = ntohs(header->id);
udp_request->crc = questions_crc(header, dns_query_len, c->namebuff);
udp_request->hash = questions_hash(header, dns_query_len, c->namebuff, c->hash_key);

udp_request->timeout_timer =
evtimer_new(udp_request->context->event_loop, timeout_timer_cb,
Expand All @@ -372,18 +373,17 @@ client_to_proxy_cb(evutil_socket_t client_proxy_handle, short ev_flags,
}

/*
* Find corresponding request by DNS id and crc of questions.
* Don't check crc if not know (0xffffffff).
* Find corresponding request by DNS id and hash of questions.
* Don't check hash if not know (0xffffffffffffffff).
*/
static UDPRequest *
lookup_request(struct context *c, uint16_t id, unsigned int crc)
lookup_request(struct context *c, uint16_t id, uint64_t hash)
{
UDPRequest *scanned_udp_request;
TAILQ_FOREACH(scanned_udp_request, &c->udp_request_queue, queue) {
if (id == scanned_udp_request->id
&& (scanned_udp_request->crc == crc || crc == 0xffffffff)) {
&& (scanned_udp_request->hash == hash || hash == 0xffffffffffffffffULL)) {
return scanned_udp_request;
break;
}
}
return NULL;
Expand Down Expand Up @@ -425,8 +425,8 @@ resolver_to_proxy_cb(evutil_socket_t proxy_resolver_handle, short ev_flags,

struct dns_header *header = (struct dns_header *)dns_reply;
uint16_t id = ntohs(header->id);
unsigned int crc = questions_crc(header, dns_reply_len, c->namebuff);
udp_request = lookup_request(c, id, crc);
uint64_t hash = questions_hash(header, dns_reply_len, c->namebuff, c->hash_key);
udp_request = lookup_request(c, id, hash);
if (udp_request == NULL) {
logger(LOG_ERR, "Received a reply that doesn't match any active query");
return;
Expand Down
2 changes: 1 addition & 1 deletion udp_request.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ typedef struct UDPRequestStatus_ {

typedef struct UDPRequest_ {
uint16_t id;
unsigned int crc;
uint64_t hash;
TAILQ_ENTRY(UDPRequest_) queue;
uint8_t client_nonce[crypto_box_HALF_NONCEBYTES];
uint8_t nmkey[crypto_box_BEFORENMBYTES];
Expand Down

0 comments on commit a9a99af

Please sign in to comment.