summaryrefslogtreecommitdiffstats
path: root/contrib/bind/bin/named/db_ixfr.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bind/bin/named/db_ixfr.c')
-rw-r--r--contrib/bind/bin/named/db_ixfr.c861
1 files changed, 861 insertions, 0 deletions
diff --git a/contrib/bind/bin/named/db_ixfr.c b/contrib/bind/bin/named/db_ixfr.c
new file mode 100644
index 0000000..a009f4d
--- /dev/null
+++ b/contrib/bind/bin/named/db_ixfr.c
@@ -0,0 +1,861 @@
+#if !defined(lint) && !defined(SABER)
+static char rcsid[] = "$Id: db_ixfr.c,v 8.18 1999/10/15 19:48:57 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * Portions Copyright (c) 1999 by Check Point Software Technologies, Inc.
+ *
+ * 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 Check Point Software Technologies Incorporated 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 CHECK POINT SOFTWARE TECHNOLOGIES
+ * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+ * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED
+ * 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.
+ */
+
+/*
+ * Manage ixfr transaction log
+ */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <res_update.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.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"
+
+#define DBIXFR_ERROR -1
+#define DBIXFR_FOUND_RR 2
+#define DBIXFR_END 3
+
+static int ixfr_getrr(struct zoneinfo *, FILE *, const char *, char *,
+ ns_updrec **, u_int32_t *, u_int32_t *);
+
+ns_updrec *
+ixfr_get_change_list(struct zoneinfo *zp,
+ u_int32_t from_serial, u_int32_t to_serial)
+{
+ FILE * fp;
+ u_int32_t old_serial, new_serial;
+ char origin[MAXDNAME];
+ struct namebuf *np, *listnp, *finlistnp;
+ LIST(ns_updrec) listuprec;
+ int ret, mode;
+ ns_updrec *uprec;
+
+ if (SEQ_GT(from_serial, to_serial))
+ return (NULL);
+ listnp = finlistnp = NULL;
+ INIT_LIST(listuprec);
+ if ((fp = fopen(zp->z_ixfr_base, "r")) == NULL) {
+ ns_warning(ns_log_db, "%s: %s",
+ zp->z_ixfr_base, strerror(errno));
+ return (NULL);
+ }
+ strcpy(origin, zp->z_origin);
+ lineno = 1;
+ np = NULL;
+ mode = 0;
+ old_serial = new_serial = 0;
+ for (;;) {
+ ret = ixfr_getrr(zp, fp, zp->z_ixfr_base, origin, &uprec,
+ &old_serial, &new_serial);
+ switch (ret) {
+ case DBIXFR_ERROR:
+ (void) my_fclose(fp);
+ ns_warning(ns_log_db, "Logical error in %s line %d",
+ zp->z_ixfr_base, lineno);
+ return (NULL);
+ case DBIXFR_FOUND_RR:
+ if (EMPTY(listuprec)) {
+ /* skip updates prior to the one we want */
+ if (uprec->r_zone != from_serial) {
+ while (uprec != NULL) {
+ ns_updrec *prev;
+
+ if (uprec->r_dp != NULL)
+ db_freedata(uprec->r_dp);
+ uprec->r_dp = NULL;
+ prev = PREV(uprec, r_link);
+ res_freeupdrec(uprec);
+ uprec = prev;
+ }
+ break;
+ }
+ }
+ APPEND(listuprec, uprec, r_link);
+ /* continue; */
+ break;
+ case DBIXFR_END:
+ (void) my_fclose(fp);
+ return (HEAD(listuprec));
+ default:
+ (void) my_fclose(fp);
+ return (NULL);
+ }
+ }
+}
+
+/*
+ * int ixfr_have_log(struct zoneinfo *zp,u_int32_t from_serial,
+ * u_int32_t to_serial)
+ *
+ * verify that ixfr transaction log contains changes
+ * from from_serial to to_serial
+ *
+ * returns:
+ * 0 = serial number is up to date
+ * 1 = transision is possible
+ * -1 = error while opening the ixfr transaction log
+ * -2 = error in parameters
+ * -3 = logical error in the history file
+ */
+int
+ixfr_have_log(struct zoneinfo *zp, u_int32_t from_serial, u_int32_t to_serial)
+{
+ FILE *fp;
+ u_int32_t old_serial = 0, new_serial = 0;
+ char buf[BUFSIZ];
+ char *cp;
+ struct stat st;
+ int nonempty_lineno = -1, prev_pktdone = 0, cont = 0,
+ inside_next = 0;
+ int err;
+ int id, rcode = NOERROR;
+
+ if (SEQ_GT(from_serial, to_serial))
+ return (-2);
+ if (from_serial == to_serial)
+ return (0);
+ /* If there is no log file, just return. */
+ if (zp->z_ixfr_base == NULL || zp->z_updatelog == NULL)
+ return (-1);
+ if (stat(zp->z_ixfr_base, &st) < 0) {
+ if (errno != ENOENT)
+ ns_error(ns_log_db,
+ "unexpected stat(%s) failure: %s",
+ zp->z_ixfr_base, strerror(errno));
+ return (-1);
+ }
+ if ((fp = fopen(zp->z_ixfr_base, "r")) == NULL) {
+ ns_warning(ns_log_db, "%s: %s",
+ zp->z_ixfr_base, strerror(errno));
+ return (-1);
+ }
+ if (fgets(buf, sizeof(buf), fp) == NULL) {
+ ns_error(ns_log_update, "fgets() from %s failed: %s",
+ zp->z_updatelog, strerror(errno));
+ fclose(fp);
+ return (-1);
+ }
+ if (strcmp(buf, LogSignature) != 0) {
+ ns_error(ns_log_update, "invalid log file %s",
+ zp->z_updatelog);
+ fclose(fp);
+ return (-3);
+ }
+ lineno = 1;
+ for (;;) {
+ if (getword(buf, sizeof buf, fp, 0)) {
+ nonempty_lineno = lineno;
+ } else {
+ if (lineno == (nonempty_lineno + 1))
+ continue;
+ inside_next = 0;
+ prev_pktdone = 1;
+ cont = 1;
+ }
+ if (!strcasecmp(buf, "[DYNAMIC_UPDATE]") ||
+ !strcasecmp(buf, "[IXFR_UPDATE]")) {
+ err = 0;
+ rcode = NOERROR;
+ cp = fgets(buf, sizeof buf, fp);
+ if (cp != NULL)
+ lineno++;
+ if (cp == NULL || !sscanf((char *) cp, "id %d", &id))
+ id = -1;
+ inside_next = 1;
+ prev_pktdone = 1;
+ cont = 1;
+ } else if (!strcasecmp(buf, "serial")) {
+ cp = fgets(buf, sizeof buf, fp);
+ if (cp != NULL)
+ lineno++;
+ if (sscanf((char *) cp, "%u", &old_serial)) {
+ if (from_serial >= old_serial) {
+ fclose(fp);
+ return (1);
+ } else {
+ fclose(fp);
+ return (-1);
+ }
+ }
+ prev_pktdone = 1;
+ cont = 1;
+ } else if (!strcasecmp(buf, "[INCR_SERIAL]")) {
+ /* XXXRTH not enough error checking here */
+ cp = fgets(buf, sizeof buf, fp);
+ if (cp != NULL)
+ lineno++;
+ if (cp == NULL ||
+ sscanf((char *) cp, "from %u to %u",
+ &old_serial, &new_serial) != 2) {
+ fclose(fp);
+ return (-3);
+ } else if (from_serial >= old_serial) {
+ fclose(fp);
+ return (1);
+ }
+ fclose(fp);
+ return (-1);
+ }
+ if (prev_pktdone) {
+ prev_pktdone = 0;
+ if (feof(fp))
+ break;
+ }
+ }
+ fclose(fp);
+ return (0);
+}
+
+/* from db_load.c */
+
+static struct map m_section[] = {
+ {"zone", S_ZONE},
+ {"prereq", S_PREREQ},
+ {"update", S_UPDATE},
+ {"reserved", S_ADDT},
+};
+#define M_SECTION_CNT (sizeof(m_section) / sizeof(struct map))
+
+/* from ns_req.c */
+
+static struct map m_opcode[] = {
+ {"nxdomain", NXDOMAIN},
+ {"yxdomain", YXDOMAIN},
+ {"nxrrset", NXRRSET},
+ {"yxrrset", YXRRSET},
+ {"delete", DELETE},
+ {"add", ADD},
+};
+#define M_OPCODE_CNT (sizeof(m_opcode) / sizeof(struct map))
+
+/* XXXRTH workaround map difficulties */
+#define M_CLASS_CNT m_class_cnt
+#define M_TYPE_CNT m_type_cnt
+
+/*
+ * int
+ * ixfr_getrr(struct zoneinfo *zp, FILE *fp,
+ * const char *filename, char *origin, struct namebuf **np,
+ * u_int32_t *old_serial, u_int32_t *new_serial)
+ *
+ * read a line from the historic of a zone.
+ *
+ * returns:
+ *
+ * DBIXFR_ERROR = an error occured
+ * DBIXFR_FOUND_RR = a rr encountered
+ * DBIXFR_END = end of file
+ */
+static int
+ixfr_getrr(struct zoneinfo *zp, FILE *fp, const char *filename, char *origin,
+ ns_updrec **uprec, u_int32_t *old_serial,
+ u_int32_t *new_serial)
+{
+ static int read_soa, read_ns, rrcount;
+
+ char data[MAXDATA], dnbuf[MAXDNAME], sclass[3];
+ const char *errtype = "Database";
+ char *dname, *cp, *cp1;
+ char buf[MAXDATA];
+ u_int32_t serial, ttl;
+ int nonempty_lineno = -1, prev_pktdone = 0, cont = 0,
+ inside_next = 0;
+ int id, rcode = NOERROR;
+ int i, c, section, opcode, matches, zonenum, err, multiline;
+ int type, class;
+ u_int32_t n;
+ enum transport transport;
+ struct map *mp;
+ int zonelist[MAXDNAME];
+ struct databuf *dp;
+ struct in_addr ina;
+ struct sockaddr_in empty_from;
+ int datasize;
+ ns_updque listuprec;
+ ns_updrec * rrecp;
+ u_long l;
+
+#define ERRTO(msg) if (1) { errtype = msg; goto err; } else (void)NULL
+
+ err = 0;
+ transport = primary_trans;
+ lineno = 1;
+ INIT_LIST(listuprec);
+ for (;;) {
+ if (!getword(buf, sizeof buf, fp, 0)) {
+ if (lineno == (nonempty_lineno + 1) && !(feof(fp))) {
+ /*
+ * End of a nonempty line inside an update
+ * packet or not inside an update packet.
+ */
+ continue;
+ }
+ /*
+ * Empty line or EOF.
+ *
+ * Marks completion of current update packet.
+ */
+ inside_next = 0;
+ prev_pktdone = 1;
+ cont = 1;
+ } else {
+ nonempty_lineno = lineno;
+ }
+
+ if (!strcasecmp(buf, "[DYNAMIC_UPDATE]") ||
+ !strcasecmp(buf, "[IXFR_UPDATE]")) {
+ err = 0;
+ rcode = NOERROR;
+ cp = fgets(buf, sizeof buf, fp);
+ if (cp != NULL)
+ lineno++;
+ if (cp == NULL || !sscanf((char *) cp, "id %d", &id))
+ id = -1;
+ inside_next = 1;
+ prev_pktdone = 1;
+ cont = 1;
+ } else if (!strcasecmp(buf, "[INCR_SERIAL]")) {
+ /* XXXRTH not enough error checking here */
+ cp = fgets(buf, sizeof buf, fp);
+ if (cp != NULL)
+ lineno++;
+ if (cp == NULL ||
+ sscanf((char *) cp, "from %u to %u",
+ old_serial, new_serial) != 2) {
+ ns_error(ns_log_update,
+ "incr_serial problem with %s",
+ zp->z_updatelog);
+ } else {
+ serial = get_serial(zp);
+ }
+ cont = 1;
+ } else if (!strcasecmp(buf, "[END_DELTA]")) {
+ prev_pktdone = 1;
+ cont = 1;
+ lineno++;
+ }
+ if (prev_pktdone) {
+ if (!EMPTY(listuprec)) {
+ n++;
+ *uprec = TAIL(listuprec);
+ return (DBIXFR_FOUND_RR);
+ }
+ prev_pktdone = 0;
+ if (feof(fp))
+ break;
+ }
+ if (cont) {
+ cont = 0;
+ continue;
+ }
+ if (!inside_next)
+ continue;
+ /*
+ * inside the same update packet, continue accumulating
+ * records.
+ */
+ section = -1;
+ n = strlen(buf);
+ if (buf[n - 1] == ':')
+ buf[--n] = '\0';
+ for (mp = m_section; mp < m_section + M_SECTION_CNT; mp++)
+ if (!strcasecmp(buf, mp->token)) {
+ section = mp->val;
+ break;
+ }
+ ttl = 0;
+ type = -1;
+ class = zp->z_class;
+ n = 0;
+ data[0] = '\0';
+ switch (section) {
+ case S_ZONE:
+ cp = fgets(buf, sizeof buf, fp);
+ if (!cp)
+ *buf = '\0';
+ n = sscanf(cp, "origin %s class %s serial %ul",
+ origin, sclass, &serial);
+ if (n != 3 || ns_samename(origin, zp->z_origin) != 1)
+ err++;
+ if (cp)
+ lineno++;
+ if (!err && inside_next) {
+ int success;
+
+ dname = origin;
+ type = T_SOA;
+ class = sym_ston(__p_class_syms, sclass,
+ &success);
+ if (!success) {
+ err++;
+ break;
+ }
+ matches = findzone(dname, class, 0,
+ zonelist, MAXDNAME);
+ if (matches)
+ zonenum = zonelist[0];
+ else
+ err++;
+ }
+ break;
+ case S_PREREQ:
+ case S_UPDATE:
+ /* Operation code. */
+ if (!getword(buf, sizeof buf, fp, 0)) {
+ err++;
+ break;
+ }
+ opcode = -1;
+ if (buf[0] == '{') {
+ n = strlen(buf);
+ for (i = 0; (u_int32_t) i < n; i++)
+ buf[i] = buf[i + 1];
+ if (buf[n - 2] == '}')
+ buf[n - 2] = '\0';
+ }
+ for (mp = m_opcode; mp < m_opcode + M_OPCODE_CNT; mp++)
+ if (!strcasecmp(buf, mp->token)) {
+ opcode = mp->val;
+ break;
+ }
+ if (opcode == -1) {
+ err++;
+ break;
+ }
+ /* Owner's domain name. */
+ if (!getword((char *) dnbuf, sizeof dnbuf, fp, 0)) {
+ err++;
+ break;
+ }
+ n = strlen((char *) dnbuf) - 1;
+ if (dnbuf[n] == '.')
+ dnbuf[n] = '\0';
+ dname = dnbuf;
+ ttl = 0;
+ type = -1;
+ class = zp->z_class;
+ n = 0;
+ data[0] = '\0';
+ (void) getword(buf, sizeof buf, fp, 1);
+ if (isdigit(buf[0])) { /* ttl */
+ if (ns_parse_ttl(buf, &l) < 0) {
+ err++;
+ break;
+ }
+ ttl = l;
+ (void) getword(buf, sizeof buf, fp, 1);
+ }
+ /* possibly class */
+ if (buf[0] != '\0') {
+ int success;
+ int maybe_class;
+
+ maybe_class = sym_ston(__p_class_syms,
+ buf, &success);
+ if (success) {
+ class = maybe_class;
+ (void) getword(buf, sizeof buf, fp, 1);
+ }
+ }
+ /* possibly type */
+ if (buf[0] != '\0') {
+ int success;
+ int maybe_type;
+
+ maybe_type = sym_ston(__p_type_syms,
+ buf, &success);
+
+ if (success) {
+ type = maybe_type;
+ (void) getword(buf, sizeof buf, fp, 1);
+ }
+ }
+ if (buf[0] != '\0') /* possibly rdata */
+ /*
+ * Convert the ascii data 'buf' to the proper
+ * format based on the type and pack into
+ * 'data'.
+ *
+ * XXX - same as in db_load(), consolidation
+ * needed
+ */
+ switch (type) {
+ case T_A:
+ if (!inet_aton(buf, &ina)) {
+ err++;
+ break;
+ }
+ n = ntohl(ina.s_addr);
+ cp = data;
+ PUTLONG(n, cp);
+ n = INT32SZ;
+ break;
+ case T_HINFO:
+ case T_ISDN:
+ n = strlen(buf);
+ data[0] = n;
+ memcpy(data + 1, buf, n);
+ n++;
+ if (!getword(buf, sizeof buf, fp, 0)) {
+ i = 0;
+ } else {
+ endline(fp);
+ i = strlen(buf);
+ }
+ data[n] = i;
+ n++;
+ memcpy(data + n + 1, buf, i);
+ n += i;
+ break;
+ case T_SOA:
+ case T_MINFO:
+ case T_RP:
+ (void) strcpy(data, buf);
+ cp = data + strlen(data) + 1;
+ if (!getword((char *) cp,
+ sizeof data - (cp - data),
+ fp, 1)) {
+ err++;
+ break;
+ }
+ cp += strlen((char *) cp) + 1;
+ if (type != T_SOA) {
+ n = cp - data;
+ break;
+ }
+ if (class != zp->z_class ||
+ ns_samename(dname, zp->z_origin) != 1) {
+ err++;
+ break;
+ }
+ c = getnonblank(fp, zp->z_updatelog);
+ if (c == '(') {
+ multiline = 1;
+ } else {
+ multiline = 0;
+ ungetc(c, fp);
+ }
+ n = getnum(fp, zp->z_updatelog, GETNUM_SERIAL);
+ if (getnum_error) {
+ err++;
+ break;
+ }
+ if (opcode == ADD && i == 0)
+ *new_serial = n;
+ PUTLONG(n, cp);
+ for (i = 0; i < 4; i++) {
+ if (!getword(buf, sizeof buf, fp, 1)) {
+ err++;
+ break;
+ }
+ if (ns_parse_ttl(buf, &l) < 0) {
+ err++;
+ break;
+ }
+ n = l;
+ PUTLONG(n, cp);
+ }
+ if (multiline &&
+ getnonblank(fp, zp->z_updatelog) != ')')
+ {
+ err++;
+ break;
+ }
+ endline(fp);
+ n = cp - data;
+ break;
+ case T_WKS:
+ if (!inet_aton(buf, &ina)) {
+ err++;
+ break;
+ }
+ n = ntohl(ina.s_addr);
+ cp = data;
+ PUTLONG(n, cp);
+ *cp = (char) getprotocol(fp, zp->z_updatelog);
+ n = INT32SZ + sizeof(char);
+ n = getservices((int) n, data,
+ fp, zp->z_updatelog);
+ break;
+ case T_NS:
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_PTR:
+ (void) strcpy(data, buf);
+ if (makename(data, origin,
+ sizeof(data)) == -1) {
+ err++;
+ break;
+ }
+ n = strlen(data) + 1;
+ break;
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ n = 0;
+ cp = buf;
+ while (isdigit(*cp))
+ n = n * 10 + (*cp++ - '0');
+ /* catch bad values */
+ cp = data;
+ PUTSHORT((u_int16_t) n, cp);
+ if (!getword(buf, sizeof(buf), fp, 1)) {
+ err++;
+ break;
+ }
+ (void) strcpy((char *) cp, buf);
+ if (makename((char *) cp, origin,
+ sizeof(data) - (cp - data)) == -1)
+ {
+ err++;
+ break;
+ }
+ /* advance pointer to end of data */
+ cp += strlen((char *) cp) + 1;
+ /* now save length */
+ n = (cp - data);
+ break;
+ case T_PX:
+ n = 0;
+ data[0] = '\0';
+ cp = buf;
+ while (isdigit(*cp))
+ n = n * 10 + (*cp++ - '0');
+ cp = data;
+ PUTSHORT((u_int16_t) n, cp);
+ for (i = 0; i < 2; i++) {
+ if (!getword(buf, sizeof(buf), fp, 0))
+ {
+ err++;
+ break;
+ }
+ (void) strcpy((char *) cp, buf);
+ cp += strlen((char *) cp) + 1;
+ }
+ n = cp - data;
+ break;
+ case T_TXT:
+ case T_X25:
+ i = strlen(buf);
+ cp = data;
+ datasize = sizeof data;
+ cp1 = buf;
+ while (i > MAXCHARSTRING) {
+ if (datasize <= MAXCHARSTRING) {
+ ns_error(ns_log_update,
+ "record too big");
+ return (-1);
+ }
+ datasize -= MAXCHARSTRING;
+ *cp++ = (char)MAXCHARSTRING;
+ memcpy(cp, cp1, MAXCHARSTRING);
+ cp += MAXCHARSTRING;
+ cp1 += MAXCHARSTRING;
+ i -= MAXCHARSTRING;
+ }
+ if (datasize < i + 1) {
+ ns_error(ns_log_update,
+ "record too big");
+ return (-1);
+ }
+ *cp++ = i;
+ memcpy(cp, cp1, i);
+ cp += i;
+ n = cp - data;
+ endline(fp);
+ /* XXXVIX: segmented texts 4.9.5 */
+ break;
+ case T_NSAP:
+ n = inet_nsap_addr(buf, (u_char *) data,
+ sizeof data);
+ endline(fp);
+ break;
+ case T_LOC:
+ cp = buf + (n = strlen(buf));
+ *cp = ' ';
+ cp++;
+ while ((i = getc(fp), *cp = i, i != EOF)
+ && *cp != '\n' && (n < MAXDATA))
+ {
+ cp++;
+ n++;
+ }
+ if (*cp == '\n')
+ ungetc(*cp, fp);
+ *cp = '\0';
+ n = loc_aton(buf, (u_char *) data);
+ if (n == 0) {
+ err++;
+ break;
+ }
+ endline(fp);
+ break;
+ case ns_t_sig:
+ case ns_t_nxt:
+ case ns_t_key:
+ case ns_t_cert:{
+ char *errmsg = NULL;
+
+ n = parse_sec_rdata(buf, sizeof(buf), 1,
+ (u_char *) data,
+ sizeof(data),
+ fp, zp, dname, ttl,
+ type, domain_ctx,
+ transport, &errmsg);
+ if (errmsg) {
+ err++;
+ endline(fp);
+ n = 0;
+ }
+ break;
+ }
+ default:
+ err++;
+ }
+ if (section == S_PREREQ) {
+ ttl = 0;
+ if (opcode == NXDOMAIN) {
+ class = C_NONE;
+ type = T_ANY;
+ n = 0;
+ } else if (opcode == YXDOMAIN) {
+ class = C_ANY;
+ type = T_ANY;
+ n = 0;
+ } else if (opcode == NXRRSET) {
+ class = C_NONE;
+ n = 0;
+ } else if (opcode == YXRRSET) {
+ if (n == 0)
+ class = C_ANY;
+ }
+ } else {/* section == S_UPDATE */
+ if (opcode == DELETE) {
+ if (n == 0) {
+ class = C_ANY;
+ if (type == -1)
+ type = T_ANY;
+ } else {
+ class = zp->z_class;
+ }
+ }
+ }
+ break;
+ case S_ADDT:
+ default:
+ ns_debug(ns_log_update, 1,
+ "cannot interpret section: %d", section);
+ inside_next = 0;
+ err++;
+ }
+ if (err) {
+ inside_next = 0;
+ ns_debug(ns_log_update, 1,
+ "merge of update id %d failed due to error at line %d",
+ id, lineno);
+ memset(&empty_from, 0, sizeof empty_from);
+ free_rrecp(&listuprec, rcode, empty_from);
+ continue;
+ }
+ rrecp = res_mkupdrec(section, dname, class, type, ttl);
+ if (section != S_ZONE) {
+ dp = savedata(class, type, ttl, (u_char *) data, n);
+ dp->d_zone = zonenum;
+ dp->d_cred = DB_C_ZONE;
+ dp->d_clev = nlabels(zp->z_origin);
+ rrecp->r_dp = dp;
+ rrecp->r_opcode = opcode;
+ } else {
+ rrecp->r_zone = zonenum;
+ rrecp->r_opcode = opcode;
+ }
+
+ /* remove add/delete pairs */
+ if (section == S_UPDATE) {
+ ns_updrec *arp;
+ int foundmatch;
+
+ arp = TAIL(listuprec);
+ foundmatch = 0;
+ while (arp) {
+ if (arp->r_section == S_UPDATE &&
+ ((arp->r_opcode == DELETE &&
+ opcode == ADD) ||
+ (opcode == DELETE &&
+ arp->r_opcode == ADD)) &&
+ arp->r_dp->d_type == dp->d_type &&
+ arp->r_dp->d_class == dp->d_class &&
+ arp->r_dp->d_ttl == dp->d_ttl &&
+ ns_samename(arp->r_dname, dname) == 1 &&
+ db_cmp(arp->r_dp, dp) == 0) {
+ db_freedata(dp);
+ db_freedata(arp->r_dp);
+ UNLINK(listuprec, arp, r_link);
+ res_freeupdrec(arp);
+ res_freeupdrec(rrecp);
+ foundmatch = 1;
+ break;
+ }
+ arp = PREV(arp, r_link);
+ }
+ if (foundmatch)
+ continue;
+ }
+
+ APPEND(listuprec, rrecp, r_link);
+ /* Override zone number with current zone serial number */
+ rrecp->r_zone = serial;
+ }
+
+ if (err)
+ return (DBIXFR_ERROR);
+
+ return (DBIXFR_END);
+}
OpenPOWER on IntegriCloud