|
@@ -22,6 +22,7 @@
|
22
|
22
|
#include <stdint.h>
|
23
|
23
|
#include <stdlib.h>
|
24
|
24
|
#include <string.h>
|
|
25
|
+#include <stdio.h>
|
25
|
26
|
#include <errno.h>
|
26
|
27
|
#include <byteswap.h>
|
27
|
28
|
#include <gpxe/refcnt.h>
|
|
@@ -47,6 +48,9 @@ static struct sockaddr_tcpip nameserver = {
|
47
|
48
|
.st_port = htons ( DNS_PORT ),
|
48
|
49
|
};
|
49
|
50
|
|
|
51
|
+/** The local domain */
|
|
52
|
+static char *localdomain;
|
|
53
|
+
|
50
|
54
|
/** A DNS request */
|
51
|
55
|
struct dns_request {
|
52
|
56
|
/** Reference counter */
|
|
@@ -179,6 +183,27 @@ static union dns_rr_info * dns_find_rr ( struct dns_request *dns,
|
179
|
183
|
return NULL;
|
180
|
184
|
}
|
181
|
185
|
|
|
186
|
+/**
|
|
187
|
+ * Append DHCP domain name if available and name is not fully qualified
|
|
188
|
+ *
|
|
189
|
+ * @v string Name as a NUL-terminated string
|
|
190
|
+ * @ret fqdn Fully-qualified domain name, malloc'd copy
|
|
191
|
+ *
|
|
192
|
+ * The caller must free fqdn which is allocated even if the name is already
|
|
193
|
+ * fully qualified.
|
|
194
|
+ */
|
|
195
|
+static char * dns_qualify_name ( const char *string ) {
|
|
196
|
+ char *fqdn;
|
|
197
|
+
|
|
198
|
+ /* Leave unchanged if already fully-qualified or no local domain */
|
|
199
|
+ if ( ( ! localdomain ) || ( strchr ( string, '.' ) != 0 ) )
|
|
200
|
+ return strdup ( string );
|
|
201
|
+
|
|
202
|
+ /* Append local domain to name */
|
|
203
|
+ asprintf ( &fqdn, "%s.%s", string, localdomain );
|
|
204
|
+ return fqdn;
|
|
205
|
+}
|
|
206
|
+
|
182
|
207
|
/**
|
183
|
208
|
* Convert a standard NUL-terminated string to a DNS name
|
184
|
209
|
*
|
|
@@ -452,19 +477,30 @@ static struct xfer_interface_operations dns_socket_operations = {
|
452
|
477
|
static int dns_resolv ( struct resolv_interface *resolv,
|
453
|
478
|
const char *name, struct sockaddr *sa ) {
|
454
|
479
|
struct dns_request *dns;
|
|
480
|
+ char *fqdn;
|
455
|
481
|
int rc;
|
456
|
482
|
|
457
|
483
|
/* Fail immediately if no DNS servers */
|
458
|
484
|
if ( ! nameserver.st_family ) {
|
459
|
485
|
DBG ( "DNS not attempting to resolve \"%s\": "
|
460
|
486
|
"no DNS servers\n", name );
|
461
|
|
- return -ENXIO;
|
|
487
|
+ rc = -ENXIO;
|
|
488
|
+ goto err_no_nameserver;
|
|
489
|
+ }
|
|
490
|
+
|
|
491
|
+ /* Ensure fully-qualified domain name if DHCP option was given */
|
|
492
|
+ fqdn = dns_qualify_name ( name );
|
|
493
|
+ if ( ! fqdn ) {
|
|
494
|
+ rc = -ENOMEM;
|
|
495
|
+ goto err_qualify_name;
|
462
|
496
|
}
|
463
|
497
|
|
464
|
498
|
/* Allocate DNS structure */
|
465
|
499
|
dns = zalloc ( sizeof ( *dns ) );
|
466
|
|
- if ( ! dns )
|
467
|
|
- return -ENOMEM;
|
|
500
|
+ if ( ! dns ) {
|
|
501
|
+ rc = -ENOMEM;
|
|
502
|
+ goto err_alloc_dns;
|
|
503
|
+ }
|
468
|
504
|
resolv_init ( &dns->resolv, &null_resolv_ops, &dns->refcnt );
|
469
|
505
|
xfer_init ( &dns->socket, &dns_socket_operations, &dns->refcnt );
|
470
|
506
|
dns->timer.expired = dns_timer_expired;
|
|
@@ -474,7 +510,7 @@ static int dns_resolv ( struct resolv_interface *resolv,
|
474
|
510
|
dns->query.dns.flags = htons ( DNS_FLAG_QUERY | DNS_FLAG_OPCODE_QUERY |
|
475
|
511
|
DNS_FLAG_RD );
|
476
|
512
|
dns->query.dns.qdcount = htons ( 1 );
|
477
|
|
- dns->qinfo = ( void * ) dns_make_name ( name, dns->query.payload );
|
|
513
|
+ dns->qinfo = ( void * ) dns_make_name ( fqdn, dns->query.payload );
|
478
|
514
|
dns->qinfo->qtype = htons ( DNS_TYPE_A );
|
479
|
515
|
dns->qinfo->qclass = htons ( DNS_CLASS_IN );
|
480
|
516
|
|
|
@@ -484,7 +520,7 @@ static int dns_resolv ( struct resolv_interface *resolv,
|
484
|
520
|
NULL ) ) != 0 ) {
|
485
|
521
|
DBGC ( dns, "DNS %p could not open socket: %s\n",
|
486
|
522
|
dns, strerror ( rc ) );
|
487
|
|
- goto err;
|
|
523
|
+ goto err_open_socket;
|
488
|
524
|
}
|
489
|
525
|
|
490
|
526
|
/* Send first DNS packet */
|
|
@@ -493,10 +529,15 @@ static int dns_resolv ( struct resolv_interface *resolv,
|
493
|
529
|
/* Attach parent interface, mortalise self, and return */
|
494
|
530
|
resolv_plug_plug ( &dns->resolv, resolv );
|
495
|
531
|
ref_put ( &dns->refcnt );
|
|
532
|
+ free ( fqdn );
|
496
|
533
|
return 0;
|
497
|
534
|
|
498
|
|
- err:
|
|
535
|
+ err_open_socket:
|
|
536
|
+ err_alloc_dns:
|
499
|
537
|
ref_put ( &dns->refcnt );
|
|
538
|
+ err_qualify_name:
|
|
539
|
+ free ( fqdn );
|
|
540
|
+ err_no_nameserver:
|
500
|
541
|
return rc;
|
501
|
542
|
}
|
502
|
543
|
|
|
@@ -521,12 +562,20 @@ struct setting dns_setting __setting = {
|
521
|
562
|
.type = &setting_type_ipv4,
|
522
|
563
|
};
|
523
|
564
|
|
|
565
|
+/** Domain name setting */
|
|
566
|
+struct setting domain_setting __setting = {
|
|
567
|
+ .name = "domain",
|
|
568
|
+ .description = "Local domain",
|
|
569
|
+ .tag = DHCP_DOMAIN_NAME,
|
|
570
|
+ .type = &setting_type_string,
|
|
571
|
+};
|
|
572
|
+
|
524
|
573
|
/**
|
525
|
|
- * Apply nameserver setting
|
|
574
|
+ * Apply DNS settings
|
526
|
575
|
*
|
527
|
576
|
* @ret rc Return status code
|
528
|
577
|
*/
|
529
|
|
-static int apply_nameserver_setting ( void ) {
|
|
578
|
+static int apply_dns_settings ( void ) {
|
530
|
579
|
struct sockaddr_in *sin_nameserver =
|
531
|
580
|
( struct sockaddr_in * ) &nameserver;
|
532
|
581
|
int len;
|
|
@@ -538,10 +587,15 @@ static int apply_nameserver_setting ( void ) {
|
538
|
587
|
inet_ntoa ( sin_nameserver->sin_addr ) );
|
539
|
588
|
}
|
540
|
589
|
|
|
590
|
+ /* Get local domain DHCP option */
|
|
591
|
+ if ( ( len = fetch_string_setting_copy ( NULL, &domain_setting,
|
|
592
|
+ &localdomain ) ) >= 0 )
|
|
593
|
+ DBG ( "DNS local domain %s\n", localdomain );
|
|
594
|
+
|
541
|
595
|
return 0;
|
542
|
596
|
}
|
543
|
597
|
|
544
|
|
-/** Nameserver setting applicator */
|
545
|
|
-struct settings_applicator nameserver_applicator __settings_applicator = {
|
546
|
|
- .apply = apply_nameserver_setting,
|
|
598
|
+/** DNS settings applicator */
|
|
599
|
+struct settings_applicator dns_applicator __settings_applicator = {
|
|
600
|
+ .apply = apply_dns_settings,
|
547
|
601
|
};
|