Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2  * edns.c -- EDNS definitions (RFC 2671).
      3  *
      4  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
      5  *
      6  * See LICENSE for the license.
      7  *
      8  */
      9 
     10 
     11 #include "config.h"
     12 
     13 #include <string.h>
     14 #ifdef HAVE_SSL
     15 #include <openssl/opensslv.h>
     16 #include <openssl/evp.h>
     17 #endif
     18 
     19 #include "dns.h"
     20 #include "edns.h"
     21 #include "nsd.h"
     22 #include "query.h"
     23 
     24 #if !defined(HAVE_SSL) || !defined(HAVE_CRYPTO_MEMCMP)
     25 /* we need fixed time compare, pull it in from tsig.c */
     26 #define CRYPTO_memcmp memcmp_fixedtime
     27 int memcmp_fixedtime(const void *s1, const void *s2, size_t n);
     28 #endif
     29 
     30 void
     31 edns_init_data(edns_data_type *data, uint16_t max_length)
     32 {
     33 	memset(data, 0, sizeof(edns_data_type));
     34 	/* record type: OPT */
     35 	data->ok[1] = (TYPE_OPT & 0xff00) >> 8;	/* type_hi */
     36 	data->ok[2] = TYPE_OPT & 0x00ff;	/* type_lo */
     37 	/* udp payload size */
     38 	data->ok[3] = (max_length & 0xff00) >> 8; /* size_hi */
     39 	data->ok[4] = max_length & 0x00ff;	  /* size_lo */
     40 
     41 	data->error[1] = (TYPE_OPT & 0xff00) >> 8;	/* type_hi */
     42 	data->error[2] = TYPE_OPT & 0x00ff;		/* type_lo */
     43 	data->error[3] = (max_length & 0xff00) >> 8;	/* size_hi */
     44 	data->error[4] = max_length & 0x00ff;		/* size_lo */
     45 	data->error[5] = 1;	/* XXX Extended RCODE=BAD VERS */
     46 
     47 	/* COOKIE OPT HDR */
     48 	data->cookie[0] = (COOKIE_CODE & 0xff00) >> 8;
     49 	data->cookie[1] = (COOKIE_CODE & 0x00ff);
     50 	data->cookie[2] = (24 & 0xff00) >> 8;
     51 	data->cookie[3] = (24 & 0x00ff);
     52 }
     53 
     54 void
     55 edns_init_nsid(edns_data_type *data, uint16_t nsid_len)
     56 {
     57        /* NSID OPT HDR */
     58        data->nsid[0] = (NSID_CODE & 0xff00) >> 8;
     59        data->nsid[1] = (NSID_CODE & 0x00ff);
     60        data->nsid[2] = (nsid_len & 0xff00) >> 8;
     61        data->nsid[3] = (nsid_len & 0x00ff);
     62 }
     63 
     64 void
     65 edns_init_record(edns_record_type *edns)
     66 {
     67 	edns->status = EDNS_NOT_PRESENT;
     68 	edns->position = 0;
     69 	edns->maxlen = 0;
     70 	edns->opt_reserved_space = 0;
     71 	edns->dnssec_ok = 0;
     72 	edns->nsid = 0;
     73 	edns->zoneversion = 0;
     74 	edns->cookie_status = COOKIE_NOT_PRESENT;
     75 	edns->cookie_len = 0;
     76 	edns->ede = -1; /* -1 means no Extended DNS Error */
     77 	edns->ede_text = NULL;
     78 	edns->ede_text_len = 0;
     79 }
     80 
     81 /** handle a single edns option in the query */
     82 static int
     83 edns_handle_option(uint16_t optcode, uint16_t optlen, buffer_type* packet,
     84 	edns_record_type* edns, struct query* query, nsd_type* nsd)
     85 {
     86 	(void) query; /* in case edns options need the query structure */
     87 	/* handle opt code and read the optlen bytes from the packet */
     88 	switch(optcode) {
     89 	case NSID_CODE:
     90 		/* is NSID enabled? */
     91 		if(nsd->nsid_len > 0) {
     92 			edns->nsid = 1;
     93 			/* we have to check optlen, and move the buffer along */
     94 			buffer_skip(packet, optlen);
     95 			/* in the reply we need space for optcode+optlen+nsid_bytes */
     96 			edns->opt_reserved_space += OPT_HDR + nsd->nsid_len;
     97 		} else {
     98 			/* ignore option */
     99 			buffer_skip(packet, optlen);
    100 		}
    101 		break;
    102 	case COOKIE_CODE:
    103 		/* Cookies enabled? */
    104 		if(nsd->do_answer_cookie) {
    105 			if (optlen == 8)
    106 				edns->cookie_status = COOKIE_INVALID;
    107 			else if (optlen < 16 || optlen > 40)
    108 				return 0; /* FORMERR */
    109 			else
    110 				edns->cookie_status = COOKIE_UNVERIFIED;
    111 
    112 			edns->cookie_len = optlen;
    113 			memcpy(edns->cookie, buffer_current(packet), optlen);
    114 			buffer_skip(packet, optlen);
    115 			edns->opt_reserved_space += OPT_HDR + 24;
    116 		} else {
    117 			buffer_skip(packet, optlen);
    118 		}
    119 		break;
    120 	case ZONEVERSION_CODE:
    121 		edns->zoneversion = 1;
    122 		if(optlen > 0)
    123 			return 0;
    124 		break;
    125 	default:
    126 		buffer_skip(packet, optlen);
    127 		break;
    128 	}
    129 	return 1;
    130 }
    131 
    132 int
    133 edns_parse_record(edns_record_type *edns, buffer_type *packet,
    134 	query_type* query, nsd_type* nsd)
    135 {
    136 	/* OPT record type... */
    137 	uint8_t  opt_owner;
    138 	uint16_t opt_type;
    139 	uint16_t opt_class;
    140 	uint8_t  opt_version;
    141 	uint16_t opt_flags;
    142 	uint16_t opt_rdlen;
    143 
    144 	edns->position = buffer_position(packet);
    145 
    146 	if (!buffer_available(packet, (OPT_LEN + OPT_RDATA)))
    147 		return 0;
    148 
    149 	opt_owner = buffer_read_u8(packet);
    150 	opt_type = buffer_read_u16(packet);
    151 	if (opt_owner != 0 || opt_type != TYPE_OPT) {
    152 		/* Not EDNS.  */
    153 		buffer_set_position(packet, edns->position);
    154 		return 0;
    155 	}
    156 
    157 	opt_class = buffer_read_u16(packet);
    158 	(void)buffer_read_u8(packet); /* opt_extended_rcode */
    159 	opt_version = buffer_read_u8(packet);
    160 	opt_flags = buffer_read_u16(packet);
    161 	opt_rdlen = buffer_read_u16(packet);
    162 
    163 	if (opt_version != 0) {
    164 		/* The only error is VERSION not implemented */
    165 		edns->status = EDNS_ERROR;
    166 		return 1;
    167 	}
    168 
    169 	if (opt_rdlen > 0) {
    170 		if(!buffer_available(packet, opt_rdlen))
    171 			return 0;
    172 		if(opt_rdlen > 65530)
    173 			return 0;
    174 		/* there is more to come, read opt code */
    175 		while(opt_rdlen >= 4) {
    176 			uint16_t optcode = buffer_read_u16(packet);
    177 			uint16_t optlen = buffer_read_u16(packet);
    178 			opt_rdlen -= 4;
    179 			if(opt_rdlen < optlen)
    180 				return 0; /* opt too long, formerr */
    181 			opt_rdlen -= optlen;
    182 			if(!edns_handle_option(optcode, optlen, packet,
    183 				edns, query, nsd))
    184 				return 0;
    185 		}
    186 		if(opt_rdlen != 0)
    187 			return 0;
    188 	}
    189 
    190 	edns->status = EDNS_OK;
    191 	edns->maxlen = opt_class;
    192 	edns->dnssec_ok = opt_flags & DNSSEC_OK_MASK;
    193 	return 1;
    194 }
    195 
    196 size_t
    197 edns_reserved_space(edns_record_type *edns)
    198 {
    199 	/* MIEK; when a pkt is too large?? */
    200 	return edns->status == EDNS_NOT_PRESENT ? 0
    201 	     : (OPT_LEN + OPT_RDATA + edns->opt_reserved_space);
    202 }
    203 
    204 int siphash(const uint8_t *in, const size_t inlen,
    205                 const uint8_t *k, uint8_t *out, const size_t outlen);
    206 
    207 /** RFC 1982 comparison, uses unsigned integers, and tries to avoid
    208  * compiler optimization (eg. by avoiding a-b<0 comparisons),
    209  * this routine matches compare_serial(), for SOA serial number checks */
    210 static int
    211 compare_1982(uint32_t a, uint32_t b)
    212 {
    213 	/* for 32 bit values */
    214 	const uint32_t cutoff = ((uint32_t) 1 << (32 - 1));
    215 
    216 	if (a == b) {
    217 		return 0;
    218 	} else if ((a < b && b - a < cutoff) || (a > b && a - b > cutoff)) {
    219 		return -1;
    220 	} else {
    221 		return 1;
    222 	}
    223 }
    224 
    225 /** if we know that b is larger than a, return the difference between them,
    226  * that is the distance between them. in RFC1982 arith */
    227 static uint32_t
    228 subtract_1982(uint32_t a, uint32_t b)
    229 {
    230 	/* for 32 bit values */
    231 	const uint32_t cutoff = ((uint32_t) 1 << (32 - 1));
    232 
    233 	if(a == b)
    234 		return 0;
    235 	if(a < b && b - a < cutoff) {
    236 		return b-a;
    237 	}
    238 	if(a > b && a - b > cutoff) {
    239 		return ((uint32_t)0xffffffff) - (a-b-1);
    240 	}
    241 	/* wrong case, b smaller than a */
    242 	return 0;
    243 }
    244 
    245 void cookie_verify(query_type *q, struct nsd* nsd, uint32_t *now_p) {
    246 	uint8_t hash[8], hash2verify[8];
    247 	uint32_t cookie_time, now_uint32;
    248 	size_t verify_size;
    249 	int i;
    250 
    251 	/* We support only draft-sury-toorop-dnsop-server-cookies sizes */
    252 	if(q->edns.cookie_len != 24)
    253 		return;
    254 
    255 	if(q->edns.cookie[8] != 1)
    256 		return;
    257 
    258 	q->edns.cookie_status = COOKIE_INVALID;
    259 
    260 	cookie_time = (q->edns.cookie[12] << 24)
    261 	            | (q->edns.cookie[13] << 16)
    262 	            | (q->edns.cookie[14] <<  8)
    263 	            |  q->edns.cookie[15];
    264 
    265 	now_uint32 = *now_p ? *now_p : (*now_p = (uint32_t)time(NULL));
    266 
    267 	if(compare_1982(now_uint32, cookie_time) > 0) {
    268 		/* ignore cookies > 1 hour in past */
    269 		if (subtract_1982(cookie_time, now_uint32) > 3600)
    270 			return;
    271 	} else if (subtract_1982(now_uint32, cookie_time) > 300) {
    272 		/* ignore cookies > 5 minutes in future */
    273 		return;
    274 	}
    275 
    276 	memcpy(hash2verify, q->edns.cookie + 16, 8);
    277 
    278 #ifdef INET6
    279 	if(q->client_addr.ss_family == AF_INET6) {
    280 		memcpy(q->edns.cookie + 16, &((struct sockaddr_in6 *)&q->client_addr)->sin6_addr, 16);
    281 		verify_size = 32;
    282 	} else {
    283 		memcpy(q->edns.cookie + 16, &((struct sockaddr_in *)&q->client_addr)->sin_addr, 4);
    284 		verify_size = 20;
    285 	}
    286 #else
    287 	memcpy( q->edns.cookie + 16, &q->client_addr.sin_addr, 4);
    288 	verify_size = 20;
    289 #endif
    290 
    291 	q->edns.cookie_status = COOKIE_INVALID;
    292 	siphash(q->edns.cookie, verify_size,
    293 		nsd->cookie_secrets[0].cookie_secret, hash, 8);
    294 	if(CRYPTO_memcmp(hash2verify, hash, 8) == 0 ) {
    295 		if (subtract_1982(cookie_time, now_uint32) < 1800) {
    296 			q->edns.cookie_status = COOKIE_VALID_REUSE;
    297 			memcpy(q->edns.cookie + 16, hash, 8);
    298 		} else
    299 			q->edns.cookie_status = COOKIE_VALID;
    300 		return;
    301 	}
    302 	for(i = 1;
    303 	    i < (int)nsd->cookie_count && i < NSD_COOKIE_HISTORY_SIZE;
    304 	    i++) {
    305 		siphash(q->edns.cookie, verify_size,
    306 		        nsd->cookie_secrets[i].cookie_secret, hash, 8);
    307 		if(CRYPTO_memcmp(hash2verify, hash, 8) == 0 ) {
    308 			q->edns.cookie_status = COOKIE_VALID;
    309 			return;
    310 		}
    311 	}
    312 }
    313 
    314 void cookie_create(query_type *q, struct nsd* nsd, uint32_t *now_p)
    315 {
    316 	uint8_t  hash[8];
    317 	uint32_t now_uint32;
    318 
    319 	if (q->edns.cookie_status == COOKIE_VALID_REUSE)
    320 		return;
    321 
    322 	now_uint32 = *now_p ? *now_p : (*now_p = (uint32_t)time(NULL));
    323 	q->edns.cookie[ 8] = 1;
    324 	q->edns.cookie[ 9] = 0;
    325 	q->edns.cookie[10] = 0;
    326 	q->edns.cookie[11] = 0;
    327 	q->edns.cookie[12] = (now_uint32 & 0xFF000000) >> 24;
    328 	q->edns.cookie[13] = (now_uint32 & 0x00FF0000) >> 16;
    329 	q->edns.cookie[14] = (now_uint32 & 0x0000FF00) >>  8;
    330 	q->edns.cookie[15] =  now_uint32 & 0x000000FF;
    331 #ifdef INET6
    332 	if (q->client_addr.ss_family == AF_INET6) {
    333 		memcpy( q->edns.cookie + 16
    334 		      , &((struct sockaddr_in6 *)&q->client_addr)->sin6_addr, 16);
    335 		siphash(q->edns.cookie, 32, nsd->cookie_secrets[0].cookie_secret, hash, 8);
    336 	} else {
    337 		memcpy( q->edns.cookie + 16
    338 		      , &((struct sockaddr_in *)&q->client_addr)->sin_addr, 4);
    339 		siphash(q->edns.cookie, 20, nsd->cookie_secrets[0].cookie_secret, hash, 8);
    340 	}
    341 #else
    342 	memcpy( q->edns.cookie + 16, &q->client_addr.sin_addr, 4);
    343 	siphash(q->edns.cookie, 20, nsd->cookie_secrets[0].cookie_secret, hash, 8);
    344 #endif
    345 	memcpy(q->edns.cookie + 16, hash, 8);
    346 }
    347 
    348