1 #if !defined(lint) && !defined(SABER)
2 static char rcsid[] = "$Id: db_ixfr.c,v 8.18 1999/10/15 19:48:57 vixie Exp $";
6 * Portions Copyright (c) 1999 by Check Point Software Technologies, Inc.
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies, and that
11 * the name of Check Point Software Technologies Incorporated not be used
12 * in advertising or publicity pertaining to distribution of the document
13 * or software without specific, written prior permission.
15 * THE SOFTWARE IS PROVIDED "AS IS" AND CHECK POINT SOFTWARE TECHNOLOGIES
16 * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
18 * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED
19 * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR
20 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
21 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
22 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26 * Manage ixfr transaction log
29 #include "port_before.h"
31 #include <sys/types.h>
32 #include <sys/param.h>
34 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <arpa/nameser.h>
38 #include <arpa/inet.h>
44 #include <res_update.h>
52 #include <isc/eventlib.h>
53 #include <isc/logging.h>
55 #include "port_after.h"
59 #define DBIXFR_ERROR -1
60 #define DBIXFR_FOUND_RR 2
63 static int ixfr_getrr(struct zoneinfo *, FILE *, const char *, char *,
64 ns_updrec **, u_int32_t *, u_int32_t *);
67 ixfr_get_change_list(struct zoneinfo *zp,
68 u_int32_t from_serial, u_int32_t to_serial)
71 u_int32_t old_serial, new_serial;
72 char origin[MAXDNAME];
73 struct namebuf *np, *listnp, *finlistnp;
74 LIST(ns_updrec) listuprec;
78 if (SEQ_GT(from_serial, to_serial))
80 listnp = finlistnp = NULL;
82 if ((fp = fopen(zp->z_ixfr_base, "r")) == NULL) {
83 ns_warning(ns_log_db, "%s: %s",
84 zp->z_ixfr_base, strerror(errno));
87 strcpy(origin, zp->z_origin);
91 old_serial = new_serial = 0;
93 ret = ixfr_getrr(zp, fp, zp->z_ixfr_base, origin, &uprec,
94 &old_serial, &new_serial);
98 ns_warning(ns_log_db, "Logical error in %s line %d",
99 zp->z_ixfr_base, lineno);
101 case DBIXFR_FOUND_RR:
102 if (EMPTY(listuprec)) {
103 /* skip updates prior to the one we want */
104 if (uprec->r_zone != from_serial) {
105 while (uprec != NULL) {
108 if (uprec->r_dp != NULL)
109 db_freedata(uprec->r_dp);
111 prev = PREV(uprec, r_link);
112 res_freeupdrec(uprec);
118 APPEND(listuprec, uprec, r_link);
122 (void) my_fclose(fp);
123 return (HEAD(listuprec));
125 (void) my_fclose(fp);
132 * int ixfr_have_log(struct zoneinfo *zp,u_int32_t from_serial,
133 * u_int32_t to_serial)
135 * verify that ixfr transaction log contains changes
136 * from from_serial to to_serial
139 * 0 = serial number is up to date
140 * 1 = transision is possible
141 * -1 = error while opening the ixfr transaction log
142 * -2 = error in parameters
143 * -3 = logical error in the history file
146 ixfr_have_log(struct zoneinfo *zp, u_int32_t from_serial, u_int32_t to_serial)
149 u_int32_t old_serial = 0, new_serial = 0;
153 int nonempty_lineno = -1, prev_pktdone = 0, cont = 0,
156 int id, rcode = NOERROR;
158 if (SEQ_GT(from_serial, to_serial))
160 if (from_serial == to_serial)
162 /* If there is no log file, just return. */
163 if (zp->z_ixfr_base == NULL || zp->z_updatelog == NULL)
165 if (stat(zp->z_ixfr_base, &st) < 0) {
168 "unexpected stat(%s) failure: %s",
169 zp->z_ixfr_base, strerror(errno));
172 if ((fp = fopen(zp->z_ixfr_base, "r")) == NULL) {
173 ns_warning(ns_log_db, "%s: %s",
174 zp->z_ixfr_base, strerror(errno));
177 if (fgets(buf, sizeof(buf), fp) == NULL) {
178 ns_error(ns_log_update, "fgets() from %s failed: %s",
179 zp->z_updatelog, strerror(errno));
183 if (strcmp(buf, LogSignature) != 0) {
184 ns_error(ns_log_update, "invalid log file %s",
191 if (getword(buf, sizeof buf, fp, 0)) {
192 nonempty_lineno = lineno;
194 if (lineno == (nonempty_lineno + 1))
200 if (!strcasecmp(buf, "[DYNAMIC_UPDATE]") ||
201 !strcasecmp(buf, "[IXFR_UPDATE]")) {
204 cp = fgets(buf, sizeof buf, fp);
207 if (cp == NULL || !sscanf((char *) cp, "id %d", &id))
212 } else if (!strcasecmp(buf, "serial")) {
213 cp = fgets(buf, sizeof buf, fp);
216 if (sscanf((char *) cp, "%u", &old_serial)) {
217 if (from_serial >= old_serial) {
227 } else if (!strcasecmp(buf, "[INCR_SERIAL]")) {
228 /* XXXRTH not enough error checking here */
229 cp = fgets(buf, sizeof buf, fp);
233 sscanf((char *) cp, "from %u to %u",
234 &old_serial, &new_serial) != 2) {
237 } else if (from_serial >= old_serial) {
256 static struct map m_section[] = {
258 {"prereq", S_PREREQ},
259 {"update", S_UPDATE},
260 {"reserved", S_ADDT},
262 #define M_SECTION_CNT (sizeof(m_section) / sizeof(struct map))
266 static struct map m_opcode[] = {
267 {"nxdomain", NXDOMAIN},
268 {"yxdomain", YXDOMAIN},
269 {"nxrrset", NXRRSET},
270 {"yxrrset", YXRRSET},
274 #define M_OPCODE_CNT (sizeof(m_opcode) / sizeof(struct map))
276 /* XXXRTH workaround map difficulties */
277 #define M_CLASS_CNT m_class_cnt
278 #define M_TYPE_CNT m_type_cnt
282 * ixfr_getrr(struct zoneinfo *zp, FILE *fp,
283 * const char *filename, char *origin, struct namebuf **np,
284 * u_int32_t *old_serial, u_int32_t *new_serial)
286 * read a line from the historic of a zone.
290 * DBIXFR_ERROR = an error occured
291 * DBIXFR_FOUND_RR = a rr encountered
292 * DBIXFR_END = end of file
295 ixfr_getrr(struct zoneinfo *zp, FILE *fp, const char *filename, char *origin,
296 ns_updrec **uprec, u_int32_t *old_serial,
297 u_int32_t *new_serial)
299 static int read_soa, read_ns, rrcount;
301 char data[MAXDATA], dnbuf[MAXDNAME], sclass[3];
302 const char *errtype = "Database";
303 char *dname, *cp, *cp1;
305 u_int32_t serial, ttl;
306 int nonempty_lineno = -1, prev_pktdone = 0, cont = 0,
308 int id, rcode = NOERROR;
309 int i, c, section, opcode, matches, zonenum, err, multiline;
312 enum transport transport;
314 int zonelist[MAXDNAME];
317 struct sockaddr_in empty_from;
323 #define ERRTO(msg) if (1) { errtype = msg; goto err; } else (void)NULL
326 transport = primary_trans;
328 INIT_LIST(listuprec);
330 if (!getword(buf, sizeof buf, fp, 0)) {
331 if (lineno == (nonempty_lineno + 1) && !(feof(fp))) {
333 * End of a nonempty line inside an update
334 * packet or not inside an update packet.
341 * Marks completion of current update packet.
347 nonempty_lineno = lineno;
350 if (!strcasecmp(buf, "[DYNAMIC_UPDATE]") ||
351 !strcasecmp(buf, "[IXFR_UPDATE]")) {
354 cp = fgets(buf, sizeof buf, fp);
357 if (cp == NULL || !sscanf((char *) cp, "id %d", &id))
362 } else if (!strcasecmp(buf, "[INCR_SERIAL]")) {
363 /* XXXRTH not enough error checking here */
364 cp = fgets(buf, sizeof buf, fp);
368 sscanf((char *) cp, "from %u to %u",
369 old_serial, new_serial) != 2) {
370 ns_error(ns_log_update,
371 "incr_serial problem with %s",
374 serial = get_serial(zp);
377 } else if (!strcasecmp(buf, "[END_DELTA]")) {
383 if (!EMPTY(listuprec)) {
385 *uprec = TAIL(listuprec);
386 return (DBIXFR_FOUND_RR);
399 * inside the same update packet, continue accumulating
404 if (buf[n - 1] == ':')
406 for (mp = m_section; mp < m_section + M_SECTION_CNT; mp++)
407 if (!strcasecmp(buf, mp->token)) {
418 cp = fgets(buf, sizeof buf, fp);
421 n = sscanf(cp, "origin %s class %s serial %ul",
422 origin, sclass, &serial);
423 if (n != 3 || ns_samename(origin, zp->z_origin) != 1)
427 if (!err && inside_next) {
432 class = sym_ston(__p_class_syms, sclass,
438 matches = findzone(dname, class, 0,
441 zonenum = zonelist[0];
448 /* Operation code. */
449 if (!getword(buf, sizeof buf, fp, 0)) {
456 for (i = 0; (u_int32_t) i < n; i++)
458 if (buf[n - 2] == '}')
461 for (mp = m_opcode; mp < m_opcode + M_OPCODE_CNT; mp++)
462 if (!strcasecmp(buf, mp->token)) {
470 /* Owner's domain name. */
471 if (!getword((char *) dnbuf, sizeof dnbuf, fp, 0)) {
475 n = strlen((char *) dnbuf) - 1;
484 (void) getword(buf, sizeof buf, fp, 1);
485 if (isdigit(buf[0])) { /* ttl */
486 if (ns_parse_ttl(buf, &l) < 0) {
491 (void) getword(buf, sizeof buf, fp, 1);
494 if (buf[0] != '\0') {
498 maybe_class = sym_ston(__p_class_syms,
502 (void) getword(buf, sizeof buf, fp, 1);
506 if (buf[0] != '\0') {
510 maybe_type = sym_ston(__p_type_syms,
515 (void) getword(buf, sizeof buf, fp, 1);
518 if (buf[0] != '\0') /* possibly rdata */
520 * Convert the ascii data 'buf' to the proper
521 * format based on the type and pack into
524 * XXX - same as in db_load(), consolidation
529 if (!inet_aton(buf, &ina)) {
533 n = ntohl(ina.s_addr);
542 memcpy(data + 1, buf, n);
544 if (!getword(buf, sizeof buf, fp, 0)) {
552 memcpy(data + n + 1, buf, i);
558 (void) strcpy(data, buf);
559 cp = data + strlen(data) + 1;
560 if (!getword((char *) cp,
561 sizeof data - (cp - data),
566 cp += strlen((char *) cp) + 1;
571 if (class != zp->z_class ||
572 ns_samename(dname, zp->z_origin) != 1) {
576 c = getnonblank(fp, zp->z_updatelog);
583 n = getnum(fp, zp->z_updatelog, GETNUM_SERIAL);
588 if (opcode == ADD && i == 0)
591 for (i = 0; i < 4; i++) {
592 if (!getword(buf, sizeof buf, fp, 1)) {
596 if (ns_parse_ttl(buf, &l) < 0) {
604 getnonblank(fp, zp->z_updatelog) != ')')
613 if (!inet_aton(buf, &ina)) {
617 n = ntohl(ina.s_addr);
620 *cp = (char) getprotocol(fp, zp->z_updatelog);
621 n = INT32SZ + sizeof(char);
622 n = getservices((int) n, data,
623 fp, zp->z_updatelog);
631 (void) strcpy(data, buf);
632 if (makename(data, origin,
633 sizeof(data)) == -1) {
637 n = strlen(data) + 1;
645 n = n * 10 + (*cp++ - '0');
646 /* catch bad values */
648 PUTSHORT((u_int16_t) n, cp);
649 if (!getword(buf, sizeof(buf), fp, 1)) {
653 (void) strcpy((char *) cp, buf);
654 if (makename((char *) cp, origin,
655 sizeof(data) - (cp - data)) == -1)
660 /* advance pointer to end of data */
661 cp += strlen((char *) cp) + 1;
662 /* now save length */
670 n = n * 10 + (*cp++ - '0');
672 PUTSHORT((u_int16_t) n, cp);
673 for (i = 0; i < 2; i++) {
674 if (!getword(buf, sizeof(buf), fp, 0))
679 (void) strcpy((char *) cp, buf);
680 cp += strlen((char *) cp) + 1;
688 datasize = sizeof data;
690 while (i > MAXCHARSTRING) {
691 if (datasize <= MAXCHARSTRING) {
692 ns_error(ns_log_update,
696 datasize -= MAXCHARSTRING;
697 *cp++ = (char)MAXCHARSTRING;
698 memcpy(cp, cp1, MAXCHARSTRING);
700 cp1 += MAXCHARSTRING;
703 if (datasize < i + 1) {
704 ns_error(ns_log_update,
713 /* XXXVIX: segmented texts 4.9.5 */
716 n = inet_nsap_addr(buf, (u_char *) data,
721 cp = buf + (n = strlen(buf));
724 while ((i = getc(fp), *cp = i, i != EOF)
725 && *cp != '\n' && (n < MAXDATA))
733 n = loc_aton(buf, (u_char *) data);
746 n = parse_sec_rdata(buf, sizeof(buf), 1,
762 if (section == S_PREREQ) {
764 if (opcode == NXDOMAIN) {
768 } else if (opcode == YXDOMAIN) {
772 } else if (opcode == NXRRSET) {
775 } else if (opcode == YXRRSET) {
779 } else {/* section == S_UPDATE */
780 if (opcode == DELETE) {
793 ns_debug(ns_log_update, 1,
794 "cannot interpret section: %d", section);
800 ns_debug(ns_log_update, 1,
801 "merge of update id %d failed due to error at line %d",
803 memset(&empty_from, 0, sizeof empty_from);
804 free_rrecp(&listuprec, rcode, empty_from);
807 rrecp = res_mkupdrec(section, dname, class, type, ttl);
808 if (section != S_ZONE) {
809 dp = savedata(class, type, ttl, (u_char *) data, n);
810 dp->d_zone = zonenum;
811 dp->d_cred = DB_C_ZONE;
812 dp->d_clev = nlabels(zp->z_origin);
814 rrecp->r_opcode = opcode;
816 rrecp->r_zone = zonenum;
817 rrecp->r_opcode = opcode;
820 /* remove add/delete pairs */
821 if (section == S_UPDATE) {
825 arp = TAIL(listuprec);
828 if (arp->r_section == S_UPDATE &&
829 ((arp->r_opcode == DELETE &&
832 arp->r_opcode == ADD)) &&
833 arp->r_dp->d_type == dp->d_type &&
834 arp->r_dp->d_class == dp->d_class &&
835 arp->r_dp->d_ttl == dp->d_ttl &&
836 ns_samename(arp->r_dname, dname) == 1 &&
837 db_cmp(arp->r_dp, dp) == 0) {
839 db_freedata(arp->r_dp);
840 UNLINK(listuprec, arp, r_link);
842 res_freeupdrec(rrecp);
846 arp = PREV(arp, r_link);
852 APPEND(listuprec, rrecp, r_link);
853 /* Override zone number with current zone serial number */
854 rrecp->r_zone = serial;
858 return (DBIXFR_ERROR);