1 /*
2  * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * Portions copyright (C) 2004 Anselm M. Hoffmeister
5  * <stockholm@users.sourceforge.net>.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of the
10  * License, or any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  * 02110-1301, USA.
21  *
22  * You can also choose to distribute this program under the terms of
23  * the Unmodified Binary Distribution Licence (as given in the file
24  * COPYING.UBDL), provided that you have satisfied its requirements.
25  */
26 
27 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
28 
29 #include <stdint.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <stdio.h>
33 #include <ctype.h>
34 #include <errno.h>
35 #include <byteswap.h>
36 #include <ipxe/refcnt.h>
37 #include <ipxe/iobuf.h>
38 #include <ipxe/xfer.h>
39 #include <ipxe/open.h>
40 #include <ipxe/resolv.h>
41 #include <ipxe/retry.h>
42 #include <ipxe/tcpip.h>
43 #include <ipxe/settings.h>
44 #include <ipxe/features.h>
45 #include <ipxe/job.h>
46 #include <ipxe/dhcp.h>
47 #include <ipxe/dhcpv6.h>
48 #include <ipxe/dns.h>
49 
50 /** @file
51  *
52  * DNS protocol
53  *
54  */
55 
56 FEATURE ( FEATURE_PROTOCOL, "DNS", DHCP_EB_FEATURE_DNS, 1 );
57 
58 /* Disambiguate the various error causes */
59 #define ENXIO_NO_RECORD __einfo_error ( EINFO_ENXIO_NO_RECORD )
60 #define EINFO_ENXIO_NO_RECORD \
61 	__einfo_uniqify ( EINFO_ENXIO, 0x01, "DNS name does not exist" )
62 #define ENXIO_NO_NAMESERVER __einfo_error ( EINFO_ENXIO_NO_NAMESERVER )
63 #define EINFO_ENXIO_NO_NAMESERVER \
64 	__einfo_uniqify ( EINFO_ENXIO, 0x02, "No DNS servers available" )
65 
66 /** A DNS server list */
67 struct dns_server {
68 	/** Server list */
69 	union {
70 		/** IPv4 addresses */
71 		struct in_addr *in;
72 		/** IPv6 addresses */
73 		struct in6_addr *in6;
74 		/** Raw data */
75 		void *data;
76 	};
77 	/** Number of servers */
78 	unsigned int count;
79 };
80 
81 /** IPv4 DNS server list */
82 static struct dns_server dns4;
83 
84 /** IPv6 DNS server list */
85 static struct dns_server dns6;
86 
87 /** Total number of DNS servers */
88 static unsigned int dns_count;
89 
90 /** Current DNS server index */
91 static unsigned int dns_index;
92 
93 /** The DNS search list */
94 static struct dns_name dns_search;
95 
96 /**
97  * Encode a DNS name using RFC1035 encoding
98  *
99  * @v string		DNS name as a string
100  * @v name		DNS name to fill in
101  * @ret len		Length of DNS name, or negative error
102  */
dns_encode(const char * string,struct dns_name * name)103 int dns_encode ( const char *string, struct dns_name *name ) {
104 	uint8_t *start = ( name->data + name->offset );
105 	uint8_t *end = ( name->data + name->len );
106 	uint8_t *dst = start;
107 	size_t len = 0;
108 	char c;
109 
110 	/* Encode name */
111 	while ( ( c = *(string++) ) ) {
112 
113 		/* Handle '.' separators */
114 		if ( c == '.' ) {
115 
116 			/* Reject consecutive '.' */
117 			if ( ( len == 0 ) && ( dst != start ) )
118 				return -EINVAL;
119 
120 			/* Terminate if this is the trailing '.' */
121 			if ( *string == '\0' )
122 				break;
123 
124 			/* Reject initial non-terminating '.' */
125 			if ( len == 0 )
126 				return -EINVAL;
127 
128 			/* Reset length */
129 			len = 0;
130 
131 		} else {
132 
133 			/* Increment length */
134 			len++;
135 
136 			/* Check for overflow */
137 			if ( len > DNS_MAX_LABEL_LEN )
138 				return -EINVAL;
139 		}
140 
141 		/* Copy byte, update length */
142 		if ( ++dst < end ) {
143 			*dst = c;
144 			dst[-len] = len;
145 		}
146 	}
147 
148 	/* Add terminating root marker */
149 	if ( len )
150 		dst++;
151 	if ( dst < end )
152 		*dst = '\0';
153 	dst++;
154 
155 	return ( dst - start );
156 }
157 
158 /**
159  * Find start of valid label within an RFC1035-encoded DNS name
160  *
161  * @v name		DNS name
162  * @v offset		Current offset
163  * @ret offset		Offset of label, or negative error
164  */
dns_label(struct dns_name * name,size_t offset)165 static int dns_label ( struct dns_name *name, size_t offset ) {
166 	const uint8_t *byte;
167 	const uint16_t *word;
168 	size_t len;
169 	size_t ptr;
170 
171 	while ( 1 ) {
172 
173 		/* Fail if we have overrun the DNS name */
174 		if ( ( offset + sizeof ( *byte) ) > name->len )
175 			return -EINVAL;
176 		byte = ( name->data + offset );
177 
178 		/* Follow compression pointer, if applicable */
179 		if ( DNS_IS_COMPRESSED ( *byte ) ) {
180 
181 			/* Fail if we have overrun the DNS name */
182 			if ( ( offset + sizeof ( *word ) ) > name->len )
183 				return -EINVAL;
184 			word = ( name->data + offset );
185 
186 			/* Extract pointer to new offset */
187 			ptr = DNS_COMPRESSED_OFFSET ( ntohs ( *word ) );
188 
189 			/* Fail if pointer does not point backwards.
190 			 * (This guarantees termination of the
191 			 * function.)
192 			 */
193 			if ( ptr >= offset )
194 				return -EINVAL;
195 
196 			/* Continue from new offset */
197 			offset = ptr;
198 			continue;
199 		}
200 
201 		/* Fail if we have overrun the DNS name */
202 		len = *byte;
203 		if ( ( offset + sizeof ( *byte ) + len ) > name->len )
204 			return -EINVAL;
205 
206 		/* We have a valid label */
207 		return offset;
208 	}
209 }
210 
211 /**
212  * Decode RFC1035-encoded DNS name
213  *
214  * @v name		DNS name
215  * @v data		Output buffer
216  * @v len		Length of output buffer
217  * @ret len		Length of decoded DNS name, or negative error
218  */
dns_decode(struct dns_name * name,char * data,size_t len)219 int dns_decode ( struct dns_name *name, char *data, size_t len ) {
220 	unsigned int recursion_limit = name->len; /* Generous upper bound */
221 	int offset = name->offset;
222 	const uint8_t *label;
223 	size_t decoded_len = 0;
224 	size_t label_len;
225 	size_t copy_len;
226 
227 	while ( recursion_limit-- ) {
228 
229 		/* Find valid DNS label */
230 		offset = dns_label ( name, offset );
231 		if ( offset < 0 )
232 			return offset;
233 
234 		/* Terminate if we have reached the root */
235 		label = ( name->data + offset );
236 		label_len = *(label++);
237 		if ( label_len == 0 ) {
238 			if ( decoded_len < len )
239 				*data = '\0';
240 			return decoded_len;
241 		}
242 
243 		/* Prepend '.' if applicable */
244 		if ( decoded_len && ( decoded_len++ < len ) )
245 			*(data++) = '.';
246 
247 		/* Copy label to output buffer */
248 		copy_len = ( ( decoded_len < len ) ? ( len - decoded_len ) : 0);
249 		if ( copy_len > label_len )
250 			copy_len = label_len;
251 		memcpy ( data, label, copy_len );
252 		data += copy_len;
253 		decoded_len += label_len;
254 
255 		/* Move to next label */
256 		offset += ( sizeof ( *label ) + label_len );
257 	}
258 
259 	/* Recursion limit exceeded */
260 	return -EINVAL;
261 }
262 
263 /**
264  * Compare DNS names for equality
265  *
266  * @v first		First DNS name
267  * @v second		Second DNS name
268  * @ret rc		Return status code
269  */
dns_compare(struct dns_name * first,struct dns_name * second)270 int dns_compare ( struct dns_name *first, struct dns_name *second ) {
271 	unsigned int recursion_limit = first->len; /* Generous upper bound */
272 	int first_offset = first->offset;
273 	int second_offset = second->offset;
274 	const uint8_t *first_label;
275 	const uint8_t *second_label;
276 	size_t label_len;
277 	size_t len;
278 
279 	while ( recursion_limit-- ) {
280 
281 		/* Find valid DNS labels */
282 		first_offset = dns_label ( first, first_offset );
283 		if ( first_offset < 0 )
284 			return first_offset;
285 		second_offset = dns_label ( second, second_offset );
286 		if ( second_offset < 0 )
287 			return second_offset;
288 
289 		/* Compare label lengths */
290 		first_label = ( first->data + first_offset );
291 		second_label = ( second->data + second_offset );
292 		label_len = *(first_label++);
293 		if ( label_len != *(second_label++) )
294 			return -ENOENT;
295 		len = ( sizeof ( *first_label ) + label_len );
296 
297 		/* Terminate if we have reached the root */
298 		if ( label_len == 0 )
299 			return 0;
300 
301 		/* Compare label contents (case-insensitively) */
302 		while ( label_len-- ) {
303 			if ( tolower ( *(first_label++) ) !=
304 			     tolower ( *(second_label++) ) )
305 				return -ENOENT;
306 		}
307 
308 		/* Move to next labels */
309 		first_offset += len;
310 		second_offset += len;
311 	}
312 
313 	/* Recursion limit exceeded */
314 	return -EINVAL;
315 }
316 
317 /**
318  * Copy a DNS name
319  *
320  * @v src		Source DNS name
321  * @v dst		Destination DNS name
322  * @ret len		Length of copied DNS name, or negative error
323  */
dns_copy(struct dns_name * src,struct dns_name * dst)324 int dns_copy ( struct dns_name *src, struct dns_name *dst ) {
325 	unsigned int recursion_limit = src->len; /* Generous upper bound */
326 	int src_offset = src->offset;
327 	size_t dst_offset = dst->offset;
328 	const uint8_t *label;
329 	size_t label_len;
330 	size_t copy_len;
331 	size_t len;
332 
333 	while ( recursion_limit-- ) {
334 
335 		/* Find valid DNS label */
336 		src_offset = dns_label ( src, src_offset );
337 		if ( src_offset < 0 )
338 			return src_offset;
339 
340 		/* Copy as an uncompressed label */
341 		label = ( src->data + src_offset );
342 		label_len = *label;
343 		len = ( sizeof ( *label ) + label_len );
344 		copy_len = ( ( dst_offset < dst->len ) ?
345 			     ( dst->len - dst_offset ) : 0 );
346 		if ( copy_len > len )
347 			copy_len = len;
348 		memcpy ( ( dst->data + dst_offset ), label, copy_len );
349 		src_offset += len;
350 		dst_offset += len;
351 
352 		/* Terminate if we have reached the root */
353 		if ( label_len == 0 )
354 			return ( dst_offset - dst->offset );
355 	}
356 
357 	/* Recursion limit exceeded */
358 	return -EINVAL;
359 }
360 
361 /**
362  * Skip RFC1035-encoded DNS name
363  *
364  * @v name		DNS name
365  * @ret offset		Offset to next name, or negative error
366  */
dns_skip(struct dns_name * name)367 int dns_skip ( struct dns_name *name ) {
368 	unsigned int recursion_limit = name->len; /* Generous upper bound */
369 	int offset = name->offset;
370 	int prev_offset;
371 	const uint8_t *label;
372 	size_t label_len;
373 
374 	while ( recursion_limit-- ) {
375 
376 		/* Find valid DNS label */
377 		prev_offset = offset;
378 		offset = dns_label ( name, prev_offset );
379 		if ( offset < 0 )
380 			return offset;
381 
382 		/* Terminate if we have reached a compression pointer */
383 		if ( offset != prev_offset )
384 			return ( prev_offset + sizeof ( uint16_t ) );
385 
386 		/* Skip this label */
387 		label = ( name->data + offset );
388 		label_len = *label;
389 		offset += ( sizeof ( *label ) + label_len );
390 
391 		/* Terminate if we have reached the root */
392 		if ( label_len == 0 )
393 			return offset;
394 	}
395 
396 	/* Recursion limit exceeded */
397 	return -EINVAL;
398 }
399 
400 /**
401  * Skip RFC1035-encoded DNS name in search list
402  *
403  * @v name		DNS name
404  * @ret offset		Offset to next non-empty name, or negative error
405  */
dns_skip_search(struct dns_name * name)406 static int dns_skip_search ( struct dns_name *name ) {
407 	int offset;
408 
409 	/* Find next name */
410 	offset = dns_skip ( name );
411 	if ( offset < 0 )
412 		return offset;
413 
414 	/* Skip over any subsequent empty names (e.g. due to padding
415 	 * bytes used in the NDP DNSSL option).
416 	 */
417 	while ( ( offset < ( ( int ) name->len ) ) &&
418 		( *( ( uint8_t * ) ( name->data + offset ) ) == 0 ) ) {
419 		offset++;
420 	}
421 
422 	return offset;
423 }
424 
425 /**
426  * Transcribe DNS name (for debugging)
427  *
428  * @v name		DNS name
429  * @ret string		Transcribed DNS name
430  */
dns_name(struct dns_name * name)431 static const char * dns_name ( struct dns_name *name ) {
432 	static char buf[256];
433 	int len;
434 
435 	len = dns_decode ( name, buf, ( sizeof ( buf ) - 1 /* NUL */ ) );
436 	return ( ( len < 0 ) ? "<INVALID>" : buf );
437 }
438 
439 /**
440  * Name a DNS query type (for debugging)
441  *
442  * @v type		Query type (in network byte order)
443  * @ret name		Type name
444  */
dns_type(uint16_t type)445 static const char * dns_type ( uint16_t type ) {
446 	switch ( type ) {
447 	case htons ( DNS_TYPE_A ):	return "A";
448 	case htons ( DNS_TYPE_AAAA ):	return "AAAA";
449 	case htons ( DNS_TYPE_CNAME ):	return "CNAME";
450 	default:			return "<UNKNOWN>";
451 	}
452 }
453 
454 /** A DNS request */
455 struct dns_request {
456 	/** Reference counter */
457 	struct refcnt refcnt;
458 	/** Name resolution interface */
459 	struct interface resolv;
460 	/** Data transfer interface */
461 	struct interface socket;
462 	/** Retry timer */
463 	struct retry_timer timer;
464 
465 	/** Socket address to fill in with resolved address */
466 	union {
467 		struct sockaddr sa;
468 		struct sockaddr_in sin;
469 		struct sockaddr_in6 sin6;
470 	} address;
471 	/** Initial query type */
472 	uint16_t qtype;
473 	/** Buffer for current query */
474 	struct {
475 		/** Query header */
476 		struct dns_header query;
477 		/** Name buffer */
478 		char name[DNS_MAX_NAME_LEN];
479 		/** Space for question */
480 		struct dns_question padding;
481 	} __attribute__ (( packed )) buf;
482 	/** Current query name */
483 	struct dns_name name;
484 	/** Question within current query */
485 	struct dns_question *question;
486 	/** Length of current query */
487 	size_t len;
488 	/** Offset of search suffix within current query */
489 	size_t offset;
490 	/** Search list */
491 	struct dns_name search;
492 	/** Recursion counter */
493 	unsigned int recursion;
494 };
495 
496 /**
497  * Mark DNS request as complete
498  *
499  * @v dns		DNS request
500  * @v rc		Return status code
501  */
dns_done(struct dns_request * dns,int rc)502 static void dns_done ( struct dns_request *dns, int rc ) {
503 
504 	/* Stop the retry timer */
505 	stop_timer ( &dns->timer );
506 
507 	/* Shut down interfaces */
508 	intf_shutdown ( &dns->socket, rc );
509 	intf_shutdown ( &dns->resolv, rc );
510 }
511 
512 /**
513  * Mark DNS request as resolved and complete
514  *
515  * @v dns		DNS request
516  * @v rc		Return status code
517  */
dns_resolved(struct dns_request * dns)518 static void dns_resolved ( struct dns_request *dns ) {
519 
520 	DBGC ( dns, "DNS %p found address %s\n",
521 	       dns, sock_ntoa ( &dns->address.sa ) );
522 
523 	/* Return resolved address */
524 	resolv_done ( &dns->resolv, &dns->address.sa );
525 
526 	/* Mark operation as complete */
527 	dns_done ( dns, 0 );
528 }
529 
530 /**
531  * Construct DNS question
532  *
533  * @v dns		DNS request
534  * @ret rc		Return status code
535  */
dns_question(struct dns_request * dns)536 static int dns_question ( struct dns_request *dns ) {
537 	static struct dns_name search_root = {
538 		.data = "",
539 		.len = 1,
540 	};
541 	struct dns_name *search = &dns->search;
542 	int len;
543 	size_t offset;
544 
545 	/* Use root suffix if search list is empty */
546 	if ( search->offset == search->len )
547 		search = &search_root;
548 
549 	/* Overwrite current suffix */
550 	dns->name.offset = dns->offset;
551 	len = dns_copy ( search, &dns->name );
552 	if ( len < 0 )
553 		return len;
554 
555 	/* Sanity check */
556 	offset = ( dns->name.offset + len );
557 	if ( offset > dns->name.len ) {
558 		DBGC ( dns, "DNS %p name is too long\n", dns );
559 		return -EINVAL;
560 	}
561 
562 	/* Construct question */
563 	dns->question = ( ( ( void * ) &dns->buf ) + offset );
564 	dns->question->qtype = dns->qtype;
565 	dns->question->qclass = htons ( DNS_CLASS_IN );
566 
567 	/* Store length */
568 	dns->len = ( offset + sizeof ( *(dns->question) ) );
569 
570 	/* Restore name */
571 	dns->name.offset = offsetof ( typeof ( dns->buf ), name );
572 
573 	/* Reset query ID */
574 	dns->buf.query.id = 0;
575 
576 	DBGC2 ( dns, "DNS %p question is %s type %s\n", dns,
577 		dns_name ( &dns->name ), dns_type ( dns->question->qtype ) );
578 
579 	return 0;
580 }
581 
582 /**
583  * Send DNS query
584  *
585  * @v dns		DNS request
586  * @ret rc		Return status code
587  */
dns_send_packet(struct dns_request * dns)588 static int dns_send_packet ( struct dns_request *dns ) {
589 	struct dns_header *query = &dns->buf.query;
590 	union {
591 		struct sockaddr sa;
592 		struct sockaddr_tcpip st;
593 		struct sockaddr_in sin;
594 		struct sockaddr_in6 sin6;
595 	} nameserver;
596 	struct xfer_metadata meta;
597 	unsigned int index;
598 
599 	/* Start retransmission timer */
600 	start_timer ( &dns->timer );
601 
602 	/* Construct DNS server address */
603 	memset ( &nameserver, 0, sizeof ( nameserver ) );
604 	nameserver.st.st_port = htons ( DNS_PORT );
605 	if ( ! dns_count ) {
606 		DBGC ( dns, "DNS %p lost DNS servers mid query\n", dns );
607 		return -EINVAL;
608 	}
609 	index = ( dns_index % dns_count );
610 	if ( index < dns6.count ) {
611 		nameserver.sin6.sin6_family = AF_INET6;
612 		memcpy ( &nameserver.sin6.sin6_addr, &dns6.in6[index],
613 			 sizeof ( nameserver.sin6.sin6_addr ) );
614 	} else {
615 		nameserver.sin.sin_family = AF_INET;
616 		nameserver.sin.sin_addr = dns4.in[index - dns6.count];
617 	}
618 
619 	/* Construct metadata */
620 	memset ( &meta, 0, sizeof ( meta ) );
621 	meta.dest = &nameserver.sa;
622 
623 	/* Generate query identifier if applicable */
624 	if ( ! query->id )
625 		query->id = random();
626 
627 	/* Send query */
628 	DBGC ( dns, "DNS %p sending %s query ID %#04x for %s type %s\n", dns,
629 	       sock_ntoa ( &nameserver.sa ), ntohs ( query->id ),
630 	       dns_name ( &dns->name ), dns_type ( dns->question->qtype ) );
631 
632 	/* Send the data */
633 	return xfer_deliver_raw_meta ( &dns->socket, query, dns->len, &meta );
634 }
635 
636 /**
637  * Handle DNS (re)transmission timer expiry
638  *
639  * @v timer		Retry timer
640  * @v fail		Failure indicator
641  */
dns_timer_expired(struct retry_timer * timer,int fail)642 static void dns_timer_expired ( struct retry_timer *timer, int fail ) {
643 	struct dns_request *dns =
644 		container_of ( timer, struct dns_request, timer );
645 
646 	/* Terminate DNS request on failure */
647 	if ( fail ) {
648 		dns_done ( dns, -ETIMEDOUT );
649 		return;
650 	}
651 
652 	/* Move to next DNS server if this is a retransmission */
653 	if ( dns->buf.query.id )
654 		dns_index++;
655 
656 	/* Send DNS query */
657 	dns_send_packet ( dns );
658 }
659 
660 /**
661  * Receive new data
662  *
663  * @v dns		DNS request
664  * @v iobuf		I/O buffer
665  * @v meta		Data transfer metadata
666  * @ret rc		Return status code
667  */
dns_xfer_deliver(struct dns_request * dns,struct io_buffer * iobuf,struct xfer_metadata * meta __unused)668 static int dns_xfer_deliver ( struct dns_request *dns,
669 			      struct io_buffer *iobuf,
670 			      struct xfer_metadata *meta __unused ) {
671 	struct dns_header *response = iobuf->data;
672 	struct dns_header *query = &dns->buf.query;
673 	unsigned int qtype = dns->question->qtype;
674 	struct dns_name buf;
675 	union dns_rr *rr;
676 	int offset;
677 	size_t answer_offset;
678 	size_t next_offset;
679 	size_t rdlength;
680 	size_t name_len;
681 	int rc;
682 
683 	/* Sanity check */
684 	if ( iob_len ( iobuf ) < sizeof ( *response ) ) {
685 		DBGC ( dns, "DNS %p received underlength packet length %zd\n",
686 		       dns, iob_len ( iobuf ) );
687 		rc = -EINVAL;
688 		goto done;
689 	}
690 
691 	/* Check response ID matches query ID */
692 	if ( response->id != query->id ) {
693 		DBGC ( dns, "DNS %p received unexpected response ID %#04x "
694 		       "(wanted %d)\n", dns, ntohs ( response->id ),
695 		       ntohs ( query->id ) );
696 		rc = -EINVAL;
697 		goto done;
698 	}
699 	DBGC ( dns, "DNS %p received response ID %#04x\n",
700 	       dns, ntohs ( response->id ) );
701 
702 	/* Check that we have exactly one question */
703 	if ( response->qdcount != htons ( 1 ) ) {
704 		DBGC ( dns, "DNS %p received response with %d questions\n",
705 		       dns, ntohs ( response->qdcount ) );
706 		rc = -EINVAL;
707 		goto done;
708 	}
709 
710 	/* Skip question section */
711 	buf.data = iobuf->data;
712 	buf.offset = sizeof ( *response );
713 	buf.len = iob_len ( iobuf );
714 	offset = dns_skip ( &buf );
715 	if ( offset < 0 ) {
716 		rc = offset;
717 		DBGC ( dns, "DNS %p received response with malformed "
718 		       "question: %s\n", dns, strerror ( rc ) );
719 		goto done;
720 	}
721 	answer_offset = ( offset + sizeof ( struct dns_question ) );
722 
723 	/* Search through response for useful answers.  Do this
724 	 * multiple times, to take advantage of useful nameservers
725 	 * which send us e.g. the CNAME *and* the A record for the
726 	 * pointed-to name.
727 	 */
728 	for ( buf.offset = answer_offset ; buf.offset != buf.len ;
729 	      buf.offset = next_offset ) {
730 
731 		/* Check for valid name */
732 		offset = dns_skip ( &buf );
733 		if ( offset < 0 ) {
734 			rc = offset;
735 			DBGC ( dns, "DNS %p received response with malformed "
736 			       "answer: %s\n", dns, strerror ( rc ) );
737 			goto done;
738 		}
739 
740 		/* Check for sufficient space for resource record */
741 		rr = ( buf.data + offset );
742 		if ( ( offset + sizeof ( rr->common ) ) > buf.len ) {
743 			DBGC ( dns, "DNS %p received response with underlength "
744 			       "RR\n", dns );
745 			rc = -EINVAL;
746 			goto done;
747 		}
748 		rdlength = ntohs ( rr->common.rdlength );
749 		next_offset = ( offset + sizeof ( rr->common ) + rdlength );
750 		if ( next_offset > buf.len ) {
751 			DBGC ( dns, "DNS %p received response with underlength "
752 			       "RR\n", dns );
753 			rc = -EINVAL;
754 			goto done;
755 		}
756 
757 		/* Skip non-matching names */
758 		if ( dns_compare ( &buf, &dns->name ) != 0 ) {
759 			DBGC2 ( dns, "DNS %p ignoring response for %s type "
760 				"%s\n", dns, dns_name ( &buf ),
761 				dns_type ( rr->common.type ) );
762 			continue;
763 		}
764 
765 		/* Handle answer */
766 		switch ( rr->common.type ) {
767 
768 		case htons ( DNS_TYPE_AAAA ):
769 
770 			/* Found the target AAAA record */
771 			if ( rdlength < sizeof ( dns->address.sin6.sin6_addr )){
772 				DBGC ( dns, "DNS %p received response with "
773 				       "underlength AAAA\n", dns );
774 				rc = -EINVAL;
775 				goto done;
776 			}
777 			dns->address.sin6.sin6_family = AF_INET6;
778 			memcpy ( &dns->address.sin6.sin6_addr,
779 				 &rr->aaaa.in6_addr,
780 				 sizeof ( dns->address.sin6.sin6_addr ) );
781 			dns_resolved ( dns );
782 			rc = 0;
783 			goto done;
784 
785 		case htons ( DNS_TYPE_A ):
786 
787 			/* Found the target A record */
788 			if ( rdlength < sizeof ( dns->address.sin.sin_addr ) ) {
789 				DBGC ( dns, "DNS %p received response with "
790 				       "underlength A\n", dns );
791 				rc = -EINVAL;
792 				goto done;
793 			}
794 			dns->address.sin.sin_family = AF_INET;
795 			dns->address.sin.sin_addr = rr->a.in_addr;
796 			dns_resolved ( dns );
797 			rc = 0;
798 			goto done;
799 
800 		case htons ( DNS_TYPE_CNAME ):
801 
802 			/* Terminate the operation if we recurse too far */
803 			if ( ++dns->recursion > DNS_MAX_CNAME_RECURSION ) {
804 				DBGC ( dns, "DNS %p recursion exceeded\n",
805 				       dns );
806 				rc = -ELOOP;
807 				dns_done ( dns, rc );
808 				goto done;
809 			}
810 
811 			/* Found a CNAME record; update query and recurse */
812 			buf.offset = ( offset + sizeof ( rr->cname ) );
813 			DBGC ( dns, "DNS %p found CNAME %s\n",
814 			       dns, dns_name ( &buf ) );
815 			dns->search.offset = dns->search.len;
816 			name_len = dns_copy ( &buf, &dns->name );
817 			dns->offset = ( offsetof ( typeof ( dns->buf ), name ) +
818 					name_len - 1 /* Strip root label */ );
819 			if ( ( rc = dns_question ( dns ) ) != 0 ) {
820 				dns_done ( dns, rc );
821 				goto done;
822 			}
823 			next_offset = answer_offset;
824 			break;
825 
826 		default:
827 			DBGC ( dns, "DNS %p got unknown record type %d\n",
828 			       dns, ntohs ( rr->common.type ) );
829 			break;
830 		}
831 	}
832 
833 	/* Stop the retry timer.  After this point, each code path
834 	 * must either restart the timer by calling dns_send_packet(),
835 	 * or mark the DNS operation as complete by calling
836 	 * dns_done()
837 	 */
838 	stop_timer ( &dns->timer );
839 
840 	/* Determine what to do next based on the type of query we
841 	 * issued and the response we received
842 	 */
843 	switch ( qtype ) {
844 
845 	case htons ( DNS_TYPE_AAAA ):
846 		/* We asked for an AAAA record and got nothing; try
847 		 * the A.
848 		 */
849 		DBGC ( dns, "DNS %p found no AAAA record; trying A\n", dns );
850 		dns->question->qtype = htons ( DNS_TYPE_A );
851 		dns_send_packet ( dns );
852 		rc = 0;
853 		goto done;
854 
855 	case htons ( DNS_TYPE_A ):
856 		/* We asked for an A record and got nothing;
857 		 * try the CNAME.
858 		 */
859 		DBGC ( dns, "DNS %p found no A record; trying CNAME\n", dns );
860 		dns->question->qtype = htons ( DNS_TYPE_CNAME );
861 		dns_send_packet ( dns );
862 		rc = 0;
863 		goto done;
864 
865 	case htons ( DNS_TYPE_CNAME ):
866 		/* We asked for a CNAME record.  If we got a response
867 		 * (i.e. if the next AAAA/A query is already set up),
868 		 * then issue it.
869 		 */
870 		if ( qtype == dns->qtype ) {
871 			dns_send_packet ( dns );
872 			rc = 0;
873 			goto done;
874 		}
875 
876 		/* If we have already reached the end of the search list,
877 		 * then terminate lookup.
878 		 */
879 		if ( dns->search.offset == dns->search.len ) {
880 			DBGC ( dns, "DNS %p found no CNAME record\n", dns );
881 			rc = -ENXIO_NO_RECORD;
882 			dns_done ( dns, rc );
883 			goto done;
884 		}
885 
886 		/* Move to next entry in search list.  This can never fail,
887 		 * since we have already used this entry.
888 		 */
889 		DBGC ( dns, "DNS %p found no CNAME record; trying next "
890 		       "suffix\n", dns );
891 		dns->search.offset = dns_skip_search ( &dns->search );
892 		if ( ( rc = dns_question ( dns ) ) != 0 ) {
893 			dns_done ( dns, rc );
894 			goto done;
895 		}
896 		dns_send_packet ( dns );
897 		goto done;
898 
899 	default:
900 		assert ( 0 );
901 		rc = -EINVAL;
902 		dns_done ( dns, rc );
903 		goto done;
904 	}
905 
906  done:
907 	/* Free I/O buffer */
908 	free_iob ( iobuf );
909 	return rc;
910 }
911 
912 /**
913  * Receive new data
914  *
915  * @v dns		DNS request
916  * @v rc		Reason for close
917  */
dns_xfer_close(struct dns_request * dns,int rc)918 static void dns_xfer_close ( struct dns_request *dns, int rc ) {
919 
920 	if ( ! rc )
921 		rc = -ECONNABORTED;
922 
923 	dns_done ( dns, rc );
924 }
925 
926 /**
927  * Report job progress
928  *
929  * @v dns		DNS request
930  * @v progress		Progress report to fill in
931  * @ret ongoing_rc	Ongoing job status code (if known)
932  */
dns_progress(struct dns_request * dns,struct job_progress * progress)933 static int dns_progress ( struct dns_request *dns,
934 			  struct job_progress *progress ) {
935 	int len;
936 
937 	/* Show current question as progress message */
938 	len = dns_decode ( &dns->name, progress->message,
939 			   ( sizeof ( progress->message ) - 1 /* NUL */ ) );
940 	if ( len < 0 ) {
941 		/* Ignore undecodable names */
942 		progress->message[0] = '\0';
943 	}
944 
945 	return 0;
946 }
947 
948 /** DNS socket interface operations */
949 static struct interface_operation dns_socket_operations[] = {
950 	INTF_OP ( xfer_deliver, struct dns_request *, dns_xfer_deliver ),
951 	INTF_OP ( intf_close, struct dns_request *, dns_xfer_close ),
952 };
953 
954 /** DNS socket interface descriptor */
955 static struct interface_descriptor dns_socket_desc =
956 	INTF_DESC ( struct dns_request, socket, dns_socket_operations );
957 
958 /** DNS resolver interface operations */
959 static struct interface_operation dns_resolv_op[] = {
960 	INTF_OP ( job_progress, struct dns_request *, dns_progress ),
961 	INTF_OP ( intf_close, struct dns_request *, dns_done ),
962 };
963 
964 /** DNS resolver interface descriptor */
965 static struct interface_descriptor dns_resolv_desc =
966 	INTF_DESC ( struct dns_request, resolv, dns_resolv_op );
967 
968 /**
969  * Resolve name using DNS
970  *
971  * @v resolv		Name resolution interface
972  * @v name		Name to resolve
973  * @v sa		Socket address to fill in
974  * @ret rc		Return status code
975  */
dns_resolv(struct interface * resolv,const char * name,struct sockaddr * sa)976 static int dns_resolv ( struct interface *resolv,
977 			const char *name, struct sockaddr *sa ) {
978 	struct dns_request *dns;
979 	struct dns_header *query;
980 	size_t search_len;
981 	int name_len;
982 	int rc;
983 
984 	/* Fail immediately if no DNS servers */
985 	if ( dns_count == 0 ) {
986 		DBG ( "DNS not attempting to resolve \"%s\": "
987 		      "no DNS servers\n", name );
988 		rc = -ENXIO_NO_NAMESERVER;
989 		goto err_no_nameserver;
990 	}
991 
992 	/* Determine whether or not to use search list */
993 	search_len = ( strchr ( name, '.' ) ? 0 : dns_search.len );
994 
995 	/* Allocate DNS structure */
996 	dns = zalloc ( sizeof ( *dns ) + search_len );
997 	if ( ! dns ) {
998 		rc = -ENOMEM;
999 		goto err_alloc_dns;
1000 	}
1001 	ref_init ( &dns->refcnt, NULL );
1002 	intf_init ( &dns->resolv, &dns_resolv_desc, &dns->refcnt );
1003 	intf_init ( &dns->socket, &dns_socket_desc, &dns->refcnt );
1004 	timer_init ( &dns->timer, dns_timer_expired, &dns->refcnt );
1005 	memcpy ( &dns->address.sa, sa, sizeof ( dns->address.sa ) );
1006 	dns->search.data = ( ( ( void * ) dns ) + sizeof ( *dns ) );
1007 	dns->search.len = search_len;
1008 	memcpy ( dns->search.data, dns_search.data, search_len );
1009 
1010 	/* Determine initial query type */
1011 	dns->qtype = ( ( dns6.count != 0 ) ?
1012 		       htons ( DNS_TYPE_AAAA ) : htons ( DNS_TYPE_A ) );
1013 
1014 	/* Construct query */
1015 	query = &dns->buf.query;
1016 	query->flags = htons ( DNS_FLAG_RD );
1017 	query->qdcount = htons ( 1 );
1018 	dns->name.data = &dns->buf;
1019 	dns->name.offset = offsetof ( typeof ( dns->buf ), name );
1020 	dns->name.len = offsetof ( typeof ( dns->buf ), padding );
1021 	name_len = dns_encode ( name, &dns->name );
1022 	if ( name_len < 0 ) {
1023 		rc = name_len;
1024 		goto err_encode;
1025 	}
1026 	dns->offset = ( offsetof ( typeof ( dns->buf ), name ) +
1027 			name_len - 1 /* Strip root label */ );
1028 	if ( ( rc = dns_question ( dns ) ) != 0 )
1029 		goto err_question;
1030 
1031 	/* Open UDP connection */
1032 	if ( ( rc = xfer_open_socket ( &dns->socket, SOCK_DGRAM,
1033 				       NULL, NULL ) ) != 0 ) {
1034 		DBGC ( dns, "DNS %p could not open socket: %s\n",
1035 		       dns, strerror ( rc ) );
1036 		goto err_open_socket;
1037 	}
1038 
1039 	/* Start timer to trigger first packet */
1040 	start_timer_nodelay ( &dns->timer );
1041 
1042 	/* Attach parent interface, mortalise self, and return */
1043 	intf_plug_plug ( &dns->resolv, resolv );
1044 	ref_put ( &dns->refcnt );
1045 	return 0;
1046 
1047  err_open_socket:
1048  err_question:
1049  err_encode:
1050 	ref_put ( &dns->refcnt );
1051  err_alloc_dns:
1052  err_no_nameserver:
1053 	return rc;
1054 }
1055 
1056 /** DNS name resolver */
1057 struct resolver dns_resolver __resolver ( RESOLV_NORMAL ) = {
1058 	.name = "DNS",
1059 	.resolv = dns_resolv,
1060 };
1061 
1062 /******************************************************************************
1063  *
1064  * Settings
1065  *
1066  ******************************************************************************
1067  */
1068 
1069 /**
1070  * Format DNS search list setting
1071  *
1072  * @v type		Setting type
1073  * @v raw		Raw setting value
1074  * @v raw_len		Length of raw setting value
1075  * @v buf		Buffer to contain formatted value
1076  * @v len		Length of buffer
1077  * @ret len		Length of formatted value, or negative error
1078  */
format_dnssl_setting(const struct setting_type * type __unused,const void * raw,size_t raw_len,char * buf,size_t len)1079 static int format_dnssl_setting ( const struct setting_type *type __unused,
1080 				  const void *raw, size_t raw_len,
1081 				  char *buf, size_t len ) {
1082 	struct dns_name name = {
1083 		.data = ( ( void * ) raw ),
1084 		.len = raw_len,
1085 	};
1086 	size_t remaining = len;
1087 	size_t total = 0;
1088 	int name_len;
1089 
1090 	while ( name.offset < raw_len ) {
1091 
1092 		/* Decode name */
1093 		remaining = ( ( total < len ) ? ( len - total ) : 0 );
1094 		name_len = dns_decode ( &name, ( buf + total ), remaining );
1095 		if ( name_len < 0 )
1096 			return name_len;
1097 		total += name_len;
1098 
1099 		/* Move to next name */
1100 		name.offset = dns_skip_search ( &name );
1101 
1102 		/* Add separator if applicable */
1103 		if ( name.offset != raw_len ) {
1104 			if ( total < len )
1105 				buf[total] = ' ';
1106 			total++;
1107 		}
1108 	}
1109 
1110 	return total;
1111 }
1112 
1113 /** A DNS search list setting type */
1114 const struct setting_type setting_type_dnssl __setting_type = {
1115 	.name = "dnssl",
1116 	.format = format_dnssl_setting,
1117 };
1118 
1119 /** IPv4 DNS server setting */
1120 const struct setting dns_setting __setting ( SETTING_IP4_EXTRA, dns ) = {
1121 	.name = "dns",
1122 	.description = "DNS server",
1123 	.tag = DHCP_DNS_SERVERS,
1124 	.type = &setting_type_ipv4,
1125 };
1126 
1127 /** IPv6 DNS server setting */
1128 const struct setting dns6_setting __setting ( SETTING_IP6_EXTRA, dns6 ) = {
1129 	.name = "dns6",
1130 	.description = "DNS server",
1131 	.tag = DHCPV6_DNS_SERVERS,
1132 	.type = &setting_type_ipv6,
1133 	.scope = &dhcpv6_scope,
1134 };
1135 
1136 /** DNS search list */
1137 const struct setting dnssl_setting __setting ( SETTING_IP_EXTRA, dnssl ) = {
1138 	.name = "dnssl",
1139 	.description = "DNS search list",
1140 	.tag = DHCP_DOMAIN_SEARCH,
1141 	.type = &setting_type_dnssl,
1142 };
1143 
1144 /**
1145  * Apply DNS server addresses
1146  *
1147  */
apply_dns_servers(void)1148 static void apply_dns_servers ( void ) {
1149 	int len;
1150 
1151 	/* Free existing server addresses */
1152 	free ( dns4.data );
1153 	free ( dns6.data );
1154 	dns4.data = NULL;
1155 	dns6.data = NULL;
1156 	dns4.count = 0;
1157 	dns6.count = 0;
1158 
1159 	/* Fetch DNS server addresses */
1160 	len = fetch_raw_setting_copy ( NULL, &dns_setting, &dns4.data );
1161 	if ( len >= 0 )
1162 		dns4.count = ( len / sizeof ( dns4.in[0] ) );
1163 	len = fetch_raw_setting_copy ( NULL, &dns6_setting, &dns6.data );
1164 	if ( len >= 0 )
1165 		dns6.count = ( len / sizeof ( dns6.in6[0] ) );
1166 	dns_count = ( dns4.count + dns6.count );
1167 }
1168 
1169 /**
1170  * Apply DNS search list
1171  *
1172  */
apply_dns_search(void)1173 static void apply_dns_search ( void ) {
1174 	char *localdomain;
1175 	int len;
1176 
1177 	/* Free existing search list */
1178 	free ( dns_search.data );
1179 	memset ( &dns_search, 0, sizeof ( dns_search ) );
1180 
1181 	/* Fetch DNS search list */
1182 	len = fetch_raw_setting_copy ( NULL, &dnssl_setting, &dns_search.data );
1183 	if ( len >= 0 ) {
1184 		dns_search.len = len;
1185 		return;
1186 	}
1187 
1188 	/* If no DNS search list exists, try to fetch the local domain */
1189 	fetch_string_setting_copy ( NULL, &domain_setting, &localdomain );
1190 	if ( localdomain ) {
1191 		len = dns_encode ( localdomain, &dns_search );
1192 		if ( len >= 0 ) {
1193 			dns_search.data = malloc ( len );
1194 			if ( dns_search.data ) {
1195 				dns_search.len = len;
1196 				dns_encode ( localdomain, &dns_search );
1197 			}
1198 		}
1199 		free ( localdomain );
1200 		return;
1201 	}
1202 }
1203 
1204 /**
1205  * Apply DNS settings
1206  *
1207  * @ret rc		Return status code
1208  */
apply_dns_settings(void)1209 static int apply_dns_settings ( void ) {
1210 	void *dbgcol = &dns_count;
1211 
1212 	/* Fetch DNS server address */
1213 	apply_dns_servers();
1214 	if ( DBG_LOG && ( dns_count != 0 ) ) {
1215 		union {
1216 			struct sockaddr sa;
1217 			struct sockaddr_in sin;
1218 			struct sockaddr_in6 sin6;
1219 		} u;
1220 		unsigned int i;
1221 
1222 		DBGC ( dbgcol, "DNS servers:" );
1223 		for ( i = 0 ; i < dns6.count ; i++ ) {
1224 			u.sin6.sin6_family = AF_INET6;
1225 			memcpy ( &u.sin6.sin6_addr, &dns6.in6[i],
1226 				 sizeof ( u.sin6.sin6_addr ) );
1227 			DBGC ( dbgcol, " %s", sock_ntoa ( &u.sa ) );
1228 		}
1229 		for ( i = 0 ; i < dns4.count ; i++ ) {
1230 			u.sin.sin_family = AF_INET;
1231 			u.sin.sin_addr = dns4.in[i];
1232 			DBGC ( dbgcol, " %s", sock_ntoa ( &u.sa ) );
1233 		}
1234 		DBGC ( dbgcol, "\n" );
1235 	}
1236 
1237 	/* Fetch DNS search list */
1238 	apply_dns_search();
1239 	if ( DBG_LOG && ( dns_search.len != 0 ) ) {
1240 		struct dns_name name;
1241 		int offset;
1242 
1243 		DBGC ( dbgcol, "DNS search list:" );
1244 		memcpy ( &name, &dns_search, sizeof ( name ) );
1245 		while ( name.offset != name.len ) {
1246 			DBGC ( dbgcol, " %s", dns_name ( &name ) );
1247 			offset = dns_skip_search ( &name );
1248 			if ( offset < 0 )
1249 				break;
1250 			name.offset = offset;
1251 		}
1252 		DBGC ( dbgcol, "\n" );
1253 	}
1254 
1255 	return 0;
1256 }
1257 
1258 /** DNS settings applicator */
1259 struct settings_applicator dns_applicator __settings_applicator = {
1260 	.apply = apply_dns_settings,
1261 };
1262