can use DNS-0x20 draft casing.

git-svn-id: file:///svn/unbound/trunk@994 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2008-02-27 09:21:31 +00:00
parent 39b2a21a81
commit 130a5f2dee
10 changed files with 170 additions and 11 deletions

View file

@ -977,7 +977,8 @@ worker_init(struct worker* worker, struct config_file *cfg,
cfg->msg_buffer_size, (size_t)cfg->outgoing_num_ports, cfg->msg_buffer_size, (size_t)cfg->outgoing_num_ports,
cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
startport, cfg->do_tcp?cfg->outgoing_num_tcp:0, startport, cfg->do_tcp?cfg->outgoing_num_tcp:0,
worker->daemon->env->infra_cache, worker->rndstate); worker->daemon->env->infra_cache, worker->rndstate,
cfg->use_caps_bits_for_id);
if(!worker->back) { if(!worker->back) {
log_err("could not create outgoing sockets"); log_err("could not create outgoing sockets");
worker_delete(worker); worker_delete(worker);

View file

@ -1,3 +1,6 @@
27 February 2008: Wouter
- option to use caps for id randomness.
26 February 2008: Wouter 26 February 2008: Wouter
- delay utility delays TCP as well. If the server that is forwarded - delay utility delays TCP as well. If the server that is forwarded
to has a TCP error, the delay utility closes the connection. to has a TCP error, the delay utility closes the connection.

View file

@ -153,7 +153,7 @@ libworker_setup(struct ub_ctx* ctx, int is_bg)
(size_t)cfg->outgoing_num_ports, cfg->out_ifs, (size_t)cfg->outgoing_num_ports, cfg->out_ifs,
cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, -1, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, -1,
cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->do_tcp?cfg->outgoing_num_tcp:0,
w->env->infra_cache, w->env->rnd); w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id);
if(!w->is_bg || w->is_bg_thread) { if(!w->is_bg || w->is_bg_thread) {
lock_basic_unlock(&ctx->cfglock); lock_basic_unlock(&ctx->cfglock);
} }

View file

