| 1 | #include "lookup.h" |
| 2 | #include "stdio_impl.h" |
| 3 | #include <ctype.h> |
| 4 | #include <errno.h> |
| 5 | #include <string.h> |
| 6 | #include <stdlib.h> |
| 7 | #include <netinet/in.h> |
| 8 | |
| 9 | int __get_resolv_conf(struct resolvconf *conf, char *search, size_t search_sz) |
| 10 | { |
| 11 | 	char line[256]; |
| 12 | 	unsigned char _buf[256]; |
| 13 | 	FILE *f, _f; |
| 14 | 	int nns = 0; |
| 15 | |
| 16 | 	conf->ndots = 1; |
| 17 | 	conf->timeout = 5; |
| 18 | 	conf->attempts = 2; |
| 19 | 	if (search) *search = 0; |
| 20 | |
| 21 | 	f = __fopen_rb_ca("/etc/resolv.conf", &_f, _buf, sizeof _buf); |
| 22 | 	if (!f) switch (errno) { |
| 23 | 	case ENOENT: |
| 24 | 	case ENOTDIR: |
| 25 | 	case EACCES: |
| 26 | 		goto no_resolv_conf; |
| 27 | 	default: |
| 28 | 		return -1; |
| 29 | 	} |
| 30 | |
| 31 | 	while (fgets(line, sizeof line, f)) { |
| 32 | 		char *p, *z; |
| 33 | 		if (!strchr(line, '\n') && !feof(f)) { |
| 34 | 			/* Ignore lines that get truncated rather than |
| 35 | 			 * potentially misinterpreting them. */ |
| 36 | 			int c; |
| 37 | 			do c = getc(f); |
| 38 | 			while (c != '\n' && c != EOF); |
| 39 | 			continue; |
| 40 | 		} |
| 41 | 		if (!strncmp(line, "options", 7) && isspace(line[7])) { |
| 42 | 			p = strstr(line, "ndots:"); |
| 43 | 			if (p && isdigit(p[6])) { |
| 44 | 				p += 6; |
| 45 | 				unsigned long x = strtoul(p, &z, 10); |
| 46 | 				if (z != p) conf->ndots = x > 15 ? 15 : x; |
| 47 | 			} |
| 48 | 			p = strstr(line, "attempts:"); |
| 49 | 			if (p && isdigit(p[9])) { |
| 50 | 				p += 9; |
| 51 | 				unsigned long x = strtoul(p, &z, 10); |
| 52 | 				if (z != p) conf->attempts = x > 10 ? 10 : x; |
| 53 | 			} |
| 54 | 			p = strstr(line, "timeout:"); |
| 55 | 			if (p && (isdigit(p[8]) || p[8]=='.')) { |
| 56 | 				p += 8; |
| 57 | 				unsigned long x = strtoul(p, &z, 10); |
| 58 | 				if (z != p) conf->timeout = x > 60 ? 60 : x; |
| 59 | 			} |
| 60 | 			continue; |
| 61 | 		} |
| 62 | 		if (!strncmp(line, "nameserver", 10) && isspace(line[10])) { |
| 63 | 			if (nns >= MAXNS) continue; |
| 64 | 			for (p=line+11; isspace(*p); p++); |
| 65 | 			for (z=p; *z && !isspace(*z); z++); |
| 66 | 			*z=0; |
| 67 | 			if (__lookup_ipliteral(conf->ns+nns, p, AF_UNSPEC) > 0) |
| 68 | 				nns++; |
| 69 | 			continue; |
| 70 | 		} |
| 71 | |
| 72 | 		if (!search) continue; |
| 73 | 		if ((strncmp(line, "domain", 6) && strncmp(line, "search", 6)) |
| 74 | 		 || !isspace(line[6])) |
| 75 | 			continue; |
| 76 | 		for (p=line+7; isspace(*p); p++); |
| 77 | 		size_t l = strlen(p); |
| 78 | 		/* This can never happen anyway with chosen buffer sizes. */ |
| 79 | 		if (l >= search_sz) continue; |
| 80 | 		memcpy(search, p, l+1); |
| 81 | 	} |
| 82 | |
| 83 | 	__fclose_ca(f); |
| 84 | |
| 85 | no_resolv_conf: |
| 86 | 	if (!nns) { |
| 87 | 		__lookup_ipliteral(conf->ns, "127.0.0.1", AF_UNSPEC); |
| 88 | 		nns = 1; |
| 89 | 	} |
| 90 | |
| 91 | 	conf->nns = nns; |
| 92 | |
| 93 | 	return 0; |
| 94 | } |