Bläddra i källkod

[dns] Add support for resolving IPv6 addresses via AAAA records

Our policy is to prefer IPv6 addreses to IPv4 addresses, but to
request IPv6 addresses only if we have an IPv6 address for the name
server itself.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 11 år sedan
förälder
incheckning
6248894f52
4 ändrade filer med 112 tillägg och 36 borttagningar
  1. 2
    2
      src/include/ipxe/dhcpv6.h
  2. 7
    0
      src/include/ipxe/dns.h
  3. 1
    1
      src/net/udp/dhcpv6.c
  4. 102
    33
      src/net/udp/dns.c

+ 2
- 2
src/include/ipxe/dhcpv6.h Visa fil

@@ -147,10 +147,10 @@ struct dhcpv6_user_class_option {
147 147
 #define DHCPV6_USER_CLASS 15
148 148
 
149 149
 /** DHCPv6 DNS recursive name server option */
150
-#define DHCPV6_DNS_SERVER 23
150
+#define DHCPV6_DNS_SERVERS 23
151 151
 
152 152
 /** DHCPv6 domain search list option */
153
-#define DHCPV6_DOMAIN_SEARCH 24
153
+#define DHCPV6_DOMAIN_LIST 24
154 154
 
155 155
 /**
156 156
  * Any DHCPv6 option

+ 7
- 0
src/include/ipxe/dns.h Visa fil

@@ -19,6 +19,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
19 19
 
20 20
 #define DNS_TYPE_A		1
21 21
 #define DNS_TYPE_CNAME		5
22
+#define DNS_TYPE_AAAA		28
22 23
 #define DNS_TYPE_ANY		255
23 24
 
24 25
 #define DNS_CLASS_IN		1
@@ -78,6 +79,11 @@ struct dns_rr_info_a {
78 79
 	struct in_addr in_addr;
79 80
 } __attribute__ (( packed ));
80 81
 
82
+struct dns_rr_info_aaaa {
83
+	struct dns_rr_info_common common;
84
+	struct in6_addr in6_addr;
85
+} __attribute__ (( packed ));
86
+
81 87
 struct dns_rr_info_cname {
82 88
 	struct dns_rr_info_common common;
83 89
 	char cname[0];
@@ -86,6 +92,7 @@ struct dns_rr_info_cname {
86 92
 union dns_rr_info {
87 93
 	struct dns_rr_info_common common;
88 94
 	struct dns_rr_info_a a;
95
+	struct dns_rr_info_aaaa aaaa;
89 96
 	struct dns_rr_info_cname cname;
90 97
 };
91 98
 

+ 1
- 1
src/net/udp/dhcpv6.c Visa fil

@@ -362,7 +362,7 @@ static int dhcpv6_register ( struct dhcpv6_option_list *options,
362 362
 
363 363
 /** Options to be requested */
364 364
 static uint16_t dhcpv6_requested_options[] = {
365
-	htons ( DHCPV6_DNS_SERVER ), htons ( DHCPV6_DOMAIN_SEARCH ),
365
+	htons ( DHCPV6_DNS_SERVERS ), htons ( DHCPV6_DOMAIN_LIST ),
366 366
 };
367 367
 
368 368
 /**

+ 102
- 33
src/net/udp/dns.c Visa fil

@@ -37,6 +37,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
37 37
 #include <ipxe/tcpip.h>
38 38
 #include <ipxe/settings.h>
39 39
 #include <ipxe/features.h>
40
+#include <ipxe/dhcp.h>
41
+#include <ipxe/dhcpv6.h>
40 42
 #include <ipxe/dns.h>
41 43
 
42 44
 /** @file
@@ -56,8 +58,15 @@ FEATURE ( FEATURE_PROTOCOL, "DNS", DHCP_EB_FEATURE_DNS, 1 );
56 58
 	__einfo_uniqify ( EINFO_ENXIO, 0x02, "No DNS servers available" )
57 59
 
58 60
 /** The DNS server */
59
-static struct sockaddr_tcpip nameserver = {
60
-	.st_port = htons ( DNS_PORT ),
61
+static union {
62
+	struct sockaddr sa;
63
+	struct sockaddr_tcpip st;
64
+	struct sockaddr_in sin;
65
+	struct sockaddr_in6 sin6;
66
+} nameserver = {
67
+	.st = {
68
+		.st_port = htons ( DNS_PORT ),
69
+	},
61 70
 };
62 71
 
63 72
 /** The local domain */
@@ -75,7 +84,13 @@ struct dns_request {
75 84
 	struct retry_timer timer;
76 85
 
77 86
 	/** Socket address to fill in with resolved address */
78
-	struct sockaddr sa;
87
+	union {
88
+		struct sockaddr sa;
89
+		struct sockaddr_in sin;
90
+		struct sockaddr_in6 sin6;
91
+	} address;
92
+	/** Initial query type */
93
+	uint16_t qtype;
79 94
 	/** Current query packet */
80 95
 	struct dns_query query;
81 96
 	/** Location of query info structure within current packet
@@ -104,6 +119,24 @@ static void dns_done ( struct dns_request *dns, int rc ) {
104 119
 	intf_shutdown ( &dns->resolv, rc );
105 120
 }
106 121
 
122
+/**
123
+ * Mark DNS request as resolved and complete
124
+ *
125
+ * @v dns		DNS request
126
+ * @v rc		Return status code
127
+ */
128
+static void dns_resolved ( struct dns_request *dns ) {
129
+
130
+	DBGC ( dns, "DNS %p found address %s\n",
131
+	       dns, sock_ntoa ( &dns->address.sa ) );
132
+
133
+	/* Return resolved address */
134
+	resolv_done ( &dns->resolv, &dns->address.sa );
135
+
136
+	/* Mark operation as complete */
137
+	dns_done ( dns, 0 );
138
+}
139
+
107 140
 /**
108 141
  * Compare DNS reply name against the query name from the original request
109 142
  *
@@ -345,7 +378,6 @@ static int dns_xfer_deliver ( struct dns_request *dns,
345 378
 			      struct xfer_metadata *meta __unused ) {
346 379
 	const struct dns_header *reply = iobuf->data;
347 380
 	union dns_rr_info *rr_info;
348
-	struct sockaddr_in *sin;
349 381
 	unsigned int qtype = dns->qinfo->qtype;
350 382
 	int rc;
351 383
 
@@ -383,20 +415,23 @@ static int dns_xfer_deliver ( struct dns_request *dns,
383 415
 	while ( ( rr_info = dns_find_rr ( dns, reply ) ) ) {
384 416
 		switch ( rr_info->common.type ) {
385 417
 
386
-		case htons ( DNS_TYPE_A ):
418
+		case htons ( DNS_TYPE_AAAA ):
387 419
 
388
-			/* Found the target A record */
389
-			DBGC ( dns, "DNS %p found address %s\n",
390
-			       dns, inet_ntoa ( rr_info->a.in_addr ) );
391
-			sin = ( struct sockaddr_in * ) &dns->sa;
392
-			sin->sin_family = AF_INET;
393
-			sin->sin_addr = rr_info->a.in_addr;
420
+			/* Found the target AAAA record */
421
+			dns->address.sin6.sin6_family = AF_INET6;
422
+			memcpy ( &dns->address.sin6.sin6_addr,
423
+				 &rr_info->aaaa.in6_addr,
424
+				 sizeof ( dns->address.sin6.sin6_addr ) );
425
+			dns_resolved ( dns );
426
+			rc = 0;
427
+			goto done;
394 428
 
395
-			/* Return resolved address */
396
-			resolv_done ( &dns->resolv, &dns->sa );
429
+		case htons ( DNS_TYPE_A ):
397 430
 
398
-			/* Mark operation as complete */
399
-			dns_done ( dns, 0 );
431
+			/* Found the target A record */
432
+			dns->address.sin.sin_family = AF_INET;
433
+			dns->address.sin.sin_addr = rr_info->a.in_addr;
434
+			dns_resolved ( dns );
400 435
 			rc = 0;
401 436
 			goto done;
402 437
 
@@ -407,7 +442,7 @@ static int dns_xfer_deliver ( struct dns_request *dns,
407 442
 			dns->qinfo = ( void * ) dns_decompress_name ( reply,
408 443
 							 rr_info->cname.cname,
409 444
 							 dns->query.payload );
410
-			dns->qinfo->qtype = htons ( DNS_TYPE_A );
445
+			dns->qinfo->qtype = dns->qtype;
411 446
 			dns->qinfo->qclass = htons ( DNS_CLASS_IN );
412 447
 			
413 448
 			/* Terminate the operation if we recurse too far */
@@ -432,6 +467,16 @@ static int dns_xfer_deliver ( struct dns_request *dns,
432 467
 	 */
433 468
 	switch ( qtype ) {
434 469
 
470
+	case htons ( DNS_TYPE_AAAA ):
471
+		/* We asked for an AAAA record and got nothing; try
472
+		 * the A.
473
+		 */
474
+		DBGC ( dns, "DNS %p found no AAAA record; trying A\n", dns );
475
+		dns->qinfo->qtype = htons ( DNS_TYPE_A );
476
+		dns_send_packet ( dns );
477
+		rc = 0;
478
+		goto done;
479
+
435 480
 	case htons ( DNS_TYPE_A ):
436 481
 		/* We asked for an A record and got nothing;
437 482
 		 * try the CNAME.
@@ -447,7 +492,7 @@ static int dns_xfer_deliver ( struct dns_request *dns,
447 492
 		 * (i.e. if the next A query is already set up), then
448 493
 		 * issue it, otherwise abort.
449 494
 		 */
450
-		if ( dns->qinfo->qtype == htons ( DNS_TYPE_A ) ) {
495
+		if ( dns->qinfo->qtype == dns->qtype ) {
451 496
 			dns_send_packet ( dns );
452 497
 			rc = 0;
453 498
 			goto done;
@@ -519,7 +564,7 @@ static int dns_resolv ( struct interface *resolv,
519 564
 	int rc;
520 565
 
521 566
 	/* Fail immediately if no DNS servers */
522
-	if ( ! nameserver.st_family ) {
567
+	if ( ! nameserver.sa.sa_family ) {
523 568
 		DBG ( "DNS not attempting to resolve \"%s\": "
524 569
 		      "no DNS servers\n", name );
525 570
 		rc = -ENXIO_NO_NAMESERVER;
@@ -543,20 +588,32 @@ static int dns_resolv ( struct interface *resolv,
543 588
 	intf_init ( &dns->resolv, &dns_resolv_desc, &dns->refcnt );
544 589
 	intf_init ( &dns->socket, &dns_socket_desc, &dns->refcnt );
545 590
 	timer_init ( &dns->timer, dns_timer_expired, &dns->refcnt );
546
-	memcpy ( &dns->sa, sa, sizeof ( dns->sa ) );
591
+	memcpy ( &dns->address.sa, sa, sizeof ( dns->address.sa ) );
592
+
593
+	/* Determine initial query type */
594
+	switch ( nameserver.sa.sa_family ) {
595
+	case AF_INET:
596
+		dns->qtype = htons ( DNS_TYPE_A );
597
+		break;
598
+	case AF_INET6:
599
+		dns->qtype = htons ( DNS_TYPE_AAAA );
600
+		break;
601
+	default:
602
+		rc = -ENOTSUP;
603
+		goto err_qtype;
604
+	}
547 605
 
548 606
 	/* Create query */
549 607
 	dns->query.dns.flags = htons ( DNS_FLAG_QUERY | DNS_FLAG_OPCODE_QUERY |
550 608
 				       DNS_FLAG_RD );
551 609
 	dns->query.dns.qdcount = htons ( 1 );
552 610
 	dns->qinfo = ( void * ) dns_make_name ( fqdn, dns->query.payload );
553
-	dns->qinfo->qtype = htons ( DNS_TYPE_A );
611
+	dns->qinfo->qtype = dns->qtype;
554 612
 	dns->qinfo->qclass = htons ( DNS_CLASS_IN );
555 613
 
556 614
 	/* Open UDP connection */
557 615
 	if ( ( rc = xfer_open_socket ( &dns->socket, SOCK_DGRAM,
558
-				       ( struct sockaddr * ) &nameserver,
559
-				       NULL ) ) != 0 ) {
616
+				       &nameserver.sa, NULL ) ) != 0 ) {
560 617
 		DBGC ( dns, "DNS %p could not open socket: %s\n",
561 618
 		       dns, strerror ( rc ) );
562 619
 		goto err_open_socket;
@@ -572,10 +629,11 @@ static int dns_resolv ( struct interface *resolv,
572 629
 	return 0;	
573 630
 
574 631
  err_open_socket:
575
- err_alloc_dns:
632
+ err_qtype:
576 633
 	ref_put ( &dns->refcnt );
577
- err_qualify_name:
634
+ err_alloc_dns:
578 635
 	free ( fqdn );
636
+ err_qualify_name:
579 637
  err_no_nameserver:
580 638
 	return rc;
581 639
 }
@@ -593,7 +651,7 @@ struct resolver dns_resolver __resolver ( RESOLV_NORMAL ) = {
593 651
  ******************************************************************************
594 652
  */
595 653
 
596
-/** DNS server setting */
654
+/** IPv4 DNS server setting */
597 655
 const struct setting dns_setting __setting ( SETTING_IPv4_EXTRA ) = {
598 656
 	.name = "dns",
599 657
 	.description = "DNS server",
@@ -601,23 +659,34 @@ const struct setting dns_setting __setting ( SETTING_IPv4_EXTRA ) = {
601 659
 	.type = &setting_type_ipv4,
602 660
 };
603 661
 
662
+/** IPv6 DNS server setting */
663
+const struct setting dns6_setting __setting ( SETTING_IPv6_EXTRA ) = {
664
+	.name = "dns6",
665
+	.description = "DNS server",
666
+	.tag = DHCPV6_DNS_SERVERS,
667
+	.type = &setting_type_ipv6,
668
+	.scope = &ipv6_scope,
669
+};
670
+
604 671
 /**
605 672
  * Apply DNS settings
606 673
  *
607 674
  * @ret rc		Return status code
608 675
  */
609 676
 static int apply_dns_settings ( void ) {
610
-	struct sockaddr_in *sin_nameserver =
611
-		( struct sockaddr_in * ) &nameserver;
612
-	int len;
613 677
 
614 678
 	/* Fetch DNS server address */
615
-	nameserver.st_family = 0;
616
-	if ( ( len = fetch_ipv4_setting ( NULL, &dns_setting,
617
-					  &sin_nameserver->sin_addr ) ) >= 0 ){
618
-		nameserver.st_family = AF_INET;
679
+	nameserver.sa.sa_family = 0;
680
+	if ( fetch_ipv6_setting ( NULL, &dns6_setting,
681
+				  &nameserver.sin6.sin6_addr ) >= 0 ) {
682
+		nameserver.sin6.sin6_family = AF_INET6;
683
+	} else if ( fetch_ipv4_setting ( NULL, &dns_setting,
684
+					 &nameserver.sin.sin_addr ) >= 0 ) {
685
+		nameserver.sin.sin_family = AF_INET;
686
+	}
687
+	if ( nameserver.sa.sa_family ) {
619 688
 		DBG ( "DNS using nameserver %s\n",
620
-		      inet_ntoa ( sin_nameserver->sin_addr ) );
689
+		      sock_ntoa ( &nameserver.sa ) );
621 690
 	}
622 691
 
623 692
 	/* Get local domain DHCP option */

Laddar…
Avbryt
Spara