@ -46,6 +46,7 @@
#include "util/data/msgparse.h" #include "util/data/msgparse.h"
#include "util/data/msgreply.h" #include "util/data/msgreply.h"
#include "util/data/msgencode.h" #include "util/data/msgencode.h"
#include "util/data/dname.h"
#include "util/netevent.h" #include "util/netevent.h"
#include "util/log.h" #include "util/log.h"
#include "util/net_help.h" #include "util/net_help.h"
@ -91,14 +92,19 @@ serviced_cmp(const void* key1, const void* key2)
if(q1->qbuflen > q2->qbuflen) if(q1->qbuflen > q2->qbuflen)
return 1; return 1;
log_assert(q1->qbuflen == q2->qbuflen); log_assert(q1->qbuflen == q2->qbuflen);
/* will not detect alternate casing of qname */ log_assert(q1->qbuflen >= 15 /* 10 header, root, type, class */);
if((r = memcmp(q1->qbuf, q2->qbuf, q1->qbuflen)) != 0) /* alternate casing of qname is still the same query */
if((r = memcmp(q1->qbuf, q2->qbuf, 10)) != 0)
return r;
if((r = memcmp(q1->qbuf+q1->qbuflen-4, q2->qbuf+q2->qbuflen-4, 4)) != 0)
return r; return r;
if(q1->dnssec != q2->dnssec) { if(q1->dnssec != q2->dnssec) {
if(q1->dnssec < q2->dnssec) if(q1->dnssec < q2->dnssec)
return -1; return -1;
return 1; return 1;
} }
if((r = query_dname_compare(q1->qbuf+10, q2->qbuf+10)) != 0)
return r;
return sockaddr_cmp(&q1->addr, q1->addrlen, &q2->addr, q2->addrlen); return sockaddr_cmp(&q1->addr, q1->addrlen, &q2->addr, q2->addrlen);
} }
@ -421,7 +427,7 @@ struct outside_network*
outside_network_create(struct comm_base *base, size_t bufsize, outside_network_create(struct comm_base *base, size_t bufsize,
size_t num_ports, char** ifs, int num_ifs, int do_ip4, size_t num_ports, char** ifs, int num_ifs, int do_ip4,
int do_ip6, int port_base, size_t num_tcp, struct infra_cache* infra, int do_ip6, int port_base, size_t num_tcp, struct infra_cache* infra,
struct ub_randstate* rnd) struct ub_randstate* rnd, int use_caps_for_id)
{ {
struct outside_network* outnet = (struct outside_network*) struct outside_network* outnet = (struct outside_network*)
calloc(1, sizeof(struct outside_network)); calloc(1, sizeof(struct outside_network));
@ -436,6 +442,7 @@ outside_network_create(struct comm_base *base, size_t bufsize,
outnet->infra = infra; outnet->infra = infra;
outnet->rnd = rnd; outnet->rnd = rnd;
outnet->svcd_overhead = 0; outnet->svcd_overhead = 0;
outnet->use_caps_for_id = use_caps_for_id;
#ifndef INET6 #ifndef INET6
do_ip6 = 0; do_ip6 = 0;
#endif #endif
@ -912,10 +919,52 @@ serviced_delete(struct serviced_query* sq)
serviced_node_del(&sq->node, NULL); serviced_node_del(&sq->node, NULL);
} }
/** perturb a dname capitalization randomly */
static void
serviced_perturb_qname(struct ub_randstate* rnd, uint8_t* qbuf, size_t len)
{
uint8_t lablen;
uint8_t* d = qbuf + 10;
long int random = 0;
int bits = 0;
log_assert(len >= 10 + 5 /* offset qname, root, qtype, qclass */);
lablen = *d++;
while(lablen) {
while(lablen--) {
/* only perturb A-Z, a-z */
if(isalpha((int)*d)) {
/* get a random bit */
if(bits == 0) {
random = ub_random(rnd);
bits = 30;
}
if(random & 0x1) {
*d = (uint8_t)toupper((int)*d);
} else {
*d = (uint8_t)tolower((int)*d);
}
random >>= 1;
bits--;
}
d++;
}
lablen = *d++;
}
if(verbosity >= VERB_ALGO) {
char buf[LDNS_MAX_DOMAINLEN+1];
dname_str(qbuf+10, buf);
verbose(VERB_ALGO, "qname perturbed to %s", buf);
}
}
/** put serviced query into a buffer */ /** put serviced query into a buffer */
static void static void
serviced_encode(struct serviced_query* sq, ldns_buffer* buff, int with_edns) serviced_encode(struct serviced_query* sq, ldns_buffer* buff, int with_edns)
{ {
/* if we are using 0x20 bits for ID randomness, perturb them */
if(sq->outnet->use_caps_for_id) {
serviced_perturb_qname(sq->outnet->rnd, sq->qbuf, sq->qbuflen);
}
/* generate query */ /* generate query */
ldns_buffer_clear(buff); ldns_buffer_clear(buff);
ldns_buffer_write_u16(buff, 0); /* id placeholder */ ldns_buffer_write_u16(buff, 0); /* id placeholder */
@ -968,6 +1017,49 @@ serviced_udp_send(struct serviced_query* sq, ldns_buffer* buff)
return 1; return 1;
} }
/** check that perturbed qname is identical */
static int
serviced_check_qname(ldns_buffer* pkt, uint8_t* qbuf, size_t qbuflen)
{
uint8_t* d1 = ldns_buffer_at(pkt, 12);
uint8_t* d2 = qbuf+10;
uint8_t len1, len2;
int count = 0;
log_assert(qbuflen >= 15 /* 10 header, root, type, class */);
len1 = *d1++;
len2 = *d2++;
if(ldns_buffer_limit(pkt) < 12+1+4) /* packet too small for qname */
return 0;
while(len1 != 0 || len2 != 0) {
if(LABEL_IS_PTR(len1)) {
d1 = ldns_buffer_at(pkt, PTR_OFFSET(len1, *d1));
if(d1 >= ldns_buffer_at(pkt, ldns_buffer_limit(pkt)))
return 0;
len1 = *d1++;
if(count++ > MAX_COMPRESS_PTRS)
return 0;
continue;
}
if(d2 > qbuf+qbuflen)
return 0;
if(len1 != len2)
return 0;
if(len1 > LDNS_MAX_LABELLEN)
return 0;
log_assert(len1 <= LDNS_MAX_LABELLEN);
log_assert(len2 <= LDNS_MAX_LABELLEN);
log_assert(len1 == len2 && len1 != 0);
/* compare the labels - bitwise identical */
if(memcmp(d1, d2, len1) != 0)
return 0;
d1 += len1;
d2 += len2;
len1 = *d1++;
len2 = *d2++;
}
return 1;
}
/** call the callbacks for a serviced query */ /** call the callbacks for a serviced query */
static void static void
serviced_callbacks(struct serviced_query* sq, int error, struct comm_point* c, serviced_callbacks(struct serviced_query* sq, int error, struct comm_point* c,
@ -985,6 +1077,36 @@ serviced_callbacks(struct serviced_query* sq, int error, struct comm_point* c,
log_assert(rem); /* should have been present */ log_assert(rem); /* should have been present */
sq->to_be_deleted = 1; sq->to_be_deleted = 1;
verbose(VERB_ALGO, "svcd callbacks start"); verbose(VERB_ALGO, "svcd callbacks start");
if(sq->outnet->use_caps_for_id && error == NETEVENT_NOERROR && c) {
/* noerror and nxdomain must have a qname in reply */
if(ldns_buffer_read_u16_at(c->buffer, 4) == 0 &&
(LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer))
== LDNS_RCODE_NOERROR ||
LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer))
== LDNS_RCODE_NXDOMAIN)) {
verbose(VERB_OPS, "no qname in reply to check 0x20ID");
log_addr(VERB_OPS, "from server",
&sq->addr, sq->addrlen);
log_buf(VERB_OPS, "for packet", c->buffer);
error = NETEVENT_CLOSED;
c = NULL;
} else if(ldns_buffer_read_u16_at(c->buffer, 4) > 0 &&
!serviced_check_qname(c->buffer, sq->qbuf,
sq->qbuflen)) {
verbose(VERB_OPS, "wrong 0x20-ID in reply qname, "
"answer dropped");
log_addr(VERB_OPS, "from server",
&sq->addr, sq->addrlen);
log_buf(VERB_OPS, "for packet", c->buffer);
error = NETEVENT_CLOSED;
c = NULL;
} else {
verbose(VERB_ALGO, "good 0x20-ID in reply qname");
/* cleanup caps, prettier cache contents. */
pkt_dname_tolower(c->buffer,
ldns_buffer_at(c->buffer, 12));
}
}
if(dobackup && c) { if(dobackup && c) {
/* make a backup of the query, since the querystate processing /* make a backup of the query, since the querystate processing
* may send outgoing queries that overwrite the buffer. * may send outgoing queries that overwrite the buffer.

View file

@ -71,6 +71,8 @@ struct outside_network {
/** serviced_callbacks malloc overhead when processing multiple /** serviced_callbacks malloc overhead when processing multiple
* identical serviced queries to the same server. */ * identical serviced queries to the same server. */
size_t svcd_overhead; size_t svcd_overhead;
/** use x20 bits to encode additional ID random bits */
int use_caps_for_id;
/** /**
* Array of udp comm point* that are used to listen to pending events. * Array of udp comm point* that are used to listen to pending events.
@ -261,12 +263,14 @@ struct serviced_query {
* @param num_tcp: number of outgoing tcp buffers to preallocate. * @param num_tcp: number of outgoing tcp buffers to preallocate.
* @param infra: pointer to infra cached used for serviced queries. * @param infra: pointer to infra cached used for serviced queries.
* @param rnd: stored to create random numbers for serviced queries. * @param rnd: stored to create random numbers for serviced queries.
* @param use_caps_for_id: enable to use 0x20 bits to encode id randomness.
* @return: the new structure (with no pending answers) or NULL on error. * @return: the new structure (with no pending answers) or NULL on error.
*/ */
struct outside_network* outside_network_create(struct comm_base* base, struct outside_network* outside_network_create(struct comm_base* base,
size_t bufsize, size_t num_ports, char** ifs, int num_ifs, size_t bufsize, size_t num_ports, char** ifs, int num_ifs,
int do_ip4, int do_ip6, int port_base, size_t num_tcp, int do_ip4, int do_ip6, int port_base, size_t num_tcp,
struct infra_cache* infra, struct ub_randstate* rnd); struct infra_cache* infra, struct ub_randstate* rnd,
int use_caps_for_id);
/** /**
* Delete outside_network structure. * Delete outside_network structure.

View file

@ -686,7 +686,7 @@ outside_network_create(struct comm_base* base, size_t bufsize,
int ATTR_UNUSED(num_ifs), int ATTR_UNUSED(do_ip4), int ATTR_UNUSED(num_ifs), int ATTR_UNUSED(do_ip4),
int ATTR_UNUSED(do_ip6), int ATTR_UNUSED(port_base), int ATTR_UNUSED(do_ip6), int ATTR_UNUSED(port_base),
size_t ATTR_UNUSED(num_tcp), struct infra_cache* ATTR_UNUSED(infra), size_t ATTR_UNUSED(num_tcp), struct infra_cache* ATTR_UNUSED(infra),
struct ub_randstate* ATTR_UNUSED(rnd)) struct ub_randstate* ATTR_UNUSED(rnd), int ATTR_UNUSED(use_caps_for_id))
{ {
struct outside_network* outnet = calloc(1, struct outside_network* outnet = calloc(1,
sizeof(struct outside_network)); sizeof(struct outside_network));

View file

@ -117,6 +117,7 @@ config_create()
cfg->harden_large_queries = 0; cfg->harden_large_queries = 0;
cfg->harden_glue = 1; cfg->harden_glue = 1;
cfg->harden_dnssec_stripped = 1; cfg->harden_dnssec_stripped = 1;
cfg->use_caps_bits_for_id = 0;
cfg->hide_identity = 0; cfg->hide_identity = 0;
cfg->hide_version = 0; cfg->hide_version = 0;
cfg->identity = NULL; cfg->identity = NULL;

View file

@ -140,6 +140,8 @@ struct config_file {
int harden_glue; int harden_glue;
/** harden against receiving no DNSSEC data for trust anchor */ /** harden against receiving no DNSSEC data for trust anchor */
int harden_dnssec_stripped; int harden_dnssec_stripped;
/** use 0x20 bits in query as random ID bits */
int use_caps_bits_for_id;
/** chrootdir, if not "" or chroot will be done */ /** chrootdir, if not "" or chroot will be done */
char* chrootdir; char* chrootdir;

View file

@ -143,10 +143,25 @@ query_dname_tolower(uint8_t* dname)
} }
} }
/** maximum compression pointer position pointed to */ void
#define MAX_COMPRESS_POS 16384 pkt_dname_tolower(ldns_buffer* pkt, uint8_t* dname)
/** max number of compression ptrs to follow */ {
#define MAX_COMPRESS_PTRS 256 uint8_t lablen;
lablen = *dname++;
while(lablen) {
if(LABEL_IS_PTR(lablen)) {
dname = ldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
lablen = *dname++;
continue;
}
while(lablen--) {
*dname = (uint8_t)tolower((int)*dname);
dname++;
}
lablen = *dname++;
}
}
size_t size_t
pkt_dname_len(ldns_buffer* pkt) pkt_dname_len(ldns_buffer* pkt)

