Commit | Line | Data |
---|---|---|
95f51977 | 1 | /* |
ca67e7b4 C |
2 | * Copyright (c) 1986 Regents of the University of California. |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms are permitted | |
6 | * provided that the above copyright notice and this paragraph are | |
7 | * duplicated in all such forms and that any documentation, | |
8 | * advertising materials, and other materials related to such | |
9 | * distribution and use acknowledge that the software was developed | |
10 | * by the University of California, Berkeley. The name of the | |
11 | * University may not be used to endorse or promote products derived | |
12 | * from this software without specific prior written permission. | |
13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
14 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
15 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
95f51977 C |
16 | */ |
17 | ||
ca67e7b4 C |
18 | #ifndef lint |
19 | static char sccsid[] = "@(#)ns_init.c 4.24 (Berkeley) 6/18/88"; | |
20 | #endif /* not lint */ | |
21 | ||
95f51977 C |
22 | #include <sys/types.h> |
23 | #include <sys/socket.h> | |
24 | #include <sys/time.h> | |
25 | #include <netinet/in.h> | |
26 | #include <stdio.h> | |
27 | #include <errno.h> | |
28 | #include <signal.h> | |
29 | #include <syslog.h> | |
30 | #include <ctype.h> | |
31 | #include <arpa/nameser.h> | |
32 | #include "ns.h" | |
33 | #include "db.h" | |
34 | ||
35 | struct zoneinfo zones[MAXZONES]; /* zone information */ | |
36 | int nzones; /* number of zones in use */ | |
ca67e7b4 C |
37 | int forward_only = 0; /* run only as a slave */ |
38 | char *cache_file; | |
39 | char *localdomain; /* "default" for non-dotted names */ | |
40 | int maint_interval = 300; /* minimum ns_maint() interval */ | |
41 | ||
42 | extern int lineno; | |
95f51977 C |
43 | |
44 | /* | |
45 | * Read boot file for configuration info. | |
46 | */ | |
ca67e7b4 | 47 | |
95f51977 C |
48 | ns_init(bootfile) |
49 | char *bootfile; | |
50 | { | |
51 | register struct zoneinfo *zp; | |
52 | char buf[BUFSIZ]; | |
95f51977 | 53 | FILE *fp; |
ca67e7b4 C |
54 | int type; |
55 | time_t next_refresh = 0; | |
95f51977 | 56 | struct itimerval ival; |
ca67e7b4 | 57 | extern int needmaint; |
95f51977 C |
58 | |
59 | #ifdef DEBUG | |
60 | if (debug >= 3) | |
61 | fprintf(ddt,"ns_init(%s)\n", bootfile); | |
62 | #endif | |
ca67e7b4 | 63 | gettime(&tt); |
95f51977 C |
64 | |
65 | if ((fp = fopen(bootfile, "r")) == NULL) { | |
66 | syslog(LOG_ERR, "%s: %m", bootfile); | |
67 | exit(1); | |
68 | } | |
ca67e7b4 | 69 | lineno = 0; |
95f51977 | 70 | |
ca67e7b4 | 71 | /* allocate cache hash table, formerly the root hash table. */ |
95f51977 C |
72 | hashtab = savehash((struct hashbuf *)NULL); |
73 | ||
ca67e7b4 C |
74 | /* allocate root-hints/file-cache hash table */ |
75 | fcachetab = savehash((struct hashbuf *)NULL); | |
76 | ||
77 | if (localdomain) | |
78 | free(localdomain); | |
79 | localdomain = NULL; | |
80 | ||
95f51977 | 81 | /* init zone data */ |
ca67e7b4 | 82 | cache_file = NULL; |
95f51977 | 83 | nzones = 1; /* zone zero is cache data */ |
ca67e7b4 C |
84 | zones[0].z_type = Z_CACHE; |
85 | while (!feof(fp) && !ferror(fp)) { | |
86 | if (!getword(buf, sizeof(buf), fp)) | |
87 | continue; | |
88 | /* read named.boot keyword and process args */ | |
89 | if (strcasecmp(buf, "cache") == 0) { | |
95f51977 C |
90 | type = Z_CACHE; |
91 | zp = zones; | |
ca67e7b4 C |
92 | } |
93 | else if (strcasecmp(buf, "primary") == 0) | |
94 | type = Z_PRIMARY; | |
95 | else if (strcasecmp(buf, "secondary") == 0) | |
96 | type = Z_SECONDARY; | |
97 | else if (strcasecmp(buf, "directory") == 0) { | |
98 | (void) getword(buf, sizeof(buf), fp); | |
99 | if (chdir(buf) < 0) { | |
100 | syslog(LOG_CRIT, "directory %s: %m\n", | |
101 | buf); | |
95f51977 C |
102 | exit(1); |
103 | } | |
ca67e7b4 C |
104 | continue; |
105 | } | |
106 | else if (strcasecmp(buf, "sortlist") == 0) { | |
107 | get_sort_list(fp); | |
108 | continue; | |
109 | } | |
110 | else if (strcasecmp(buf, "forwarders") == 0) { | |
111 | get_forwarders(fp); | |
112 | continue; | |
113 | } | |
114 | else if (strcasecmp(buf, "slave") == 0) { | |
115 | forward_only++; | |
116 | endline(fp); | |
117 | continue; | |
118 | } | |
119 | else if (strcasecmp(buf, "domain") == 0) { | |
120 | if (getword(buf, sizeof(buf), fp)) | |
121 | localdomain = savestr(buf); | |
122 | endline(fp); | |
123 | continue; | |
124 | } else { | |
125 | syslog(LOG_ERR, "%s: line %d: unknown field '%s'\n", | |
126 | bootfile, lineno, buf); | |
127 | endline(fp); | |
128 | continue; | |
129 | } | |
130 | if (nzones >= MAXZONES) { | |
131 | syslog(LOG_ERR, "too many zones (MAXZONES=%d)\n", | |
132 | MAXZONES); | |
133 | endline(fp); | |
134 | continue; | |
135 | } | |
136 | if (type != Z_CACHE) | |
95f51977 | 137 | zp = &zones[nzones++]; |
ca67e7b4 C |
138 | if (zp->z_origin) { |
139 | free(zp->z_origin); | |
140 | zp->z_origin = 0; | |
141 | } | |
142 | if (zp->z_source) { | |
143 | free(zp->z_source); | |
144 | zp->z_source = 0; | |
95f51977 C |
145 | } |
146 | zp->z_type = type; | |
147 | zp->z_addrcnt = 0; | |
ca67e7b4 | 148 | zp->z_auth = 0; |
95f51977 C |
149 | /* |
150 | * read zone origin | |
151 | */ | |
ca67e7b4 C |
152 | if (!getword(buf, sizeof(buf), fp)) { |
153 | syslog(LOG_ERR, "%s: line %d: missing origin\n", | |
154 | bootfile, lineno); | |
155 | continue; | |
156 | } | |
95f51977 C |
157 | if (buf[0] == '.') |
158 | buf[0] = '\0'; | |
159 | zp->z_origin = savestr(buf); | |
160 | /* | |
161 | * read source file or host address | |
162 | */ | |
ca67e7b4 C |
163 | if (!getword(buf, sizeof(buf), fp)) { |
164 | syslog(LOG_ERR, "%s: line %d: missing origin\n", | |
165 | bootfile, lineno); | |
166 | continue; | |
167 | } | |
95f51977 | 168 | #ifdef DEBUG |
ca67e7b4 C |
169 | if (debug) |
170 | fprintf(ddt,"zone[%d] type %d: '%s'", | |
171 | zp-zones, zp->z_type, | |
172 | *(zp->z_origin) == '\0' ? "." : zp->z_origin); | |
95f51977 | 173 | #endif |
ca67e7b4 C |
174 | zp->z_time = 0; |
175 | zp->z_refresh = 0; /* by default, no dumping */ | |
176 | switch (type) { | |
177 | case Z_CACHE: | |
178 | zp->z_source = savestr(buf); | |
95f51977 | 179 | #ifdef DEBUG |
ca67e7b4 C |
180 | if (debug) |
181 | fprintf(ddt,", source = %s\n", zp->z_source); | |
95f51977 | 182 | #endif |
ca67e7b4 C |
183 | if (getword(buf, sizeof(buf), fp)) { |
184 | #ifdef notyet | |
185 | zp->z_refresh = atoi(buf); | |
186 | if (zp->z_refresh <= 0) { | |
187 | syslog(LOG_ERR, | |
188 | "%s: line %d: bad refresh '%s', ignored\n", | |
189 | bootfile, lineno, buf); | |
190 | zp->z_refresh = 0; | |
191 | } else if (cache_file == NULL) | |
192 | cache_file = zp->z_source; | |
193 | #else | |
194 | syslog(LOG_WARNING, | |
195 | "%s: line %d: cache refresh ignored\n", | |
196 | bootfile, lineno); | |
197 | #endif | |
198 | endline(fp); | |
199 | } | |
200 | (void) db_load(zp->z_source, zp->z_origin, zp); | |
201 | break; | |
202 | ||
95f51977 | 203 | case Z_PRIMARY: |
ca67e7b4 | 204 | zp->z_source = savestr(buf); |
95f51977 C |
205 | #ifdef DEBUG |
206 | if (debug) | |
ca67e7b4 | 207 | fprintf(ddt,", source = %s\n", zp->z_source); |
95f51977 | 208 | #endif |
ca67e7b4 C |
209 | if (db_load(zp->z_source, zp->z_origin, zp) == 0) |
210 | zp->z_auth = 1; | |
211 | #ifdef ALLOW_UPDATES | |
212 | /* Guarantee calls to ns_maint() */ | |
213 | zp->z_refresh = maint_interval; | |
214 | #else | |
215 | zp->z_refresh = 0; | |
216 | zp->z_time = 0; | |
217 | #endif ALLOW_UPDATES | |
95f51977 C |
218 | break; |
219 | ||
220 | case Z_SECONDARY: | |
ca67e7b4 C |
221 | #ifdef DEBUG |
222 | if (debug) | |
223 | fprintf(ddt,"\n\taddrs: %s, ", buf); | |
224 | #endif | |
95f51977 | 225 | zp->z_addr[zp->z_addrcnt].s_addr = |
ca67e7b4 C |
226 | inet_addr(buf); |
227 | /* Indicate no cache for this zone yet */ | |
228 | zp->z_source = (char *) NULL; | |
95f51977 | 229 | if (zp->z_addr[zp->z_addrcnt].s_addr != (unsigned)-1) |
ca67e7b4 | 230 | zp->z_addrcnt++; |
95f51977 | 231 | while (getword(buf, sizeof(buf), fp)) { |
95f51977 | 232 | zp->z_addr[zp->z_addrcnt].s_addr = |
ca67e7b4 | 233 | inet_addr(buf); |
95f51977 C |
234 | if (zp->z_addr[zp->z_addrcnt].s_addr == |
235 | (unsigned)-1) { | |
ca67e7b4 C |
236 | zp->z_source = savestr(buf); |
237 | break; | |
95f51977 C |
238 | } |
239 | #ifdef DEBUG | |
240 | if (debug) | |
ca67e7b4 | 241 | fprintf(ddt,"%s, ",buf); |
95f51977 | 242 | #endif |
ca67e7b4 C |
243 | if (++zp->z_addrcnt >= NSMAX) { |
244 | zp->z_addrcnt = NSMAX; | |
95f51977 C |
245 | #ifdef DEBUG |
246 | if (debug) | |
247 | fprintf(ddt, | |
ca67e7b4 | 248 | "\nns.h NSMAX reached\n"); |
95f51977 C |
249 | #endif |
250 | break; | |
251 | } | |
252 | } | |
253 | #ifdef DEBUG | |
254 | if (debug) | |
ca67e7b4 | 255 | fprintf(ddt,"addrcnt = %d\n", zp->z_addrcnt); |
95f51977 C |
256 | #endif |
257 | zoneinit(zp); | |
95f51977 C |
258 | break; |
259 | ||
ca67e7b4 C |
260 | } |
261 | if (zp->z_refresh && zp->z_time == 0) | |
262 | zp->z_time = zp->z_refresh + tt.tv_sec; | |
95f51977 | 263 | #ifdef DEBUG |
ca67e7b4 C |
264 | if (debug) |
265 | fprintf(ddt, "z_time %d, z_refresh %d\n", | |
266 | zp->z_time, zp->z_refresh); | |
95f51977 | 267 | #endif |
ca67e7b4 C |
268 | if (zp->z_time != 0 && |
269 | (next_refresh == 0 || next_refresh > zp->z_time)) | |
270 | next_refresh = zp->z_time; | |
95f51977 C |
271 | } |
272 | (void) fclose(fp); | |
ca67e7b4 C |
273 | |
274 | /* | |
275 | * Schedule calls to ns_maint(). | |
276 | */ | |
277 | bzero((char *)&ival, sizeof(ival)); | |
278 | if (next_refresh) { | |
279 | gettime(&tt); | |
280 | if (next_refresh <= tt.tv_sec) | |
281 | needmaint = 1; | |
282 | else { | |
95f51977 | 283 | ival.it_value.tv_sec = next_refresh - tt.tv_sec; |
ca67e7b4 C |
284 | if (ival.it_value.tv_sec < maint_interval) |
285 | ival.it_value.tv_sec = maint_interval; | |
95f51977 | 286 | } |
ca67e7b4 | 287 | } |
95f51977 | 288 | (void) setitimer(ITIMER_REAL, &ival, (struct itimerval *)NULL); |
ca67e7b4 C |
289 | #ifdef DEBUG |
290 | if (debug) { | |
291 | fprintf(ddt,"exit ns_init() "); | |
292 | if (needmaint || ival.it_value.tv_sec) | |
293 | fprintf(ddt,"Next interrupt in %d sec\n", | |
294 | ival.it_value.tv_sec); | |
295 | else | |
296 | fprintf(ddt,"No maintenance scheduled\n"); | |
297 | } | |
95f51977 C |
298 | #endif |
299 | } | |
300 | ||
301 | zoneinit(zp) | |
ca67e7b4 | 302 | register struct zoneinfo *zp; |
95f51977 | 303 | { |
95f51977 C |
304 | |
305 | #ifdef DEBUG | |
306 | if (debug) | |
307 | fprintf(ddt,"zoneinit()\n"); | |
308 | #endif | |
309 | ||
ca67e7b4 C |
310 | /* |
311 | * Try to load zone from backup file, | |
312 | * if one was specified and it exists. | |
313 | * If not, or if the data are out of date, | |
314 | * we will refresh the zone from a primary | |
315 | * immediately. | |
316 | */ | |
317 | if (zp->z_source == NULL || | |
318 | db_load(zp->z_source, zp->z_origin, zp) != 0) { | |
319 | /* | |
320 | * Set zone to be refreshed immediately. | |
321 | */ | |
322 | zp->z_refresh = INIT_REFRESH; | |
323 | zp->z_retry = INIT_REFRESH; | |
324 | zp->z_time = tt.tv_sec; | |
325 | } else | |
326 | zp->z_auth = 1; | |
327 | } | |
328 | ||
329 | #ifdef ALLOW_UPDATES | |
330 | /* | |
331 | * Look for the authoritative zone with the longest matching RHS of dname | |
332 | * and return its zone # or zero if not found. | |
333 | */ | |
334 | findzone(dname, class) | |
335 | char *dname; | |
336 | int class; | |
337 | { | |
338 | char *dZoneName, *zoneName, *index(), *dotPos; | |
339 | int dZoneNameLen, zoneNameLen; | |
340 | int maxMatchLen = 0; | |
341 | int maxMatchZoneNum = 0; | |
342 | int zoneNum; | |
95f51977 | 343 | |
95f51977 | 344 | #ifdef DEBUG |
ca67e7b4 C |
345 | if (debug >= 4) |
346 | fprintf(ddt, "findzone(dname=%s, class=%d)\n", dname, class); | |
347 | if (debug >= 5) { | |
348 | fprintf(ddt, "zone dump:\n"); | |
349 | for (zoneNum = 1; zoneNum < nzones; zoneNum++) | |
350 | printzoneinfo(zoneNum); | |
351 | } | |
352 | #endif DEBUG | |
353 | ||
354 | dZoneName = index(dname, '.'); | |
355 | if (dZoneName == NULL) | |
356 | dZoneName = ""; /* root */ | |
357 | else | |
358 | dZoneName++; /* There is a '.' in dname, so use remainder of | |
359 | string as the zone name */ | |
360 | dZoneNameLen = strlen(dZoneName); | |
361 | for (zoneNum = 1; zoneNum < nzones; zoneNum++) { | |
362 | zoneName = (zones[zoneNum]).z_origin; | |
363 | zoneNameLen = strlen(zoneName); | |
364 | /* The zone name may or may not end with a '.' */ | |
365 | dotPos = index(zoneName, '.'); | |
366 | if (dotPos) | |
367 | zoneNameLen--; | |
368 | if (dZoneNameLen != zoneNameLen) | |
369 | continue; | |
95f51977 | 370 | #ifdef DEBUG |
ca67e7b4 C |
371 | if (debug >= 5) |
372 | fprintf(ddt, "about to strncasecmp('%s', '%s', %d)\n", | |
373 | dZoneName, zoneName, dZoneNameLen); | |
95f51977 | 374 | #endif |
ca67e7b4 | 375 | if (strncasecmp(dZoneName, zoneName, dZoneNameLen) == 0) { |
95f51977 | 376 | #ifdef DEBUG |
ca67e7b4 C |
377 | if (debug >= 5) |
378 | fprintf(ddt, "match\n"); | |
95f51977 | 379 | #endif |
95f51977 | 380 | /* |
ca67e7b4 C |
381 | * See if this is as long a match as any so far. |
382 | * Check if "<=" instead of just "<" so that if | |
383 | * root domain (whose name length is 0) matches, | |
384 | * we use it's zone number instead of just 0 | |
95f51977 | 385 | */ |
ca67e7b4 C |
386 | if (maxMatchLen <= zoneNameLen) { |
387 | maxMatchZoneNum = zoneNum; | |
388 | maxMatchLen = zoneNameLen; | |
95f51977 C |
389 | } |
390 | } | |
95f51977 | 391 | #ifdef DEBUG |
ca67e7b4 C |
392 | else |
393 | if (debug >= 5) | |
394 | fprintf(ddt, "no match\n"); | |
95f51977 C |
395 | #endif |
396 | } | |
ca67e7b4 C |
397 | #ifdef DEBUG |
398 | if (debug >= 4) | |
399 | fprintf(ddt, "findzone: returning %d\n", maxMatchZoneNum); | |
400 | #endif DEBUG | |
401 | return (maxMatchZoneNum); | |
95f51977 | 402 | } |
ca67e7b4 | 403 | #endif ALLOW_UPDATES |
95f51977 | 404 | |
ca67e7b4 C |
405 | soa_zinfo(zp, cp, eom) |
406 | register struct zoneinfo *zp; | |
407 | register u_char *cp; | |
408 | u_char *eom; | |
95f51977 C |
409 | { |
410 | cp += 3 * sizeof(u_short); | |
411 | cp += sizeof(u_long); | |
ca67e7b4 C |
412 | cp += dn_skipname(cp, eom); |
413 | cp += dn_skipname(cp, eom); | |
414 | GETLONG(zp->z_serial, cp); | |
415 | GETLONG(zp->z_refresh, cp); | |
416 | gettime(&tt); | |
95f51977 | 417 | zp->z_time = tt.tv_sec + zp->z_refresh; |
ca67e7b4 C |
418 | GETLONG(zp->z_retry, cp); |
419 | GETLONG(zp->z_expire, cp); | |
420 | GETLONG(zp->z_minimum, cp); | |
421 | } | |
422 | ||
423 | get_forwarders(fp) | |
424 | FILE *fp; | |
425 | { | |
426 | char buf[BUFSIZ]; | |
427 | struct fwdinfo *fip = NULL, *ftp = NULL; | |
428 | ||
429 | extern struct sockaddr_in nsaddr; | |
430 | extern struct fwdinfo *fwdtab; | |
431 | ||
432 | #ifdef DEBUG | |
433 | if (debug) | |
434 | fprintf(ddt,"forwarders "); | |
435 | #endif | |
436 | while (getword(buf, sizeof(buf), fp)) { | |
437 | if (strlen(buf) == 0) | |
438 | break; | |
439 | #ifdef DEBUG | |
440 | if (debug) | |
441 | fprintf(ddt," %s",buf); | |
442 | #endif | |
443 | if (ftp == NULL) | |
444 | ftp = (struct fwdinfo *)malloc(sizeof(struct fwdinfo)); | |
445 | if ( isdigit(buf[0]) && | |
446 | (ftp->fwdaddr.sin_addr.s_addr = inet_addr(buf)) | |
447 | != (unsigned)-1) { | |
448 | ftp->fwdaddr.sin_port = nsaddr.sin_port; | |
449 | ftp->fwdaddr.sin_family = AF_INET; | |
450 | } else { | |
451 | syslog(LOG_ERR, "'%s' (ignored, NOT dotted quad)", buf); | |
452 | #ifdef DEBUG | |
453 | if (debug) | |
454 | fprintf(ddt," (ignored, NOT dotted quad)"); | |
455 | #endif | |
456 | continue; | |
457 | } | |
458 | ftp->next = NULL; | |
459 | if (fwdtab == NULL) | |
460 | fwdtab = ftp; /* First time only */ | |
461 | else | |
462 | fip->next = ftp; | |
463 | fip = ftp; | |
464 | ftp = NULL; | |
465 | } | |
466 | if (ftp) | |
467 | free((char *)ftp); | |
468 | ||
469 | #ifdef DEBUG | |
470 | if (debug) | |
471 | fprintf(ddt,"\n"); | |
472 | if (debug > 2) | |
473 | for (ftp = fwdtab; ftp != NULL; ftp = ftp->next) | |
474 | fprintf(ddt,"ftp x%x %s next x%x\n", ftp, | |
475 | inet_ntoa(ftp->fwdaddr.sin_addr), ftp->next); | |
476 | #endif | |
95f51977 | 477 | } |