1 /*
2  * read a zone that is split up with ldns-zsplit and re-create
3  * the original zone
4  *
5  * From:
6  * zone1: SOA a b c d e f
7  * zone2: SOA f g h i k l
8  *
9  * Go back to:
10  * zone: SOA a b c d e f g h i j k l
11  *
12  * This is useful in combination with ldns-zsplit
13  *
14  * See the file LICENSE for the license
15  */
16 
17 #include "config.h"
18 #include <errno.h>
19 #include <ldns/ldns.h>
20 
21 #define FIRST_ZONE 	0
22 #define MIDDLE_ZONE 	1
23 #define LAST_ZONE 	2
24 
25 static void
usage(FILE * f,char * progname)26 usage(FILE *f, char *progname)
27 {
28 		fprintf(f, "Usage: %s [OPTIONS] <zonefiles>\n", progname);
29 		fprintf(f, "  Concatenate signed zone snippets created with ldns-zsplit\n");
30 		fprintf(f, "  back together. The generate zone file is printed to stdout\n");
31 		fprintf(f, "  The new zone should be equal to the original zone (before splitting)\n");
32 		fprintf(f, "OPTIONS:\n");
33 		fprintf(f, "-o ORIGIN\tUse this as initial origin, for zones starting with @\n");
34 		fprintf(f, "-v\t\tShow the version number and exit\n");
35 }
36 
37 int
main(int argc,char ** argv)38 main(int argc, char **argv)
39 {
40 	char *progname;
41 	FILE *fp;
42 	int c;
43 	ldns_rdf *origin;
44 	size_t i, j;
45 	int where;
46 	ldns_zone *z;
47 	ldns_rr_list *zrr;
48 	ldns_rr *current_rr;
49 	ldns_rr *soa;
50 	ldns_rdf *last_owner;
51 	ldns_rr  *last_rr;
52 	ldns_rr  *pop_rr;
53 
54 	progname = strdup(argv[0]);
55 	origin = NULL;
56 
57 	while ((c = getopt(argc, argv, "o:v")) != -1) {
58 		switch(c) {
59 			case 'o':
60 				origin = ldns_dname_new_frm_str(strdup(optarg));
61 				if (!origin) {
62 					fprintf(stderr, "Cannot convert the origin %s to a domainname\n", optarg);
63 					exit(EXIT_FAILURE);
64 				}
65 				break;
66 			case 'v':
67 				printf("zone file concatenator version %s (ldns version %s)\n", LDNS_VERSION, ldns_version());
68 				exit(EXIT_SUCCESS);
69 				break;
70 			default:
71 				fprintf(stderr, "Unrecognized option\n");
72 				usage(stdout, progname);
73 				exit(EXIT_FAILURE);
74 		}
75 	}
76 
77 	argc -= optind;
78 	argv += optind;
79 
80 	if (argc < 1) {
81 		usage(stdout, progname);
82 		exit(EXIT_FAILURE);
83 	}
84 
85 	for (i = 0; i < (size_t)argc; i++) {
86 
87 		if (!(fp = fopen(argv[i], "r"))) {
88 			fprintf(stderr, "Error opening key file %s: %s\n", argv[i], strerror(errno));
89 			exit(EXIT_FAILURE);
90 		}
91 
92 		if (ldns_zone_new_frm_fp(&z, fp, origin, 0, 0) != LDNS_STATUS_OK) {
93 			fprintf(stderr, "Zone file %s could not be parsed correctly\n", argv[i]);
94 			exit(EXIT_FAILURE);
95 		}
96 
97 		zrr = ldns_zone_rrs(z);
98 		soa = ldns_zone_soa(z); /* SOA is stored separately */
99 
100 		fprintf(stderr, "%s\n", argv[i]);
101 
102 		if (0 == i) {
103 			where = FIRST_ZONE;
104 
105 			/* remove the last equal named RRs */
106 			last_rr = ldns_rr_list_pop_rr(zrr);
107 			last_owner = ldns_rr_owner(last_rr);
108 			/* remove until no match */
109 			do {
110 				pop_rr = ldns_rr_list_pop_rr(zrr);
111 			} while(ldns_rdf_compare(last_owner, ldns_rr_owner(pop_rr)) == 0) ;
112 			/* we popped one to many, put it back */
113 			ldns_rr_list_push_rr(zrr, pop_rr);
114 		} else if ((size_t)(argc - 1) == i) {
115 			where = LAST_ZONE;
116 		} else {
117 			where = MIDDLE_ZONE;
118 
119 			/* remove the last equal named RRs */
120 			last_rr = ldns_rr_list_pop_rr(zrr);
121 			last_owner = ldns_rr_owner(last_rr);
122 			/* remove until no match */
123 			do {
124 				pop_rr = ldns_rr_list_pop_rr(zrr);
125 			} while(ldns_rdf_compare(last_owner, ldns_rr_owner(pop_rr)) == 0) ;
126 			/* we popped one to many, put it back */
127 			ldns_rr_list_push_rr(zrr, pop_rr);
128 		}
129 
130 		/* printing the RRs */
131 		for (j = 0; j < ldns_rr_list_rr_count(zrr); j++) {
132 
133 			current_rr = ldns_rr_list_rr(zrr, j);
134 
135 			switch(where) {
136 				case FIRST_ZONE:
137 					if (soa) {
138 						ldns_rr_print(stdout, soa);
139 						soa = NULL;
140 					}
141 					break;
142 				case MIDDLE_ZONE:
143 					/* rm SOA */
144 					/* SOA isn't printed by default */
145 
146 					/* rm SOA aux records
147 					 * this also takes care of the DNSKEYs + RRSIGS
148 					 */
149 					if (ldns_rdf_compare(ldns_rr_owner(current_rr),
150 							ldns_rr_owner(soa)) == 0) {
151 						continue;
152 					}
153 					break;
154 				case LAST_ZONE:
155 					/* rm SOA */
156 					/* SOA isn't printed by default */
157 
158 					/* rm SOA aux records
159 					 * this also takes care of the DNSKEYs + RRSIGS
160 					 */
161 					if (ldns_rdf_compare(ldns_rr_owner(current_rr),
162 							ldns_rr_owner(soa)) == 0) {
163 						continue;
164 					}
165 					break;
166 			}
167 			ldns_rr_print(stdout, current_rr);
168 		}
169 	}
170         exit(EXIT_SUCCESS);
171 }
172