These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / ipxe / 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 };