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