mirror of https://github.com/ipxe/ipxe.git
[dns] Use all configured DNS servers
When no response is obtained from the first configured DNS server, fall back to attempting the other configured servers. Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/121/head
parent
a95a2eafc5
commit
366206517e
|
@ -63,18 +63,33 @@ FEATURE ( FEATURE_PROTOCOL, "DNS", DHCP_EB_FEATURE_DNS, 1 );
|
||||||
#define EINFO_ENXIO_NO_NAMESERVER \
|
#define EINFO_ENXIO_NO_NAMESERVER \
|
||||||
__einfo_uniqify ( EINFO_ENXIO, 0x02, "No DNS servers available" )
|
__einfo_uniqify ( EINFO_ENXIO, 0x02, "No DNS servers available" )
|
||||||
|
|
||||||
/** The DNS server */
|
/** A DNS server list */
|
||||||
static union {
|
struct dns_server {
|
||||||
struct sockaddr sa;
|
/** Server list */
|
||||||
struct sockaddr_tcpip st;
|
union {
|
||||||
struct sockaddr_in sin;
|
/** IPv4 addresses */
|
||||||
struct sockaddr_in6 sin6;
|
struct in_addr *in;
|
||||||
} nameserver = {
|
/** IPv6 addresses */
|
||||||
.st = {
|
struct in6_addr *in6;
|
||||||
.st_port = htons ( DNS_PORT ),
|
/** Raw data */
|
||||||
},
|
void *data;
|
||||||
|
};
|
||||||
|
/** Number of servers */
|
||||||
|
unsigned int count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** IPv4 DNS server list */
|
||||||
|
static struct dns_server dns4;
|
||||||
|
|
||||||
|
/** IPv6 DNS server list */
|
||||||
|
static struct dns_server dns6;
|
||||||
|
|
||||||
|
/** Total number of DNS servers */
|
||||||
|
static unsigned int dns_count;
|
||||||
|
|
||||||
|
/** Current DNS server index */
|
||||||
|
static unsigned int dns_index;
|
||||||
|
|
||||||
/** The DNS search list */
|
/** The DNS search list */
|
||||||
static struct dns_name dns_search;
|
static struct dns_name dns_search;
|
||||||
|
|
||||||
|
@ -555,6 +570,9 @@ static int dns_question ( struct dns_request *dns ) {
|
||||||
/* Restore name */
|
/* Restore name */
|
||||||
dns->name.offset = offsetof ( typeof ( dns->buf ), name );
|
dns->name.offset = offsetof ( typeof ( dns->buf ), name );
|
||||||
|
|
||||||
|
/* Reset query ID */
|
||||||
|
dns->buf.query.id = 0;
|
||||||
|
|
||||||
DBGC2 ( dns, "DNS %p question is %s type %s\n", dns,
|
DBGC2 ( dns, "DNS %p question is %s type %s\n", dns,
|
||||||
dns_name ( &dns->name ), dns_type ( dns->question->qtype ) );
|
dns_name ( &dns->name ), dns_type ( dns->question->qtype ) );
|
||||||
|
|
||||||
|
@ -569,24 +587,54 @@ static int dns_question ( struct dns_request *dns ) {
|
||||||
*/
|
*/
|
||||||
static int dns_send_packet ( struct dns_request *dns ) {
|
static int dns_send_packet ( struct dns_request *dns ) {
|
||||||
struct dns_header *query = &dns->buf.query;
|
struct dns_header *query = &dns->buf.query;
|
||||||
|
union {
|
||||||
|
struct sockaddr sa;
|
||||||
|
struct sockaddr_tcpip st;
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
struct sockaddr_in6 sin6;
|
||||||
|
} nameserver;
|
||||||
|
struct xfer_metadata meta;
|
||||||
|
unsigned int index;
|
||||||
|
|
||||||
/* Start retransmission timer */
|
/* Start retransmission timer */
|
||||||
start_timer ( &dns->timer );
|
start_timer ( &dns->timer );
|
||||||
|
|
||||||
/* Generate query identifier */
|
/* Construct DNS server address */
|
||||||
query->id = random();
|
memset ( &nameserver, 0, sizeof ( nameserver ) );
|
||||||
|
nameserver.st.st_port = htons ( DNS_PORT );
|
||||||
|
if ( ! dns_count ) {
|
||||||
|
DBGC ( dns, "DNS %p lost DNS servers mid query\n", dns );
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
index = ( dns_index % dns_count );
|
||||||
|
if ( index < dns6.count ) {
|
||||||
|
nameserver.sin6.sin6_family = AF_INET6;
|
||||||
|
memcpy ( &nameserver.sin6.sin6_addr, &dns6.in6[index],
|
||||||
|
sizeof ( nameserver.sin6.sin6_addr ) );
|
||||||
|
} else {
|
||||||
|
nameserver.sin.sin_family = AF_INET;
|
||||||
|
nameserver.sin.sin_addr = dns4.in[index - dns6.count];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Construct metadata */
|
||||||
|
memset ( &meta, 0, sizeof ( meta ) );
|
||||||
|
meta.dest = &nameserver.sa;
|
||||||
|
|
||||||
|
/* Generate query identifier if applicable */
|
||||||
|
if ( ! query->id )
|
||||||
|
query->id = random();
|
||||||
|
|
||||||
/* Send query */
|
/* Send query */
|
||||||
DBGC ( dns, "DNS %p sending query ID %#04x for %s type %s\n", dns,
|
DBGC ( dns, "DNS %p sending %s query ID %#04x for %s type %s\n", dns,
|
||||||
ntohs ( query->id ), dns_name ( &dns->name ),
|
sock_ntoa ( &nameserver.sa ), ntohs ( query->id ),
|
||||||
dns_type ( dns->question->qtype ) );
|
dns_name ( &dns->name ), dns_type ( dns->question->qtype ) );
|
||||||
|
|
||||||
/* Send the data */
|
/* Send the data */
|
||||||
return xfer_deliver_raw ( &dns->socket, query, dns->len );
|
return xfer_deliver_raw_meta ( &dns->socket, query, dns->len, &meta );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle DNS retransmission timer expiry
|
* Handle DNS (re)transmission timer expiry
|
||||||
*
|
*
|
||||||
* @v timer Retry timer
|
* @v timer Retry timer
|
||||||
* @v fail Failure indicator
|
* @v fail Failure indicator
|
||||||
|
@ -595,11 +643,18 @@ static void dns_timer_expired ( struct retry_timer *timer, int fail ) {
|
||||||
struct dns_request *dns =
|
struct dns_request *dns =
|
||||||
container_of ( timer, struct dns_request, timer );
|
container_of ( timer, struct dns_request, timer );
|
||||||
|
|
||||||
|
/* Terminate DNS request on failure */
|
||||||
if ( fail ) {
|
if ( fail ) {
|
||||||
dns_done ( dns, -ETIMEDOUT );
|
dns_done ( dns, -ETIMEDOUT );
|
||||||
} else {
|
return;
|
||||||
dns_send_packet ( dns );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Move to next DNS server if this is a retransmission */
|
||||||
|
if ( dns->buf.query.id )
|
||||||
|
dns_index++;
|
||||||
|
|
||||||
|
/* Send DNS query */
|
||||||
|
dns_send_packet ( dns );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -927,7 +982,7 @@ static int dns_resolv ( struct interface *resolv,
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Fail immediately if no DNS servers */
|
/* Fail immediately if no DNS servers */
|
||||||
if ( ! nameserver.sa.sa_family ) {
|
if ( dns_count == 0 ) {
|
||||||
DBG ( "DNS not attempting to resolve \"%s\": "
|
DBG ( "DNS not attempting to resolve \"%s\": "
|
||||||
"no DNS servers\n", name );
|
"no DNS servers\n", name );
|
||||||
rc = -ENXIO_NO_NAMESERVER;
|
rc = -ENXIO_NO_NAMESERVER;
|
||||||
|
@ -953,17 +1008,8 @@ static int dns_resolv ( struct interface *resolv,
|
||||||
memcpy ( dns->search.data, dns_search.data, search_len );
|
memcpy ( dns->search.data, dns_search.data, search_len );
|
||||||
|
|
||||||
/* Determine initial query type */
|
/* Determine initial query type */
|
||||||
switch ( nameserver.sa.sa_family ) {
|
dns->qtype = ( ( dns6.count != 0 ) ?
|
||||||
case AF_INET:
|
htons ( DNS_TYPE_AAAA ) : htons ( DNS_TYPE_A ) );
|
||||||
dns->qtype = htons ( DNS_TYPE_A );
|
|
||||||
break;
|
|
||||||
case AF_INET6:
|
|
||||||
dns->qtype = htons ( DNS_TYPE_AAAA );
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
rc = -ENOTSUP;
|
|
||||||
goto err_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Construct query */
|
/* Construct query */
|
||||||
query = &dns->buf.query;
|
query = &dns->buf.query;
|
||||||
|
@ -984,7 +1030,7 @@ static int dns_resolv ( struct interface *resolv,
|
||||||
|
|
||||||
/* Open UDP connection */
|
/* Open UDP connection */
|
||||||
if ( ( rc = xfer_open_socket ( &dns->socket, SOCK_DGRAM,
|
if ( ( rc = xfer_open_socket ( &dns->socket, SOCK_DGRAM,
|
||||||
&nameserver.sa, NULL ) ) != 0 ) {
|
NULL, NULL ) ) != 0 ) {
|
||||||
DBGC ( dns, "DNS %p could not open socket: %s\n",
|
DBGC ( dns, "DNS %p could not open socket: %s\n",
|
||||||
dns, strerror ( rc ) );
|
dns, strerror ( rc ) );
|
||||||
goto err_open_socket;
|
goto err_open_socket;
|
||||||
|
@ -1001,7 +1047,6 @@ static int dns_resolv ( struct interface *resolv,
|
||||||
err_open_socket:
|
err_open_socket:
|
||||||
err_question:
|
err_question:
|
||||||
err_encode:
|
err_encode:
|
||||||
err_type:
|
|
||||||
ref_put ( &dns->refcnt );
|
ref_put ( &dns->refcnt );
|
||||||
err_alloc_dns:
|
err_alloc_dns:
|
||||||
err_no_nameserver:
|
err_no_nameserver:
|
||||||
|
@ -1096,6 +1141,31 @@ const struct setting dnssl_setting __setting ( SETTING_IP_EXTRA, dnssl ) = {
|
||||||
.type = &setting_type_dnssl,
|
.type = &setting_type_dnssl,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply DNS server addresses
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void apply_dns_servers ( void ) {
|
||||||
|
int len;
|
||||||
|
|
||||||
|
/* Free existing server addresses */
|
||||||
|
free ( dns4.data );
|
||||||
|
free ( dns6.data );
|
||||||
|
dns4.data = NULL;
|
||||||
|
dns6.data = NULL;
|
||||||
|
dns4.count = 0;
|
||||||
|
dns6.count = 0;
|
||||||
|
|
||||||
|
/* Fetch DNS server addresses */
|
||||||
|
len = fetch_raw_setting_copy ( NULL, &dns_setting, &dns4.data );
|
||||||
|
if ( len >= 0 )
|
||||||
|
dns4.count = ( len / sizeof ( dns4.in[0] ) );
|
||||||
|
len = fetch_raw_setting_copy ( NULL, &dns6_setting, &dns6.data );
|
||||||
|
if ( len >= 0 )
|
||||||
|
dns6.count = ( len / sizeof ( dns6.in6[0] ) );
|
||||||
|
dns_count = ( dns4.count + dns6.count );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply DNS search list
|
* Apply DNS search list
|
||||||
*
|
*
|
||||||
|
@ -1109,8 +1179,7 @@ static void apply_dns_search ( void ) {
|
||||||
memset ( &dns_search, 0, sizeof ( dns_search ) );
|
memset ( &dns_search, 0, sizeof ( dns_search ) );
|
||||||
|
|
||||||
/* Fetch DNS search list */
|
/* Fetch DNS search list */
|
||||||
len = fetch_setting_copy ( NULL, &dnssl_setting, NULL, NULL,
|
len = fetch_raw_setting_copy ( NULL, &dnssl_setting, &dns_search.data );
|
||||||
&dns_search.data );
|
|
||||||
if ( len >= 0 ) {
|
if ( len >= 0 ) {
|
||||||
dns_search.len = len;
|
dns_search.len = len;
|
||||||
return;
|
return;
|
||||||
|
@ -1138,19 +1207,31 @@ static void apply_dns_search ( void ) {
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int apply_dns_settings ( void ) {
|
static int apply_dns_settings ( void ) {
|
||||||
|
void *dbgcol = &dns_count;
|
||||||
|
|
||||||
/* Fetch DNS server address */
|
/* Fetch DNS server address */
|
||||||
nameserver.sa.sa_family = 0;
|
apply_dns_servers();
|
||||||
if ( fetch_ipv6_setting ( NULL, &dns6_setting,
|
if ( DBG_LOG && ( dns_count != 0 ) ) {
|
||||||
&nameserver.sin6.sin6_addr ) >= 0 ) {
|
union {
|
||||||
nameserver.sin6.sin6_family = AF_INET6;
|
struct sockaddr sa;
|
||||||
} else if ( fetch_ipv4_setting ( NULL, &dns_setting,
|
struct sockaddr_in sin;
|
||||||
&nameserver.sin.sin_addr ) >= 0 ) {
|
struct sockaddr_in6 sin6;
|
||||||
nameserver.sin.sin_family = AF_INET;
|
} u;
|
||||||
}
|
unsigned int i;
|
||||||
if ( nameserver.sa.sa_family ) {
|
|
||||||
DBG ( "DNS using nameserver %s\n",
|
DBGC ( dbgcol, "DNS servers:" );
|
||||||
sock_ntoa ( &nameserver.sa ) );
|
for ( i = 0 ; i < dns6.count ; i++ ) {
|
||||||
|
u.sin6.sin6_family = AF_INET6;
|
||||||
|
memcpy ( &u.sin6.sin6_addr, &dns6.in6[i],
|
||||||
|
sizeof ( u.sin6.sin6_addr ) );
|
||||||
|
DBGC ( dbgcol, " %s", sock_ntoa ( &u.sa ) );
|
||||||
|
}
|
||||||
|
for ( i = 0 ; i < dns4.count ; i++ ) {
|
||||||
|
u.sin.sin_family = AF_INET;
|
||||||
|
u.sin.sin_addr = dns4.in[i];
|
||||||
|
DBGC ( dbgcol, " %s", sock_ntoa ( &u.sa ) );
|
||||||
|
}
|
||||||
|
DBGC ( dbgcol, "\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fetch DNS search list */
|
/* Fetch DNS search list */
|
||||||
|
@ -1159,16 +1240,16 @@ static int apply_dns_settings ( void ) {
|
||||||
struct dns_name name;
|
struct dns_name name;
|
||||||
int offset;
|
int offset;
|
||||||
|
|
||||||
DBG ( "DNS search list:" );
|
DBGC ( dbgcol, "DNS search list:" );
|
||||||
memcpy ( &name, &dns_search, sizeof ( name ) );
|
memcpy ( &name, &dns_search, sizeof ( name ) );
|
||||||
while ( name.offset != name.len ) {
|
while ( name.offset != name.len ) {
|
||||||
DBG ( " %s", dns_name ( &name ) );
|
DBGC ( dbgcol, " %s", dns_name ( &name ) );
|
||||||
offset = dns_skip_search ( &name );
|
offset = dns_skip_search ( &name );
|
||||||
if ( offset < 0 )
|
if ( offset < 0 )
|
||||||
break;
|
break;
|
||||||
name.offset = offset;
|
name.offset = offset;
|
||||||
}
|
}
|
||||||
DBG ( "\n" );
|
DBGC ( dbgcol, "\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue