resolv.c 4.79 KB
Newer Older
Ted Lemon's avatar
Ted Lemon committed
1 2 3 4 5
/* resolv.c

   Parser for /etc/resolv.conf file. */

/*
6
 * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
7
 * Copyright (c) 1996-2003 by Internet Software Consortium
Ted Lemon's avatar
Ted Lemon committed
8
 *
9 10 11
 * 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/.
Ted Lemon's avatar
Ted Lemon committed
12
 *
13 14 15 16 17 18 19
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Ted Lemon's avatar
Ted Lemon committed
20
 *
21 22 23 24
 *   Internet Systems Consortium, Inc.
 *   950 Charter Street
 *   Redwood City, CA 94063
 *   <info@isc.org>
25
 *   https://www.isc.org/
Ted Lemon's avatar
Ted Lemon committed
26
 *
Ted Lemon's avatar
Ted Lemon committed
27 28 29 30 31 32 33 34 35 36 37
 */

#include "dhcpd.h"

struct name_server *name_servers;
struct domain_search_list *domains;
char path_resolv_conf [] = _PATH_RESOLV_CONF;

void read_resolv_conf (parse_time)
	TIME parse_time;
{
Ted Lemon's avatar
Ted Lemon committed
38 39
	int file;
	struct parse *cfile;
40
	const char *val;
Ted Lemon's avatar
Ted Lemon committed
41 42 43
	int token;
	struct name_server *sp, *sl, *ns;
	struct domain_search_list *dp, *dl, *nd;
44
	isc_result_t status;
Ted Lemon's avatar
Ted Lemon committed
45

46
	if ((file = open (path_resolv_conf, O_RDONLY)) < 0) {
47
		log_error ("Can't open %s: %m", path_resolv_conf);
48 49 50
		return;
	}

51 52 53 54
	cfile = NULL;
	status = new_parse(&cfile, file, NULL, 0, path_resolv_conf, 1);
	if (status != ISC_R_SUCCESS || cfile == NULL)
		return;
Ted Lemon's avatar
Ted Lemon committed
55

Ted Lemon's avatar
Ted Lemon committed
56
	do {
57
		token = next_token (&val, (unsigned *)0, cfile);
58
		if (token == END_OF_FILE)
Ted Lemon's avatar
Ted Lemon committed
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
			break;
		else if (token == EOL)
			continue;
		else if (token == DOMAIN || token == SEARCH) {
			do {
				struct domain_search_list *nd, **dp;
				char *dn;

				dn = parse_host_name (cfile);
				if (!dn)
					break;

				dp = &domains;
				for (nd = domains; nd; nd = nd -> next) {
					dp = &nd -> next;
					if (!strcmp (nd -> domain, dn))
						break;
				}
				if (!nd) {
78
					nd = new_domain_search_list (MDL);
Ted Lemon's avatar
Ted Lemon committed
79
					if (!nd)
Ted Lemon's avatar
Ted Lemon committed
80 81
						log_fatal ("No memory for %s",
							   dn);
Ted Lemon's avatar
Ted Lemon committed
82 83 84 85 86 87
					nd -> next =
						(struct domain_search_list *)0;
					*dp = nd;
					nd -> domain = dn;
				}
				nd -> rcdate = parse_time;
88 89
				token = peek_token (&val,
						    (unsigned *)0, cfile);
90
			} while (token != EOL);
Ted Lemon's avatar
Ted Lemon committed
91
			if (token != EOL) {
Ted Lemon's avatar
Ted Lemon committed
92 93
				parse_warn (cfile,
					    "junk after domain declaration");
Ted Lemon's avatar
Ted Lemon committed
94 95
				skip_to_semi (cfile);
			}
96
			skip_token(&val, (unsigned *)0, cfile);
Ted Lemon's avatar
Ted Lemon committed
97 98 99 100 101 102 103 104 105 106 107 108 109 110
		} else if (token == NAMESERVER) {
			struct name_server *ns, **sp;
			struct iaddr iaddr;

			parse_ip_addr (cfile, &iaddr);

			sp = &name_servers;
			for (ns = name_servers; ns; ns = ns -> next) {
				sp = &ns -> next;
				if (!memcmp (&ns -> addr.sin_addr,
					     iaddr.iabuf, iaddr.len))
					break;
			}
			if (!ns) {
111
				ns = new_name_server (MDL);
Ted Lemon's avatar
Ted Lemon committed
112
				if (!ns)
Ted Lemon's avatar
Ted Lemon committed
113
				    log_fatal ("No memory for nameserver %s",
Ted Lemon's avatar
Ted Lemon committed
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
					       piaddr (iaddr));
				ns -> next = (struct name_server *)0;
				*sp = ns;
				memcpy (&ns -> addr.sin_addr,
					iaddr.iabuf, iaddr.len);
#ifdef HAVE_SA_LEN
				ns -> addr.sin_len = sizeof ns -> addr;
#endif
				ns -> addr.sin_family = AF_INET;
				ns -> addr.sin_port = htons (53);
				memset (ns -> addr.sin_zero, 0,
					sizeof ns -> addr.sin_zero);
			}
			ns -> rcdate = parse_time;
			skip_to_semi (cfile);
129 130
		} else
			skip_to_semi (cfile); /* Ignore what we don't grok. */
Ted Lemon's avatar
Ted Lemon committed
131
	} while (1);
132
	skip_token(&val, (unsigned *)0, cfile);
Ted Lemon's avatar
Ted Lemon committed
133 134 135 136 137 138 139 140 141 142

	/* Lose servers that are no longer in /etc/resolv.conf. */
	sl = (struct name_server *)0;
	for (sp = name_servers; sp; sp = ns) {
		ns = sp -> next;
		if (sp -> rcdate != parse_time) {
			if (sl)
				sl -> next = sp -> next;
			else
				name_servers = sp -> next;
143 144 145
			/* We can't actually free the name server structure,
			   because somebody might be hanging on to it.    If
			   your /etc/resolv.conf file changes a lot, this
Francis Dupont's avatar
Francis Dupont committed
146
			   could be a noticeable memory leak. */
Ted Lemon's avatar
Ted Lemon committed
147 148 149 150 151 152 153 154 155 156 157 158 159
		} else
			sl = sp;
	}

	/* Lose domains that are no longer in /etc/resolv.conf. */
	dl = (struct domain_search_list *)0;
	for (dp = domains; dp; dp = nd) {
		nd = dp -> next;
		if (dp -> rcdate != parse_time) {
			if (dl)
				dl -> next = dp -> next;
			else
				domains = dp -> next;
160
			free_domain_search_list (dp, MDL);
Ted Lemon's avatar
Ted Lemon committed
161 162 163
		} else
			dl = dp;
	}
Ted Lemon's avatar
Ted Lemon committed
164
	end_parse (&cfile);
Ted Lemon's avatar
Ted Lemon committed
165 166 167 168
}

/* Pick a name server from the /etc/resolv.conf file. */

169
struct name_server *first_name_server ()
Ted Lemon's avatar
Ted Lemon committed
170 171 172 173 174 175
{
	static TIME rcdate;
	struct stat st;

	/* Check /etc/resolv.conf and reload it if it's changed. */
	if (cur_time > rcdate) {
176
		if (stat (path_resolv_conf, &st) < 0) {
177
			log_error ("Can't stat %s", path_resolv_conf);
178
			return (struct name_server *)0;
179
		}
Ted Lemon's avatar
Ted Lemon committed
180 181 182 183 184 185 186
		if (st.st_mtime > rcdate) {
			rcdate = cur_time + 1;
			
			read_resolv_conf (rcdate);
		}
	}

187
	return name_servers;
Ted Lemon's avatar
Ted Lemon committed
188
}