1/* resolv.c
2
3   Parser for /etc/resolv.conf file. */
4
5/*
6 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1996-2003 by Internet Software Consortium
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 *
21 *   Internet Systems Consortium, Inc.
22 *   950 Charter Street
23 *   Redwood City, CA 94063
24 *   <info@isc.org>
25 *   http://www.isc.org/
26 *
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29 * To learn more about Internet Systems Consortium, see
30 * ``http://www.isc.org/''.  To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
33 */
34
35#ifndef lint
36static char copyright[] =
37"$Id: resolv.c,v 1.4 2005/08/11 17:13:21 drochner Exp $ Copyright (c) 2004 Internet Systems Consortium.  All rights reserved.\n";
38#endif /* not lint */
39
40#include "dhcpd.h"
41
42struct name_server *name_servers;
43struct domain_search_list *domains;
44char path_resolv_conf [] = _PATH_RESOLV_CONF;
45
46void read_resolv_conf (parse_time)
47	TIME parse_time;
48{
49	int file;
50	struct parse *cfile;
51	const char *val;
52	int token;
53	struct name_server *sp, *sl, *ns;
54	struct domain_search_list *dp, *dl, *nd;
55
56	if ((file = open (path_resolv_conf, O_RDONLY)) < 0) {
57		log_error ("Can't open %s: %m", path_resolv_conf);
58		return;
59	}
60
61	cfile = (struct parse *)0;
62	new_parse (&cfile, file, (char *)0, 0, path_resolv_conf, 1);
63
64	do {
65		token = next_token (&val, (unsigned *)0, cfile);
66		if (token == END_OF_FILE)
67			break;
68		else if (token == EOL)
69			continue;
70		else if (token == DOMAIN || token == SEARCH) {
71			do {
72				struct domain_search_list *nd, **dp;
73				char *dn;
74
75				dn = parse_host_name (cfile);
76				if (!dn)
77					break;
78
79				dp = &domains;
80				for (nd = domains; nd; nd = nd -> next) {
81					dp = &nd -> next;
82					if (!strcmp (nd -> domain, dn))
83						break;
84				}
85				if (!nd) {
86					nd = new_domain_search_list (MDL);
87					if (!nd)
88						log_fatal ("No memory for %s",
89							   dn);
90					nd -> next =
91						(struct domain_search_list *)0;
92					*dp = nd;
93					nd -> domain = dn;
94					dn = (char *)0;
95				}
96				nd -> rcdate = parse_time;
97				token = peek_token (&val,
98						    (unsigned *)0, cfile);
99			} while (token != EOL);
100			if (token != EOL) {
101				parse_warn (cfile,
102					    "junk after domain declaration");
103				skip_to_semi (cfile);
104			}
105			token = next_token (&val, (unsigned *)0, cfile);
106		} else if (token == NAMESERVER) {
107			struct name_server *ns, **sp;
108			struct iaddr iaddr;
109
110			parse_ip_addr (cfile, &iaddr);
111
112			sp = &name_servers;
113			for (ns = name_servers; ns; ns = ns -> next) {
114				sp = &ns -> next;
115				if (!memcmp (&ns -> addr.sin_addr,
116					     iaddr.iabuf, iaddr.len))
117					break;
118			}
119			if (!ns) {
120				ns = new_name_server (MDL);
121				if (!ns)
122				    log_fatal ("No memory for nameserver %s",
123					       piaddr (iaddr));
124				ns -> next = (struct name_server *)0;
125				*sp = ns;
126				memset (&ns->addr, 0, sizeof ns->addr);
127				memcpy (&ns -> addr.sin_addr,
128					iaddr.iabuf, iaddr.len);
129#ifdef HAVE_SA_LEN
130				ns -> addr.sin_len = sizeof ns -> addr;
131#endif
132				ns -> addr.sin_family = AF_INET;
133				ns -> addr.sin_port = htons (53);
134			}
135			ns -> rcdate = parse_time;
136			skip_to_semi (cfile);
137		} else
138			skip_to_semi (cfile); /* Ignore what we don't grok. */
139	} while (1);
140	token = next_token (&val, (unsigned *)0, cfile);
141
142	/* Lose servers that are no longer in /etc/resolv.conf. */
143	sl = (struct name_server *)0;
144	for (sp = name_servers; sp; sp = ns) {
145		ns = sp -> next;
146		if (sp -> rcdate != parse_time) {
147			if (sl)
148				sl -> next = sp -> next;
149			else
150				name_servers = sp -> next;
151			/* We can't actually free the name server structure,
152			   because somebody might be hanging on to it.    If
153			   your /etc/resolv.conf file changes a lot, this
154			   could be a noticable memory leak. */
155		} else
156			sl = sp;
157	}
158
159	/* Lose domains that are no longer in /etc/resolv.conf. */
160	dl = (struct domain_search_list *)0;
161	for (dp = domains; dp; dp = nd) {
162		nd = dp -> next;
163		if (dp -> rcdate != parse_time) {
164			if (dl)
165				dl -> next = dp -> next;
166			else
167				domains = dp -> next;
168			free_domain_search_list (dp, MDL);
169		} else
170			dl = dp;
171	}
172	close (file);
173	end_parse (&cfile);
174}
175
176/* Pick a name server from the /etc/resolv.conf file. */
177
178struct name_server *first_name_server ()
179{
180	static TIME rcdate;
181	struct stat st;
182
183	/* Check /etc/resolv.conf and reload it if it's changed. */
184	if (cur_time > rcdate) {
185		if (stat (path_resolv_conf, &st) < 0) {
186			log_error ("Can't stat %s", path_resolv_conf);
187			return (struct name_server *)0;
188		}
189		if (st.st_mtime > rcdate) {
190			rcdate = cur_time + 1;
191
192			read_resolv_conf (rcdate);
193		}
194	}
195
196	return name_servers;
197}
198