mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
can use DNS-0x20 draft casing.
git-svn-id: file:///svn/unbound/trunk@994 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
39b2a21a81
commit
130a5f2dee
10 changed files with 170 additions and 11 deletions
|
|
@ -977,7 +977,8 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
|||
cfg->msg_buffer_size, (size_t)cfg->outgoing_num_ports,
|
||||
cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
|
||||
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) {
|
||||
log_err("could not create outgoing sockets");
|
||||
worker_delete(worker);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
27 February 2008: Wouter
|
||||
- option to use caps for id randomness.
|
||||
|
||||
26 February 2008: Wouter
|
||||
- delay utility delays TCP as well. If the server that is forwarded
|
||||
to has a TCP error, the delay utility closes the connection.
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ libworker_setup(struct ub_ctx* ctx, int is_bg)
|
|||
(size_t)cfg->outgoing_num_ports, cfg->out_ifs,
|
||||
cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, -1,
|
||||
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) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@
|
|||
#include "util/data/msgparse.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/data/msgencode.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "util/netevent.h"
|
||||
#include "util/log.h"
|
||||
#include "util/net_help.h"
|
||||
|
|
@ -91,14 +92,19 @@ serviced_cmp(const void* key1, const void* key2)
|
|||
if(q1->qbuflen > q2->qbuflen)
|
||||
return 1;
|
||||
log_assert(q1->qbuflen == q2->qbuflen);
|
||||
/* will not detect alternate casing of qname */
|
||||
if((r = memcmp(q1->qbuf, q2->qbuf, q1->qbuflen)) != 0)
|
||||
log_assert(q1->qbuflen >= 15 /* 10 header, root, type, class */);
|
||||
/* 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;
|
||||
if(q1->dnssec != q2->dnssec) {
|
||||
if(q1->dnssec < q2->dnssec)
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -421,7 +427,7 @@ struct outside_network*
|
|||
outside_network_create(struct comm_base *base, 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, struct infra_cache* infra,
|
||||
struct ub_randstate* rnd)
|
||||
struct ub_randstate* rnd, int use_caps_for_id)
|
||||
{
|
||||
struct outside_network* outnet = (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->rnd = rnd;
|
||||
outnet->svcd_overhead = 0;
|
||||
outnet->use_caps_for_id = use_caps_for_id;
|
||||
#ifndef INET6
|
||||
do_ip6 = 0;
|
||||
#endif
|
||||
|
|
@ -912,10 +919,52 @@ serviced_delete(struct serviced_query* sq)
|
|||
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 */
|
||||
static void
|
||||
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 */
|
||||
ldns_buffer_clear(buff);
|
||||
ldns_buffer_write_u16(buff, 0); /* id placeholder */
|
||||
|
|
@ -968,6 +1017,49 @@ serviced_udp_send(struct serviced_query* sq, ldns_buffer* buff)
|
|||
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 */
|
||||
static void
|
||||
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 */
|
||||
sq->to_be_deleted = 1;
|
||||
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) {
|
||||
/* make a backup of the query, since the querystate processing
|
||||
* may send outgoing queries that overwrite the buffer.
|
||||
|
|
|
|||
|
|
@ -71,6 +71,8 @@ struct outside_network {
|
|||
/** serviced_callbacks malloc overhead when processing multiple
|
||||
* identical serviced queries to the same server. */
|
||||
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.
|
||||
|
|
@ -261,12 +263,14 @@ struct serviced_query {
|
|||
* @param num_tcp: number of outgoing tcp buffers to preallocate.
|
||||
* @param infra: pointer to infra cached used 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.
|
||||
*/
|
||||
struct outside_network* outside_network_create(struct comm_base* base,
|
||||
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,
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -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(do_ip6), int ATTR_UNUSED(port_base),
|
||||
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,
|
||||
sizeof(struct outside_network));
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ config_create()
|
|||
cfg->harden_large_queries = 0;
|
||||
cfg->harden_glue = 1;
|
||||
cfg->harden_dnssec_stripped = 1;
|
||||
cfg->use_caps_bits_for_id = 0;
|
||||
cfg->hide_identity = 0;
|
||||
cfg->hide_version = 0;
|
||||
cfg->identity = NULL;
|
||||
|
|
|
|||
|
|
@ -140,6 +140,8 @@ struct config_file {
|
|||
int harden_glue;
|
||||
/** harden against receiving no DNSSEC data for trust anchor */
|
||||
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 */
|
||||
char* chrootdir;
|
||||
|
|
|
|||
|
|
@ -143,10 +143,25 @@ query_dname_tolower(uint8_t* dname)
|
|||
}
|
||||
}
|
||||
|
||||
/** maximum compression pointer position pointed to */
|
||||
#define MAX_COMPRESS_POS 16384
|
||||
/** max number of compression ptrs to follow */
|
||||
#define MAX_COMPRESS_PTRS 256
|
||||
void
|
||||
pkt_dname_tolower(ldns_buffer* pkt, uint8_t* dname)
|
||||
{
|
||||
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
|
||||
pkt_dname_len(ldns_buffer* pkt)
|
||||
|
|
|
|||
|
|
@ -46,6 +46,9 @@
|
|||
#define UTIL_DATA_DNAME_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,
|
||||
* @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 */
|
||||
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
|
||||
* have to be lowercased, comparison routine does this.
|
||||
|
|
|
|||
Loading…
Reference in a new issue