Commit fb65cccb authored by Ghislain MARY's avatar Ghislain MARY

Handle scope link IPv6 addresses for nameservers.

parent 24b9e4b6
......@@ -116,6 +116,8 @@
#include <sys/system_properties.h>
#endif
#include <bctoolbox/port.h>
/*
* C O M P I L E R V E R S I O N & F E A T U R E D E T E C T I O N
*
......@@ -4639,7 +4641,8 @@ static enum dns_resconf_keyword dns_resconf_keyword(const char *word) {
int dns_resconf_pton(struct sockaddr_storage *ss, const char *src) {
struct { char buf[128], *p; } addr = { "", addr.buf };
unsigned short port = 0;
int ch, af = AF_INET, error;
struct addrinfo *ai;
int ch, af = AF_INET;
while ((ch = *src++)) {
switch (ch) {
......@@ -4671,13 +4674,11 @@ int dns_resconf_pton(struct sockaddr_storage *ss, const char *src) {
} /* while() */
inet:
if ((error = dns_pton(af, addr.buf, dns_sa_addr(af, ss, NULL))))
return error;
port = (!port)? 53 : port;
*dns_sa_port(af, ss) = htons(port);
dns_sa_family(ss) = af;
ai = bctbx_ip_address_to_addrinfo(af, SOCK_DGRAM, addr.buf, port);
if (ai == NULL) return dns_soerr();
memcpy(ss, ai->ai_addr, ai->ai_addrlen);
bctbx_freeaddrinfo(ai);
return 0;
} /* dns_resconf_pton() */
......@@ -6087,12 +6088,11 @@ error:
} /* dns_hints_query() */
/** ugly hack to support specifying ports other than 53 in resolv.conf. */
static unsigned short dns_hints_port(struct dns_hints *hints, int af, void *addr) {
/**
* Fill a whole sockaddr from the the nameservers' sockaddr contained in the hints. This is needed for scope link IPv6 nameservers.
**/
static void dns_fill_sockaddr_from_hints(struct dns_hints *hints, int af, struct sockaddr *addr) {
struct dns_hints_soa *soa;
void *addrsoa;
socklen_t addrlen;
unsigned short port;
unsigned i;
for (soa = hints->head; soa; soa = soa->next) {
......@@ -6100,20 +6100,19 @@ static unsigned short dns_hints_port(struct dns_hints *hints, int af, void *addr
if (af != soa->addrs[i].ss.ss_family)
continue;
if (!(addrsoa = dns_sa_addr(af, &soa->addrs[i].ss, &addrlen)))
if ((af == AF_INET)
&& (memcmp(&((struct sockaddr_in *)&soa->addrs[i].ss)->sin_addr, &((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr))))
continue;
if (memcmp(addr, addrsoa, addrlen))
if ((af == AF_INET6)
&& (memcmp(&((struct sockaddr_in6 *)&soa->addrs[i].ss)->sin6_addr, &((struct sockaddr_in6 *)addr)->sin6_addr, sizeof(struct in6_addr))))
continue;
port = *dns_sa_port(af, &soa->addrs[i].ss);
return (port)? port : htons(53);
memcpy(addr, &soa->addrs[i].ss, dns_af_len(af));
return;
}
}
return htons(53);
} /* dns_hints_port() */
}
int dns_hints_dump(struct dns_hints *hints, FILE *fp) {
......@@ -6734,6 +6733,7 @@ static int dns_so_tcp_recv(struct dns_socket *so) {
int dns_so_check(struct dns_socket *so) {
struct sockaddr_storage reset_ss;
int error;
long n;
......@@ -6742,6 +6742,8 @@ retry:
case DNS_SO_UDP_INIT:
so->state++;
case DNS_SO_UDP_CONN:
memset(&reset_ss, 0, sizeof(reset_ss));
connect(so->udp, (struct sockaddr *)&reset_ss, sizeof(reset_ss)); // Reset the previous connection
if (0 != connect(so->udp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote)))
goto soerr;
......@@ -7658,8 +7660,9 @@ exec:
if ((error = dns_aaaa_parse((struct dns_aaaa *)dns_sa_addr(saddr.ss_family, &saddr, &saddr_len), &rr, F->hints)))
goto error;
}
*dns_sa_port(saddr.ss_family, &saddr) = (R->sp == 0) ? dns_hints_port(R->hints, saddr.ss_family, (struct sockaddr *)&saddr) : htons(53);
if (R->sp == 0) dns_fill_sockaddr_from_hints(R->hints, saddr.ss_family, (struct sockaddr *)&saddr);
else *dns_sa_port(saddr.ss_family, &saddr) = htons(53);
if (DNS_DEBUG) {
char addr[INET_ADDRSTRLEN + 1];
......
......@@ -471,6 +471,37 @@ static void dns_fallback(void) {
destroy_endpoint(client);
}
static void dns_fallback_because_of_scope_link_ipv6(void) {
struct addrinfo *ai;
int timeout;
endpoint_t *client = create_endpoint();
const char *nameservers[]={
"fe80::fdc5:99ef:ac05:5c55%enp0s25", /* Scope link IPv6 name server that will not respond */
"8.8.8.8", /* public nameserver, should work*/
NULL
};
if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
timeout = belle_sip_stack_get_dns_timeout(client->stack);
set_custom_resolv_conf(client->stack,nameservers);
client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_SIP_DOMAIN, SIP_PORT, AF_INET, a_resolve_done, client);
BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx);
BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout));
BC_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL);
if (client->ai_list) {
struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr;
int ntohsi = (int)ntohs(sock_in->sin_port);
BC_ASSERT_EQUAL(ntohsi, SIP_PORT, int, "%d");
ai = bctbx_ip_address_to_addrinfo(AF_INET, SOCK_STREAM, IPV4_SIP_IP, SIP_PORT);
if (ai) {
BC_ASSERT_EQUAL(sock_in->sin_addr.s_addr, ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr, int, "%d");
bctbx_freeaddrinfo(ai);
}
}
destroy_endpoint(client);
}
static void ipv6_dns_server(void) {
struct addrinfo *ai;
int timeout;
......@@ -559,6 +590,7 @@ test_t resolver_tests[] = {
{ "Local SRV+A query", local_full_query },
{ "No query needed", no_query_needed },
{ "DNS fallback", dns_fallback },
{ "DNS fallback because of scope link IPv6", dns_fallback_because_of_scope_link_ipv6 },
{ "IPv6 DNS server", ipv6_dns_server },
{ "IPv4 and v6 DNS servers", ipv4_and_ipv6_dns_server }
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment