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->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);
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue