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