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