1 /*------------------------------------------------------------------------------
2 *
3 * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4 * The YADIFA TM software product is provided under the BSD 3-clause license:
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of EURid nor the names of its contributors may be
16 * used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 *------------------------------------------------------------------------------
32 *
33 */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <fcntl.h>
40
41 #include <dnscore/fdtools.h>
42 #include <dnscore/dns_resource_record.h>
43 #include <dnscore/file_input_stream.h>
44 #include <dnscore/file_output_stream.h>
45 #include <dnscore/buffer_input_stream.h>
46 #include <dnscore/buffer_output_stream.h>
47
48 #define JOURNAL_CJF_BASE 1
49
50 #include <dnsdb/zdb.h>
51 #include <dnsdb/zdb_utils.h>
52 #include <dnsdb/journal-cjf-common.h>
53 #include <dnsdb/journal-cjf-page-cache.h>
54 #include <dnsdb/journal-jnl.h>
55 #include <dnsdb/rrsig.h>
56 #include <dnscore/logger_channel_stream.h>
57
58 #define MODE_JNL 0
59 #define MODE_CJF 1
60 #define MODE_AXFR 2
61
62 static bool g_dump = FALSE;
63 static bool g_generate_update_files = FALSE;
64 static bool g_clean_mode = FALSE;
65 static int g_mode = MODE_JNL;
66
67 static const char *default_channel = "stdout default";
68
69 struct logger_name_handle_s
70 {
71 const char *name;
72 logger_handle **handlep;
73 };
74
75 static const struct logger_name_handle_s logger_name_handles[] =
76 {
77 {"system", &g_system_logger},
78 {"database", &g_database_logger},
79 {NULL, NULL}
80 };
81
82 static void
config_logger_setdefault()83 config_logger_setdefault()
84 {
85 logger_start();
86
87 output_stream stdout_os;
88 logger_channel *stdout_channel;
89
90 fd_output_stream_attach(&stdout_os, dup_ex(1));
91 stdout_channel = logger_channel_alloc();
92 logger_channel_stream_open(&stdout_os, FALSE, stdout_channel);
93 logger_channel_register(default_channel, stdout_channel);
94
95 for(const struct logger_name_handle_s *name_handle = logger_name_handles; name_handle->name != NULL; name_handle++)
96 {
97 logger_handle_create(name_handle->name, name_handle->handlep);
98 #if !DEBUG
99 logger_handle_add_channel(name_handle->name, MSG_PROD_MASK, default_channel);
100 #else
101 logger_handle_add_channel(name_handle->name, MSG_ALL_MASK, default_channel);
102 #endif
103 }
104
105 #if DEBUG
106 log_debug("logging to stdout");
107 #endif
108 }
109
cjf_read_page_hdr(int fd,off_t ofs,journal_cjf_page_tbl_header * page)110 static int cjf_read_page_hdr(int fd, off_t ofs, journal_cjf_page_tbl_header *page)
111 {
112 off_t pos = lseek(fd, ofs, SEEK_SET);
113 if(pos != ofs)
114 {
115 return -1;
116 }
117
118 ssize_t n = readfully(fd, page, JOURNAL_CJF_PAGE_HEADER_SIZE);
119 if(n != JOURNAL_CJF_PAGE_HEADER_SIZE)
120 {
121 return -2;
122 }
123
124 return 1;
125 }
126
127 struct journal_cjf_page
128 {
129 journal_cjf_page_tbl_header hdr;
130 journal_cjf_page_tbl_item item[0x200];
131 u32 pos;
132 u32 end;
133 u32 serial_from;
134 u32 serial_to;
135 };
136 typedef struct journal_cjf_page journal_cjf_page;
137
cjf_scan_page(int fd,u32 ofs)138 static int cjf_scan_page(int fd, u32 ofs)
139 {
140 static const u8 PAGE_MAGIC_ARRAY[4] = {'P', 'A', 'G', 'E'};
141 u8 tmp[512];
142
143 off_t pos = lseek(fd, ofs, SEEK_SET);
144
145 if(pos != ofs)
146 {
147 formatln("; could not seek position %u: %r", ofs, ERRNO_ERROR);
148 return -1;
149 }
150
151 int o = 0;
152
153 for(;;)
154 {
155 int n = read(fd, tmp, sizeof(tmp));
156 if(n < 0)
157 {
158 if(errno != EINTR)
159 {
160 return -1;
161 }
162
163 continue;
164 }
165 if(n == 0)
166 {
167 return -2;
168 }
169
170 for(int i = 0; i < n; ++i)
171 {
172 char c = (char)tmp[i];
173 if(c != PAGE_MAGIC_ARRAY[o])
174 {
175 o = 0;
176 }
177 else
178 {
179 ++o;
180 if(o == 4)
181 {
182 return pos + i - 3;
183 }
184 }
185 }
186
187 pos += n;
188 }
189 }
190
cjf_read_page(int fd,u32 ofs,journal_cjf_page ** out_page)191 static int cjf_read_page(int fd, u32 ofs, journal_cjf_page **out_page)
192 {
193 journal_cjf_page_tbl_header hdr;
194
195 if(cjf_read_page_hdr(fd, ofs, &hdr) > 0)
196 {
197 if(hdr.magic == CJF_PAGE_MAGIC)
198 {
199 formatln("; page @%u=%x", ofs, ofs);
200 formatln("; next: @%u=%x,", hdr.next_page_offset, hdr.next_page_offset);
201 formatln("; end : @%u=%x", hdr.stream_end_offset, hdr.stream_end_offset);
202 formatln("; item: %u/%u", hdr.count, hdr.size);
203
204 if(hdr.size > 0x200)
205 {
206 formatln("; page size is most likely wrong");
207 return -3;
208 }
209
210 if(hdr.count > hdr.size)
211 {
212 formatln("; item count is most likely wrong");
213 return -4;
214 }
215
216 journal_cjf_page *page;
217 MALLOC_OR_DIE(journal_cjf_page*, page, sizeof(journal_cjf_page), GENERIC_TAG);
218 page->hdr = hdr;
219 page->pos = ofs;
220 ssize_t item_size = CJF_SECTION_INDEX_SLOT_SIZE * hdr.size;
221 ssize_t n = readfully(fd, &page->item, item_size);
222 if(n != item_size)
223 {
224 free(page);
225 formatln("; could not read page: expected %lli but got %lli", item_size, n);
226 return -5;
227 }
228
229 u32 e = lseek(fd, 0, SEEK_CUR);
230 u32 l = hdr.stream_end_offset;
231
232 if((hdr.count > 0) && (page->item[0].stream_file_offset != e))
233 {
234 formatln("; page @%u=%x: item[%3i] starts at %u=%x when %u=%x was expected", ofs, ofs, 0, page->item[0].stream_file_offset, page->item[0].stream_file_offset, e, e);
235 }
236
237 for(u16 i = 0; i < hdr.count; ++i)
238 {
239 u32 o = page->item[i].stream_file_offset;
240 /*
241 if(o >= e)
242 {
243 formatln("page @%u=%x: item[%3i] starts at %u=%x when %u=%x was expected", ofs, ofs, i, o, o, e, e);
244 }
245 */
246 if(o > l)
247 {
248 formatln("; page @%u=%x: item[%3i] ends at %u=%x after %u=%x limit", ofs, ofs, i, o, o, l, l);
249 }
250 }
251
252 for(u16 i = 1; i < hdr.count; ++i)
253 {
254 if(serial_ge(page->item[i - 1].ends_with_serial, page->item[i].ends_with_serial))
255 {
256 formatln("; page @%u=%x: item[%3i] serial = %u <= %u", ofs, ofs, i, page->item[i].ends_with_serial, page->item[i - 1].ends_with_serial);
257 }
258 }
259
260 *out_page = page;
261
262 return 1; // page makes sense
263 }
264 else
265 {
266 formatln("; page @%u=%x has wrong magic", ofs, ofs);
267 return -4;
268 }
269 }
270
271 return -5;
272 }
273
cjf_read_page_records(int fd,journal_cjf_page * page)274 static int cjf_read_page_records(int fd, journal_cjf_page *page)
275 {
276 off_t exp = page->pos + JOURNAL_CJF_PAGE_HEADER_SIZE + CJF_SECTION_INDEX_SLOT_SIZE * page->hdr.size;
277 off_t pos = lseek(fd, exp, SEEK_SET);
278
279 if(pos != exp)
280 {
281 return -1;
282 }
283
284 // read all records and match them to the page data
285
286 input_stream fis;
287 input_stream bis;
288 ya_result ret;
289
290 fd_input_stream_attach(&fis, fd);
291 buffer_input_stream_init(&bis, &fis, 4096);
292 dns_resource_record rr;
293 dns_resource_record_init(&rr);
294
295 int soa_count = 0;
296 int line_count = -1;
297 u32 serial;
298 u32 serial_from = 0;
299 u32 serial_to = 0;
300 ya_result return_value = ERROR;
301
302 for(;;)
303 {
304 if((ret = dns_resource_record_read(&rr, &bis)) <= 0)
305 {
306 // no more record (error or end of stream)
307 if(g_dump)
308 {
309 formatln("$");
310 }
311 break;
312 }
313
314 if(soa_count == 0)
315 {
316 if(rr.tctr.qtype != TYPE_SOA)
317 {
318 formatln("; page @%u=%x record stream does not start by an SOA (%{dnsrr})", page->pos, page->pos, &rr);
319 break;
320 }
321 }
322
323 if(line_count >= page->hdr.count)
324 {
325 formatln("; page @%u=%x line %i @%u=%x successfully scanned a record %{dnsrr} outside of line bounds", page->pos, page->pos, line_count, pos, pos, &rr);
326 }
327
328 if(rr.tctr.qtype == TYPE_SOA)
329 {
330 ya_result err = rr_soa_get_serial(rr.rdata, rr.rdata_size, &serial);
331 if(FAIL(err))
332 {
333 formatln("; page @%u=%x line %i @%u=%x could not get serial from first SOA: %r", page->pos, page->pos, line_count, pos, pos, err);
334 break;
335 }
336
337 ++soa_count;
338
339 if((soa_count & 1) != 0)
340 {
341 ++line_count;
342
343 if(line_count < page->hdr.count)
344 {
345 // odd
346 u32 e = page->item[line_count].stream_file_offset;
347
348 if(e != pos)
349 {
350 formatln("; page @%u=%x line %i @%u=%x does not start at the expected position %u=%x", page->pos, page->pos, line_count, pos, pos, e, e);
351 }
352
353 serial_from = serial;
354
355 if(line_count > 0)
356 {
357 if(serial_from != serial_to)
358 {
359 formatln("; page @%u=%x line %i @%u=%x serial %u does not match previous serial %u", page->pos, page->pos, line_count, pos, pos, serial_from, serial_to);
360 }
361 }
362 else
363 {
364 page->serial_from = serial_from;
365 }
366 }
367 else
368 {
369 formatln("; page @%u=%x line %i @%u=%x successfully scanned an SOA %{dnsrr} outside of line bounds", page->pos, page->pos, line_count, pos, pos, &rr);
370 }
371 }
372 else
373 {
374 // even
375
376 serial_to = serial;
377
378 page->serial_to = serial_to;
379
380 if(line_count < page->hdr.count)
381 {
382 return_value = SUCCESS;
383
384 if(serial_ge(serial_from, serial_to))
385 {
386 formatln("; page @%u=%x line %i @%u=%x serial %u not follow previous serial %u", page->pos, page->pos, line_count, pos, pos, serial_from, serial_to);
387 }
388
389 if(serial_to != page->item[line_count].ends_with_serial)
390 {
391 formatln("; page @%u=%x line %i @%u=%x serial %u not end at expected value %u", page->pos, page->pos, line_count, pos, pos, serial_from, serial_to);
392 }
393 }
394 else
395 {
396 formatln("; page @%u=%x line %i @%u=%x successfully scanned an SOA %{dnsrr} outside of line bounds", page->pos, page->pos, line_count, pos, pos, &rr);
397 }
398 }
399 }
400
401 if(g_dump)
402 {
403 rdata_desc rdatadesc={rr.tctr.qtype, rr.rdata_size, rr.rdata};
404
405 formatln("%c | %{dnsname} %i %{dnstype} %{dnsclass} %{rdatadesc}",
406 (soa_count&1)?'-':'+',
407 rr.name,
408 ntohl(rr.tctr.ttl),
409 &rr.tctr.qtype,
410 &rr.tctr.qclass,
411 &rdatadesc);
412
413 // formatln("%c | %{dnsrr}", (soa_count&1)?'-':'+', &rr);
414 }
415
416 pos += ret;
417 }
418
419 page->end = pos;
420
421 formatln("; page @%u=%x streams covering serials %u to %u ended at position %u", page->pos, page->pos, page->serial_from, page->serial_to, page->end);
422
423 dns_resource_record_clear(&rr);
424
425 fd_input_stream_detach(buffer_input_stream_get_filtered(&bis));
426 input_stream_close(&bis);
427
428 return return_value;
429 }
430
431 #define PAGES_MAX 256
432
433 struct journal_cjf_page_tbl_entry
434 {
435 journal_cjf_page_tbl_header hdr;
436 int group;
437 };
438
439 typedef struct journal_cjf_page_tbl_entry journal_cjf_page_tbl_entry;
440
cjf_scan(const char * name)441 static int cjf_scan(const char *name)
442 {
443 int fd;
444 cjf_header hdr;
445
446 fd = open_ex(name, O_RDONLY);
447
448 if(fd < 0)
449 {
450 return -1;
451 }
452
453 formatln("; '%s' opened", name);
454
455 s64 size = filesize(name);
456 if(size <= (s64)CJF_HEADER_REAL_SIZE)
457 {
458 close_ex(fd);
459 return -2;
460 }
461
462 ssize_t n = readfully(fd, &hdr, CJF_HEADER_REAL_SIZE);
463
464 if(n != CJF_HEADER_REAL_SIZE)
465 {
466 close_ex(fd);
467 return -3;
468 }
469
470 if(hdr.magic_plus_version != CJF_CJF0_MAGIC)
471 {
472 close_ex(fd);
473 return -4;
474 }
475
476 formatln("; serial from %u to %u", hdr.serial_begin, hdr.serial_end);
477 formatln("; first page starts at %u", hdr.first_index_offset);
478 formatln("; page index starts at %u", hdr.table_index_offset);
479 formatln("; last SOA starts at %u", hdr.last_soa_offset);
480 formatln("; the last page ends before %u", hdr.last_page_offset_next);
481
482 if(hdr.flags & JOURNAL_CFJ_FLAGS_OTHER_ENDIAN)
483 {
484 println("; other-endian: 1");
485 close_ex(fd);
486 return -5;
487 }
488 if(hdr.flags & JOURNAL_CFJ_FLAGS_MY_ENDIAN)
489 {
490 println("; my-endian: 1");
491 }
492 if(hdr.flags & JOURNAL_CFJ_FLAGS_NOT_EMPTY)
493 {
494 println("; empty: 1");
495 }
496 if(hdr.flags & JOURNAL_CFJ_FLAGS_DIRTY)
497 {
498 println("; dirty: 1");
499 }
500 if(hdr.flags & JOURNAL_CFJ_FLAGS_UNINITIALISED)
501 {
502 println("; not-initialised: 1");
503 }
504
505 // read a page, scan the records.
506
507 u32 page_ofs = CJF_HEADER_REAL_SIZE;
508
509 journal_cjf_page *page;
510
511 for(;;)
512 {
513 if(cjf_read_page(fd, page_ofs, &page) >= 0)
514 {
515 // got a page
516 // scan the records and match them to the page
517
518 if(ISOK(cjf_read_page_records(fd, page)))
519 {
520 page_ofs = page->end;
521 }
522 else
523 {
524 // try to scan page from just after
525 ++page_ofs;
526 }
527 }
528 else
529 {
530 // broken page
531 // try to find the next magic "PAGE" in the file
532
533 int next = cjf_scan_page(fd, page_ofs + 1);
534 if(next > 0)
535 {
536 formatln("; page candidate at %u=%x", next, next);
537 page_ofs = next;
538 }
539 else
540 {
541 formatln("; no more page candidate found");
542 break;
543 }
544 }
545 }
546
547 close_ex(fd);
548
549 return 0;
550 }
551
552 static void
axfr_scan(const char * filename)553 axfr_scan(const char *filename)
554 {
555 input_stream is;
556 ya_result ret;
557
558 dns_resource_record rr;
559
560 if(FAIL(ret = file_input_stream_open(&is, filename)))
561 {
562 formatln("; %s: %r", filename, ret);
563 return;
564 }
565
566 buffer_input_stream_init(&is, &is, 4096);
567
568 dns_resource_record_init(&rr);
569
570 for(int i = 0;; ++i)
571 {
572 if((ret = dns_resource_record_read(&rr, &is)) <= 0)
573 {
574 if(ret < 0)
575 {
576 formatln("; %s: record %i: %r", filename, i, ret);
577 }
578 break;
579 }
580
581 if((rr.tctr.qtype == TYPE_SOA) && (i > 0))
582 {
583 continue;
584 }
585
586 formatln("%{dnszrr}", &rr);
587 }
588
589 dns_resource_record_clear(&rr);
590 }
591
592 static void
jnl_scan(const char * filepath)593 jnl_scan(const char *filepath)
594 {
595 journal *jnl = NULL;
596 const char *filename = strrchr(filepath, '/');
597 input_stream is;
598 size_t filename_len;
599 dns_resource_record rr;
600 dns_resource_record last_soa_rr;
601 ya_result ret;
602 u32 serial_from = 0;
603 u32 serial_to = 0;
604 u32 update_file_index = 0;
605 output_stream fos;
606 bool fos_ready = FALSE;
607
608 u8 origin[MAX_DOMAIN_LENGTH];
609
610 if(filename == NULL)
611 {
612 filename = filepath;
613 }
614 else
615 {
616 ++filename;
617 }
618
619 filename_len = strlen(filename);
620 if(filename_len < 5)
621 {
622 formatln("; jnl: '%s' name is too small to parse", filepath);
623 return;
624 }
625
626 if(FAIL(ret = cstr_to_dnsname_with_check_len(origin, filename, filename_len - 4)))
627 {
628 formatln("; jnl: '%s' cannot be parsed for origin: %r", filepath, ret);
629 return;
630 }
631
632 if(FAIL(ret = journal_jnl_open_file(&jnl, filepath, origin, FALSE)))
633 {
634 formatln("; jnl: '%s' file cannot be opened as a journal: %r", filepath, ret);
635 return;
636 }
637
638 ++jnl->rc;
639
640 if(FAIL(ret = journal_get_serial_range(jnl, &serial_from, &serial_to)))
641 {
642 formatln("; jnl: '%s' file cannot get serial range: %r", filepath, ret);
643 return;
644 }
645
646 dns_resource_record_init(&rr);
647
648 formatln("; jnl: '%s' serial range: %u to %u", filepath, serial_from, serial_to);
649
650 if(FAIL(ret = journal_get_ixfr_stream_at_serial(jnl, serial_from, &is, &rr)))
651 {
652 formatln("; jnl: '%s' file cannot read from its announced first serial %i : %r", filepath, serial_from, ret);
653 return;
654 }
655
656 if(g_clean_mode)
657 {
658 dns_resource_record_init(&last_soa_rr);
659 ret = journal_get_last_soa(jnl, &last_soa_rr);
660 formatln("%{dnsrr}", &last_soa_rr);
661 }
662
663 char mode = '+';
664
665 for(;;)
666 {
667 ret = dns_resource_record_read(&rr, &is);
668
669 if(ret <= 0)
670 {
671 if(FAIL(ret))
672 {
673 formatln("; jnl: '%s' failed to read next record: %r", filepath, ret);
674 }
675 else
676 {
677 formatln("; jnl: '%s' end of file", filepath);
678 }
679
680 break;
681 }
682
683 if(rr.tctr.qtype == TYPE_SOA)
684 {
685 mode ^= ('+'^'-');
686
687 if(g_generate_update_files)
688 {
689 if(mode == '+')
690 {
691 if(fos_ready)
692 {
693 osformatln(&fos, "show\nsend");
694 output_stream_close(&fos);
695 fos_ready = FALSE;
696 }
697 }
698 }
699 }
700
701 if(g_clean_mode)
702 {
703 formatln("%{dnsrr}", &rr);
704 }
705 else
706 {
707 formatln("%c %{dnsrr}", mode, &rr);
708 }
709
710 if(g_generate_update_files)
711 {
712 switch(rr.tctr.qtype)
713 {
714 case TYPE_SOA:
715 case TYPE_NSEC:
716 case TYPE_NSEC3:
717 case TYPE_NSEC3PARAM:
718 {
719 break;
720 }
721 default:
722 {
723 if(mode == '-')
724 {
725 if(rr.tctr.qtype != TYPE_RRSIG)
726 {
727 if(!fos_ready)
728 {
729 char name[280];
730 snformat(name, sizeof(name), "%{dnsname}..update-%08i.txt", origin, update_file_index++);
731 file_output_stream_create(&fos, name, 0644);
732 buffer_output_stream_init(&fos, &fos, 4096);
733 osformatln(&fos, "zone %{dnsname}\nclass IN\nttl 86400", origin);
734 fos_ready = TRUE;
735 }
736
737 osformatln(&fos, "update del %{dnsrr}", &rr);
738 }
739 }
740 else
741 {
742 if((rr.tctr.qtype != TYPE_RRSIG) || ((rr.tctr.qtype == TYPE_RRSIG) && (rrsig_get_type_covered_from_rdata(rr.rdata, rr.rdata_size) == TYPE_DNSKEY)))
743 {
744 if(!fos_ready)
745 {
746 char name[280];
747 snformat(name, sizeof(name), "%{dnsname}..update-%08i.txt", origin, update_file_index++);
748 file_output_stream_create(&fos, name, 0644);
749 buffer_output_stream_init(&fos, &fos, 4096);
750 osformatln(&fos, "zone %{dnsname}\nclass IN\nttl 86400", origin);
751 fos_ready = TRUE;
752 }
753
754 osformatln(&fos, "update add %{dnsrr}", &rr);
755 }
756 }
757
758 break;
759 }
760 }
761 }
762 }
763
764 if(g_clean_mode)
765 {
766 formatln("%{dnsrr}", &last_soa_rr);
767 dns_resource_record_finalize(&last_soa_rr);
768 }
769
770 dns_resource_record_finalize(&rr);
771
772 journal_release(jnl);
773
774 formatln("; jnl: '%s' released", filepath);
775 }
776
777 /*
778 *
779 */
main(int argc,char ** argv)780 int main(int argc, char** argv)
781 {
782 dnscore_init();
783 zdb_init();
784
785 config_logger_setdefault();
786
787 for(int i = 1; i < argc; ++i)
788 {
789 if(strcmp(argv[i], "-dump") == 0)
790 {
791 g_dump = TRUE;
792 continue;
793 }
794
795 if(strcmp(argv[i], "-axfr") == 0)
796 {
797 g_mode = MODE_AXFR;
798 continue;
799 }
800
801 if(strcmp(argv[i], "-cjf") == 0)
802 {
803 g_mode = MODE_CJF;
804 continue;
805 }
806
807 if(strcmp(argv[i], "-jnl") == 0)
808 {
809 g_mode = MODE_JNL;
810 continue;
811 }
812
813 if(strcmp(argv[i], "-clean") == 0)
814 {
815 g_clean_mode= TRUE;
816 continue;
817 }
818
819 if(strcmp(argv[i], "-genupdate") == 0)
820 {
821 g_generate_update_files = TRUE;
822 continue;
823 }
824
825 switch(g_mode)
826 {
827 case MODE_JNL:
828 {
829 formatln("scanning '%s' (jnl)", argv[i]);
830 jnl_scan(argv[i]);
831 break;
832 }
833 case MODE_CJF:
834 {
835 formatln("scanning '%s' (cjf)", argv[i]);
836 cjf_scan(argv[i]);
837 break;
838 }
839 case MODE_AXFR:
840 {
841 axfr_scan(argv[i]);
842 break;
843 }
844 }
845
846 }
847
848 zdb_finalize();
849 dnscore_finalize();
850 return (EXIT_SUCCESS);
851 }
852