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