summaryrefslogtreecommitdiff
path: root/examples/ldns-zsplit.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/ldns-zsplit.c')
-rw-r--r--examples/ldns-zsplit.c272
1 files changed, 272 insertions, 0 deletions
diff --git a/examples/ldns-zsplit.c b/examples/ldns-zsplit.c
new file mode 100644
index 000000000000..84f2ddb9675a
--- /dev/null
+++ b/examples/ldns-zsplit.c
@@ -0,0 +1,272 @@
+/*
+ * read a zone from disk and split it up:
+ *
+ * zone: SOA a b c d e f g h i j k l
+ * becomes:
+ * zone1: SOA a b c d e f
+ * zone2: SOA f g h i k l
+ *
+ * ldns-catzone removes the last name and put
+ * the zone back together.
+ *
+ * This way you can incremental sign a zone
+ *
+ * See the file LICENSE for the license
+ */
+
+#include "config.h"
+#include <errno.h>
+#include <ldns/ldns.h>
+
+#define DEFAULT_SPLIT 1000
+#define FILE_SIZE 255
+#define SPLIT_MAX 999
+#define NO_SPLIT 0
+#define INTENT_TO_SPLIT 1
+#define SPLIT_NOW 2
+
+static void
+usage(FILE *f, char *progname)
+{
+ fprintf(f, "Usage: %s [OPTIONS] <zonefile> [keys]\n", progname);
+ fprintf(f, " Cut a zone file into pieces, each part is put in a file\n");
+ fprintf(f, " named: '<zonefile>.NNN'. Where NNN is a integer ranging 000 to 999.\n");
+ fprintf(f, " If key files are given they are inserted in each part.\n");
+ fprintf(f, " The original SOA is also included in each part, making them correct DNS\n");
+ fprintf(f, " (mini) zones.\n");
+ fprintf(f, " This utility can be used to parallel sign a large zone.\n");
+ fprintf(f, " To make it work the original zone needs to be canonical ordered.\n");
+ fprintf(f, "\nOPTIONS:\n");
+ fprintf(f, " -n NUMBER\tsplit after this many RRs\n");
+ fprintf(f, " -o ORIGIN\tuse this as initial origin, for zones starting with @\n");
+ fprintf(f, " -z\t\tsort the zone prior to splitting. The current ldns zone\n");
+ fprintf(f, " \t\timplementation makes this unuseable for large zones.\n");
+ fprintf(f, " -v\t\tshow version number and exit\n");
+}
+
+
+/* key the keys from the cmd line */
+static ldns_rr_list *
+open_keyfiles(char **files, uint16_t filec)
+{
+ uint16_t i;
+ ldns_rr_list *pubkeys;
+ ldns_rr *k;
+ FILE *kfp;
+
+ pubkeys = ldns_rr_list_new();
+
+ for (i = 0; i < filec; i++) {
+ if (!(kfp = fopen(files[i], "r"))) {
+ fprintf(stderr, "Error opening key file %s: %s\n", files[i], strerror(errno));
+ return NULL;
+ }
+ if (ldns_rr_new_frm_fp(&k, kfp, NULL, NULL, NULL) != LDNS_STATUS_OK) {
+ fprintf(stderr, "Error parsing the key file %s: %s\n", files[i], strerror(errno));
+ return NULL;
+ }
+ fclose(kfp);
+ ldns_rr_list_push_rr(pubkeys, k);
+ }
+ return pubkeys;
+}
+
+/* open a new zone file with the correct suffix */
+static FILE *
+open_newfile(char *basename, ldns_zone *z, size_t counter, ldns_rr_list *keys)
+{
+ char filename[FILE_SIZE];
+ FILE *fp;
+
+ if (counter > SPLIT_MAX) {
+ fprintf(stderr, "Maximum split count reached %u\n", (unsigned int) counter);
+ return NULL;
+ }
+
+ snprintf(filename, FILE_SIZE, "%s.%03u", basename, (unsigned int) counter);
+
+ if (!(fp = fopen(filename, "w"))) {
+ fprintf(stderr, "Cannot open zone %s: %s\n", filename, strerror(errno));
+ return NULL;
+ } else {
+ fprintf(stderr, "%s\n", filename);
+ }
+ ldns_rr_print(fp, ldns_zone_soa(z));
+ if (keys) {
+ ldns_rr_list_print(fp, keys);
+
+ }
+ return fp;
+}
+
+int
+main(int argc, char **argv)
+{
+ char *progname;
+ FILE *fp;
+ ldns_zone *z;
+ ldns_rr_list *zrrs;
+ ldns_rdf *lastname;
+ int c;
+ int line_nr;
+ size_t split;
+ size_t i;
+ int splitting;
+ int compare;
+ size_t file_counter;
+ ldns_rdf *origin;
+ ldns_rdf *current_rdf;
+ ldns_rr *current_rr;
+ ldns_rr_list *last_rrset;
+ ldns_rr_list *pubkeys;
+ bool sort;
+ ldns_status s;
+
+ progname = strdup(argv[0]);
+ split = 0;
+ splitting = NO_SPLIT;
+ file_counter = 0;
+ lastname = NULL;
+ origin = NULL;
+ last_rrset = ldns_rr_list_new();
+ sort = false;
+
+ while ((c = getopt(argc, argv, "n:o:zv")) != -1) {
+ switch(c) {
+ case 'n':
+ split = (size_t)atoi(optarg);
+ if (split == 0) {
+ fprintf(stderr, "-n want a integer\n");
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 'o':
+ origin = ldns_dname_new_frm_str(strdup(optarg));
+ if (!origin) {
+ fprintf(stderr, "Cannot convert the origin %s to a domainname\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 'v':
+ printf("zone file splitter version %s (ldns version %s)\n", LDNS_VERSION, ldns_version());
+ exit(EXIT_SUCCESS);
+ break;
+ case 'z':
+ sort = true;
+ break;
+ default:
+ fprintf(stderr, "Unrecognized option\n");
+ usage(stdout, progname);
+ exit(EXIT_FAILURE);
+ }
+ }
+ if (split == 0) {
+ split = DEFAULT_SPLIT;
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ usage(stdout, progname);
+ exit(EXIT_FAILURE);
+ }
+
+ if (!(fp = fopen(argv[0], "r"))) {
+ fprintf(stderr, "Unable to open %s: %s\n", argv[0], strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ /* get the keys */
+ pubkeys = open_keyfiles(argv + 1, (uint16_t) argc - 1);
+
+ /* suck in the entire zone ... */
+ if (!origin) {
+ origin = ldns_dname_new_frm_str(".");
+ }
+
+ s = ldns_zone_new_frm_fp_l(&z, fp, origin, 0, LDNS_RR_CLASS_IN, &line_nr);
+ fclose(fp);
+
+ if (s != LDNS_STATUS_OK) {
+ fprintf(stderr, "Zone file %s could not be parsed correctly: %s at line %d\n",
+ argv[0],
+ ldns_get_errorstr_by_id(s),
+ line_nr);
+ exit(EXIT_FAILURE);
+ }
+ /* these kind of things can kill you... */
+ if (sort) {
+ ldns_zone_sort(z);
+ }
+
+ zrrs = ldns_zone_rrs(z);
+ if (ldns_rr_list_rr_count(zrrs) / split > SPLIT_MAX) {
+ fprintf(stderr, "The zone is too large for the used -n value: %u\n", (unsigned int) split);
+ exit(EXIT_FAILURE);
+ }
+
+
+ /* Setup */
+ if (!(fp = open_newfile(argv[0], z, file_counter, pubkeys))) {
+ exit(EXIT_FAILURE);
+ }
+
+ for(i = 0; i < ldns_rr_list_rr_count(zrrs); i++) {
+
+ current_rr = ldns_rr_list_rr(zrrs, i);
+ current_rdf = ldns_rr_owner(current_rr);
+
+ compare = ldns_dname_compare(current_rdf, lastname);
+
+ if (compare == 0) {
+ ldns_rr_list_push_rr(last_rrset, current_rr);
+ }
+
+ if (i > 0 && (i % split) == 0) {
+ splitting = INTENT_TO_SPLIT;
+ }
+
+ if (splitting == INTENT_TO_SPLIT) {
+ if (compare != 0) {
+ splitting = SPLIT_NOW;
+ }
+ }
+
+ if (splitting == SPLIT_NOW) {
+ fclose(fp);
+
+ lastname = NULL;
+ splitting = NO_SPLIT;
+ file_counter++;
+ if (!(fp = open_newfile(argv[0], z, file_counter, pubkeys))) {
+ exit(EXIT_FAILURE);
+ }
+
+ /* insert the last RRset in the new file */
+ ldns_rr_list_print(fp, last_rrset);
+
+ /* print the current rr */
+ ldns_rr_print(fp, current_rr);
+
+ /* remove them */
+ ldns_rr_list_free(last_rrset);
+ last_rrset = ldns_rr_list_new();
+ /* add the current RR */
+ ldns_rr_list_push_rr(last_rrset, current_rr);
+ continue;
+ }
+ if (splitting == NO_SPLIT || splitting == INTENT_TO_SPLIT) {
+ ldns_rr_print(fp, current_rr);
+ }
+ if (compare != 0) {
+ /* remove them and then add the current one */
+ ldns_rr_list_free(last_rrset);
+ last_rrset = ldns_rr_list_new();
+ ldns_rr_list_push_rr(last_rrset, current_rr);
+ }
+ lastname = current_rdf;
+ }
+ fclose(fp);
+ exit(EXIT_SUCCESS);
+}