Flesh out BUF_CMD_FLUSH support.
[dragonfly.git] / contrib / dhcp-3.0 / common / resolv.c
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
36 static char copyright[] =
37 "$Id: resolv.c,v 1.16.2.2 2004/06/10 17:59:20 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium.  All rights reserved.\n";
38 #endif /* not lint */
39
40 #include "dhcpd.h"
41
42 struct name_server *name_servers;
43 struct domain_search_list *domains;
44 char path_resolv_conf [] = _PATH_RESOLV_CONF;
45
46 void 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         int declaration = 0;
54         struct name_server *sp, *sl, *ns;
55         struct domain_search_list *dp, *dl, *nd;
56         struct iaddr *iaddr;
57
58         if ((file = open (path_resolv_conf, O_RDONLY)) < 0) {
59                 log_error ("Can't open %s: %m", path_resolv_conf);
60                 return;
61         }
62
63         cfile = (struct parse *)0;
64         new_parse (&cfile, file, (char *)0, 0, path_resolv_conf, 1);
65
66         do {
67                 token = next_token (&val, (unsigned *)0, cfile);
68                 if (token == END_OF_FILE)
69                         break;
70                 else if (token == EOL)
71                         continue;
72                 else if (token == DOMAIN || token == SEARCH) {
73                         do {
74                                 struct domain_search_list *nd, **dp;
75                                 char *dn;
76
77                                 dn = parse_host_name (cfile);
78                                 if (!dn)
79                                         break;
80
81                                 dp = &domains;
82                                 for (nd = domains; nd; nd = nd -> next) {
83                                         dp = &nd -> next;
84                                         if (!strcmp (nd -> domain, dn))
85                                                 break;
86                                 }
87                                 if (!nd) {
88                                         nd = new_domain_search_list (MDL);
89                                         if (!nd)
90                                                 log_fatal ("No memory for %s",
91                                                            dn);
92                                         nd -> next =
93                                                 (struct domain_search_list *)0;
94                                         *dp = nd;
95                                         nd -> domain = dn;
96                                         dn = (char *)0;
97                                 }
98                                 nd -> rcdate = parse_time;
99                                 token = peek_token (&val,
100                                                     (unsigned *)0, cfile);
101                         } while (token != EOL);
102                         if (token != EOL) {
103                                 parse_warn (cfile,
104                                             "junk after domain declaration");
105                                 skip_to_semi (cfile);
106                         }
107                         token = next_token (&val, (unsigned *)0, cfile);
108                 } else if (token == NAMESERVER) {
109                         struct name_server *ns, **sp;
110                         struct iaddr iaddr;
111
112                         parse_ip_addr (cfile, &iaddr);
113
114                         sp = &name_servers;
115                         for (ns = name_servers; ns; ns = ns -> next) {
116                                 sp = &ns -> next;
117                                 if (!memcmp (&ns -> addr.sin_addr,
118                                              iaddr.iabuf, iaddr.len))
119                                         break;
120                         }
121                         if (!ns) {
122                                 ns = new_name_server (MDL);
123                                 if (!ns)
124                                     log_fatal ("No memory for nameserver %s",
125                                                piaddr (iaddr));
126                                 ns -> next = (struct name_server *)0;
127                                 *sp = ns;
128                                 memcpy (&ns -> addr.sin_addr,
129                                         iaddr.iabuf, iaddr.len);
130 #ifdef HAVE_SA_LEN
131                                 ns -> addr.sin_len = sizeof ns -> addr;
132 #endif
133                                 ns -> addr.sin_family = AF_INET;
134                                 ns -> addr.sin_port = htons (53);
135                                 memset (ns -> addr.sin_zero, 0,
136                                         sizeof ns -> addr.sin_zero);
137                         }
138                         ns -> rcdate = parse_time;
139                         skip_to_semi (cfile);
140                 } else
141                         skip_to_semi (cfile); /* Ignore what we don't grok. */
142         } while (1);
143         token = next_token (&val, (unsigned *)0, cfile);
144
145         /* Lose servers that are no longer in /etc/resolv.conf. */
146         sl = (struct name_server *)0;
147         for (sp = name_servers; sp; sp = ns) {
148                 ns = sp -> next;
149                 if (sp -> rcdate != parse_time) {
150                         if (sl)
151                                 sl -> next = sp -> next;
152                         else
153                                 name_servers = sp -> next;
154                         /* We can't actually free the name server structure,
155                            because somebody might be hanging on to it.    If
156                            your /etc/resolv.conf file changes a lot, this
157                            could be a noticable memory leak. */
158                 } else
159                         sl = sp;
160         }
161
162         /* Lose domains that are no longer in /etc/resolv.conf. */
163         dl = (struct domain_search_list *)0;
164         for (dp = domains; dp; dp = nd) {
165                 nd = dp -> next;
166                 if (dp -> rcdate != parse_time) {
167                         if (dl)
168                                 dl -> next = dp -> next;
169                         else
170                                 domains = dp -> next;
171                         free_domain_search_list (dp, MDL);
172                 } else
173                         dl = dp;
174         }
175         close (file);
176         end_parse (&cfile);
177 }
178
179 /* Pick a name server from the /etc/resolv.conf file. */
180
181 struct name_server *first_name_server ()
182 {
183         FILE *rc;
184         static TIME rcdate;
185         struct stat st;
186
187         /* Check /etc/resolv.conf and reload it if it's changed. */
188         if (cur_time > rcdate) {
189                 if (stat (path_resolv_conf, &st) < 0) {
190                         log_error ("Can't stat %s", path_resolv_conf);
191                         return (struct name_server *)0;
192                 }
193                 if (st.st_mtime > rcdate) {
194                         char rcbuf [512];
195                         char *s, *t, *u;
196                         rcdate = cur_time + 1;
197                         
198                         read_resolv_conf (rcdate);
199                 }
200         }
201
202         return name_servers;
203 }