View file

@ -46,6 +46,9 @@
#define UTIL_DATA_DNAME_H #define UTIL_DATA_DNAME_H
#include "util/storage/lruhash.h" #include "util/storage/lruhash.h"
/** max number of compression ptrs to follow */
#define MAX_COMPRESS_PTRS 256
/** /**
* Determine length of dname in buffer, no compression ptrs allowed, * Determine length of dname in buffer, no compression ptrs allowed,
* @param query: the ldns buffer, current position at start of dname. * @param query: the ldns buffer, current position at start of dname.
@ -65,6 +68,14 @@ size_t dname_valid(uint8_t* dname, size_t len);
/** lowercase query dname */ /** lowercase query dname */
void query_dname_tolower(uint8_t* dname); void query_dname_tolower(uint8_t* dname);
/**
* lowercase pkt dname (follows compression pointers)
* @param pkt: the packet, used to follow compression pointers. Position
* is unchanged.
* @param dname: start of dname in packet.
*/
void pkt_dname_tolower(ldns_buffer* pkt, uint8_t* dname);
/** /**
* Compare query dnames (uncompressed storage). The Dnames passed do not * Compare query dnames (uncompressed storage). The Dnames passed do not
* have to be lowercased, comparison routine does this. * have to be lowercased, comparison routine does this.