Преглед изворни кода

[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 година
родитељ
комит
6248894f52
4 измењених фајлова са 112 додато и 36 уклоњено
  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 Прегледај датотеку

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

+ 7
- 0
src/include/ipxe/dns.h Прегледај датотеку

19
 
19
 
20
 #define DNS_TYPE_A		1
20
 #define DNS_TYPE_A		1
21
 #define DNS_TYPE_CNAME		5
21
 #define DNS_TYPE_CNAME		5
22
+#define DNS_TYPE_AAAA		28
22
 #define DNS_TYPE_ANY		255
23
 #define DNS_TYPE_ANY		255
23
 
24
 
24
 #define DNS_CLASS_IN		1
25
 #define DNS_CLASS_IN		1
78
 	struct in_addr in_addr;
79
 	struct in_addr in_addr;
79
 } __attribute__ (( packed ));
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
 struct dns_rr_info_cname {
87
 struct dns_rr_info_cname {
82
 	struct dns_rr_info_common common;
88
 	struct dns_rr_info_common common;
83
 	char cname[0];
89
 	char cname[0];
86
 union dns_rr_info {
92
 union dns_rr_info {
87
 	struct dns_rr_info_common common;
93
 	struct dns_rr_info_common common;
88
 	struct dns_rr_info_a a;
94
 	struct dns_rr_info_a a;
95
+	struct dns_rr_info_aaaa aaaa;
89
 	struct dns_rr_info_cname cname;
96
 	struct dns_rr_info_cname cname;
90
 };
97
 };
91
 
98
 

+ 1
- 1
src/net/udp/dhcpv6.c Прегледај датотеку

362
 
362
 
363
 /** Options to be requested */
363
 /** Options to be requested */
364
 static uint16_t dhcpv6_requested_options[] = {
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 Прегледај датотеку

37
 #include <ipxe/tcpip.h>
37
 #include <ipxe/tcpip.h>
38
 #include <ipxe/settings.h>
38
 #include <ipxe/settings.h>
39
 #include <ipxe/features.h>
39
 #include <ipxe/features.h>
40
+#include <ipxe/dhcp.h>
41
+#include <ipxe/dhcpv6.h>
40
 #include <ipxe/dns.h>
42
 #include <ipxe/dns.h>
41
 
43
 
42
 /** @file
44
 /** @file
56
 	__einfo_uniqify ( EINFO_ENXIO, 0x02, "No DNS servers available" )
58
 	__einfo_uniqify ( EINFO_ENXIO, 0x02, "No DNS servers available" )
57
 
59
 
58
 /** The DNS server */
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
 /** The local domain */
72
 /** The local domain */
75
 	struct retry_timer timer;
84
 	struct retry_timer timer;
76
 
85
 
77
 	/** Socket address to fill in with resolved address */
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
 	/** Current query packet */
94
 	/** Current query packet */
80
 	struct dns_query query;
95
 	struct dns_query query;
81
 	/** Location of query info structure within current packet
96
 	/** Location of query info structure within current packet
104
 	intf_shutdown ( &dns->resolv, rc );
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
  * Compare DNS reply name against the query name from the original request
141
  * Compare DNS reply name against the query name from the original request
109
  *
142
  *
345
 			      struct xfer_metadata *meta __unused ) {
378
 			      struct xfer_metadata *meta __unused ) {
346
 	const struct dns_header *reply = iobuf->data;
379
 	const struct dns_header *reply = iobuf->data;
347
 	union dns_rr_info *rr_info;
380
 	union dns_rr_info *rr_info;
348
-	struct sockaddr_in *sin;
349
 	unsigned int qtype = dns->qinfo->qtype;
381
 	unsigned int qtype = dns->qinfo->qtype;
350
 	int rc;
382
 	int rc;
351
 
383
 
383
 	while ( ( rr_info = dns_find_rr ( dns, reply ) ) ) {
415
 	while ( ( rr_info = dns_find_rr ( dns, reply ) ) ) {
384
 		switch ( rr_info->common.type ) {
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
 			rc = 0;
435
 			rc = 0;
401
 			goto done;
436
 			goto done;
402
 
437
 
407
 			dns->qinfo = ( void * ) dns_decompress_name ( reply,
442
 			dns->qinfo = ( void * ) dns_decompress_name ( reply,
408
 							 rr_info->cname.cname,
443
 							 rr_info->cname.cname,
409
 							 dns->query.payload );
444
 							 dns->query.payload );
410
-			dns->qinfo->qtype = htons ( DNS_TYPE_A );
445
+			dns->qinfo->qtype = dns->qtype;
411
 			dns->qinfo->qclass = htons ( DNS_CLASS_IN );
446
 			dns->qinfo->qclass = htons ( DNS_CLASS_IN );
412
 			
447
 			
413
 			/* Terminate the operation if we recurse too far */
448
 			/* Terminate the operation if we recurse too far */
432
 	 */
467
 	 */
433
 	switch ( qtype ) {
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
 	case htons ( DNS_TYPE_A ):
480
 	case htons ( DNS_TYPE_A ):
436
 		/* We asked for an A record and got nothing;
481
 		/* We asked for an A record and got nothing;
437
 		 * try the CNAME.
482
 		 * try the CNAME.
447
 		 * (i.e. if the next A query is already set up), then
492
 		 * (i.e. if the next A query is already set up), then
448
 		 * issue it, otherwise abort.
493
 		 * issue it, otherwise abort.
449
 		 */
494
 		 */
450
-		if ( dns->qinfo->qtype == htons ( DNS_TYPE_A ) ) {
495
+		if ( dns->qinfo->qtype == dns->qtype ) {
451
 			dns_send_packet ( dns );
496
 			dns_send_packet ( dns );
452
 			rc = 0;
497
 			rc = 0;
453
 			goto done;
498
 			goto done;
519
 	int rc;
564
 	int rc;
520
 
565
 
521
 	/* Fail immediately if no DNS servers */
566
 	/* Fail immediately if no DNS servers */
522
-	if ( ! nameserver.st_family ) {
567
+	if ( ! nameserver.sa.sa_family ) {
523
 		DBG ( "DNS not attempting to resolve \"%s\": "
568
 		DBG ( "DNS not attempting to resolve \"%s\": "
524
 		      "no DNS servers\n", name );
569
 		      "no DNS servers\n", name );
525
 		rc = -ENXIO_NO_NAMESERVER;
570
 		rc = -ENXIO_NO_NAMESERVER;
543
 	intf_init ( &dns->resolv, &dns_resolv_desc, &dns->refcnt );
588
 	intf_init ( &dns->resolv, &dns_resolv_desc, &dns->refcnt );
544
 	intf_init ( &dns->socket, &dns_socket_desc, &dns->refcnt );
589
 	intf_init ( &dns->socket, &dns_socket_desc, &dns->refcnt );
545
 	timer_init ( &dns->timer, dns_timer_expired, &dns->refcnt );
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
 	/* Create query */
606
 	/* Create query */
549
 	dns->query.dns.flags = htons ( DNS_FLAG_QUERY | DNS_FLAG_OPCODE_QUERY |
607
 	dns->query.dns.flags = htons ( DNS_FLAG_QUERY | DNS_FLAG_OPCODE_QUERY |
550
 				       DNS_FLAG_RD );
608
 				       DNS_FLAG_RD );
551
 	dns->query.dns.qdcount = htons ( 1 );
609
 	dns->query.dns.qdcount = htons ( 1 );
552
 	dns->qinfo = ( void * ) dns_make_name ( fqdn, dns->query.payload );
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
 	dns->qinfo->qclass = htons ( DNS_CLASS_IN );
612
 	dns->qinfo->qclass = htons ( DNS_CLASS_IN );
555
 
613
 
556
 	/* Open UDP connection */
614
 	/* Open UDP connection */
557
 	if ( ( rc = xfer_open_socket ( &dns->socket, SOCK_DGRAM,
615
 	if ( ( rc = xfer_open_socket ( &dns->socket, SOCK_DGRAM,
558
-				       ( struct sockaddr * ) &nameserver,
559
-				       NULL ) ) != 0 ) {
616
+				       &nameserver.sa, NULL ) ) != 0 ) {
560
 		DBGC ( dns, "DNS %p could not open socket: %s\n",
617
 		DBGC ( dns, "DNS %p could not open socket: %s\n",
561
 		       dns, strerror ( rc ) );
618
 		       dns, strerror ( rc ) );
562
 		goto err_open_socket;
619
 		goto err_open_socket;
572
 	return 0;	
629
 	return 0;	
573
 
630
 
574
  err_open_socket:
631
  err_open_socket:
575
- err_alloc_dns:
632
+ err_qtype:
576
 	ref_put ( &dns->refcnt );
633
 	ref_put ( &dns->refcnt );
577
- err_qualify_name:
634
+ err_alloc_dns:
578
 	free ( fqdn );
635
 	free ( fqdn );
636
+ err_qualify_name:
579
  err_no_nameserver:
637
  err_no_nameserver:
580
 	return rc;
638
 	return rc;
581
 }
639
 }
593
  ******************************************************************************
651
  ******************************************************************************
594
  */
652
  */
595
 
653
 
596
-/** DNS server setting */
654
+/** IPv4 DNS server setting */
597
 const struct setting dns_setting __setting ( SETTING_IPv4_EXTRA ) = {
655
 const struct setting dns_setting __setting ( SETTING_IPv4_EXTRA ) = {
598
 	.name = "dns",
656
 	.name = "dns",
599
 	.description = "DNS server",
657
 	.description = "DNS server",
601
 	.type = &setting_type_ipv4,
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
  * Apply DNS settings
672
  * Apply DNS settings
606
  *
673
  *
607
  * @ret rc		Return status code
674
  * @ret rc		Return status code
608
  */
675
  */
609
 static int apply_dns_settings ( void ) {
676
 static int apply_dns_settings ( void ) {
610
-	struct sockaddr_in *sin_nameserver =
611
-		( struct sockaddr_in * ) &nameserver;
612
-	int len;
613
 
677
 
614
 	/* Fetch DNS server address */
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
 		DBG ( "DNS using nameserver %s\n",
688
 		DBG ( "DNS using nameserver %s\n",
620
-		      inet_ntoa ( sin_nameserver->sin_addr ) );
689
+		      sock_ntoa ( &nameserver.sa ) );
621
 	}
690
 	}
622
 
691
 
623
 	/* Get local domain DHCP option */
692
 	/* Get local domain DHCP option */

Loading…
Откажи
Сачувај