mirror of git://git.musl-libc.org/musl
factor resolv.conf parsing out of res_msend to its own file
this change is made in preparation for adding search domains, for which higher-level code will need to parse resolv.conf. simply parsing it twice for each lookup would be one reasonable option, but the existing parser code was buggy anyway, which suggested to me that it's a bad idea to have two variants of this code in two different places. the old code in res_msend potentially misinterpreted overly long lines in resolv.conf, and stopped parsing after it found 3 nameservers, even if there were relevant options left to be parsed later in the file.
This commit is contained in:
parent
19df86cbb3
commit
d6cb08bcac
|
@ -2,6 +2,7 @@
|
||||||
#define LOOKUP_H
|
#define LOOKUP_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
struct address {
|
struct address {
|
||||||
int family;
|
int family;
|
||||||
|
@ -15,6 +16,14 @@ struct service {
|
||||||
unsigned char proto, socktype;
|
unsigned char proto, socktype;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MAXNS 3
|
||||||
|
|
||||||
|
struct resolvconf {
|
||||||
|
struct address ns[MAXNS];
|
||||||
|
unsigned nns, attempts, ndots;
|
||||||
|
unsigned timeout;
|
||||||
|
};
|
||||||
|
|
||||||
/* The limit of 48 results is a non-sharp bound on the number of addresses
|
/* The limit of 48 results is a non-sharp bound on the number of addresses
|
||||||
* that can fit in one 512-byte DNS packet full of v4 results and a second
|
* that can fit in one 512-byte DNS packet full of v4 results and a second
|
||||||
* packet full of v6 results. Due to headers, the actual limit is lower. */
|
* packet full of v6 results. Due to headers, the actual limit is lower. */
|
||||||
|
@ -25,4 +34,6 @@ int __lookup_serv(struct service buf[static MAXSERVS], const char *name, int pro
|
||||||
int __lookup_name(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, int flags);
|
int __lookup_name(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, int flags);
|
||||||
int __lookup_ipliteral(struct address buf[static 1], const char *name, int family);
|
int __lookup_ipliteral(struct address buf[static 1], const char *name, int family);
|
||||||
|
|
||||||
|
int __get_resolv_conf(struct resolvconf *, char *, size_t);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -31,14 +31,11 @@ int __res_msend(int nqueries, const unsigned char *const *queries,
|
||||||
const int *qlens, unsigned char *const *answers, int *alens, int asize)
|
const int *qlens, unsigned char *const *answers, int *alens, int asize)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
FILE *f, _f;
|
int timeout, attempts, retry_interval, servfail_retry;
|
||||||
unsigned char _buf[256];
|
|
||||||
char line[64], *s, *z;
|
|
||||||
int timeout = 5000, attempts = 2, retry_interval, servfail_retry;
|
|
||||||
union {
|
union {
|
||||||
struct sockaddr_in sin;
|
struct sockaddr_in sin;
|
||||||
struct sockaddr_in6 sin6;
|
struct sockaddr_in6 sin6;
|
||||||
} sa = {0}, ns[3] = {{0}};
|
} sa = {0}, ns[MAXNS] = {{0}};
|
||||||
socklen_t sl = sizeof sa.sin;
|
socklen_t sl = sizeof sa.sin;
|
||||||
int nns = 0;
|
int nns = 0;
|
||||||
int family = AF_INET;
|
int family = AF_INET;
|
||||||
|
@ -48,66 +45,31 @@ int __res_msend(int nqueries, const unsigned char *const *queries,
|
||||||
int cs;
|
int cs;
|
||||||
struct pollfd pfd;
|
struct pollfd pfd;
|
||||||
unsigned long t0, t1, t2;
|
unsigned long t0, t1, t2;
|
||||||
struct address iplit;
|
struct resolvconf conf;
|
||||||
|
|
||||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
|
||||||
|
|
||||||
/* Get nameservers from resolv.conf, fallback to localhost */
|
/* Get nameservers & timeout/retry settings from resolv.conf */
|
||||||
f = __fopen_rb_ca("/etc/resolv.conf", &_f, _buf, sizeof _buf);
|
if (__get_resolv_conf(&conf, 0, 0) < 0) return -1;
|
||||||
if (!f) switch (errno) {
|
|
||||||
case ENOENT:
|
|
||||||
case ENOTDIR:
|
|
||||||
case EACCES:
|
|
||||||
goto no_resolv_conf;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
for (nns=0; nns<3 && fgets(line, sizeof line, f); ) {
|
|
||||||
if (!strncmp(line, "options", 7) && isspace(line[7])) {
|
|
||||||
unsigned long x;
|
|
||||||
char *p, *z;
|
|
||||||
p = strstr(line, "timeout:");
|
|
||||||
if (p && isdigit(p[8])) {
|
|
||||||
p += 8;
|
|
||||||
x = strtoul(p, &z, 10);
|
|
||||||
if (z != p) timeout = x < 30 ? x*1000 : 30000;
|
|
||||||
}
|
|
||||||
p = strstr(line, "attempts:");
|
|
||||||
if (p && isdigit(p[9])) {
|
|
||||||
p += 9;
|
|
||||||
x = strtoul(p, &z, 10);
|
|
||||||
if (z != p) attempts = x < 10 ? x : 10;
|
|
||||||
if (!attempts) attempts = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (strncmp(line, "nameserver", 10) || !isspace(line[10]))
|
|
||||||
continue;
|
|
||||||
for (s=line+11; isspace(*s); s++);
|
|
||||||
for (z=s; *z && !isspace(*z); z++);
|
|
||||||
*z=0;
|
|
||||||
|
|
||||||
if (__lookup_ipliteral(&iplit, s, AF_UNSPEC)>0) {
|
timeout = 1000*conf.timeout;
|
||||||
if (iplit.family == AF_INET) {
|
attempts = conf.attempts;
|
||||||
memcpy(&ns[nns].sin.sin_addr, iplit.addr, 4);
|
|
||||||
ns[nns].sin.sin_port = htons(53);
|
nns = conf.nns;
|
||||||
ns[nns++].sin.sin_family = AF_INET;
|
for (nns=0; nns<conf.nns; nns++) {
|
||||||
} else {
|
struct address *iplit = &conf.ns[nns];
|
||||||
sl = sizeof sa.sin6;
|
if (iplit->family == AF_INET) {
|
||||||
memcpy(&ns[nns].sin6.sin6_addr, iplit.addr, 16);
|
memcpy(&ns[nns].sin.sin_addr, iplit->addr, 4);
|
||||||
ns[nns].sin6.sin6_port = htons(53);
|
ns[nns].sin.sin_port = htons(53);
|
||||||
ns[nns].sin6.sin6_scope_id = iplit.scopeid;
|
ns[nns].sin.sin_family = AF_INET;
|
||||||
ns[nns++].sin6.sin6_family = family = AF_INET6;
|
} else {
|
||||||
}
|
sl = sizeof sa.sin6;
|
||||||
|
memcpy(&ns[nns].sin6.sin6_addr, iplit->addr, 16);
|
||||||
|
ns[nns].sin6.sin6_port = htons(53);
|
||||||
|
ns[nns].sin6.sin6_scope_id = iplit->scopeid;
|
||||||
|
ns[nns].sin6.sin6_family = family = AF_INET6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
__fclose_ca(f);
|
|
||||||
no_resolv_conf:
|
|
||||||
if (!nns) {
|
|
||||||
ns[0].sin.sin_family = AF_INET;
|
|
||||||
ns[0].sin.sin_port = htons(53);
|
|
||||||
ns[0].sin.sin_addr.s_addr = htonl(0x7f000001);
|
|
||||||
nns=1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get local address and open/bind a socket */
|
/* Get local address and open/bind a socket */
|
||||||
sa.sin.sin_family = family;
|
sa.sin.sin_family = family;
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
#include "lookup.h"
|
||||||
|
#include "stdio_impl.h"
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
int __get_resolv_conf(struct resolvconf *conf, char *search, size_t search_sz)
|
||||||
|
{
|
||||||
|
char line[256];
|
||||||
|
unsigned char _buf[256];
|
||||||
|
FILE *f, _f;
|
||||||
|
int nns;
|
||||||
|
|
||||||
|
conf->ndots = 1;
|
||||||
|
conf->timeout = 5;
|
||||||
|
conf->attempts = 2;
|
||||||
|
if (search) *search = 0;
|
||||||
|
|
||||||
|
f = __fopen_rb_ca("/etc/resolv.conf", &_f, _buf, sizeof _buf);
|
||||||
|
if (!f) switch (errno) {
|
||||||
|
case ENOENT:
|
||||||
|
case ENOTDIR:
|
||||||
|
case EACCES:
|
||||||
|
goto no_resolv_conf;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fgets(line, sizeof line, f)) {
|
||||||
|
char *p, *z;
|
||||||
|
if (!strchr(line, '\n') && !feof(f)) {
|
||||||
|
/* Ignore lines that get truncated rather than
|
||||||
|
* potentially misinterpreting them. */
|
||||||
|
int c;
|
||||||
|
do c = getc(f);
|
||||||
|
while (c != '\n' && c != EOF);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strncmp(line, "options", 7) && isspace(line[7])) {
|
||||||
|
p = strstr(line, "ndots:");
|
||||||
|
if (p && isdigit(p[6])) {
|
||||||
|
p += 6;
|
||||||
|
unsigned long x = strtoul(p, &z, 10);
|
||||||
|
if (z != p) conf->ndots = x > 15 ? 15 : x;
|
||||||
|
}
|
||||||
|
p = strstr(line, "attempts:");
|
||||||
|
if (p && isdigit(p[6])) {
|
||||||
|
p += 6;
|
||||||
|
unsigned long x = strtoul(p, &z, 10);
|
||||||
|
if (z != p) conf->attempts = x > 10 ? 10 : x;
|
||||||
|
}
|
||||||
|
p = strstr(line, "timeout:");
|
||||||
|
if (p && (isdigit(p[8]) || p[8]=='.')) {
|
||||||
|
p += 8;
|
||||||
|
unsigned long x = strtoul(p, &z, 10);
|
||||||
|
if (z != p) conf->timeout = x > 60 ? 60 : x;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strncmp(line, "nameserver", 10) && isspace(line[10])) {
|
||||||
|
if (nns >= MAXNS) continue;
|
||||||
|
for (p=line+11; isspace(*p); p++);
|
||||||
|
for (z=p; *z && !isspace(*z); z++);
|
||||||
|
*z=0;
|
||||||
|
if (__lookup_ipliteral(conf->ns+nns, p, AF_UNSPEC) > 0)
|
||||||
|
nns++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!search) continue;
|
||||||
|
if (strncmp(line, "domain", 6) || strncmp(line, "search", 6)
|
||||||
|
|| !isspace(line[6]))
|
||||||
|
continue;
|
||||||
|
for (p=line+7; isspace(*p); p++);
|
||||||
|
size_t l = strlen(p);
|
||||||
|
/* This can never happen anyway with chosen buffer sizes. */
|
||||||
|
if (l >= search_sz) continue;
|
||||||
|
memcpy(search, p, l+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
__fclose_ca(f);
|
||||||
|
|
||||||
|
no_resolv_conf:
|
||||||
|
if (!nns) {
|
||||||
|
__lookup_ipliteral(conf->ns, "127.0.0.1", AF_UNSPEC);
|
||||||
|
nns = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
conf->nns = nns;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue