This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / usr.sbin / named / db_update.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1986, 1990 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static char sccsid[] = "@(#)db_update.c 4.28 (Berkeley) 3/21/91";
36#endif /* not lint */
37
38#include <sys/param.h>
39#include <sys/socket.h>
40#include <sys/time.h>
41#include <netinet/in.h>
42#include <arpa/nameser.h>
43#include <stdio.h>
44#include <syslog.h>
45#include "ns.h"
46#include "db.h"
47
48extern struct timeval tt;
49extern FILE *ddt;
50extern struct sockaddr_in from_addr; /* Source addr of last packet */
51extern int needs_prime_cache;
52
53int max_cache_ttl = (7*24*60*60); /* ONE_WEEK maximum ttl */
54int min_cache_ttl = (5*60); /* 5 minute minimum ttl */
55
56/*
57 * Update data base. Flags control the action.
58 * Inverse query tables modified.
59 */
60db_update(name, odp, newdp, flags, htp)
61 char name[];
62 struct databuf *odp, *newdp;
63 int flags;
64 struct hashbuf *htp;
65{
66 register struct namebuf *np;
67 register struct databuf *dp, *pdp;
68 char *fname;
69 int foundRR = 0;
70
71#ifdef DEBUG
72 if (debug >= 3)
73 fprintf(ddt,"db_update(%s, 0x%x, 0x%x, 0%o, 0x%x)%s\n",
74 name, odp, newdp, flags, htp,
75 (odp && (odp->d_flags&DB_F_HINT)) ? " hint":"" );
76#endif
77 np = nlookup(name, &htp, &fname, newdp != NULL);
78 if (np == NULL || fname != name)
79 return (NONAME);
80
81 /* Reflect certain updates in hint cache also... */
82 /* Don't stick data we are authoritative for in hints. */
83 if (!(flags & DB_NOHINTS) && (odp != NULL) &&
84 (odp->d_zone <= 0) && !(odp->d_flags & DB_F_HINT) &&
85 ((name[0] == '\0' && odp->d_type == T_NS) ||
86 (odp->d_type == T_A)))
87 {
88 register struct databuf *dp;
89#ifdef DEBUG
90 if (debug >= 3)
91 fprintf(ddt,"db_update: hint '%s' %d\n",
92 name, odp->d_ttl);
93#endif
94 dp = savedata(odp->d_class, odp->d_type, odp->d_ttl,
95 odp->d_data, odp->d_size);
96 dp->d_zone = DB_Z_CACHE;
97 dp->d_flags = DB_F_HINT;
98 if (db_update(name, dp,dp, (flags|DB_NOHINTS), fcachetab) != OK) {
99#ifdef DEBUG
100 if (debug > 2)
101 fprintf(ddt, "db_update: hint %x freed\n", dp);
102#endif
103 (void) free((char *)dp);
104 }
105 }
106
107 if (odp != NULL) {
108 pdp = NULL;
109 for (dp = np->n_data; dp != NULL; ) {
110 if (!match(dp, odp->d_class, odp->d_type)) {
111 if ((dp->d_type == T_CNAME ||
112 odp->d_type == T_CNAME) &&
113 odp->d_mark == dp->d_mark &&
114 zones[odp->d_zone].z_type != Z_CACHE) {
115 syslog(LOG_ERR,
116 "%s has CNAME and other data (illegal)\n",
117 name);
118#ifdef DEBUG
119 if (debug)
120 fprintf(ddt,
121 "db_update: %s: CNAME and more (%d, %d)\n",
122 name, odp->d_type, dp->d_type);
123#endif
124 }
125 goto skip;
126 }
127#ifdef DEBUG
128 if (debug >= 5)
129 fprintf(ddt,"db_update: flags = %#x, sizes = %d, %d (%d)\n",
130 flags, odp->d_size, dp->d_size,
131 db_cmp(dp, odp));
132#endif
133 if (flags & DB_NOTAUTH && dp->d_zone) {
134#ifdef DEBUG
135 if (debug)
136 fprintf(ddt,
137 "%s attempted update to auth zone %d '%s'\n",
138 inet_ntoa(from_addr.sin_addr),
139 dp->d_zone, zones[dp->d_zone].z_origin);
140#endif
141 return (AUTH);
142 }
143 if ((flags & DB_NODATA) && !db_cmp(dp, odp)) {
144 /* refresh ttl if cache entry */
145 if (dp->d_zone == 0) {
146 if (odp->d_zone != 0) { /* XXX */
147 /* changing cache->auth */
148 dp->d_zone = odp->d_zone;
149 dp->d_ttl = odp->d_ttl;
150#ifdef DEBUG
151 if (debug > 3)
152 fprintf(ddt,
153 "db_update: cache entry now in auth zone\n");
154#endif
155 return (DATAEXISTS);
156 }
157 fixttl(odp);
158 if (odp->d_ttl > dp->d_ttl)
159 dp->d_ttl = odp->d_ttl;
160#ifdef DEBUG
161 if (debug >= 3)
162 fprintf(ddt,"db_update: new ttl %d, +%d\n",
163 dp->d_ttl, dp->d_ttl - tt.tv_sec);
164#endif
165 }
166 return (DATAEXISTS);
167 }
168 /*
169 * If the old databuf has some data, check that the
170 * data matches that in the new databuf (so UPDATED
171 * will delete only the matching RR)
172 */
173 if (odp->d_size > 0) {
174 if (db_cmp(dp, odp))
175 goto skip;
176 }
177 foundRR = 1;
178 if (flags & DB_DELETE)
179 dp = rm_datum(dp, np, pdp);
180 else {
181skip: pdp = dp;
182 dp = dp->d_next;
183 }
184 }
185 if (!foundRR) {
186 if (flags & DB_DELETE)
187 return(NODATA);
188 if (flags & DB_MEXIST)
189 return(NODATA);
190 }
191 }
192 if (newdp == NULL)
193 return (OK);
194 fixttl(newdp);
195#ifdef DEBUG
196 if (debug >= 3)
197 fprintf(ddt,"db_update: adding%s %x\n",
198 (newdp->d_flags&DB_F_HINT) ? " hint":"", newdp);
199#endif
200 if (!(newdp->d_flags & DB_F_HINT))
201 addinv(np, newdp); /* modify inverse query tables */
202
203 /* Add to end of list, generally preserving order */
204 newdp->d_next = NULL;
205 if ((dp = np->n_data) == NULL) {
206 np->n_data = newdp;
207 return (OK);
208 }
209 /* XXX: need to check for duplicate WKS records and flag error */
210 while (dp->d_next != NULL) {
211 if ((flags & DB_NODATA) && !db_cmp(dp, newdp))
212 return (DATAEXISTS);
213 dp = dp->d_next;
214 }
215 if ((flags & DB_NODATA) && !db_cmp(dp, newdp))
216 return (DATAEXISTS);
217 dp->d_next = newdp;
218 return (OK);
219}
220
221fixttl(dp)
222register struct databuf *dp;
223{
224 if (dp->d_zone == 0 && !(dp->d_flags & DB_F_HINT)) {
225 if (dp->d_ttl <= tt.tv_sec)
226 return;
227 else if (dp->d_ttl < tt.tv_sec+min_cache_ttl)
228 dp->d_ttl = tt.tv_sec+min_cache_ttl;
229 else if (dp->d_ttl > tt.tv_sec+max_cache_ttl)
230 dp->d_ttl = tt.tv_sec+max_cache_ttl;
231 }
232 return;
233}
234
235struct invbuf *invtab[INVHASHSZ]; /* Inverse query hash table */
236
237/*
238 * Add data 'dp' to inverse query tables for name 'np'.
239 */
240addinv(np, dp)
241 struct namebuf *np;
242 struct databuf *dp;
243{
244 register struct invbuf *ip;
245 register int hval, i;
246
247 switch (dp->d_type) {
248 case T_A:
249 case T_UID:
250 case T_GID:
251 break;
252
253 default:
254 return;
255 }
256
257 hval = dhash(dp->d_data, dp->d_size);
258 for (ip = invtab[hval]; ip != NULL; ip = ip->i_next)
259 for (i = 0; i < INVBLKSZ; i++)
260 if (ip->i_dname[i] == NULL) {
261 ip->i_dname[i] = np;
262 return;
263 }
264 ip = saveinv();
265 ip->i_next = invtab[hval];
266 invtab[hval] = ip;
267 ip->i_dname[0] = np;
268}
269
270/*
271 * Remove data 'odp' from inverse query table.
272 */
273rminv(odp)
274 struct databuf *odp;
275{
276 register struct invbuf *ip;
277 register struct databuf *dp;
278 struct namebuf *np;
279 register int i;
280
281 for (ip = invtab[dhash(odp->d_data, odp->d_size)]; ip != NULL;
282 ip = ip->i_next) {
283 for (i = 0; i < INVBLKSZ; i++) {
284 if ((np = ip->i_dname[i]) == NULL)
285 break;
286 for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
287 if (!match(dp, odp->d_class, odp->d_type))
288 continue;
289 if (db_cmp(dp, odp))
290 continue;
291 while (i < INVBLKSZ-1) {
292 ip->i_dname[i] = ip->i_dname[i+1];
293 i++;
294 }
295 ip->i_dname[i] = NULL;
296 return;
297 }
298 }
299 }
300}
301
302/*
303 * Compute hash value from data.
304 */
305dhash(dp, dlen)
306 char *dp;
307 int dlen;
308{
309 register char *cp;
310 register unsigned hval;
311 register int n;
312
313 n = dlen;
314 if (n > 8)
315 n = 8;
316 hval = 0;
317 for (cp = dp; --n >= 0; ) {
318 hval <<= 1;
319 hval += *cp++;
320 }
321 return (hval % INVHASHSZ);
322}
323
324/*
325 * Compare type, class and data from databufs for equivalence.
326 * Must be case insensitive for some domain names.
327 * Return 0 if equivalent, nonzero otherwise.
328 */
329db_cmp(dp1, dp2)
330 register struct databuf *dp1, *dp2;
331
332{
333 register char *cp1, *cp2;
334 int len;
335
336 if (dp1->d_type != dp2->d_type || dp1->d_class != dp2->d_class)
337 return(1);
338 if (dp1->d_size != dp2->d_size)
339 return(1);
340 if (dp1->d_mark != dp2->d_mark)
341 return(1); /* old and new RR's are distinct */
342 switch (dp1->d_type) {
343
344 case T_A:
345 case T_UID:
346 case T_GID:
347 case T_WKS:
348 case T_NULL:
349#ifdef ALLOW_T_UNSPEC
350 case T_UNSPEC:
351#endif ALLOW_T_UNSPEC
352 return(bcmp(dp1->d_data, dp2->d_data, dp1->d_size));
353
354 case T_NS:
355 case T_CNAME:
356 case T_PTR:
357 case T_MB:
358 case T_MG:
359 case T_MR:
360 case T_UINFO:
361 return(strcasecmp(dp1->d_data, dp2->d_data));
362
363 case T_HINFO:
364 cp1 = dp1->d_data;
365 cp2 = dp2->d_data;
366 len = *cp1;
367 if (strncasecmp(++cp1, ++cp2, len))
368 return(1);
369 cp1 += len;
370 cp2 += len;
371 len = *cp1;
372 return(strncasecmp(++cp1, ++cp2, len));
373
374 case T_SOA:
375 case T_MINFO:
376 if (strcasecmp(dp1->d_data, dp2->d_data))
377 return(1);
378 cp1 = dp1->d_data + strlen(dp1->d_data) + 1;
379 cp2 = dp2->d_data + strlen(dp2->d_data) + 1;
380 if (dp1->d_type != T_SOA)
381 return(strcasecmp(cp1, cp2));
382 if (strcasecmp(cp1, cp2))
383 return(1);
384 cp1 += strlen(cp1) + 1;
385 cp2 += strlen(cp2) + 1;
386 return(bcmp(cp1, cp2, sizeof(u_long) * 5));
387
388 case T_MX:
389 cp1 = dp1->d_data;
390 cp2 = dp2->d_data;
391 if (*cp1++ != *cp2++ || *cp1++ != *cp2++) /* cmp prio */
392 return(1);
393 return(strcasecmp(cp1, cp2));
394
395 case T_TXT:
396 if (dp1->d_size != dp2->d_size)
397 return(1);
398 return(bcmp(dp1->d_data, dp2->d_data, dp1->d_size));
399
400 default:
401 return (1);
402 }
403}