summaryrefslogtreecommitdiff
path: root/examples/ldns-compare-zones.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/ldns-compare-zones.c')
-rw-r--r--examples/ldns-compare-zones.c283
1 files changed, 283 insertions, 0 deletions
diff --git a/examples/ldns-compare-zones.c b/examples/ldns-compare-zones.c
new file mode 100644
index 000000000000..663b744acc57
--- /dev/null
+++ b/examples/ldns-compare-zones.c
@@ -0,0 +1,283 @@
+/*
+ * ldns-compare-zones compares two zone files
+ *
+ * Written by Ondrej Sury in 2007
+ *
+ * Modified a bit by NLnet Labs.
+ *
+ * See the file LICENSE for the license
+ */
+
+#include "config.h"
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <time.h>
+
+#include <ldns/ldns.h>
+
+#include <errno.h>
+
+#define OP_INS '+'
+#define OP_DEL '-'
+#define OP_CHG '~'
+
+static void
+usage(char *prog)
+{
+ printf("Usage: %s [-v] [-i] [-d] [-c] [-s] <zonefile1> <zonefile2>\n",
+ prog);
+ printf(" -i - print inserted\n");
+ printf(" -d - print deleted\n");
+ printf(" -c - print changed\n");
+ printf(" -a - print all differences (-i -d -c)\n");
+ printf(" -s - do not exclude SOA record from comparison\n");
+ printf(" -z - do not sort zones\n");
+}
+
+int
+main(int argc, char **argv)
+{
+ char *fn1, *fn2;
+ FILE *fp1, *fp2;
+ ldns_zone *z1, *z2;
+ ldns_status s;
+ size_t i , j;
+ ldns_rr_list *rrl1, *rrl2;
+ int rr_cmp, rr_chg = 0;
+ ldns_rr *rr1 = NULL, *rr2 = NULL, *rrx = NULL;
+ int line_nr1 = 0, line_nr2 = 0;
+ size_t rrc1 , rrc2;
+ size_t num_ins = 0, num_del = 0, num_chg = 0;
+ int c;
+ bool opt_deleted = false, opt_inserted = false, opt_changed = false;
+ bool sort = true, inc_soa = false;
+ char op = 0;
+
+ while ((c = getopt(argc, argv, "ahvdicsz")) != -1) {
+ switch (c) {
+ case 'h':
+ usage(argv[0]);
+ exit(EXIT_SUCCESS);
+ break;
+ case 'v':
+ printf("%s version %s (ldns version %s)\n",
+ argv[0],
+ LDNS_VERSION,
+ ldns_version());
+ exit(EXIT_SUCCESS);
+ break;
+ case 's':
+ inc_soa = true;
+ break;
+ case 'z':
+ sort = false;
+ break;
+ case 'd':
+ opt_deleted = true;
+ break;
+ case 'i':
+ opt_inserted = true;
+ break;
+ case 'c':
+ opt_changed = true;
+ break;
+ case 'a':
+ opt_deleted = true;
+ opt_inserted = true;
+ opt_changed = true;
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 2) {
+ argc -= optind;
+ argv -= optind;
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ fn1 = argv[0];
+ fp1 = fopen(fn1, "r");
+ if (!fp1) {
+ fprintf(stderr, "Unable to open %s: %s\n", fn1, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ /* Read first zone */
+ s = ldns_zone_new_frm_fp_l(&z1, fp1, NULL, 0,
+ LDNS_RR_CLASS_IN, &line_nr1);
+ if (s != LDNS_STATUS_OK) {
+ fclose(fp1);
+ fprintf(stderr, "%s: %s at %d\n",
+ fn1,
+ ldns_get_errorstr_by_id(s),
+ line_nr1);
+ exit(EXIT_FAILURE);
+ }
+ fclose(fp1);
+
+ fn2 = argv[1];
+ fp2 = fopen(fn2, "r");
+ if (!fp2) {
+ fprintf(stderr, "Unable to open %s: %s\n", fn2, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ /* Read second zone */
+ s = ldns_zone_new_frm_fp_l(&z2, fp2, NULL, 0,
+ LDNS_RR_CLASS_IN, &line_nr2);
+ if (s != LDNS_STATUS_OK) {
+ ldns_zone_deep_free(z1);
+ fclose(fp2);
+ fprintf(stderr, "%s: %s at %d\n",
+ fn2,
+ ldns_get_errorstr_by_id(s),
+ line_nr2);
+ exit(EXIT_FAILURE);
+ }
+ fclose(fp2);
+
+ rrl1 = ldns_zone_rrs(z1);
+ rrc1 = ldns_rr_list_rr_count(rrl1);
+
+ rrl2 = ldns_zone_rrs(z2);
+ rrc2 = ldns_rr_list_rr_count(rrl2);
+
+ if (sort) {
+ /* canonicalize zone 1 */
+ ldns_rr2canonical(ldns_zone_soa(z1));
+ for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(z1)); i++) {
+ ldns_rr2canonical(ldns_rr_list_rr(ldns_zone_rrs(z1), i));
+ }
+ /* sort zone 1 */
+ ldns_zone_sort(z1);
+ /* canonicalize zone 2 */
+ ldns_rr2canonical(ldns_zone_soa(z2));
+ for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(z2)); i++) {
+ ldns_rr2canonical(ldns_rr_list_rr(ldns_zone_rrs(z2), i));
+ }
+ /* sort zone 2 */
+ ldns_zone_sort(z2);
+ }
+
+ if(inc_soa) {
+ ldns_rr_list* wsoa = ldns_rr_list_new();
+ ldns_rr_list_push_rr(wsoa, ldns_zone_soa(z1));
+ ldns_rr_list_cat(wsoa, rrl1);
+ rrl1 = wsoa;
+ rrc1 = ldns_rr_list_rr_count(rrl1);
+ wsoa = ldns_rr_list_new();
+ ldns_rr_list_push_rr(wsoa, ldns_zone_soa(z2));
+ ldns_rr_list_cat(wsoa, rrl2);
+ rrl2 = wsoa;
+ rrc2 = ldns_rr_list_rr_count(rrl2);
+ if(sort) {
+ ldns_rr_list_sort(rrl1);
+ ldns_rr_list_sort(rrl2);
+ }
+ }
+
+ /*
+ * Walk through both zones. The previously seen resource record is
+ * kept (in the variable rrx) so that we can recognize when we are
+ * handling a new owner name. If the owner name changes, we have to
+ * set the operator again.
+ */
+ for (i = 0, j = 0; i < rrc1 || j < rrc2;) {
+ rr_cmp = 0;
+ if (i < rrc1 && j < rrc2) {
+ rr1 = ldns_rr_list_rr(rrl1, i);
+ rr2 = ldns_rr_list_rr(rrl2, j);
+ rr_cmp = ldns_rr_compare(rr1, rr2);
+
+ /* Completely skip if the rrs are equal */
+ if (rr_cmp == 0) {
+ i++;
+ j++;
+ continue;
+ }
+ rr_chg = ldns_dname_compare(ldns_rr_owner(rr1),
+ ldns_rr_owner(rr2));
+ } else if (i >= rrc1) {
+ /* we have reached the end of zone 1, so the current record
+ * from zone 2 automatically sorts higher
+ */
+ rr1 = NULL;
+ rr2 = ldns_rr_list_rr(rrl2, j);
+ rr_chg = rr_cmp = 1;
+ } else if (j >= rrc2) {
+ /* we have reached the end of zone 2, so the current record
+ * from zone 1 automatically sorts lower
+ */
+ rr1 = ldns_rr_list_rr(rrl1, i);
+ rr2 = NULL;
+ rr_chg = rr_cmp = -1;
+ }
+ if (rr_cmp < 0) {
+ i++;
+ if ((rrx != NULL) && (ldns_dname_compare(ldns_rr_owner(rr1),
+ ldns_rr_owner(rrx)
+ ) != 0)) {
+ /* The owner name is different, forget previous rr */
+ rrx = NULL;
+ }
+ if (rrx == NULL) {
+ if (rr_chg == 0) {
+ num_chg++;
+ op = OP_CHG;
+ } else {
+ num_del++;
+ op = OP_DEL;
+ }
+ rrx = rr1;
+ }
+ if (((op == OP_DEL) && opt_deleted) ||
+ ((op == OP_CHG) && opt_changed)) {
+ printf("%c-", op);
+ ldns_rr_print(stdout, rr1);
+ }
+ } else if (rr_cmp > 0) {
+ j++;
+ if ((rrx != NULL) && (ldns_dname_compare(ldns_rr_owner(rr2),
+ ldns_rr_owner(rrx)
+ ) != 0)) {
+ rrx = NULL;
+ }
+ if (rrx == NULL) {
+ if (rr_chg == 0) {
+ num_chg++;
+ op = OP_CHG;
+ } else {
+ num_ins++;
+ op = OP_INS;
+ }
+ /* remember this rr for it's name in the next iteration */
+ rrx = rr2;
+ }
+ if (((op == OP_INS) && opt_inserted) ||
+ ((op == OP_CHG) && opt_changed)) {
+ printf("%c+", op);
+ ldns_rr_print(stdout, rr2);
+ }
+ }
+ }
+
+ printf("\t%c%u\t%c%u\t%c%u\n",
+ OP_INS,
+ (unsigned int) num_ins,
+ OP_DEL,
+ (unsigned int) num_del,
+ OP_CHG,
+ (unsigned int) num_chg);
+
+ /* Free resources */
+ if(inc_soa) {
+ ldns_rr_list_free(rrl1);
+ ldns_rr_list_free(rrl2);
+ }
+ ldns_zone_deep_free(z2);
+ ldns_zone_deep_free(z1);
+
+ return 0;
+}