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