2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-09-01 15:05:23 +00:00

libirs: handle scoped IPv6 addresses in /etc/resolv.conf

Commonly used network configuration tools write scoped IPv6 nameserver
addresses to /etc/resolv.conf.  libirs only handles these when it is
compiled with -DIRS_HAVE_SIN6_SCOPE_ID, which is not the default, and
only handles numeric scopes, which is not what network configuration
tools typically use.  This causes dig to be practically unable to handle
scoped IPv6 nameserver addresses in /etc/resolv.conf.

Fix the problem by:

  - not requiring a custom compile-time flag to be set in order for
    scoped IPv6 addresses to be processed by getaddrinfo(),

  - parsing non-numeric scope identifiers using if_nametoindex(),

  - setting the sin6_scope_id field in struct sockaddr_in6 structures
    returned by getaddrinfo() even if the AI_CANONNAME flag is not set.
This commit is contained in:
Michał Kępień
2018-10-23 14:50:00 +02:00
parent 2791bf9285
commit 76d49c05be
4 changed files with 63 additions and 27 deletions

View File

@@ -181,6 +181,47 @@ static void _freeaddrinfo(struct addrinfo *ai);
#define FOUND_IPV6 0x2 #define FOUND_IPV6 0x2
#define FOUND_MAX 2 #define FOUND_MAX 2
/*%
* Try converting the scope identifier in 'src' to a network interface index.
* Upon success, return true and store the resulting index in 'dst'. Upon
* failure, return false.
*/
static bool
parse_scopeid(const char *src, uint32_t *dst) {
uint32_t scopeid = 0;
REQUIRE(src != NULL);
REQUIRE(dst != NULL);
#ifdef HAVE_IF_NAMETOINDEX
/*
* Try using if_nametoindex() first if it is available. As it does not
* handle numeric scopes, we do not simply return if it fails.
*/
scopeid = (uint32_t)if_nametoindex(src);
#endif
/*
* Fall back to numeric scope processing if if_nametoindex() either
* fails or is unavailable.
*/
if (scopeid == 0) {
char *endptr = NULL;
scopeid = (uint32_t)strtoul(src, &endptr, 10);
/*
* The scope identifier must not be empty and no trailing
* characters are allowed after it.
*/
if (src == endptr || endptr == NULL || *endptr != '\0') {
return (false);
}
}
*dst = scopeid;
return (true);
}
#define ISC_AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST) #define ISC_AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST)
/*% /*%
* Get a list of IP addresses and port numbers for host hostname and * Get a list of IP addresses and port numbers for host hostname and
@@ -365,39 +406,24 @@ getaddrinfo(const char *hostname, const char *servname,
char abuf[sizeof(struct in6_addr)]; char abuf[sizeof(struct in6_addr)];
char nbuf[NI_MAXHOST]; char nbuf[NI_MAXHOST];
int addrsize, addroff; int addrsize, addroff;
#ifdef IRS_HAVE_SIN6_SCOPE_ID
char *p, *ep;
char ntmp[NI_MAXHOST]; char ntmp[NI_MAXHOST];
uint32_t scopeid; uint32_t scopeid = 0;
#endif
#ifdef IRS_HAVE_SIN6_SCOPE_ID
/* /*
* Scope identifier portion. * Scope identifier portion.
*/ */
ntmp[0] = '\0'; ntmp[0] = '\0';
if (strchr(hostname, '%') != NULL) { if (strchr(hostname, '%') != NULL) {
char *p;
strlcpy(ntmp, hostname, sizeof(ntmp)); strlcpy(ntmp, hostname, sizeof(ntmp));
p = strchr(ntmp, '%'); p = strchr(ntmp, '%');
ep = NULL;
/* if (p != NULL && parse_scopeid(p + 1, &scopeid)) {
* Vendors may want to support non-numeric
* scopeid around here.
*/
if (p != NULL)
scopeid = (uint32_t)strtoul(p + 1,
&ep, 10);
if (p != NULL && ep != NULL && ep[0] == '\0')
*p = '\0'; *p = '\0';
else { } else {
ntmp[0] = '\0'; ntmp[0] = '\0';
scopeid = 0;
} }
} else }
scopeid = 0;
#endif
if (inet_pton(AF_INET, hostname, (struct in_addr *)abuf) if (inet_pton(AF_INET, hostname, (struct in_addr *)abuf)
== 1) { == 1) {
@@ -415,7 +441,6 @@ getaddrinfo(const char *hostname, const char *servname,
addroff = offsetof(struct sockaddr_in, sin_addr); addroff = offsetof(struct sockaddr_in, sin_addr);
family = AF_INET; family = AF_INET;
goto common; goto common;
#ifdef IRS_HAVE_SIN6_SCOPE_ID
} else if (ntmp[0] != '\0' && } else if (ntmp[0] != '\0' &&
inet_pton(AF_INET6, ntmp, abuf) == 1) { inet_pton(AF_INET6, ntmp, abuf) == 1) {
if (family && family != AF_INET6) if (family && family != AF_INET6)
@@ -424,7 +449,6 @@ getaddrinfo(const char *hostname, const char *servname,
addroff = offsetof(struct sockaddr_in6, sin6_addr); addroff = offsetof(struct sockaddr_in6, sin6_addr);
family = AF_INET6; family = AF_INET6;
goto common; goto common;
#endif
} else if (inet_pton(AF_INET6, hostname, abuf) == 1) { } else if (inet_pton(AF_INET6, hostname, abuf) == 1) {
if (family != 0 && family != AF_INET6) if (family != 0 && family != AF_INET6)
return (EAI_NONAME); return (EAI_NONAME);
@@ -444,12 +468,10 @@ getaddrinfo(const char *hostname, const char *servname,
ai->ai_socktype = socktype; ai->ai_socktype = socktype;
SIN(ai->ai_addr)->sin_port = port; SIN(ai->ai_addr)->sin_port = port;
memmove((char *)ai->ai_addr + addroff, abuf, addrsize); memmove((char *)ai->ai_addr + addroff, abuf, addrsize);
if (ai->ai_family == AF_INET6) {
SIN6(ai->ai_addr)->sin6_scope_id = scopeid;
}
if ((flags & AI_CANONNAME) != 0) { if ((flags & AI_CANONNAME) != 0) {
#ifdef IRS_HAVE_SIN6_SCOPE_ID
if (ai->ai_family == AF_INET6)
SIN6(ai->ai_addr)->sin6_scope_id =
scopeid;
#endif
if (getnameinfo(ai->ai_addr, if (getnameinfo(ai->ai_addr,
(socklen_t)ai->ai_addrlen, (socklen_t)ai->ai_addrlen,
nbuf, sizeof(nbuf), NULL, 0, nbuf, sizeof(nbuf), NULL, 0,

View File

@@ -64,6 +64,9 @@ ATF_TC_BODY(irs_resconf_load, tc) {
}, { }, {
"testdata/nameserver-v6.conf", ISC_R_SUCCESS, "testdata/nameserver-v6.conf", ISC_R_SUCCESS,
NULL, ISC_R_SUCCESS NULL, ISC_R_SUCCESS
}, {
"testdata/nameserver-v6-scoped.conf", ISC_R_SUCCESS,
NULL, ISC_R_SUCCESS
}, { }, {
"testdata/options-debug.conf", ISC_R_SUCCESS, "testdata/options-debug.conf", ISC_R_SUCCESS,
NULL, ISC_R_SUCCESS NULL, ISC_R_SUCCESS

View File

@@ -0,0 +1,10 @@
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
nameserver fe80::1%1

View File

@@ -3298,6 +3298,7 @@
./lib/irs/tests/resconf_test.c C 2016,2018 ./lib/irs/tests/resconf_test.c C 2016,2018
./lib/irs/tests/testdata/domain.conf CONF-SH 2016,2018 ./lib/irs/tests/testdata/domain.conf CONF-SH 2016,2018
./lib/irs/tests/testdata/nameserver-v4.conf CONF-SH 2016,2018 ./lib/irs/tests/testdata/nameserver-v4.conf CONF-SH 2016,2018
./lib/irs/tests/testdata/nameserver-v6-scoped.conf CONF-SH 2018
./lib/irs/tests/testdata/nameserver-v6.conf CONF-SH 2016,2018 ./lib/irs/tests/testdata/nameserver-v6.conf CONF-SH 2016,2018
./lib/irs/tests/testdata/options-bad-ndots.conf CONF-SH 2018 ./lib/irs/tests/testdata/options-bad-ndots.conf CONF-SH 2018
./lib/irs/tests/testdata/options-debug.conf CONF-SH 2016,2018 ./lib/irs/tests/testdata/options-debug.conf CONF-SH 2016,2018