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