xref: /openbsd-src/usr.sbin/nsd/xfr-inspect.c (revision b71395ea3d4830c6fd338870b804059761b8292d)
1ee5153b7Sflorian /* xfr-inspect - list the contents and inspect an zone transfer XFR file
2ee5153b7Sflorian  * By W.C.A. Wijngaards
3ee5153b7Sflorian  * Copyright 2017, NLnet Labs.
4ee5153b7Sflorian  * BSD, see LICENSE.
5ee5153b7Sflorian  */
6ee5153b7Sflorian 
7ee5153b7Sflorian #include "config.h"
8ee5153b7Sflorian #include "util.h"
9ee5153b7Sflorian #include "buffer.h"
10ee5153b7Sflorian #include "packet.h"
11ee5153b7Sflorian #include "rdata.h"
12ee5153b7Sflorian #include "namedb.h"
13ee5153b7Sflorian #include "difffile.h"
14ee5153b7Sflorian #include <stdio.h>
15ee5153b7Sflorian #include <errno.h>
16ee5153b7Sflorian #include <string.h>
17ee5153b7Sflorian #include <stdlib.h>
18ee5153b7Sflorian #include <unistd.h>
19ee5153b7Sflorian #include <ctype.h>
20ee5153b7Sflorian 
21ee5153b7Sflorian /** verbosity for inspect */
22ee5153b7Sflorian static int v = 0;
23ee5153b7Sflorian /** shorthand for ease */
24ee5153b7Sflorian #ifdef ULL
25ee5153b7Sflorian #undef ULL
26ee5153b7Sflorian #endif
27ee5153b7Sflorian #define ULL (unsigned long long)
28ee5153b7Sflorian 
29ee5153b7Sflorian /** print usage text */
30ee5153b7Sflorian static void
usage(void)31ee5153b7Sflorian usage(void)
32ee5153b7Sflorian {
33ee5153b7Sflorian 	printf("usage:	xfr-inspect [options] file\n");
34ee5153b7Sflorian 	printf(" -h		this help\n");
35ee5153b7Sflorian 	printf(" -v		increase verbosity: "
36ee5153b7Sflorian 	       "with -v(list chunks), -vv(inside chunks)\n");
37ee5153b7Sflorian 	printf(" -l		list contents of transfer\n");
38ee5153b7Sflorian }
39ee5153b7Sflorian 
40ee5153b7Sflorian static int
xi_diff_read_64(FILE * in,uint64_t * result)41ee5153b7Sflorian xi_diff_read_64(FILE *in, uint64_t* result)
42ee5153b7Sflorian {
43ee5153b7Sflorian 	if (fread(result, sizeof(*result), 1, in) == 1) {
44ee5153b7Sflorian 		return 1;
45ee5153b7Sflorian 	} else {
46ee5153b7Sflorian 		return 0;
47ee5153b7Sflorian 	}
48ee5153b7Sflorian }
49ee5153b7Sflorian 
50ee5153b7Sflorian static int
xi_diff_read_32(FILE * in,uint32_t * result)51ee5153b7Sflorian xi_diff_read_32(FILE *in, uint32_t* result)
52ee5153b7Sflorian {
53ee5153b7Sflorian 	if (fread(result, sizeof(*result), 1, in) == 1) {
54ee5153b7Sflorian 		*result = ntohl(*result);
55ee5153b7Sflorian 		return 1;
56ee5153b7Sflorian 	} else {
57ee5153b7Sflorian 		return 0;
58ee5153b7Sflorian 	}
59ee5153b7Sflorian }
60ee5153b7Sflorian 
61ee5153b7Sflorian static int
xi_diff_read_8(FILE * in,uint8_t * result)62ee5153b7Sflorian xi_diff_read_8(FILE *in, uint8_t* result)
63ee5153b7Sflorian {
64ee5153b7Sflorian         if (fread(result, sizeof(*result), 1, in) == 1) {
65ee5153b7Sflorian                 return 1;
66ee5153b7Sflorian         } else {
67ee5153b7Sflorian                 return 0;
68ee5153b7Sflorian         }
69ee5153b7Sflorian }
70ee5153b7Sflorian 
71ee5153b7Sflorian static int
xi_diff_read_str(FILE * in,char * buf,size_t len)72ee5153b7Sflorian xi_diff_read_str(FILE* in, char* buf, size_t len)
73ee5153b7Sflorian {
74ee5153b7Sflorian 	uint32_t disklen;
75ee5153b7Sflorian 	if(!xi_diff_read_32(in, &disklen))
76ee5153b7Sflorian 		return 0;
77ee5153b7Sflorian 	if(disklen >= len)
78ee5153b7Sflorian 		return 0;
79ee5153b7Sflorian 	if(fread(buf, disklen, 1, in) != 1)
80ee5153b7Sflorian 		return 0;
81ee5153b7Sflorian 	buf[disklen] = 0;
82ee5153b7Sflorian 	return 1;
83ee5153b7Sflorian }
84ee5153b7Sflorian 
85ee5153b7Sflorian 
86ee5153b7Sflorian /** inspect header of xfr file, return num_parts */
87ee5153b7Sflorian static int
inspect_header(FILE * in)88ee5153b7Sflorian inspect_header(FILE* in)
89ee5153b7Sflorian {
90ee5153b7Sflorian 	char zone_buf[3072];
91ee5153b7Sflorian 	char patname_buf[2048];
92ee5153b7Sflorian 
93ee5153b7Sflorian 	uint32_t old_serial, new_serial, num_parts, type;
94ee5153b7Sflorian 	uint64_t time_end_0, time_start_0;
95ee5153b7Sflorian 	uint32_t time_end_1, time_start_1;
96ee5153b7Sflorian 	uint8_t committed;
97ee5153b7Sflorian 
98ee5153b7Sflorian 	time_t time_end, time_start;
99ee5153b7Sflorian 
100ee5153b7Sflorian 	if(!xi_diff_read_32(in, &type)) {
101ee5153b7Sflorian 		printf("could not read type, file short\n");
102ee5153b7Sflorian 		fclose(in);
103ee5153b7Sflorian 		exit(1);
104ee5153b7Sflorian 	}
105ee5153b7Sflorian 	if(type != DIFF_PART_XFRF) {
106ee5153b7Sflorian 		printf("type:	%x (BAD FILE TYPE)\n", type);
107ee5153b7Sflorian 		fclose(in);
108ee5153b7Sflorian 		exit(1);
109ee5153b7Sflorian 	}
110ee5153b7Sflorian 	if(!xi_diff_read_8(in, &committed) ||
111ee5153b7Sflorian 		!xi_diff_read_32(in, &num_parts) ||
112ee5153b7Sflorian 		!xi_diff_read_64(in, &time_end_0) ||
113ee5153b7Sflorian 		!xi_diff_read_32(in, &time_end_1) ||
114ee5153b7Sflorian 		!xi_diff_read_32(in, &old_serial) ||
115ee5153b7Sflorian 		!xi_diff_read_32(in, &new_serial) ||
116ee5153b7Sflorian 		!xi_diff_read_64(in, &time_start_0) ||
117ee5153b7Sflorian 		!xi_diff_read_32(in, &time_start_1) ||
118ee5153b7Sflorian 		!xi_diff_read_str(in, zone_buf, sizeof(zone_buf)) ||
119ee5153b7Sflorian 		!xi_diff_read_str(in, patname_buf, sizeof(patname_buf))) {
120ee5153b7Sflorian 		printf("diff file bad commit part, file too short");
121ee5153b7Sflorian 		fclose(in);
122ee5153b7Sflorian 		exit(1);
123ee5153b7Sflorian 	}
124ee5153b7Sflorian 	time_end = (time_t)time_end_0;
125ee5153b7Sflorian 	time_start = (time_t)time_start_0;
126ee5153b7Sflorian 
127ee5153b7Sflorian 	/* printf("type:		%x\n", (int)type); */
128ee5153b7Sflorian 	printf("committed:	%d (%s)\n", (int)committed,
129ee5153b7Sflorian 		committed?"yes":"no");
130ee5153b7Sflorian 	printf("num_parts:	%d\n", (int)num_parts);
131ee5153b7Sflorian 	printf("time_end:	%d.%6.6d %s", (int)time_end_0,
132ee5153b7Sflorian 		(int)time_end_1, ctime(&time_end));
133ee5153b7Sflorian 	printf("old_serial:	%u\n", (unsigned)old_serial);
134ee5153b7Sflorian 	printf("new_serial:	%u\n", (unsigned)new_serial);
135ee5153b7Sflorian 	printf("time_start:	%d.%6.6d %s", (int)time_start_0,
136ee5153b7Sflorian 		(int)time_start_1, ctime(&time_start));
137ee5153b7Sflorian 	printf("zone:		%s\n", zone_buf);
138ee5153b7Sflorian 	printf("patname:	%s\n", patname_buf);
139ee5153b7Sflorian 
140ee5153b7Sflorian 	return num_parts;
141ee5153b7Sflorian }
142ee5153b7Sflorian 
143ee5153b7Sflorian /** print records in packet */
144ee5153b7Sflorian static void
print_records(region_type * region,buffer_type * pkt,int num,int qsection)145ee5153b7Sflorian print_records(region_type* region, buffer_type* pkt, int num, int qsection)
146ee5153b7Sflorian {
147ee5153b7Sflorian 	domain_table_type* table;
148ee5153b7Sflorian 	int i;
149ee5153b7Sflorian 	rr_type* rr;
150ee5153b7Sflorian 	region_type* tmpregion = region_create(xalloc, free);
151ee5153b7Sflorian 	buffer_type* tmpbuf;
152ee5153b7Sflorian 	if(!tmpregion) {
153ee5153b7Sflorian 		printf("out of memory\n");
154ee5153b7Sflorian 		return;
155ee5153b7Sflorian 	}
156ee5153b7Sflorian 	tmpbuf = buffer_create(region, QIOBUFSZ);
157ee5153b7Sflorian 	if(!tmpbuf) {
158ee5153b7Sflorian 		printf("out of memory\n");
159ee5153b7Sflorian 		return;
160ee5153b7Sflorian 	}
161ee5153b7Sflorian 	table = domain_table_create(tmpregion);
162ee5153b7Sflorian 	if(!table) {
163ee5153b7Sflorian 		printf("out of memory\n");
164ee5153b7Sflorian 		return;
165ee5153b7Sflorian 	}
166ee5153b7Sflorian 
167ee5153b7Sflorian 	for(i=0; i<num; ++i) {
168ee5153b7Sflorian 		rr = packet_read_rr(region, table, pkt, qsection);
169ee5153b7Sflorian 		if(!rr) {
170ee5153b7Sflorian 			printf("; cannot read rr %d\n", i);
171ee5153b7Sflorian 			return;
172ee5153b7Sflorian 		}
173ee5153b7Sflorian 		if(qsection) {
174ee5153b7Sflorian 			printf("%s", dname_to_string(domain_dname(rr->owner),
175ee5153b7Sflorian 				NULL));
176ee5153b7Sflorian 			printf("\t%s", rrclass_to_string(rr->klass));
177ee5153b7Sflorian 			if(rr->type == TYPE_IXFR)
178ee5153b7Sflorian 				printf("\tIXFR\n");
179ee5153b7Sflorian 			else if(rr->type == TYPE_AXFR)
180ee5153b7Sflorian 				printf("\tAXFR\n");
181ee5153b7Sflorian 			else printf("\t%s\n", rrtype_to_string(rr->type));
182ee5153b7Sflorian 		} else {
183ee5153b7Sflorian 			if(!print_rr(stdout, NULL, rr, tmpregion, tmpbuf)) {
184ee5153b7Sflorian 				printf("; cannot print rr %d\n", i);
185ee5153b7Sflorian 			}
186ee5153b7Sflorian 		}
187ee5153b7Sflorian 	}
188ee5153b7Sflorian 	region_destroy(tmpregion);
189ee5153b7Sflorian }
190ee5153b7Sflorian 
191ee5153b7Sflorian /** inspect packet (IXFR or AXFR) */
192ee5153b7Sflorian static void
inspect_packet(region_type * region,buffer_type * pkt)193ee5153b7Sflorian inspect_packet(region_type* region, buffer_type* pkt)
194ee5153b7Sflorian {
195ee5153b7Sflorian 	printf("\n");
196ee5153b7Sflorian 	if(buffer_limit(pkt) < QHEADERSZ) {
197ee5153b7Sflorian 		printf("packet too short\n");
198ee5153b7Sflorian 		return;
199ee5153b7Sflorian 	}
200ee5153b7Sflorian 	printf("; id=%4.4x ; flags%s%s%s%s%s%s%s%s ; rcode %s ; opcode %d\n",
201ee5153b7Sflorian 		ID(pkt), QR(pkt)?" QR":"", AA(pkt)?" AA":"", TC(pkt)?" TC":"",
202ee5153b7Sflorian 		RD(pkt)?" RD":"", RA(pkt)?" RA":"", Z(pkt)?" Z":"",
203ee5153b7Sflorian 		AD(pkt)?" AD":"", CD(pkt)?" CD":"", rcode2str(RCODE(pkt)),
204ee5153b7Sflorian 		OPCODE(pkt));
205ee5153b7Sflorian 	printf("; qdcount %d ; ancount %d ; nscount %d ; arcount %d\n",
206ee5153b7Sflorian 		QDCOUNT(pkt), ANCOUNT(pkt), NSCOUNT(pkt), ARCOUNT(pkt));
207ee5153b7Sflorian 	buffer_skip(pkt, QHEADERSZ);
208ee5153b7Sflorian 
209ee5153b7Sflorian 	if(QDCOUNT(pkt) != 0) {
210ee5153b7Sflorian 		printf("; QUESTION SECTION\n");
211ee5153b7Sflorian 		print_records(region, pkt, QDCOUNT(pkt), 1);
212ee5153b7Sflorian 	}
213ee5153b7Sflorian 	if(ANCOUNT(pkt) != 0) {
214ee5153b7Sflorian 		printf("; ANSWER SECTION\n");
215ee5153b7Sflorian 		print_records(region, pkt, ANCOUNT(pkt), 0);
216ee5153b7Sflorian 	}
217ee5153b7Sflorian 	if(NSCOUNT(pkt) != 0) {
218ee5153b7Sflorian 		printf("; AUTHORITY SECTION\n");
219ee5153b7Sflorian 		print_records(region, pkt, NSCOUNT(pkt), 0);
220ee5153b7Sflorian 	}
221ee5153b7Sflorian 	if(ARCOUNT(pkt) != 0) {
222ee5153b7Sflorian 		printf("; ADDITIONAL SECTION\n");
223ee5153b7Sflorian 		print_records(region, pkt, ARCOUNT(pkt), 0);
224ee5153b7Sflorian 	}
225ee5153b7Sflorian }
226ee5153b7Sflorian 
227ee5153b7Sflorian /** inspect part of xfr file */
228ee5153b7Sflorian static void
inspect_part(FILE * in,int partnum)229ee5153b7Sflorian inspect_part(FILE* in, int partnum)
230ee5153b7Sflorian {
231ee5153b7Sflorian 	uint32_t pkttype, msglen, msglen2;
232ee5153b7Sflorian 	region_type* region;
233ee5153b7Sflorian 	buffer_type* packet;
234ee5153b7Sflorian 	region = region_create(xalloc, free);
235ee5153b7Sflorian 	if(!region) {
236ee5153b7Sflorian 		printf("out of memory\n");
237ee5153b7Sflorian 		fclose(in);
238ee5153b7Sflorian 		exit(1);
239ee5153b7Sflorian 	}
240ee5153b7Sflorian 	packet = buffer_create(region, QIOBUFSZ);
241ee5153b7Sflorian 	if(!xi_diff_read_32(in, &pkttype)) {
242ee5153b7Sflorian 		printf("cannot read part %d\n", partnum);
243ee5153b7Sflorian 		fclose(in);
244ee5153b7Sflorian 		exit(1);
245ee5153b7Sflorian 	}
246ee5153b7Sflorian 	if(pkttype != DIFF_PART_XXFR) {
247ee5153b7Sflorian 		printf("bad part %d: not type XXFR\n", partnum);
248ee5153b7Sflorian 		fclose(in);
249ee5153b7Sflorian 		exit(1);
250ee5153b7Sflorian 	}
251ee5153b7Sflorian 	if(!xi_diff_read_32(in, &msglen)) {
252ee5153b7Sflorian 		printf("bad part %d: not msglen, file too short\n", partnum);
253ee5153b7Sflorian 		fclose(in);
254ee5153b7Sflorian 		exit(1);
255ee5153b7Sflorian 	}
256ee5153b7Sflorian 	if(msglen < QHEADERSZ || msglen > QIOBUFSZ) {
257ee5153b7Sflorian 		printf("bad part %d: msglen %u (too short or too long)\n",
258ee5153b7Sflorian 			partnum, (unsigned)msglen);
259ee5153b7Sflorian 		fclose(in);
260ee5153b7Sflorian 		exit(1);
261ee5153b7Sflorian 	}
262ee5153b7Sflorian 	if(fread(buffer_begin(packet), msglen, 1, in) != 1) {
263ee5153b7Sflorian 		printf("bad part %d: short packet, file too short, %s\n",
264ee5153b7Sflorian 			partnum, strerror(errno));
265ee5153b7Sflorian 		fclose(in);
266ee5153b7Sflorian 		exit(1);
267ee5153b7Sflorian 	}
268ee5153b7Sflorian 	if(!xi_diff_read_32(in, &msglen2)) {
269ee5153b7Sflorian 		printf("bad part %d: cannot read msglen2, file too short\n", partnum);
270ee5153b7Sflorian 		fclose(in);
271ee5153b7Sflorian 		exit(1);
272ee5153b7Sflorian 	}
273ee5153b7Sflorian 	if(v==0) {
274ee5153b7Sflorian 		region_destroy(region);
275ee5153b7Sflorian 		return;
276ee5153b7Sflorian 	}
277ee5153b7Sflorian 
278ee5153b7Sflorian 	printf("\n");
279ee5153b7Sflorian 	/* printf("type	: %x\n", pkttype); */
280ee5153b7Sflorian 	printf("part	: %d\n", partnum);
281ee5153b7Sflorian 	printf("msglen	: %u\n", (unsigned)msglen);
282ee5153b7Sflorian 	printf("msglen2	: %u (%s)\n", (unsigned)msglen2,
283ee5153b7Sflorian 		(msglen==msglen2)?"ok":"wrong");
284ee5153b7Sflorian 
285ee5153b7Sflorian 	if(v>=2) {
286ee5153b7Sflorian 		buffer_set_limit(packet, msglen);
287ee5153b7Sflorian 		inspect_packet(region, packet);
288ee5153b7Sflorian 	}
289ee5153b7Sflorian 
290ee5153b7Sflorian 	region_destroy(region);
291ee5153b7Sflorian }
292ee5153b7Sflorian 
293ee5153b7Sflorian /** inspect parts of xfr file */
294ee5153b7Sflorian static void
inspect_parts(FILE * in,int num)295ee5153b7Sflorian inspect_parts(FILE* in, int num)
296ee5153b7Sflorian {
297ee5153b7Sflorian 	int i;
298ee5153b7Sflorian 	for(i=0; i<num; i++) {
299ee5153b7Sflorian 		inspect_part(in, i);
300ee5153b7Sflorian 	}
301ee5153b7Sflorian }
302ee5153b7Sflorian 
303ee5153b7Sflorian /** inspect trail of xfr file */
304ee5153b7Sflorian static void
inspect_trail(FILE * in)305ee5153b7Sflorian inspect_trail(FILE* in)
306ee5153b7Sflorian {
307ee5153b7Sflorian 	char log_buf[5120];
308ee5153b7Sflorian 	if(!xi_diff_read_str(in, log_buf, sizeof(log_buf))) {
309ee5153b7Sflorian 		printf("bad trail: cannot read log string\n");
310ee5153b7Sflorian 		fclose(in);
311ee5153b7Sflorian 		exit(1);
312ee5153b7Sflorian 	}
313ee5153b7Sflorian 	printf("\n");
314ee5153b7Sflorian 	printf("log:	%s\n", log_buf);
315ee5153b7Sflorian }
316ee5153b7Sflorian 
317ee5153b7Sflorian /** inspect contents of xfr file */
318ee5153b7Sflorian static void
inspect_file(char * fname)319ee5153b7Sflorian inspect_file(char* fname)
320ee5153b7Sflorian {
321ee5153b7Sflorian 	FILE* in;
322ee5153b7Sflorian 	int num;
323ee5153b7Sflorian 	log_init("udb-inspect");
324ee5153b7Sflorian 	if(!(in=fopen(fname, "r"))) {
325ee5153b7Sflorian 		printf("cannot open %s: %s\n", fname, strerror(errno));
326ee5153b7Sflorian 		exit(1);
327ee5153b7Sflorian 	}
328ee5153b7Sflorian 	printf("file:	%s\n", fname);
329ee5153b7Sflorian 	num = inspect_header(in);
330ee5153b7Sflorian 	inspect_parts(in, num);
331ee5153b7Sflorian 	inspect_trail(in);
332ee5153b7Sflorian 	fclose(in);
333ee5153b7Sflorian }
334ee5153b7Sflorian 
335ee5153b7Sflorian /** list header of xfr file, return num_parts */
336ee5153b7Sflorian static int
list_header(FILE * in)337ee5153b7Sflorian list_header(FILE* in)
338ee5153b7Sflorian {
339ee5153b7Sflorian 	char zone_buf[3072];
340ee5153b7Sflorian 	char patname_buf[2048];
341ee5153b7Sflorian 
342ee5153b7Sflorian 	uint32_t old_serial, new_serial, num_parts, type;
343ee5153b7Sflorian 	uint64_t time_end_0, time_start_0;
344ee5153b7Sflorian 	uint32_t time_end_1, time_start_1;
345ee5153b7Sflorian 	uint8_t committed;
346ee5153b7Sflorian 
347ee5153b7Sflorian 	time_t time_end, time_start;
348ee5153b7Sflorian 
349ee5153b7Sflorian 	if(!xi_diff_read_32(in, &type)) {
350ee5153b7Sflorian 		printf("could not read type, file short\n");
351ee5153b7Sflorian 		fclose(in);
352ee5153b7Sflorian 		exit(1);
353ee5153b7Sflorian 	}
354ee5153b7Sflorian 	if(type != DIFF_PART_XFRF) {
355ee5153b7Sflorian 		printf("type:	%x (BAD FILE TYPE)\n", type);
356ee5153b7Sflorian 		fclose(in);
357ee5153b7Sflorian 		exit(1);
358ee5153b7Sflorian 	}
359ee5153b7Sflorian 	if(!xi_diff_read_8(in, &committed) ||
360ee5153b7Sflorian 		!xi_diff_read_32(in, &num_parts) ||
361ee5153b7Sflorian 		!xi_diff_read_64(in, &time_end_0) ||
362ee5153b7Sflorian 		!xi_diff_read_32(in, &time_end_1) ||
363ee5153b7Sflorian 		!xi_diff_read_32(in, &old_serial) ||
364ee5153b7Sflorian 		!xi_diff_read_32(in, &new_serial) ||
365ee5153b7Sflorian 		!xi_diff_read_64(in, &time_start_0) ||
366ee5153b7Sflorian 		!xi_diff_read_32(in, &time_start_1) ||
367ee5153b7Sflorian 		!xi_diff_read_str(in, zone_buf, sizeof(zone_buf)) ||
368ee5153b7Sflorian 		!xi_diff_read_str(in, patname_buf, sizeof(patname_buf))) {
369ee5153b7Sflorian 		printf("diff file bad commit part, file too short");
370ee5153b7Sflorian 		fclose(in);
371ee5153b7Sflorian 		exit(1);
372ee5153b7Sflorian 	}
373ee5153b7Sflorian 	time_end = (time_t)time_end_0;
374ee5153b7Sflorian 	time_start = (time_t)time_start_0;
375ee5153b7Sflorian 
376ee5153b7Sflorian 	/* printf("; type:		%x\n", (int)type); */
377*bfd0b123Sflorian 	printf("; committed:	%d (%s)\n", (int)committed,
378ee5153b7Sflorian 		committed?"yes":"no");
379ee5153b7Sflorian 	printf("; num_parts:	%d\n", (int)num_parts);
380ee5153b7Sflorian 	printf("; time_end:	%d.%6.6d %s", (int)time_end_0,
381ee5153b7Sflorian 		(int)time_end_1, ctime(&time_end));
382ee5153b7Sflorian 	printf("; old_serial:	%u\n", (unsigned)old_serial);
383ee5153b7Sflorian 	printf("; new_serial:	%u\n", (unsigned)new_serial);
384ee5153b7Sflorian 	printf("; time_start:	%d.%6.6d %s", (int)time_start_0,
385ee5153b7Sflorian 		(int)time_start_1, ctime(&time_start));
386ee5153b7Sflorian 	printf("; zone:		%s\n", zone_buf);
387ee5153b7Sflorian 	printf("; patname:	%s\n", patname_buf);
388ee5153b7Sflorian 
389ee5153b7Sflorian 	return num_parts;
390ee5153b7Sflorian }
391ee5153b7Sflorian 
392ee5153b7Sflorian /** list packet (IXFR or AXFR) */
393ee5153b7Sflorian static void
list_packet(region_type * region,buffer_type * pkt,int partnum)394ee5153b7Sflorian list_packet(region_type* region, buffer_type* pkt, int partnum)
395ee5153b7Sflorian {
396ee5153b7Sflorian 	if(buffer_limit(pkt) < QHEADERSZ) {
397ee5153b7Sflorian 		printf("packet too short\n");
398ee5153b7Sflorian 		return;
399ee5153b7Sflorian 	}
400ee5153b7Sflorian 	buffer_skip(pkt, QHEADERSZ);
401ee5153b7Sflorian 
402ee5153b7Sflorian 	if(partnum == 0 && QDCOUNT(pkt) == 1) {
403ee5153b7Sflorian 		/* print query AXFR or IXFR */
404ee5153b7Sflorian 		printf("; ");
405ee5153b7Sflorian 		print_records(region, pkt, QDCOUNT(pkt), 1);
406ee5153b7Sflorian 	}
407ee5153b7Sflorian 	if(ANCOUNT(pkt) != 0) {
408ee5153b7Sflorian 		print_records(region, pkt, ANCOUNT(pkt), 0);
409ee5153b7Sflorian 	}
410ee5153b7Sflorian }
411ee5153b7Sflorian 
412ee5153b7Sflorian /** list part of xfr file */
413ee5153b7Sflorian static void
list_part(FILE * in,int partnum)414ee5153b7Sflorian list_part(FILE* in, int partnum)
415ee5153b7Sflorian {
416ee5153b7Sflorian 	uint32_t pkttype, msglen, msglen2;
417ee5153b7Sflorian 	region_type* region;
418ee5153b7Sflorian 	buffer_type* packet;
419ee5153b7Sflorian 	region = region_create(xalloc, free);
420ee5153b7Sflorian 	if(!region) {
421ee5153b7Sflorian 		printf("out of memory\n");
422ee5153b7Sflorian 		fclose(in);
423ee5153b7Sflorian 		exit(1);
424ee5153b7Sflorian 	}
425ee5153b7Sflorian 	packet = buffer_create(region, QIOBUFSZ);
426ee5153b7Sflorian 	if(!xi_diff_read_32(in, &pkttype)) {
427ee5153b7Sflorian 		printf("cannot read part %d\n", partnum);
428ee5153b7Sflorian 		fclose(in);
429ee5153b7Sflorian 		exit(1);
430ee5153b7Sflorian 	}
431ee5153b7Sflorian 	if(pkttype != DIFF_PART_XXFR) {
432ee5153b7Sflorian 		printf("bad part %d: not type XXFR\n", partnum);
433ee5153b7Sflorian 		fclose(in);
434ee5153b7Sflorian 		exit(1);
435ee5153b7Sflorian 	}
436ee5153b7Sflorian 	if(!xi_diff_read_32(in, &msglen)) {
437ee5153b7Sflorian 		printf("bad part %d: not msglen, file too short\n", partnum);
438ee5153b7Sflorian 		fclose(in);
439ee5153b7Sflorian 		exit(1);
440ee5153b7Sflorian 	}
441ee5153b7Sflorian 	if(msglen < QHEADERSZ || msglen > QIOBUFSZ) {
442ee5153b7Sflorian 		printf("bad part %d: msglen %u (too short or too long)\n",
443ee5153b7Sflorian 			partnum, (unsigned)msglen);
444ee5153b7Sflorian 		fclose(in);
445ee5153b7Sflorian 		exit(1);
446ee5153b7Sflorian 	}
447ee5153b7Sflorian 	if(fread(buffer_begin(packet), msglen, 1, in) != 1) {
448ee5153b7Sflorian 		printf("bad part %d: short packet, file too short, %s\n",
449ee5153b7Sflorian 			partnum, strerror(errno));
450ee5153b7Sflorian 		fclose(in);
451ee5153b7Sflorian 		exit(1);
452ee5153b7Sflorian 	}
453ee5153b7Sflorian 	if(!xi_diff_read_32(in, &msglen2)) {
454ee5153b7Sflorian 		printf("bad part %d: cannot read msglen2, file too short\n", partnum);
455ee5153b7Sflorian 		fclose(in);
456ee5153b7Sflorian 		exit(1);
457ee5153b7Sflorian 	}
458ee5153b7Sflorian 
459ee5153b7Sflorian 	buffer_set_limit(packet, msglen);
460ee5153b7Sflorian 	list_packet(region, packet, partnum);
461ee5153b7Sflorian 	region_destroy(region);
462ee5153b7Sflorian }
463ee5153b7Sflorian 
464ee5153b7Sflorian /** list parts of xfr file */
465ee5153b7Sflorian static void
list_parts(FILE * in,int num)466ee5153b7Sflorian list_parts(FILE* in, int num)
467ee5153b7Sflorian {
468ee5153b7Sflorian 	int i;
469ee5153b7Sflorian 	for(i=0; i<num; i++) {
470ee5153b7Sflorian 		list_part(in, i);
471ee5153b7Sflorian 	}
472ee5153b7Sflorian }
473ee5153b7Sflorian 
474ee5153b7Sflorian /** list contents of xfr file */
475ee5153b7Sflorian static void
list_file(char * fname)476ee5153b7Sflorian list_file(char* fname)
477ee5153b7Sflorian {
478ee5153b7Sflorian 	FILE* in;
479ee5153b7Sflorian 	int num;
480ee5153b7Sflorian 	log_init("udb-inspect");
481ee5153b7Sflorian 	if(!(in=fopen(fname, "r"))) {
482ee5153b7Sflorian 		printf("cannot open %s: %s\n", fname, strerror(errno));
483ee5153b7Sflorian 		exit(1);
484ee5153b7Sflorian 	}
485ee5153b7Sflorian 	num = list_header(in);
486ee5153b7Sflorian 	list_parts(in, num);
487ee5153b7Sflorian 
488ee5153b7Sflorian 	fclose(in);
489ee5153b7Sflorian }
490ee5153b7Sflorian 
491ee5153b7Sflorian /** getopt global, in case header files fail to declare it. */
492ee5153b7Sflorian extern int optind;
493ee5153b7Sflorian /** getopt global, in case header files fail to declare it. */
494ee5153b7Sflorian extern char* optarg;
495ee5153b7Sflorian 
496ee5153b7Sflorian /**
497ee5153b7Sflorian  * main program. Set options given commandline arguments.
498ee5153b7Sflorian  * @param argc: number of commandline arguments.
499ee5153b7Sflorian  * @param argv: array of commandline arguments.
500ee5153b7Sflorian  * @return: exit status of the program.
501ee5153b7Sflorian  */
502ee5153b7Sflorian int
main(int argc,char * argv[])503ee5153b7Sflorian main(int argc, char* argv[])
504ee5153b7Sflorian {
505ee5153b7Sflorian 	int c, list=0;
506ee5153b7Sflorian 	while( (c=getopt(argc, argv, "hlv")) != -1) {
507ee5153b7Sflorian 		switch(c) {
508ee5153b7Sflorian 		case 'l':
509ee5153b7Sflorian 			list=1;
510ee5153b7Sflorian 			break;
511ee5153b7Sflorian 		case 'v':
512ee5153b7Sflorian 			v++;
513ee5153b7Sflorian 			break;
514ee5153b7Sflorian 		default:
515ee5153b7Sflorian 		case 'h':
516ee5153b7Sflorian 			usage();
517ee5153b7Sflorian 			return 1;
518ee5153b7Sflorian 		}
519ee5153b7Sflorian 	}
520ee5153b7Sflorian 	argc -= optind;
521ee5153b7Sflorian 	argv += optind;
522ee5153b7Sflorian 	if(argc != 1) {
523ee5153b7Sflorian 		usage();
524ee5153b7Sflorian 		return 1;
525ee5153b7Sflorian 	}
526ee5153b7Sflorian 	if(list) list_file(argv[0]);
527ee5153b7Sflorian 	else	inspect_file(argv[0]);
528ee5153b7Sflorian 
529ee5153b7Sflorian 	return 0;
530ee5153b7Sflorian }
531