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