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