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