1 /*****************************************************************
2 **
3 ** @(#) gen6dns.c (c) Feb 2009 - Nov 2015 by hznet H.Zuleger
4 **
5 *****************************************************************/
6 #include <unistd.h>
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <errno.h>
10 #include <string.h>
11 #include <ctype.h>
12 #include <assert.h>
13 #ifdef HAVE_CONFIG_H
14 # include "config.h"
15 #endif
16 #if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
17 # include <getopt.h>
18 #endif
19
20 #include "debug.h"
21
22 #include "misc.h"
23 #include "ip6.h"
24 #include "hostid.h"
25 #include "subnet.h"
26 #include "scope.h"
27 #include "filep.h"
28 #include "parse.h"
29 #include "squeezev6.h"
30 #include "hostptr.h"
31 #define extern
32 #include "gen6dns.h"
33 #undef extern
34
35 extern int optopt;
36 extern int opterr;
37 extern int optind;
38 extern char *optarg;
39
40 /* option vars */
41 const char *version = VERSION;
42
43 #if MAXFILEP <= MAXSNET
44 # error "The maximum number of file pointers must be larger than the # of subnets\n"
45 # error "(please change MAXFILEP and/or MAXSNET)\n"
46 #endif
47
48 #define BINDCONFIG 0 /* for later version */
49
50 static int revzone = 0;
51
52 #if defined(BINDCONFIG) && BINDCONFIG
53 int bindconfig;
54 const char *multiline;
55 #endif
56
57 #if defined(DYNUPDATE) && DYNUPDATE
58 # if defined(BINDCONFIG) && BINDCONFIG
59 /* don't remove leading ':' (see man getopt_long) */
60 # define short_options ":6:aBdl:C::D::frb:hmo:p:P:RsSt:vVw"
61 # else
62 # define short_options ":6:adl:C::D::frb:ho:p:P:RsSt:vVw"
63 #endif
64 #else
65 # if defined(BINDCONFIG) && BINDCONFIG
66 # define short_options ":6:aBC::D::frb:hmo:p:RsSt:vVw"
67 # else
68 # define short_options ":6:aC::D::frb:ho:p:RsSt:vVw"
69 # endif
70 #endif
71
72 #if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
73 static struct option long_options[] = {
74 { "help", no_argument, NULL, 'h' },
75 { "version", no_argument, NULL, 'V' },
76 { "revzone", no_argument, NULL, 'R' },
77 { "verbose", no_argument, NULL, 'v' },
78 { "comment", optional_argument, NULL, 'C' },
79 { "write", no_argument, NULL, 'w' },
80 { "append", no_argument, NULL, 'a' },
81 #if defined(BINDCONFIG) && BINDCONFIG
82 { "bind-config", no_argument, NULL, 'B' },
83 { "multiline", no_argument, NULL, 'm' },
84 #endif
85 { "forward", no_argument, NULL, 'f' },
86 { "reverse", no_argument, NULL, 'r' },
87 { "bits", required_argument, NULL, 'b' },
88 { "ttl", required_argument, NULL, 't' },
89 { "6to4", required_argument, NULL, '6' },
90 { "origin", required_argument, NULL, 'o' },
91 { "delim", optional_argument, NULL, 'D' },
92 { "prefix", required_argument, NULL, 'p' }, /* lower p */
93 { "prefix-add", required_argument, NULL, 'p' }, /* lower p */
94 { "add-prefix", required_argument, NULL, 'p' }, /* lower p */
95 #if defined(DYNUPDATE) && DYNUPDATE
96 { "prefix-remove", required_argument, NULL, 'P' }, /* upper P */
97 { "prefix-del", required_argument, NULL, 'P' }, /* upper P */
98 { "del-prefix", required_argument, NULL, 'P' }, /* upper P */
99 { "ddns-update", no_argument, NULL, 'd' },
100 { "lookup", required_argument, NULL, 'l' },
101 #endif
102 { "squeeze", no_argument, NULL, 's' },
103 { "full-squeeze", no_argument, NULL, 'S' },
104 };
105 #endif
106
107 /* static function declaration */
108 static void usage (const char *mesg);
109 static int gen_dns (int type, const ip6_t *prfx, const scope_t *scope, const host_t *host, const ip6_t *hid, ip6_t *sid, const char *extra_rr);
110 static int gen_forw_upd (int del, const ip6_t *prfx, const scope_t *scope, const host_t *host, const ip6_t *hid, ip6_t *sid, const char *extra_rr);
111 static int gen_forw_dns (const ip6_t *prfx, const scope_t *scope, const host_t *host, const ip6_t *hid, ip6_t *sid, const char *extra_rr);
112 static int gen_rev_dns (const ip6_t *prfx, const scope_t *scope, const host_t *host, const ip6_t *hid, ip6_t *sid);
113 static int print_forw_upd (FILE *fp, int del, const char *host, const ip6_t *ipv6, long ttl);
114 static int print_forw_dns (FILE *fp, const char *host, const ip6_t *ipv6, long ttl);
115 static int print_rev_dns (FILE *fp, const char *host, const char *origin, const ip6_t *ip, int nibbles, long ttl, unsigned long subnetid);
116 #if defined(BINDCONFIG) && BINDCONFIG
117 static void print_zoneconfig (const char *zone, const char *fname, const char *multiline);
118 #endif
119
main(int argc,char * argv[])120 int main (int argc, char*argv[])
121 {
122 FILE *outfp;
123 int opt_index;
124 int c;
125 char tmpstr[127+1];
126
127 if ( (progname = strrchr (*argv, '/')) == NULL )
128 progname = *argv;
129 else
130 progname++;
131
132 opterr = 0; /* prevent the printing of the getopt() build-in error messages */
133
134 parm.forw = parm.rev = 0;
135 parm.revbits = 0;
136 parm.filemode = 0;
137 #if defined(BINDCONFIG) && BINDCONFIG
138 bindconfig = 0;
139 multiline = "";
140 #endif
141
142 #if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
143 while ( (c = getopt_long (argc, argv, short_options, long_options, &opt_index)) != -1 )
144 #else
145 while ( (c = getopt (argc, argv, short_options)) != -1 )
146 #endif
147 {
148 switch ( c )
149 {
150 case 'V': fprintf (stderr, "%s version %s\n", progname, version);
151 fprintf (stderr, "based on but not compatible with gen6dns v0.3 (c) Feb 2009 - Apr 2010\n");
152 fprintf (stderr, "compiled for a maximum of \n");
153 fprintf (stderr, "\t%5d different prefixes\n", MAXPREFIXES);
154 fprintf (stderr, "\t%5d different scopes\n", MAXSCOPES);
155 fprintf (stderr, "\t%5d subnets\n", MAXSNET);
156 fprintf (stderr, "\t%5d file handles\n", MAXFILEP);
157 exit (0);
158 break;
159 case 'v': parm.verbose++;
160 break;
161 case 'w': parm.filemode = 1;
162 break;
163 case 'a': parm.filemode = 2;
164 break;
165 #if defined(BINDCONFIG) && BINDCONFIG
166 case 'B': bindconfig = 1;
167 break;
168 case 'm': multiline = "\n";
169 break;
170 #endif
171 case 'f': parm.forw = 1;
172 break;
173 case 'r': parm.rev = 1;
174 break;
175 case 'b': parm.revbits = atoi (optarg);
176 if ( parm.revbits < 0 || parm.revbits > 128 )
177 usage ("illegal reverse mask");
178 if ( parm.revbits % 4 != 0 )
179 usage ("Option -b: reverse mask must be on nibble boundary");
180 break;
181 case 'R': revzone = 1;
182 break;
183 case 's': parm.squeeze++;
184 break;
185 case 'S': parm.squeeze = 2;
186 break;
187 case 'h': usage (NULL);
188 break;
189 case 't': ttlfromstr (optarg, &parm.ttl);
190 break;
191 case 'C': if ( optarg )
192 {
193 if ( *optarg == parm.delim || isspace (*optarg))
194 {
195 error ("Option -C \'%c\' would change the comment char to the delimiter char. Option skipped\n", *optarg);
196 }
197 else
198 parm.comment_char = *optarg;
199 }
200 break;
201 case 'D': if ( optarg )
202 parm.delim = *optarg;
203 else
204 parm.delim = ';';
205 break;
206 case 'o': {
207 int len;
208 len = strlen (optarg);
209 parm.origin = malloc (len + 1 + 1);
210 if ( !parm.origin )
211 usage ("out of memory");
212 if ( optarg[len-1] != '.' )
213 snprintf (parm.origin, len+2, "%s.", optarg);
214 else
215 snprintf (parm.origin, len+2, "%s", optarg);
216 }
217 break;
218 case 'p': { /* a prefix to add */
219 ip6_t prfx;
220
221 if ( ip6fromstr (&prfx, optarg) < 0 )
222 usage ("illegal prefix");
223 prfxput (&prfx, 0);
224 }
225 break;
226 case 'P': { /* a prefix to remove */
227 ip6_t prfx;
228
229 if ( *optarg )
230 {
231 if ( ip6fromstr (&prfx, optarg) < 0 )
232 usage ("illegal prefix");
233 prfxput (&prfx, 1);
234 }
235 else
236 prfxput (NULL, 1);
237 }
238 break;
239 case 'd': parm.ddns = 1; /* dynamic update mode ... */
240 parm.forw = 1; /* ... is only defined in forward mode ... */
241 if ( !parm.ttl ) /* ... and needs a ttl */
242 parm.ttl = 86400;
243 break;
244 case 'l': parm.lookup = optarg;
245 break;
246 case '6': {
247 ip6_t prfx;
248 int ip[4];
249
250 if ( sscanf (optarg, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]) != 4 )
251 {
252 snprintf (tmpstr, sizeof (tmpstr), "Illegal ipv4 address %s\n", optarg);
253 usage (tmpstr);
254 }
255 snprintf (tmpstr, sizeof (tmpstr), "2002:%02x%02x:%02x%02x::/48\n",
256 ip[0], ip[1], ip[2], ip[3]);
257 if ( ip6fromstr (&prfx, tmpstr) < 0 )
258 usage ("illegal 6to4 prefix");
259 prfxput (&prfx, 0);
260 }
261 break;
262 case ':': snprintf (tmpstr, sizeof (tmpstr), "option \"-%c\" requires an argument\n", optopt);
263 usage (tmpstr);
264 break;
265 case '?': if ( isprint (optopt) )
266 snprintf (tmpstr, sizeof (tmpstr), "%s: unknown option \"-%c\"\n", progname, optopt);
267 else
268 snprintf (tmpstr, sizeof (tmpstr), "%s: unknown option char \\x%x\n", progname, optopt);
269 usage (tmpstr);
270 break;
271 default: abort();
272 }
273 }
274 argc -= optind;
275 argv += optind;
276
277 if ( revzone ) /* Option -R given ? */
278 {
279 while ( argc-- > 0 )
280 hostptr (parm.revbits, *argv++);
281
282 exit (0);
283 }
284
285 if ( parm.forw == 0 && parm.rev == 0 )
286 parm.forw = parm.rev = 1; /* default is to generate forward and reverse */
287
288 /* some error checking */
289 #if defined(BINDCONFIG) && BINDCONFIG
290 if ( bindconfig && !parm.filemode )
291 usage ("-B is only supported in filemode (-w or -a)");
292 #endif
293
294 if ( parm.rev ) /* check reverse bits for reasonable value */
295 {
296 prfx_t *prf;
297 int prefmask;
298
299 prf = prfxstart ();
300 if ( prf == NULL ) /* no prefix list available */
301 usage ("option -p needed in reverse mode");
302 prefmask = 128;
303 while ( prf )
304 {
305 int pmask;
306
307 pmask = ip6getmask (prf->prfx);
308 prefmask = min (prefmask, pmask);
309 prf = prfxnext ();
310 }
311 dbg_val2 ("revbits = %d; min of prefixmasks %d\n", parm.revbits, prefmask);
312 if ( parm.revbits < prefmask )
313 #if 1
314 parm.revbits = prefmask; /* set it to a reasonable value ... */
315 #else
316 /* ...instead of printing an error message */
317 usage ("reverse mask must be greater or equal than the network prefix");
318 #endif
319 }
320
321 /* open outputfiles if we are in file mode */
322 if ( parm.filemode )
323 {
324 int n;
325
326 n = filep_init (NULL, parm.filemode == 1 ? "w": "a");
327 if ( parm.verbose )
328 fprintf (stderr, "No of concurrent open files is %d while %d files in total can be handled\n", n, MAXFILEP);
329 outfp = NULL;
330 }
331 else
332 outfp = stdout;
333
334 /* loop through file arguments */
335 if ( argc <= 0 )
336 parsefile ("stdin", outfp, gen_dns);
337 else
338 while ( argc-- > 0 )
339 {
340 parsefile (*argv++, outfp, gen_dns);
341 }
342 if ( parm.ddns )
343 {
344 if ( parm.verbose )
345 fprintf (outfp, "debug\n");
346 fprintf (outfp, "send\n");
347 }
348
349
350 if ( parm.filemode )
351 {
352 #if defined(BINDCONFIG) && BINDCONFIG
353 if ( bindconfig )
354 {
355 int i;
356 int eol;
357 long id;
358 char fname[20+1];
359
360 id = -1L;
361 eol = filep_first (&i);
362 while ( !eol )
363 {
364 //snprintf (fname, sizeof (fname), "%0*lx", (parm.revbits - prefmask) / 4, id);
365 print_zoneconfig (filep_getzone (&i), filep_getname (&i), multiline);
366 eol = filep_next (&i);
367 }
368 }
369 #endif
370 filep_close ();
371 }
372
373 return 0;
374 }
375
376 /*****************************************************************
377 ** gendns() generic rr output function
378 *****************************************************************/
gen_dns(int type,const ip6_t * prfx,const scope_t * scope,const host_t * host,const ip6_t * hid,ip6_t * sid,const char * extra_rr)379 static int gen_dns (int type, const ip6_t *prfx, const scope_t *scope, const host_t *host, const ip6_t *hid, ip6_t *sid, const char *extra_rr)
380 {
381 switch ( type )
382 {
383 case 'D': /* dynamic update del */
384 case 'd': /* dynamic update add */
385 return gen_forw_upd (type == 'D', prfx, scope, host, hid, sid, extra_rr);
386 case 'f':
387 return gen_forw_dns (prfx, scope, host, hid, sid, extra_rr);
388 case 'r':
389 return gen_rev_dns (prfx, scope, host, hid, sid);
390 default:
391 fatal ("fatal error: illegal gen_dns type %d\n", type);
392 }
393 /* NOTREACHED */
394 return -1;
395 }
396
397 /*****************************************************************
398 **
399 ** gen_forw_upd ()
400 **
401 ** Generate a forward DNS update request
402 ** address build from "prfx", sid, and hid.
403 ** The scope is used to build the filename to print the AAAA
404 ** record.
405 **
406 *****************************************************************/
gen_forw_upd(int del,const ip6_t * prfx,const scope_t * scope,const host_t * host,const ip6_t * hid,ip6_t * sid,const char * extra_rr)407 static int gen_forw_upd (int del, const ip6_t *prfx, const scope_t *scope, const host_t *host, const ip6_t *hid, ip6_t *sid, const char *extra_rr)
408 {
409 const scope_t *scp;
410 FILE *outfp;
411 ip6_t ipv6;
412 int ret;
413 char fqdn[255+1];
414
415 ip6copy (&ipv6, prfx);
416 ip6setsbit (sid, ip6getebit (&ipv6));
417 ip6append (&ipv6, sid);
418 ip6append (&ipv6, hid);
419
420 if ( scope )
421 scp = scope;
422 else
423 scp = &parm.defscope;
424
425 if ( parm.filemode )
426 {
427 #if 0
428 char fname[MAXFNAME+1];
429
430 /* do we have a view field, and it's not empty or "none" */
431 if ( scp->view && scp->view[0] && strcmp (scp->view, "none") != 0 )
432 snprintf (fname, sizeof (fname), FORW_FILE_VIEW_TMPL,
433 scp->view, scp->domain ? scp->domain: parm.origin);
434 else
435 snprintf (fname, sizeof (fname), FORW_FILE_TMPL,
436 scp->domain ? scp->domain: parm.origin);
437 outfp = filep_open (fname);
438 #else
439 fatal ("Views are actually not supported in dynamic update mode\n");
440 #endif
441 }
442 else
443 outfp = stdout;
444
445 if ( parm.lookup == NULL || strcmp (parm.lookup, host->name) == 0 )
446 {
447 snprintf (fqdn, sizeof (fqdn), "%s.%s", host->name, scp->domain ? scp->domain: parm.origin);
448 ret = print_forw_upd (outfp, del, fqdn, &ipv6, host->ttl ? host->ttl: parm.ttl);
449 if ( extra_rr && *extra_rr )
450 #if 0
451 fprintf (outfp, "%s", extra_rr);
452 #else
453 fatal ("The extra RR records are actually not supported in dynamic update mode\n");
454 #endif
455 }
456 else
457 ret = 1;
458
459 return ret;
460 }
461
print_forw_upd(FILE * fp,int del,const char * host,const ip6_t * ipv6,long ttl)462 static int print_forw_upd (FILE *fp, int del, const char *host, const ip6_t *ipv6, long ttl)
463 {
464 char str[127+1];
465 ip6_t ip;
466
467 fprintf (fp, "update %s ", del ? "del": "add");
468 fprintf (fp, "%s \t", host); /* the label */
469
470 if ( del )
471 fprintf (fp, "\t");
472 else
473 fprintf (fp, "%lu\t", ttl); /* optional ttl */
474
475 ip6copy (&ip, ipv6);
476 ip6tostr (str, sizeof (str), &ip); /* address to string */
477 squeezev6 (str, str, 1);
478
479 fprintf (fp, "IN AAAA %s", str); /* the AAAA record */
480
481 fprintf (fp, "\n");
482
483 return 1;
484 }
485
486 /*****************************************************************
487 **
488 ** gen_forw_dns ()
489 **
490 ** Generate a forward DNS record for "host" with an IPv6
491 ** address build from "prfx", sid, and hid.
492 ** The scope is used to build the filename to print the AAAA
493 ** record.
494 **
495 *****************************************************************/
gen_forw_dns(const ip6_t * prfx,const scope_t * scope,const host_t * host,const ip6_t * hid,ip6_t * sid,const char * extra_rr)496 static int gen_forw_dns (const ip6_t *prfx, const scope_t *scope, const host_t *host, const ip6_t *hid, ip6_t *sid, const char *extra_rr)
497 {
498 const scope_t *scp;
499 FILE *outfp;
500 ip6_t ipv6;
501 int ret;
502 char fname[MAXFNAME+1];
503
504 ip6copy (&ipv6, prfx);
505 ip6setsbit (sid, ip6getebit (&ipv6));
506 ip6append (&ipv6, sid);
507 ip6append (&ipv6, hid);
508
509 if ( scope )
510 scp = scope;
511 else
512 scp = &parm.defscope;
513
514 if ( parm.filemode )
515 {
516 /* do we have a view field, and it's not empty or "none" */
517 if ( scp->view && scp->view[0] && strcmp (scp->view, "none") != 0 )
518 snprintf (fname, sizeof (fname), FORW_FILE_VIEW_TMPL,
519 scp->view, scp->domain ? scp->domain: parm.origin);
520 else
521 snprintf (fname, sizeof (fname), FORW_FILE_TMPL,
522 scp->domain ? scp->domain: parm.origin);
523 outfp = filep_open (fname);
524 }
525 else
526 outfp = stdout;
527
528 ret = print_forw_dns (outfp, host->name, &ipv6, host->ttl ? host->ttl: parm.ttl);
529 if ( extra_rr && *extra_rr )
530 fprintf (outfp, "%s", extra_rr);
531 return ret;
532 }
533
print_forw_dns(FILE * fp,const char * host,const ip6_t * ipv6,long ttl)534 static int print_forw_dns (FILE *fp, const char *host, const ip6_t *ipv6, long ttl)
535 {
536 char str[127+1];
537 ip6_t ip;
538
539 fprintf (fp, "%-21s\t", host); /* the label */
540
541 if ( ttl )
542 fprintf (fp, "%7lu\t", ttl); /* optional ttl */
543 else
544 fprintf (fp, "\t");
545
546 ip6copy (&ip, ipv6);
547 ip6tostr (str, sizeof (str), &ip); /* address to string */
548 if ( parm.squeeze )
549 squeezev6 (str, str, parm.squeeze >= 2);
550
551 fprintf (fp, "IN AAAA\t%s ", str); /* the AAAA record */
552
553 fprintf (fp, "\n");
554
555 return 1;
556 }
557
558 /*****************************************************************
559 **
560 ** gen_rev_dns ()
561 **
562 ** Generate a reverse DNS record for the ipv6 address build
563 ** out of the "prfx", sid and hid.
564 ** The target of the ptr record is "host" plus the origin
565 ** from the scope or from the command line parameter.
566 ** The scope is used to build the filename to print the PTR
567 ** record to.
568 **
569 *****************************************************************/
gen_rev_dns(const ip6_t * prfx,const scope_t * scope,const host_t * host,const ip6_t * hid,ip6_t * sid)570 static int gen_rev_dns (const ip6_t *prfx, const scope_t *scope, const host_t *host, const ip6_t *hid, ip6_t *sid)
571 {
572 int nibbles;
573 int mask_nibbles;
574 int size;
575 int i;
576 FILE *outfp;
577 ip6_t ipv6;
578 unsigned long subnetid;
579 const scope_t *scp;
580 char fname[MAXFNAME+1];
581
582 ip6copy (&ipv6, prfx);
583 ip6setsbit (sid, ip6getebit (&ipv6));
584 ip6append (&ipv6, sid);
585 ip6append (&ipv6, hid);
586
587 if ( scope )
588 scp = scope;
589 else
590 scp = &parm.defscope;
591
592 /* we are looking only for nibbles */
593 nibbles = parm.revbits / 4;
594
595 mask_nibbles = ip6getmask (prfx);
596 assert ( mask_nibbles > 0 );
597 mask_nibbles /= 4;
598 size = nibbles - mask_nibbles; /* size of subnetid in nibbles */
599 if ( size < 0 )
600 size = 0;
601
602 subnetid = 0L; /* which subnet is this ? */
603 i = mask_nibbles; /* start at prefmask nibbles! */
604 while ( i < nibbles )
605 {
606 subnetid += ip6getnibble (&ipv6, i++);
607 if ( i < nibbles )
608 subnetid <<= 4;
609 }
610
611 if ( parm.filemode ) /* in filemode lookup the fp for the reverse file */
612 {
613 /* do we have a view field, and it's not empty or "none" */
614 if ( scp->view && scp->view[0] && strcmp (scp->view, "none") != 0 )
615 snprintf (fname, sizeof (fname), REV_FILE_VIEW_TMPL, scp->view, size, subnetid);
616 else
617 snprintf (fname, sizeof (fname), REV_FILE_TMPL, size, subnetid);
618
619 if ( (outfp = filep_open (fname)) == NULL )
620 fatal ("error in opening reverse outputfile for subnet %0*lx\n", size, subnetid);
621 }
622 else
623 outfp = stdout;
624
625 return print_rev_dns (outfp, host->name, scp->domain ? scp->domain: parm.origin,
626 &ipv6, nibbles, host->ttl ? host->ttl : parm.ttl, subnetid);
627 }
628
print_rev_dns(FILE * fp,const char * host,const char * origin,const ip6_t * ip,int nibbles,long ttl,unsigned long subnetid)629 static int print_rev_dns (FILE *fp, const char *host, const char *origin, const ip6_t *ip, int nibbles, long ttl, unsigned long subnetid)
630 {
631 int i;
632
633 assert ( fp != NULL );
634 assert ( host != NULL );
635 assert ( origin != NULL );
636 assert ( ip != NULL && ip6isset (ip) );
637
638 /* for a PTR record the label is a subdomain for each nibble. */
639 /* print out nibbles starting with the right most one */
640 i = 32;
641 while ( i-- > nibbles )
642 fprintf (fp, "%01x%c", ip6getnibble (ip, i), i > nibbles ? '.': ' ');
643 fprintf (fp, " ");
644
645 if ( ttl )
646 fprintf (fp, "%7lu ", ttl); /* optional the ttl */
647 else
648 fprintf (fp, "%7s ", "");
649
650 fprintf (fp, "IN PTR\t%s.%s ", host, origin); /* the PTR record */
651 if ( subnetid )
652 fprintf (fp, "; subnetid: %0*lx", 4, subnetid); /* comment indicating which subnet this PTR is in */
653 fprintf (fp, "\n");
654
655 return 1;
656 }
657
658 #if defined(BINDCONFIG) && BINDCONFIG
print_zoneconfig(const char * zone,const char * fname,const char * multiline)659 void print_zoneconfig (const char *zone, const char *fname, const char *multiline)
660 {
661 printf ("zone \"%s\" IN {%s", zone, multiline);
662 printf ("\ttype master;%s", multiline);
663 printf ("\tfile \"%s\";\t%s", fname, multiline);
664 printf ("};\n");
665 }
666 #endif
667
668 #if defined(BINDCONFIG) && BINDCONFIG
669 # define bconfigstr " [-B [-m]]"
670 #else
671 # define bconfigstr ""
672 #endif
673 #define pdconfigstr "{-p prefix} {-P prefix}"
674 #define pconfigstr "{-p prefix |-6 ipv4addr }"
usage(const char * mesg)675 static void usage (const char *mesg)
676 {
677 char str[127+1];
678
679 if ( mesg && *mesg )
680 {
681 fprintf (stderr, "%s error: ", progname);
682 fprintf (stderr, "%s\n", mesg);
683 fprintf (stderr, "\n");
684 }
685 fprintf (stderr, "usage: %s -h|-V\n", progname);
686 fprintf (stderr, "usage: %s -R [-b mask] <prefix>|<hostname> [...]\n", progname);
687 fprintf (stderr, "usage: %s [-f] [-s|-S] [-w|-a" bconfigstr "] [-t ttl] [-D<char>] [-C<char>] " pconfigstr " [file ...]\n", progname);
688 fprintf (stderr, "usage: %s [-r] [-b mask] [-w|-a" bconfigstr "] [-t ttl] [-D<char>] [-C<char>] [-o origin] " pconfigstr " [file ...]\n", progname);
689 #if defined(DYNUPDATE) && DYNUPDATE
690 fprintf (stderr, "usage: %s -d [-l label] [-t ttl] [-D<char>] [-C<char>] [-o origin] " pdconfigstr " [file ...]\n", progname);
691 #endif
692 fprintf (stderr, "\t-h, --help\t\t print out this help message \n");
693 fprintf (stderr, "\t-V, --version\t\t print out version and exit \n");
694 fprintf (stderr, "\t-R, --revzone\t\t print the ip6.arpa zone of the given prefix \n");
695 fprintf (stderr, "\t-v, --verbose\t\t give some hints about what's going on in the background \n");
696 fprintf (stderr, "\t\t\t\t use -v more often to increase the verbosity (up to level 2)\n");
697 fprintf (stderr, "\t-D, --delim[=char]\t use <char> additionally to white space as delimiter (default is ';')\n");
698 fprintf (stderr, "\t-C, --comment[=char]\t use <char> as comment character (default is '#')\n");
699 fprintf (stderr, "\t-s, --squeeze\t\t print ipv6 addresses w/o leading zeros (like 2001:db8:0:0:0:0:0:1/128)\n");
700 fprintf (stderr, "\t-S, --full-squeeze\t compress ipv6 address slightly more (like 2001:db8::1/128)\n");
701 fprintf (stderr, "\t-t, --ttl <ttlspec>\t specify ttl of RR (default is none or the host specific one)\n");
702 fprintf (stderr, "\t\t\t\t known ttl units are s(ecs), m(ins), h(ours), d(ays) or w(eeks) \n");
703 #if defined(DYNUPDATE) && DYNUPDATE
704 fprintf (stderr, "\t-d, --ddns-update\t print dynamic update messages to stdout (this implies -f) \n");
705 fprintf (stderr, "\t-l, --lookup=label\t The update add/del is done only for the host matching \"label\" \n");
706 #endif
707 fprintf (stderr, "\t-f, --forward\t\t generate AAAA records for forward zone only \n");
708 fprintf (stderr, "\t-r, --reverse\t\t generate PTR records for reverse zone only\n");
709 fprintf (stderr, "\t\t\t\t The default is to generate forward and reverse zone entries\n");
710 fprintf (stderr, "\t\t\t\t (The use of the -w switch is highly recommended then)\n");
711 fprintf (stderr, "\t-b, --bits[=mask]\t split zone files on <mask> boundary (default is prefix size)\n");
712 //fprintf (stderr, "\n sizeof str = %lu\n", sizeof (str));
713 fprintf (stderr, "\t-w, --write\t\t write output to file instead of stdout\n");
714 snprintf (str, sizeof (str), FORW_FILE_TMPL, "<origin>");
715 fprintf (stderr, "\t\t\t\t filename is %s for the forward or ", str);
716 snprintf (str, sizeof (str), REV_FILE_TMPL, 4, 0L);
717 fprintf (stderr, "%s for the reverse zone\n", str);
718 //fprintf (stderr, "\t\t\t\t %s for the reverse zones\n", str);
719 fprintf (stderr, "\t\t\t\t This option potentially generates a lot of files (up to the\n");
720 fprintf (stderr, "\t\t\t\t compiled in # of %d)\n", MAXFILEP);
721 fprintf (stderr, "\t-a, --append\t\t same as -w but append to file instead of overwriting \n");
722 fprintf (stderr, "\t-o, --origin=zone\t specify forward domain (default is %s)\n", parm.origin);
723 fprintf (stderr, "\t-p, --add-prefix=prefix\t network prefix to add (default is %s)\n", DEF_PREFIX);
724 #if defined(DYNUPDATE) && DYNUPDATE
725 fprintf (stderr, "\t-P, --del-prefix=prefix\t network prefix to delete (default is none)\n");
726 #endif
727 fprintf (stderr, "\t-6, --6to4=ipv4\t\t same as -p but argument is an ipv4 address\n");
728 fprintf (stderr, "\t\t\t\t resulting prefix is a 6to4 prefix (2002:ipv4:addr::/48)\n");
729
730 exit (0);
731 }
732