summaryrefslogtreecommitdiff
path: root/src/network/resolvconf.c
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2016-01-28 18:24:34 -0500
committerRich Felker <dalias@aerifal.cx>2016-01-28 18:39:22 -0500
commitd6cb08bcaca4ff1f921375510ca72bccea969c75 (patch)
tree35a357b3c880d2a71aac9056ddb30c1646418d77 /src/network/resolvconf.c
parent19df86cbb39f2429f7c7e20c99c606c38a5fd4e9 (diff)
downloadmusl-d6cb08bcaca4ff1f921375510ca72bccea969c75.tar.gz
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.
Diffstat (limited to 'src/network/resolvconf.c')
-rw-r--r--src/network/resolvconf.c93
1 files changed, 93 insertions, 0 deletions
diff --git a/src/network/resolvconf.c b/src/network/resolvconf.c
new file mode 100644
index 00000000..0743a88f
--- /dev/null
+++ b/src/network/resolvconf.c
@@ -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;
+}