2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
4 * Portions copyright (C) 2004 Anselm M. Hoffmeister
5 * <stockholm@users.sourceforge.net>.
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.
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.
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
23 FILE_LICENCE ( GPL2_OR_LATER );
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>
51 FEATURE ( FEATURE_PROTOCOL, "DNS", DHCP_EB_FEATURE_DNS, 1 );
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" )
64 struct sockaddr_tcpip st;
65 struct sockaddr_in sin;
66 struct sockaddr_in6 sin6;
69 .st_port = htons ( DNS_PORT ),
73 /** The DNS search list */
74 static struct dns_name dns_search;
77 * Encode a DNS name using RFC1035 encoding
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
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 );
91 while ( ( c = *(string++) ) ) {
93 /* Handle '.' separators */
96 /* Reject consecutive '.' */
97 if ( ( len == 0 ) && ( dst != start ) )
100 /* Terminate if this is the trailing '.' */
101 if ( *string == '\0' )
104 /* Reject initial non-terminating '.' */
113 /* Increment length */
116 /* Check for overflow */
117 if ( len > DNS_MAX_LABEL_LEN )
121 /* Copy byte, update length */
128 /* Add terminating root marker */
135 return ( dst - start );
139 * Find start of valid label within an RFC1035-encoded DNS name
142 * @v offset Current offset
143 * @ret offset Offset of label, or negative error
145 static int dns_label ( struct dns_name *name, size_t offset ) {
147 const uint16_t *word;
153 /* Fail if we have overrun the DNS name */
154 if ( ( offset + sizeof ( *byte) ) > name->len )
156 byte = ( name->data + offset );
158 /* Follow compression pointer, if applicable */
159 if ( DNS_IS_COMPRESSED ( *byte ) ) {
161 /* Fail if we have overrun the DNS name */
162 if ( ( offset + sizeof ( *word ) ) > name->len )
164 word = ( name->data + offset );
166 /* Extract pointer to new offset */
167 ptr = DNS_COMPRESSED_OFFSET ( ntohs ( *word ) );
169 /* Fail if pointer does not point backwards.
170 * (This guarantees termination of the
176 /* Continue from new offset */
181 /* Fail if we have overrun the DNS name */
183 if ( ( offset + sizeof ( *byte ) + len ) > name->len )
186 /* We have a valid label */
192 * Decode RFC1035-encoded 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
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;
207 while ( recursion_limit-- ) {
209 /* Find valid DNS label */
210 offset = dns_label ( name, offset );
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 )
223 /* Prepend '.' if applicable */
224 if ( decoded_len && ( decoded_len++ < len ) )
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 );
233 decoded_len += label_len;
235 /* Move to next label */
236 offset += ( sizeof ( *label ) + label_len );
239 /* Recursion limit exceeded */
244 * Compare DNS names for equality
246 * @v first First DNS name
247 * @v second Second DNS name
248 * @ret rc Return status code
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;
259 while ( recursion_limit-- ) {
261 /* Find valid DNS labels */
262 first_offset = dns_label ( first, first_offset );
263 if ( first_offset < 0 )
265 second_offset = dns_label ( second, second_offset );
266 if ( second_offset < 0 )
267 return second_offset;
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++) )
275 len = ( sizeof ( *first_label ) + label_len );
277 /* Terminate if we have reached the root */
278 if ( label_len == 0 )
281 /* Compare label contents (case-insensitively) */
282 while ( label_len-- ) {
283 if ( tolower ( *(first_label++) ) !=
284 tolower ( *(second_label++) ) )
288 /* Move to next labels */
290 second_offset += len;
293 /* Recursion limit exceeded */
300 * @v src Source DNS name
301 * @v dst Destination DNS name
302 * @ret len Length of copied DNS name, or negative error
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;
313 while ( recursion_limit-- ) {
315 /* Find valid DNS label */
316 src_offset = dns_label ( src, src_offset );
317 if ( src_offset < 0 )
320 /* Copy as an uncompressed label */
321 label = ( src->data + src_offset );
323 len = ( sizeof ( *label ) + label_len );
324 copy_len = ( ( dst_offset < dst->len ) ?
325 ( dst->len - dst_offset ) : 0 );
326 if ( copy_len > len )
328 memcpy ( ( dst->data + dst_offset ), label, copy_len );
332 /* Terminate if we have reached the root */
333 if ( label_len == 0 )
334 return ( dst_offset - dst->offset );
337 /* Recursion limit exceeded */
342 * Skip RFC1035-encoded DNS name
345 * @ret offset Offset to next name, or negative error
347 int dns_skip ( struct dns_name *name ) {
348 unsigned int recursion_limit = name->len; /* Generous upper bound */
349 int offset = name->offset;
351 const uint8_t *label;
354 while ( recursion_limit-- ) {
356 /* Find valid DNS label */
357 prev_offset = offset;
358 offset = dns_label ( name, prev_offset );
362 /* Terminate if we have reached a compression pointer */
363 if ( offset != prev_offset )
364 return ( prev_offset + sizeof ( uint16_t ) );
366 /* Skip this label */
367 label = ( name->data + offset );
369 offset += ( sizeof ( *label ) + label_len );
371 /* Terminate if we have reached the root */
372 if ( label_len == 0 )
376 /* Recursion limit exceeded */
381 * Skip RFC1035-encoded DNS name in search list
384 * @ret offset Offset to next non-empty name, or negative error
386 static int dns_skip_search ( struct dns_name *name ) {
390 offset = dns_skip ( name );
394 /* Skip over any subsequent empty names (e.g. due to padding
395 * bytes used in the NDP DNSSL option).
397 while ( ( offset < ( ( int ) name->len ) ) &&
398 ( *( ( uint8_t * ) ( name->data + offset ) ) == 0 ) ) {
406 * Transcribe DNS name (for debugging)
409 * @ret string Transcribed DNS name
411 static const char * dns_name ( struct dns_name *name ) {
412 static char buf[256];
415 len = dns_decode ( name, buf, sizeof ( buf ) );
416 return ( ( len < 0 ) ? "<INVALID>" : buf );
420 * Name a DNS query type (for debugging)
422 * @v type Query type (in network byte order)
423 * @ret name Type name
425 static const char * dns_type ( uint16_t 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>";
436 /** Reference counter */
437 struct refcnt refcnt;
438 /** Name resolution interface */
439 struct interface resolv;
440 /** Data transfer interface */
441 struct interface socket;
443 struct retry_timer timer;
445 /** Socket address to fill in with resolved address */
448 struct sockaddr_in sin;
449 struct sockaddr_in6 sin6;
451 /** Initial query type */
453 /** Buffer for current query */
456 struct dns_header query;
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 */
468 /** Offset of search suffix within current query */
471 struct dns_name search;
472 /** Recursion counter */
473 unsigned int recursion;
477 * Mark DNS request as complete
480 * @v rc Return status code
482 static void dns_done ( struct dns_request *dns, int rc ) {
484 /* Stop the retry timer */
485 stop_timer ( &dns->timer );
487 /* Shut down interfaces */
488 intf_shutdown ( &dns->socket, rc );
489 intf_shutdown ( &dns->resolv, rc );
493 * Mark DNS request as resolved and complete
496 * @v rc Return status code
498 static void dns_resolved ( struct dns_request *dns ) {
500 DBGC ( dns, "DNS %p found address %s\n",
501 dns, sock_ntoa ( &dns->address.sa ) );
503 /* Return resolved address */
504 resolv_done ( &dns->resolv, &dns->address.sa );
506 /* Mark operation as complete */
511 * Construct DNS question
514 * @ret rc Return status code
516 static int dns_question ( struct dns_request *dns ) {
517 static struct dns_name search_root = {
521 struct dns_name *search = &dns->search;
525 /* Use root suffix if search list is empty */
526 if ( search->offset == search->len )
527 search = &search_root;
529 /* Overwrite current suffix */
530 dns->name.offset = dns->offset;
531 len = dns_copy ( search, &dns->name );
536 offset = ( dns->name.offset + len );
537 if ( offset > dns->name.len ) {
538 DBGC ( dns, "DNS %p name is too long\n", dns );
542 /* Construct question */
543 dns->question = ( ( ( void * ) &dns->buf ) + offset );
544 dns->question->qtype = dns->qtype;
545 dns->question->qclass = htons ( DNS_CLASS_IN );
548 dns->len = ( offset + sizeof ( *(dns->question) ) );
551 dns->name.offset = offsetof ( typeof ( dns->buf ), name );
553 DBGC2 ( dns, "DNS %p question is %s type %s\n", dns,
554 dns_name ( &dns->name ), dns_type ( dns->question->qtype ) );
563 * @ret rc Return status code
565 static int dns_send_packet ( struct dns_request *dns ) {
566 struct dns_header *query = &dns->buf.query;
568 /* Start retransmission timer */
569 start_timer ( &dns->timer );
571 /* Generate query identifier */
572 query->id = random();
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 ) );
580 return xfer_deliver_raw ( &dns->socket, query, dns->len );
584 * Handle DNS retransmission timer expiry
586 * @v timer Retry timer
587 * @v fail Failure indicator
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 );
594 dns_done ( dns, -ETIMEDOUT );
596 dns_send_packet ( dns );
604 * @v iobuf I/O buffer
605 * @v meta Data transfer metadata
606 * @ret rc Return status code
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;
617 size_t answer_offset;
624 if ( iob_len ( iobuf ) < sizeof ( *response ) ) {
625 DBGC ( dns, "DNS %p received underlength packet length %zd\n",
626 dns, iob_len ( iobuf ) );
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 ) );
639 DBGC ( dns, "DNS %p received response ID %#04x\n",
640 dns, ntohs ( response->id ) );
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 ) );
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 );
657 DBGC ( dns, "DNS %p received response with malformed "
658 "question: %s\n", dns, strerror ( rc ) );
661 answer_offset = ( offset + sizeof ( struct dns_question ) );
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
668 for ( buf.offset = answer_offset ; buf.offset != buf.len ;
669 buf.offset = next_offset ) {
671 /* Check for valid name */
672 offset = dns_skip ( &buf );
675 DBGC ( dns, "DNS %p received response with malformed "
676 "answer: %s\n", dns, strerror ( rc ) );
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 "
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 "
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 ) );
706 switch ( rr->common.type ) {
708 case htons ( DNS_TYPE_AAAA ):
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 );
717 dns->address.sin6.sin6_family = AF_INET6;
718 memcpy ( &dns->address.sin6.sin6_addr,
720 sizeof ( dns->address.sin6.sin6_addr ) );
721 dns_resolved ( dns );
725 case htons ( DNS_TYPE_A ):
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 );
734 dns->address.sin.sin_family = AF_INET;
735 dns->address.sin.sin_addr = rr->a.in_addr;
736 dns_resolved ( dns );
740 case htons ( DNS_TYPE_CNAME ):
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",
747 dns_done ( dns, rc );
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 );
763 next_offset = answer_offset;
767 DBGC ( dns, "DNS %p got unknown record type %d\n",
768 dns, ntohs ( rr->common.type ) );
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
778 stop_timer ( &dns->timer );
780 /* Determine what to do next based on the type of query we
781 * issued and the response we received
785 case htons ( DNS_TYPE_AAAA ):
786 /* We asked for an AAAA record and got nothing; try
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 );
795 case htons ( DNS_TYPE_A ):
796 /* We asked for an A record and got nothing;
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 );
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),
810 if ( qtype == dns->qtype ) {
811 dns_send_packet ( dns );
816 /* If we have already reached the end of the search list,
817 * then terminate lookup.
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 );
826 /* Move to next entry in search list. This can never fail,
827 * since we have already used this entry.
829 DBGC ( dns, "DNS %p found no CNAME record; trying next "
831 dns->search.offset = dns_skip_search ( &dns->search );
832 if ( ( rc = dns_question ( dns ) ) != 0 ) {
833 dns_done ( dns, rc );
836 dns_send_packet ( dns );
842 dns_done ( dns, rc );
847 /* Free I/O buffer */
856 * @v rc Reason for close
858 static void dns_xfer_close ( struct dns_request *dns, int rc ) {
863 dns_done ( dns, rc );
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 ),
872 /** DNS socket interface descriptor */
873 static struct interface_descriptor dns_socket_desc =
874 INTF_DESC ( struct dns_request, socket, dns_socket_operations );
876 /** DNS resolver interface operations */
877 static struct interface_operation dns_resolv_op[] = {
878 INTF_OP ( intf_close, struct dns_request *, dns_done ),
881 /** DNS resolver interface descriptor */
882 static struct interface_descriptor dns_resolv_desc =
883 INTF_DESC ( struct dns_request, resolv, dns_resolv_op );
886 * Resolve name using DNS
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
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;
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;
909 /* Determine whether or not to use search list */
910 search_len = ( strchr ( name, '.' ) ? 0 : dns_search.len );
912 /* Allocate DNS structure */
913 dns = zalloc ( sizeof ( *dns ) + search_len );
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 );
927 /* Determine initial query type */
928 switch ( nameserver.sa.sa_family ) {
930 dns->qtype = htons ( DNS_TYPE_A );
933 dns->qtype = htons ( DNS_TYPE_AAAA );
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 ) {
952 dns->offset = ( offsetof ( typeof ( dns->buf ), name ) +
953 name_len - 1 /* Strip root label */ );
954 if ( ( rc = dns_question ( dns ) ) != 0 )
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;
965 /* Start timer to trigger first packet */
966 start_timer_nodelay ( &dns->timer );
968 /* Attach parent interface, mortalise self, and return */
969 intf_plug_plug ( &dns->resolv, resolv );
970 ref_put ( &dns->refcnt );
977 ref_put ( &dns->refcnt );
983 /** DNS name resolver */
984 struct resolver dns_resolver __resolver ( RESOLV_NORMAL ) = {
986 .resolv = dns_resolv,
989 /******************************************************************************
993 ******************************************************************************
997 * Format DNS search list setting
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
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 ),
1013 size_t remaining = len;
1017 while ( name.offset < raw_len ) {
1020 remaining = ( ( total < len ) ? ( len - total ) : 0 );
1021 name_len = dns_decode ( &name, ( buf + total ), remaining );
1026 /* Move to next name */
1027 name.offset = dns_skip_search ( &name );
1029 /* Add separator if applicable */
1030 if ( name.offset != raw_len ) {
1040 /** A DNS search list setting type */
1041 const struct setting_type setting_type_dnssl __setting_type = {
1043 .format = format_dnssl_setting,
1046 /** IPv4 DNS server setting */
1047 const struct setting dns_setting __setting ( SETTING_IP_EXTRA, dns ) = {
1049 .description = "DNS server",
1050 .tag = DHCP_DNS_SERVERS,
1051 .type = &setting_type_ipv4,
1054 /** IPv6 DNS server setting */
1055 const struct setting dns6_setting __setting ( SETTING_IP_EXTRA, dns6 ) = {
1057 .description = "DNS server",
1058 .tag = DHCPV6_DNS_SERVERS,
1059 .type = &setting_type_ipv6,
1060 .scope = &ipv6_scope,
1063 /** DNS search list */
1064 const struct setting dnssl_setting __setting ( SETTING_IP_EXTRA, dnssl ) = {
1066 .description = "DNS search list",
1067 .tag = DHCP_DOMAIN_SEARCH,
1068 .type = &setting_type_dnssl,
1072 * Apply DNS search list
1075 static void apply_dns_search ( void ) {
1079 /* Free existing search list */
1080 free ( dns_search.data );
1081 memset ( &dns_search, 0, sizeof ( dns_search ) );
1083 /* Fetch DNS search list */
1084 len = fetch_setting_copy ( NULL, &dnssl_setting, NULL, NULL,
1087 dns_search.len = len;
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 );
1096 dns_search.data = malloc ( len );
1097 if ( dns_search.data ) {
1098 dns_search.len = len;
1099 dns_encode ( localdomain, &dns_search );
1102 free ( localdomain );
1108 * Apply DNS settings
1110 * @ret rc Return status code
1112 static int apply_dns_settings ( void ) {
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;
1123 if ( nameserver.sa.sa_family ) {
1124 DBG ( "DNS using nameserver %s\n",
1125 sock_ntoa ( &nameserver.sa ) );
1128 /* Fetch DNS search list */
1130 if ( DBG_LOG && ( dns_search.len != 0 ) ) {
1131 struct dns_name name;
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 );
1141 name.offset = offset;
1149 /** DNS settings applicator */
1150 struct settings_applicator dns_applicator __settings_applicator = {
1151 .apply = apply_dns_settings,