/** match two rr lists */ static int match_list(ldns_rr_list* q, ldns_rr_list *p) { size_t i; if(ldns_rr_list_rr_count(q) != ldns_rr_list_rr_count(p)) { verbose(3, "rrlistcount different %d %d", (int)ldns_rr_list_rr_count(q), (int)ldns_rr_list_rr_count(p)); return 0; } for(i=0; i<ldns_rr_list_rr_count(q); i++) { if(matches_nolocation) { if(!ldns_rr_list_contains_rr(p, ldns_rr_list_rr(q, i))) { verbose(3, "rr %u not found", (unsigned)i); return 0; } } else { if(ldns_rr_compare(ldns_rr_list_rr(q, i), ldns_rr_list_rr(p, i)) != 0) { verbose(3, "rr %u different", (unsigned)i); return 0; } /* and check the ttl */ if(ldns_rr_ttl(ldns_rr_list_rr(q, i)) != ldns_rr_ttl(ldns_rr_list_rr(p, i))) { verbose(3, "rr %u ttl different", (unsigned)i); return 0; } } } return 1; }
ldns_status ldns_dnssec_rrs_add_rr(ldns_dnssec_rrs *rrs, ldns_rr *rr) { int cmp; ldns_dnssec_rrs *new_rrs; if (!rrs || !rr) { return LDNS_STATUS_ERR; } /* this could be done more efficiently; name and type should already be equal */ cmp = ldns_rr_compare(rrs->rr, rr); /* should we error on equal? */ if (cmp <= 0) { if (rrs->next) { return ldns_dnssec_rrs_add_rr(rrs->next, rr); } else { new_rrs = ldns_dnssec_rrs_new(); new_rrs->rr = rr; rrs->next = new_rrs; } } else if (cmp > 0) { /* put the current old rr in the new next, put the new rr in the current container */ new_rrs = ldns_dnssec_rrs_new(); new_rrs->rr = rrs->rr; new_rrs->next = rrs->next; rrs->rr = rr; rrs->next = new_rrs; } return LDNS_STATUS_OK; }
/** match two rr lists */ static int match_list(ldns_rr_list* q, ldns_rr_list *p, bool mttl) { size_t i; if(ldns_rr_list_rr_count(q) != ldns_rr_list_rr_count(p)) return 0; for(i=0; i<ldns_rr_list_rr_count(q); i++) { if(ldns_rr_compare(ldns_rr_list_rr(q, i), ldns_rr_list_rr(p, i)) != 0) { verbose(3, "rr %d different", (int)i); return 0; } if(mttl && ldns_rr_ttl(ldns_rr_list_rr(q, i)) != ldns_rr_ttl(ldns_rr_list_rr(p, i))) { verbose(3, "rr %d ttl different", (int)i); return 0; } } return 1; }
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(argc, argv); 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(argc, argv); 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; }