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