diff options
Diffstat (limited to 'contrib/bind/bin/named/db_update.c')
-rw-r--r-- | contrib/bind/bin/named/db_update.c | 1002 |
1 files changed, 0 insertions, 1002 deletions
diff --git a/contrib/bind/bin/named/db_update.c b/contrib/bind/bin/named/db_update.c deleted file mode 100644 index 494a0de..0000000 --- a/contrib/bind/bin/named/db_update.c +++ /dev/null @@ -1,1002 +0,0 @@ -#if !defined(lint) && !defined(SABER) -static const char sccsid[] = "@(#)db_update.c 4.28 (Berkeley) 3/21/91"; -static const char rcsid[] = "$Id: db_update.c,v 8.50 2001/10/24 23:53:09 marka Exp $"; -#endif /* not lint */ - -/* - * Copyright (c) 1986, 1990 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Portions Copyright (c) 1993 by Digital Equipment Corporation. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies, and that - * the name of Digital Equipment Corporation not be used in advertising or - * publicity pertaining to distribution of the document or software without - * specific, written prior permission. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT - * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - */ - -/* - * Portions Copyright (c) 1996-2000 by Internet Software Consortium. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - */ - -#include "port_before.h" - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/socket.h> -#include <sys/un.h> - -#include <netinet/in.h> -#include <arpa/inet.h> -#include <arpa/nameser.h> - -#include <resolv.h> -#include <stdio.h> -#include <string.h> -#include <syslog.h> -#include <time.h> - -#include <isc/eventlib.h> -#include <isc/logging.h> - -#include "port_after.h" - -#include "named.h" - -/* int - * isRefByNS(name, htp) - * recurse through all of `htp' looking for NS RR's that refer to `name'. - * returns: - * nonzero if at least one such NS RR exists - * cautions: - * this is very expensive; probably you only want to use on fcachetab. - */ -static int -isRefByNS(const char *name, struct hashbuf *htp) { - struct namebuf *np; - struct databuf *dp; - - for (np = htp->h_tab[0]; np != NULL; np = np->n_next) { - for (dp = np->n_data; dp != NULL; dp = dp->d_next) { - if ((dp->d_class == C_ANY || - dp->d_class == C_IN || - dp->d_class == C_HS) && - dp->d_type == T_NS && - !dp->d_rcode && - ns_samename(name, (const char *)dp->d_data) == 1) { - return (1); - } - } - if (np->n_hash && isRefByNS(name, np->n_hash)) - return (1); - } - return (0); -} - - -/* int - * findMyZone(struct namebuf *np, int class) - * surf the zone cuts and find this zone the hard way - * return value: - * zone number or DB_Z_CACHE if it's outside a zone - * interesting cases: - * DEC.COM SOA (primary) - * CRL.DEC.COM NS (in primary) - * if you start at CRL.. here, you find the DEC.COM zone - * if you start at NS.CRL.. here, you're in the cache - * DEC.COM SOA (primary) - * CRL.DEC.COM NS (in primary) - * CRL.DEC.COM SOA (slave) - * CRL.DEC.COM NS (in slave) - * if you start at CRL.. here, you find the CRL.DEC.COM zone - * if you start at NS.CRL.. here, you're in the CRL.. zone - */ -int -findMyZone(struct namebuf *np, int class) { - for ((void)NULL; np; np = np_parent(np)) { - struct databuf *dp; - - /* if we encounter an SOA, we're in its zone (which can be - * the cache or an authoritative zone, depending). - */ - for (dp = np->n_data; dp; dp = dp->d_next) - if (match(dp, class, T_SOA) && dp->d_type == T_SOA) - return (dp->d_zone); - - /* if we find an NS at some node without having seen an SOA - * (above), then we're out in the cache somewhere. - */ - for (dp = np->n_data; dp; dp = dp->d_next) - if (match(dp, class, T_NS) && dp->d_type == T_NS) - return (DB_Z_CACHE); - } - - /* The cache has not yet been primed. */ - return (DB_Z_CACHE); -} - -/* int - * db_update(name, odp, newdp, savedpp, flags, htp, from) - * update data base node at `name'. `flags' controls the action. - * side effects: - * inverse query tables modified, if we're using them. - * return value: - * OK - success - * NONAME - name doesn't exist - * AUTH - you can't do that - * DATAEXISTS - there's something there and DB_NODATA was specified - * NODATA - there's no data, and (DB_DELETE or DB_MEXIST) was spec'd - * - * Policy: How to add data if one more RR is -ve data - * - * NEND NOERROR_NODATA - * NXD NXDOMAIN - * - * match - * old - * Data NEND NXD - * Data Merge Data Data - * new NEND NEND NEND NEND - * NXD NXD NXD NXD - * - * no match - * old - * Data NEND NXD - * Data Merge Merge Data - * new NEND Merge Merge NEND - * NXD NXD NXD NXD - * - */ -/* XXX: this code calls nlookup, which can create namebuf's. if this code - * has to exit with a fatal error, it should scan from the new np upward - * and for each node which has no children and no data it should remove - * the namebuf. design notes: (1) there's no harm in doing this even if - * success occurred; (2) stopping on the first nonremovable np is optimal; - * the code for removal should be taken out of clean_cache() and made - * general enough for this use, and for clean_cache()'s continued use. - * vix, 21jul94 - */ -int -db_update(const char *name, - struct databuf *odp, struct databuf *newdp, - struct databuf **savedpp, - int flags, struct hashbuf *htp, struct sockaddr_in from) -{ - struct databuf *dp, *pdp; - struct namebuf *np; - int zn, isHintNS; - int check_ttl = 0; - int deleted_something = 0; - const char *fname; -#ifdef BIND_UPDATE - int found_other_ns = 0; - struct databuf *tmpdp; -#endif - - ns_debug(ns_log_db, 3, "db_update(%s, %p, %p, %p, 0%o, %p)%s", - name, odp, newdp, savedpp, flags, htp, - (odp && (odp->d_flags&DB_F_HINT)) ? " hint" : ""); - np = nlookup(name, &htp, &fname, newdp != NULL); - if (np == NULL || fname != name) - return (NONAME); - - if (newdp && zones[newdp->d_zone].z_type == Z_PRIMARY) - check_ttl = 1; - - /* don't let nonauthoritative updates write in authority zones */ - if (newdp && ((zn = findMyZone(np, newdp->d_class)) != DB_Z_CACHE) && -#ifdef STUBS - (zones[zn].z_type != Z_STUB) && -#endif - (flags & DB_NOTAUTH)) { - int foundRR = 0; - - /* - * Don't generate the warning if the update - * would have been harmless (identical data). - */ - for (dp = np->n_data; dp != NULL; dp = dp->d_next) { - if (!db_cmp(dp, newdp)) { - foundRR++; - break; - } - } - if (!foundRR) - ns_debug(ns_log_db, 5, - "[%s].%d update? to auth zone \"%s\" (%s)", - inet_ntoa(from.sin_addr), - ntohs(from.sin_port), - zones[zn].z_origin, - name); - return (AUTH); - } - - if (newdp && zn && !(flags & DB_NOTAUTH)) { - if (nlabels(zones[zn].z_origin) > newdp->d_clev) { - if ((!ISVALIDGLUE(newdp) && - zones[newdp->d_zone].z_type == Z_PRIMARY) || - (newdp->d_type == T_NS && - !ns_samename(name, zones[zn].z_origin))) { - ns_info(ns_log_db, - "domain %s %s record in zone %s should be in zone %s", - name, p_type(newdp->d_type), - zones[newdp->d_zone].z_origin, - zones[zn].z_origin); - return (NONGLUE); - } else - ns_debug(ns_log_db, 5, - "attempted update child zone %s, %s %s", - zones[zn].z_origin, name, - p_type(newdp->d_type)); - return (AUTH); - } - } - - /* some special checks for root NS' A RR's */ - isHintNS = isRefByNS(name, fcachetab); -#ifdef DEPRECATED - if (newdp && isHintNS && newdp->d_type == T_A) { - /* upgrade credibility of additional data for rootsrv addrs */ - if (newdp->d_cred == DB_C_ADDITIONAL) { - ns_debug(ns_log_db, 3, - "upgrading credibility for A RR (%s)", - name); - /* XXX: should copy NS RR's, but we really just want - * to prevent deprecation later so this will do. - */ - newdp->d_cred = DB_C_ANSWER; - newdp->d_clev = 0; - } - } -#endif - - /* Reflect certain updates in hint cache also... */ - /* Don't stick data we are authoritative for in hints. */ - if (!(flags & DB_NOHINTS) && - (flags & DB_PRIMING) && - (odp != NULL) && - (htp != fcachetab) && - (DB_Z_SPECIAL(odp->d_zone)) && - !(odp->d_flags & DB_F_HINT) && - (!newdp || !newdp->d_rcode) && - ((name[0] == '\0' && odp->d_type == T_NS) || - (odp->d_type == T_A && isHintNS) - ) - ) - { - ns_debug(ns_log_db, 3, "db_update: hint '%s' %u", - name, odp->d_ttl); - dp = savedata(odp->d_class, odp->d_type, odp->d_ttl, - odp->d_data, odp->d_size); - dp->d_zone = DB_Z_CACHE; - dp->d_flags = DB_F_HINT; - dp->d_cred = DB_C_CACHE; - dp->d_secure = odp->d_secure; /* BEW - this should be ok */ - dp->d_clev = 0; - if (db_update(name, - dp, dp, NULL, - (flags|DB_NOHINTS), - fcachetab, from) - != OK) - ns_debug(ns_log_db, 3, - "db_update: hint %p freed", dp); - db_detach(&dp); - } - - if (odp != NULL) { - int foundRR = 0; - - pdp = NULL; - for (dp = np->n_data; dp != NULL; ) { - if (!rrmatch(name, dp, odp)) { - /* {class,type} doesn't match. these are - * the aggregation cases. - */ - /* Check that CNAMEs are only accompanied by - * Secure DNS RR's (KEY, SIG, and NXT). - */ - if (((dp->d_type == T_CNAME && - odp->d_type != T_KEY && - odp->d_type != T_SIG && - odp->d_type != T_NXT) || - (odp->d_type == T_CNAME && - dp->d_type != T_KEY && - dp->d_type != T_SIG && - dp->d_type != T_NXT)) && - odp->d_class == dp->d_class && - /* XXXRTH d_mark removed in 4.9.5, - but still here for dynamic - update */ - odp->d_mark == dp->d_mark && - !dp->d_rcode && - !odp->d_rcode && -#ifdef BIND_UPDATE - /* updating a CNAME with another CNAME is permitted */ - (dp->d_type != T_CNAME || - odp->d_type != T_CNAME) && -#endif - zones[odp->d_zone].z_type != Z_CACHE) { - ns_info(ns_log_db, - "%s has CNAME and other data (invalid)", - name); - if (zones[odp->d_zone].z_type == - Z_PRIMARY) - return (CNAMEANDOTHER); - goto skip; - } - if (!newdp || newdp->d_class != dp->d_class) - goto skip; - - /* if the new data is authorative - * remove any data for this domain with - * the same class that isn't as credable - */ - if (newdp->d_cred == DB_C_ZONE && - newdp->d_cred > dp->d_cred) - /* better credibility and the old datum - * was not from a zone file. remove - * the old datum. - */ - goto delete; - -#if 0 /* caught by findMyZone() now. */ - /* if we have authoritative data for a - * node, don't add in other data. - */ - if (dp->d_cred == DB_C_ZONE && - newdp->d_cred < dp->d_cred) - return (AUTH); -#endif - - /* if the new data is authoritative - * but isn't as credible, reject it. - */ - if (newdp->d_cred == DB_C_ZONE && - dp->d_cred == DB_C_ZONE) { - /* Both records are from a zone file. - * If their credibility levels differ, - * we're dealing with a zone cut. The - * record with lower clev is from the - * upper zone's file and is therefore - * glue. - */ - - /* BEW/OG: we see no reason to override - * these rules with new security based - * rules. - */ - if (newdp->d_clev < dp->d_clev) { - if (!ISVALIDGLUE(newdp)) { - ns_info(ns_log_db, - "domain %s %s record in zone %s should be in zone %s, ignored", - name, p_type(newdp->d_type), - zones[newdp->d_zone].z_origin, - zones[dp->d_zone].z_origin); - } - return (AUTH); - } - if (newdp->d_clev > dp->d_clev) { - if (!ISVALIDGLUE(dp)) { - ns_info(ns_log_db, - "domain %s %s record in zone %s should be in zone %s, deleted", - name, p_type(dp->d_type), - zones[dp->d_zone].z_origin, - zones[newdp->d_zone].z_origin); - } - goto delete; - } - } - - /* process NXDOMAIN */ - /* policy */ - if (newdp->d_rcode == NXDOMAIN) { - if (dp->d_cred < DB_C_AUTH && - newdp->d_secure >= dp->d_secure) - goto delete; - else - return (DATAEXISTS); - } - - if (dp->d_rcode == NXDOMAIN) - goto delete; - - /* process NOERROR_NODATA */ - /* NO PROCESSING REQUIRED */ - - goto skip; - } /*if {class,type} did not match*/ - - /* - * {type,class} did match. This is the replace case. - */ - ns_debug(ns_log_db, 5, - "db_update: flags = %#x, sizes = %d, %d (cmp %d)", - flags, odp->d_size, dp->d_size, - db_cmp(dp, odp)); - if (newdp) { - ns_debug(ns_log_db, 4, -"credibility for %s is %d(%d)(sec %d) from [%s].%d, is %d(%d)(sec %d) in cache", - *name ? name : ".", - newdp->d_cred, - newdp->d_clev, - newdp->d_secure, - inet_ntoa(from.sin_addr), - ntohs(from.sin_port), - dp->d_cred, - dp->d_secure, - dp->d_clev); - if ((newdp->d_secure > dp->d_secure) || - (newdp->d_secure == dp->d_secure && - (newdp->d_cred > dp->d_cred))) - { - /* better credibility / security. - * remove the old datum. - */ - goto delete; - } - if ((newdp->d_secure < dp->d_secure) || - (newdp->d_secure == dp->d_secure && - (newdp->d_cred < dp->d_cred))) - { - /* credibility / security is worse. - * ignore it. - */ - return (AUTH); - } - /* BEW/OG: from above, we know the security - * levels are the same. - */ - if (newdp->d_cred == DB_C_ZONE && - dp->d_cred == DB_C_ZONE ) { - /* Both records are from a zone file. - * If their credibility levels differ, - * we're dealing with a zone cut. The - * record with lower clev is from the - * upper zone's file and is therefore - * glue. - */ - - /* XXX - Tricky situation here is you - * have 2 zones a.b.c and sub.a.b.c - * being served by the same server. - * named will send NS records for - * sub.a.b.c during zone transfer of - * a.b.c zone. If we're slave for - * both zones, and we reload zone - * a.b.c, we'll get the NS records - * (and possibly A records to go with - * them?) for sub.a.b.c as part of the - * a.b.c zone transfer. But we've - * already got a more credible record - * from the sub.a.b.c zone. So we want - * to ignore the new record, but we - * shouldn't syslog because there's - * nothing the user can do to prevent - * the situation. Perhaps we should - * only complain when we are primary? - */ - - if (newdp->d_clev < dp->d_clev) { - if (!ISVALIDGLUE(newdp)) { - ns_info(ns_log_db, - "domain %s %s record in zone %s should be in zone %s, ignored", - name, p_type(newdp->d_type), - zones[newdp->d_zone].z_origin, - zones[dp->d_zone].z_origin); - } - return (AUTH); - } - if (newdp->d_clev > dp->d_clev) { - if (!ISVALIDGLUE(dp)) { - ns_info(ns_log_db, - "domain %s %s record in zone %s should be in zone %s, deleted", - name, p_type(dp->d_type), - zones[dp->d_zone].z_origin, - zones[newdp->d_zone].z_origin); - } - goto delete; - } - } - - /* credibility is the same. - * let it aggregate in the normal way. - */ - - /* - * if the new or old RR is -ve, delete old. - */ - if (dp->d_rcode || newdp->d_rcode) { - /* XXX: how can a zone rr be neg? */ - if (dp->d_cred != DB_C_ZONE) - goto delete; - else - return (DATAEXISTS); - } - - /* - * Some RR types should not be aggregated. - */ - if (dp->d_type == T_SOA) { -#ifdef BIND_UPDATE - u_int32_t dp_ser, ndp_ser; - u_char *dp_cp, *ndp_cp; - - dp_cp = findsoaserial(dp->d_data); - ndp_cp = findsoaserial(newdp->d_data); - GETLONG(dp_ser, dp_cp); - GETLONG(ndp_ser, ndp_cp); - - if (SEQ_GT(ndp_ser, dp_ser)) - goto delete; - else - return (SERIAL); -#else - goto delete; -#endif /*BIND_UPDATE*/ - } - if (dp->d_type == T_WKS && - !memcmp(dp->d_data, newdp->d_data, - INT32SZ + sizeof(u_char))) - goto delete; - if (dp->d_type == T_CNAME && - !NS_OPTION_P(OPTION_MULTIPLE_CNAMES) && - db_cmp(dp, odp) != 0) { - if ((flags & DB_REPLACE) == 0 && - zones[dp->d_zone].z_type == - Z_PRIMARY) { - ns_warning(ns_log_db, - "%s has multiple CNAMES", - name); - return (CNAMEANDOTHER); - } else - goto delete; - } -#if 0 -/* BEW - this _seriously_ breaks DNSSEC. Is it necessary for dynamic update? */ -#ifdef BIND_UPDATE - if (dp->d_type == T_SIG) - /* - * Type covered has already been - * checked. - */ - goto delete; -#endif -#endif - if (dp->d_type == T_NXT) { - goto delete; - } - if (dp->d_type == T_SIG && - SIG_COVERS(dp) == T_NXT) { - struct sig_record *sr1, *sr2; - - sr1 = (struct sig_record *) dp->d_data; - sr2 = (struct sig_record *) - newdp->d_data; - if (sr1->sig_alg_n == sr2->sig_alg_n) - goto delete; - } - if (check_ttl) { - if (newdp->d_ttl != dp->d_ttl) - ns_warning(ns_log_db, - "%s %s %s differing ttls: corrected", - name[0]?name:".", - p_class(dp->d_class), - p_type(dp->d_type)); - if (newdp->d_ttl > dp->d_ttl) { - newdp->d_ttl = dp->d_ttl; - } else { - dp->d_ttl = newdp->d_ttl; - } - } - } - if ((flags & DB_NODATA) && !db_cmp(dp, odp)) { - /* Refresh ttl if cache entry. */ - if (dp->d_zone == DB_Z_CACHE) { - if (odp->d_zone != DB_Z_CACHE) { - /* Changing cache->auth. */ - dp->d_zone = odp->d_zone; - dp->d_ttl = odp->d_ttl; - ns_debug(ns_log_db, 4, - "db_update: cache entry now in auth zone"); - return (DATAEXISTS); - } - fixttl(odp); - if (odp->d_ttl > dp->d_ttl) - dp->d_ttl = odp->d_ttl; - ns_debug(ns_log_db, 3, - "db_update: new ttl %u +%lu", - dp->d_ttl, - (u_long)(dp->d_ttl - tt.tv_sec) - ); - } - return (DATAEXISTS); - } - /* - * If the old databuf has some data, check that the - * data matches that in the new databuf. - */ - if (odp->d_size > 0) - if (db_cmp(dp, odp)) - goto skip; - if (odp->d_clev < dp->d_clev) - goto skip; - if ((odp->d_secure < dp->d_secure) || - ((odp->d_secure == dp->d_secure) && - (odp->d_cred < dp->d_cred))) - goto skip; -#ifdef BIND_UPDATE - if (ns_samename(name, zones[dp->d_zone].z_origin) == 1 - && newdp == NULL) { - /* do not delete SOA or NS records as a set */ - /* XXXRTH isn't testing d_size unnecessary? */ - if ((odp->d_size == 0) && - (odp->d_class == C_ANY) && - (odp->d_type == T_ANY || - odp->d_type == T_SOA || - odp->d_type == T_NS) && - (dp->d_type == T_SOA || - dp->d_type == T_NS)) - goto skip; - /* XXXRTH I added this to prevent SOA deletion - I'm using the same style of comparison as - the other code in this section. Do we - really need to look at dp->d_type here? - We're in the "match" section... */ - if ((odp->d_type == T_SOA) && - (dp->d_type == T_SOA)) - goto skip; - /* do not delete the last NS record - for the zone */ - if ((odp->d_type == T_NS) && - (dp->d_type == T_NS)) { - found_other_ns = 0; - for (tmpdp = np->n_data; - tmpdp && !found_other_ns; - tmpdp = tmpdp->d_next) - if ((tmpdp->d_type == T_NS) && - (tmpdp != dp)) - found_other_ns = 1; - if (!found_other_ns) { - ns_debug(ns_log_db, 3, - "cannot delete last remaining NS record for zone %s", - name); - goto skip; - } - } - } -#endif - - foundRR = 1; - if (flags & DB_DELETE) { - delete: -#ifdef BIND_UPDATE - /* - * XXX assume here that savedpp!=NULL iff. db_update - * has been called by the dyanmic update code. - * Maybe a new flag is more appropriate? - */ - if (savedpp != NULL) - foundRR = 1; -#endif - deleted_something = 1; - dp = rm_datum(dp, np, pdp, savedpp); - } else { - skip: pdp = dp; - dp = dp->d_next; - } - } - if (!foundRR) { - if (flags & DB_DELETE) - return (NODATA); - if (flags & DB_MEXIST) - return (NODATA); - } - } - if (newdp == NULL) { - if (deleted_something) { - while (np->n_data == NULL && np->n_hash == NULL) { - np = purge_node(htp, np); - if (np == NULL) - break; - } - } - return (OK); - } - /* XXX: empty nodes bypass credibility checks above; should check - * response source address here if flags&NOTAUTH. - */ - fixttl(newdp); - ns_debug(ns_log_db, 3, "db_update: adding%s %p", - (newdp->d_flags&DB_F_HINT) ? " hint":"", newdp); - - if (newdp->d_zone == DB_Z_CACHE && - (newdp->d_flags & DB_F_HINT) == 0) - newdp->d_addr = from.sin_addr; - - /* Add to end of list, generally preserving order */ - newdp->d_next = NULL; - if ((dp = np->n_data) == NULL) { - DRCNTINC(newdp); - if (newdp->d_flags & DB_F_ACTIVE) - panic("db_update: DB_F_ACTIVE set", NULL); - newdp->d_flags |= DB_F_ACTIVE; - np->n_data = newdp; - return (OK); - } - while (dp->d_next != NULL) { - if ((flags & DB_NODATA) && !db_cmp(dp, newdp)) - return (DATAEXISTS); - dp = dp->d_next; - } - if ((flags & DB_NODATA) && !db_cmp(dp, newdp)) - return (DATAEXISTS); - DRCNTINC(newdp); - if (newdp->d_flags & DB_F_ACTIVE) - panic("db_update: DB_F_ACTIVE set", NULL); - newdp->d_flags |= DB_F_ACTIVE; - dp->d_next = newdp; - return (OK); -} - -void -fixttl(struct databuf *dp) { - if (dp->d_zone == DB_Z_CACHE && (dp->d_flags & DB_F_HINT) == 0) { - if (dp->d_ttl <= (u_int32_t)tt.tv_sec) - return; - else if (dp->d_ttl < (u_int32_t)tt.tv_sec+min_cache_ttl) - dp->d_ttl = (u_int32_t)tt.tv_sec+min_cache_ttl; - else if (dp->d_ttl > (u_int32_t)tt.tv_sec+max_cache_ttl) - dp->d_ttl = (u_int32_t)tt.tv_sec+max_cache_ttl; - } -} - -/* - * Compare type, class and data from databufs for equivalence. - * All domain names in RR's must be compared case-insensitively. - * Return 0 if equivalent, nonzero otherwise. - */ -int -db_cmp(const struct databuf *dp1, const struct databuf *dp2) { - const u_char *cp1, *cp2; - int len, len2; - - /* XXXDYNUP- should be changed to - if (!match(dp1, dp2->d_type, dp2->d_class) */ - if (dp1->d_type != dp2->d_type || dp1->d_class != dp2->d_class) - return (1); - /* XXXDYNUP - should be changed to (dp1->d_size != dp2->d_size && - dp1->d_size != 0 && dp2->d_size != 0) */ - if (dp1->d_size != dp2->d_size) - return (1); - /* d_mark is only used for dynamic updates currently */ -#ifndef BIND_UPDATE - if (dp1->d_mark != dp2->d_mark) - return (1); /* old and new RR's are distinct */ -#endif - if (dp1->d_rcode && dp2->d_rcode) - return ((dp1->d_rcode == dp1->d_rcode)?0:1); - if (dp1->d_rcode || dp2->d_rcode) - return (1); - - switch (dp1->d_type) { - - case T_A: - case T_WKS: - case T_NULL: - case T_NSAP: - case T_AAAA: - case T_LOC: - case T_KEY: - /* Only binary data */ - return (memcmp(dp1->d_data, dp2->d_data, dp1->d_size)); - - case T_NS: - case T_CNAME: - case T_PTR: - case T_MB: - case T_MG: - case T_MR: - /* Only a domain name */ - if (ns_samename((const char *)dp1->d_data, - (const char *)dp2->d_data) == 1) - return (0); - else - return (1); - - case T_SIG: - /* Binary data, a domain name, more binary data */ - if (dp1->d_size < NS_SIG_SIGNER) - return (1); - if (memcmp(dp1->d_data, dp2->d_data, NS_SIG_SIGNER)) - return (1); - len = NS_SIG_SIGNER + - strlen((const char *)dp1->d_data + NS_SIG_SIGNER); - if (ns_samename((const char *)dp1->d_data + NS_SIG_SIGNER, - (const char *)dp2->d_data + NS_SIG_SIGNER) != 1) - return (1); - return (memcmp(dp1->d_data + len, - dp2->d_data + len, - dp1->d_size - len)); - - case T_NXT: - /* First a domain name, then binary data */ - if (ns_samename((const char *)dp1->d_data, - (const char *)dp2->d_data) != 1) - return (1); - len = strlen((const char *)dp1->d_data)+1; - return (memcmp(dp1->d_data + len, - dp2->d_data + len, - dp1->d_size - len)); - - case T_HINFO: - case T_ISDN: - cp1 = dp1->d_data; - cp2 = dp2->d_data; - len = *cp1; - len2 = *cp2; - if (len != len2) - return (1); - if (strncasecmp((const char *)++cp1, (const char *)++cp2, len)) - return (1); - cp1 += len; - cp2 += len; - len = *cp1; - len2 = *cp2; - if (len != len2) - return (1); - return (strncasecmp((const char *)++cp1, (const char *)++cp2, - len)); - - case T_SOA: - case T_MINFO: - case T_RP: - if (ns_samename((const char *)dp1->d_data, - (const char *)dp2->d_data) != 1) - return (1); - cp1 = dp1->d_data + strlen((const char *)dp1->d_data) + 1; - cp2 = dp2->d_data + strlen((const char *)dp2->d_data) + 1; - if (ns_samename((const char *)cp1, (const char *)cp2) != 1) - return (1); - if (dp1->d_type != T_SOA) - return (0); - cp1 += strlen((const char *)cp1) + 1; - cp2 += strlen((const char *)cp2) + 1; - return (memcmp(cp1, cp2, INT32SZ * 5)); - - case T_NAPTR: { - int t1,t2; - - if (dp1->d_size != dp2->d_size) - return (1); - cp1 = dp1->d_data; - cp2 = dp2->d_data; - - /* Order */ - if (*cp1++ != *cp2++ || *cp1++ != *cp2++) - return (1); - - /* Preference */ - if (*cp1++ != *cp2++ || *cp1++ != *cp2++) - return (1); - - /* Flags */ - t1 = *cp1++; t2 = *cp2++; - if (t1 != t2 || memcmp(cp1, cp2, t1)) - return (1); - cp1 += t1; cp2 += t2; - - /* Services */ - t1 = *cp1++; t2 = *cp2++; - if (t1 != t2 || memcmp(cp1, cp2, t1)) - return (1); - cp1 += t1; cp2 += t2; - - /* Regexp */ - t1 = *cp1++; t2 = *cp2++; - if (t1 != t2 || memcmp(cp1, cp2, t1)) - return (1); - cp1 += t1; cp2 += t2; - - /* Replacement */ - if (ns_samename((const char *)cp1, (const char *)cp2) != 1) - return (1); - - /* they all checked out! */ - return (0); - } - - case T_MX: - case T_AFSDB: - case T_RT: - case T_SRV: - cp1 = dp1->d_data; - cp2 = dp2->d_data; - if (*cp1++ != *cp2++ || *cp1++ != *cp2++) /* cmp prio */ - return (1); - if (dp1->d_type == T_SRV) { - if (*cp1++ != *cp2++ || *cp1++ != *cp2++) /* weight */ - return (1); - if (*cp1++ != *cp2++ || *cp1++ != *cp2++) /* port */ - return (1); - } - if (ns_samename((const char *)cp1, (const char *)cp2) != 1) - return (1); - return (0); - - case T_PX: - cp1 = dp1->d_data; - cp2 = dp2->d_data; - if (*cp1++ != *cp2++ || *cp1++ != *cp2++) /* cmp prio */ - return (1); - if (ns_samename((const char *)cp1, (const char *)cp2) != 1) - return (1); - cp1 += strlen((const char *)cp1) + 1; - cp2 += strlen((const char *)cp2) + 1; - if (ns_samename((const char *)cp1, (const char *)cp2) != 1) - return (1); - return (0); - - case T_TXT: - case T_X25: - if (dp1->d_size != dp2->d_size) - return (1); - return (memcmp(dp1->d_data, dp2->d_data, dp1->d_size)); - - default: - return (1); - } -} |