Blob


1 /*
2 * Copyright (c) 2014 Peter J. Philipp. All rights reserved.
3 * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
4 * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
5 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
6 * Copyright (c) 2001 Markus Friedl. All rights reserved.
7 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
8 * Copyright (c) 2001 Theo de Raadt. All rights reserved.
9 *
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 */
23 %{
24 #include "include.h"
25 #include "dns.h"
26 #include "db.h"
29 extern void dolog(int, char *, ...);
30 extern char *dns_label(char *, int *);
31 extern u_int8_t find_region(struct sockaddr_storage *, int);
32 extern int insert_region(char *, char *, u_int8_t);
33 extern int insert_axfr(char *, char *);
34 extern int insert_notifyslave(char *, char *);
35 extern int insert_filter(char *, char *);
36 extern int insert_recurse(char *, char *);
37 extern int insert_whitelist(char *, char *);
38 extern int insert_wildcard(char *, char *);
39 extern void slave_shutdown(void);
40 void yyerror(const char *);
42 extern int whitelist;
43 extern int notify;
44 extern int errno;
45 extern int debug;
46 extern int verbose;
47 extern int bflag;
48 extern int iflag;
49 extern int lflag;
50 extern int nflag;
51 extern int rflag;
52 extern int bcount;
53 extern int icount;
54 extern int ratelimit;
55 extern int ratelimit_packets_per_second;
56 extern u_int16_t port;
57 extern u_int32_t cachesize;
58 extern char *bind_list[255];
59 extern char *interface_list[255];
63 TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
64 static struct file {
65 TAILQ_ENTRY(file) entry;
66 FILE *stream;
67 char *name;
68 int lineno;
69 int errors;
70 } *file, *topfile;
72 #define STATE_IP 1
73 #define STATE_ZONE 2
75 #define WILDCARDVERSION 6
77 #define CONFIG_START 0x1
78 #define CONFIG_VERSION 0x2
79 #define CONFIG_REGION 0x4
80 #define CONFIG_ZONE 0x8
81 #define CONFIG_INCLUDE 0x10
82 #define CONFIG_WILDCARDONLYFOR 0x20
83 #define CONFIG_RECURSEFOR 0x40
84 #define CONFIG_LOGGING 0x80
85 #define CONFIG_AXFRFOR 0x100
86 #define CONFIG_AXFRPORT 0x200
88 typedef struct {
89 union {
90 char *string;
91 int intval;
92 } v;
93 int lineno;
94 } YYSTYPE;
96 #ifdef __APPLE__
97 #define YYSTYPE_IS_DECLARED 1
98 #endif
100 static const char rcsid[] = "$Id: parse.y,v 1.25 2014/11/07 10:33:12 pjp Exp $";
101 static int version = 0;
102 static int state = 0;
103 static uint8_t region = 0;
104 static uint64_t confstatus = 0;
105 static DB *mydb;
107 YYSTYPE yylval;
110 char *converted_name;
111 int converted_namelen;
112 DBT key, data;
113 struct logging logging;
114 int axfrport = 0;
115 time_t time_changed;
119 char *check_rr(char *, char *, int, int *);
120 int fill_a(char *, char *, int, char *);
121 int fill_aaaa(char *, char *, int, char *);
122 int fill_balance(char *, char *, int, char *);
123 int fill_ptr(char *, char *, int, char *);
124 int fill_cname(char *, char *, int, char *);
125 int fill_mx(char *, char *, int, int, char *);
126 int fill_naptr(char *, char *, int, int, int, char *, char *, char *, char *);
127 int fill_ns(char *, char *, int, char *);
128 int fill_soa(char *, char *, int, char *, char *, int, int, int, int, int);
129 int fill_spf(char *, char *, int, char *);
130 int fill_sshfp(char *, char *, int, int, int, char *);
131 int fill_srv(char *, char *, int, int, int, int, char *);
132 int fill_txt(char *, char *, int, char *);
133 int findeol(void);
134 int get_ip(char *, int);
135 char *get_prefixlen(char *, char *, int);
136 int get_quotedstring(char *, int);
137 int get_record(struct domain *, char *, int);
138 int get_string(char *, int);
139 int lgetc(int);
140 struct tab * lookup(struct tab *, char *);
141 int lungetc(int);
142 int parse_file(DB *, char *);
143 struct file *pushfile(const char *, int);
144 int popfile(void);
145 struct rrtab *rrlookup(struct rrtab *, char *);
146 void set_record(struct domain *, char *, int);
147 static int temp_inet_net_pton_ipv6(const char *, void *, size_t);
148 int yyparse(void);
151 struct rrtab {
152 char *name;
153 u_int16_t type;
154 } myrrtab[] = {
155 { "a", DNS_TYPE_A } ,
156 { "soa", DNS_TYPE_SOA },
157 { "cname", DNS_TYPE_CNAME },
158 { "ptr", DNS_TYPE_PTR },
159 { "mx", DNS_TYPE_MX },
160 { "aaaa", DNS_TYPE_AAAA },
161 { "ns", DNS_TYPE_NS },
162 { "txt", DNS_TYPE_TXT },
163 { "hint", DNS_TYPE_HINT },
164 { "delegate", DNS_TYPE_DELEGATE },
165 { "balance", DNS_TYPE_BALANCE },
166 { "srv", DNS_TYPE_SRV },
167 { "spf", DNS_TYPE_SPF },
168 { "sshfp", DNS_TYPE_SSHFP },
169 { "naptr", DNS_TYPE_NAPTR },
170 { NULL, 0 },
171 };
176 %}
179 %token VERSION OBRACE EBRACE REGION AXFRFOR RECURSEFOR
180 %token DOT COLON TEXT WOF INCLUDE ZONE COMMA CRLF
181 %token ERROR AXFRPORT LOGGING OPTIONS FILTER NOTIFY
182 %token WHITELIST
184 %token <v.string> POUND
185 %token <v.string> SEMICOLON
186 %token <v.string> STRING
187 %token <v.string> IP
188 %token <v.string> IPV6
189 %token <v.string> SLASH
190 %token <v.string> QUOTEDSTRING
192 %token <v.intval> NUMBER
194 %type <v.string> quotednumber quotedfilename ipcidr
196 %start cmd_list
198 %%
199 cmd_list:
200 | cmd_list cmd
203 cmd :
204 version
205 | axfrport
206 | include
207 | zone
208 | region CRLF
209 | wof CRLF
210 | axfr CRLF
211 | notify CRLF
212 | whitelist CRLF
213 | filter CRLF
214 | recurse CRLF
215 | logging
216 | comment CRLF
217 | options
221 comment:
222 comment comments
223 | comments
226 comments:
227 SEMICOLON
228 | POUND
231 version:
232 VERSION quotednumber SEMICOLON CRLF
234 version = atoi($2);
235 if (version != WILDCARDVERSION) {
236 dolog(LOG_ERR, "version of configfile is wrong,"
237 " must be \"%d\"!\n", WILDCARDVERSION);
238 return (-1);
240 free ($2);
242 confstatus |= CONFIG_VERSION;
246 axfrport:
247 AXFRPORT quotednumber SEMICOLON CRLF
249 if ((confstatus & CONFIG_VERSION) != CONFIG_VERSION) {
250 dolog(LOG_INFO, "There must be a version at the top of the first configfile\n");
251 return (-1);
254 axfrport = atoi($2);
255 free ($2);
259 quotednumber:
260 QUOTEDSTRING
262 if (debug)
263 printf("quotednumber is %s\n", $$);
267 include:
268 includes CRLF
271 includes:
272 INCLUDE quotedfilename SEMICOLON {
273 struct file *nfile;
275 if ((confstatus & CONFIG_VERSION) != CONFIG_VERSION) {
276 dolog(LOG_INFO, "There must be a version at the top of the first configfile\n");
277 return (-1);
280 if ((nfile = pushfile($2, 0)) == NULL) {
281 fprintf(stderr, "failed to include file %s\n", $2);
282 free($2);
283 return (-1);
286 free($2);
288 file = nfile;
292 quotedfilename:
293 QUOTEDSTRING
295 if (debug)
296 printf("quotedfilename is %s\n", $$);
300 /* zone */
302 zone:
303 ZONE zonelabel zonecontent
305 if ((confstatus & CONFIG_VERSION) != CONFIG_VERSION) {
306 dolog(LOG_INFO, "There must be a version at the top of the first configfile\n");
307 return (-1);
312 zonelabel:
313 QUOTEDSTRING
316 zonecontent:
317 OBRACE zonestatements EBRACE CRLF
318 | OBRACE CRLF zonestatements EBRACE CRLF
322 zonestatements :
323 zonestatements zonestatement
324 | zonestatement
328 zonestatement:
330 /* centroid.eu,soa,3600,uranus.centroid.eu.,pjp.solarscale.de.,1258740680,3600,1800,7200,3600 */
332 STRING COMMA STRING COMMA NUMBER COMMA STRING COMMA STRING COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER CRLF
334 if (strcasecmp($3, "soa") == 0) {
335 if (fill_soa($1, $3, $5, $7, $9, $11, $13, $15, $17, $19) < 0) {
336 return -1;
339 if (debug)
340 printf("%s SOA\n", $1);
341 } else {
342 if (debug)
343 printf("soa error\n");
344 return -1;
348 free ($1);
349 free ($3);
350 free ($7);
351 free ($9);
354 STRING COMMA STRING COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA QUOTEDSTRING CRLF
356 if (strcasecmp($3, "sshfp") == 0) {
357 if (fill_sshfp($1, $3, $5, $7, $9, $11) < 0) {
358 return -1;
361 } else {
362 if (debug)
363 printf("another sshfp record I don't know about?");
364 return (-1);
367 free ($1);
368 free ($3);
369 free ($11);
372 STRING COMMA STRING COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA STRING CRLF
374 if (strcasecmp($3, "srv") == 0) {
375 if (fill_srv($1, $3, $5, $7, $9, $11, $13) < 0) {
376 return -1;
379 } else {
380 if (debug)
381 printf("2 another record I don't know about?");
382 return (-1);
385 free ($1);
386 free ($3);
387 free ($13);
390 STRING COMMA STRING COMMA NUMBER COMMA STRING CRLF {
391 if (strcasecmp($3, "ns") == 0 ||
392 strcasecmp($3, "delegate") == 0 ||
393 strcasecmp($3, "hint") == 0) {
394 if (fill_ns($1, $3, $5, $7) < 0) {
395 return -1;
398 if (debug)
399 printf("%s NS\n", $1);
401 } else if (strcasecmp($3, "ptr") == 0) {
402 if (fill_ptr($1, $3, $5, $7) < 0) {
403 return -1;
406 if (debug)
407 printf("%s PTR\n", $1);
409 } else if (strcasecmp($3, "cname") == 0) {
410 if (fill_cname($1, $3, $5, $7) < 0) {
411 return -1;
414 if (debug)
415 printf("%s CNAME\n", $3);
417 } else {
418 if (debug)
419 printf("%s other\n", $3);
420 return -1;
423 free ($1);
424 free ($3);
425 free ($7);
428 STRING COMMA STRING COMMA NUMBER COMMA IPV6 CRLF {
429 if (strcasecmp($3, "aaaa") == 0) {
430 if (fill_aaaa($1, $3, $5, $7) < 0) {
431 return -1;
434 if (debug)
435 printf("%s AAAA\n", $1);
436 } else {
438 if (debug)
439 printf("error AAAA\n");
440 return (-1);
442 free ($1);
443 free ($3);
444 free ($7);
447 STRING COMMA STRING COMMA NUMBER COMMA IP CRLF
449 if (strcasecmp($3, "a") == 0) {
450 if (fill_a($1, $3, $5, $7) < 0) {
451 return -1;
454 if (debug)
455 printf("%s A\n", $1);
457 } else if (strcasecmp($3, "balance") == 0) {
458 if (fill_balance($1, $3, $5, $7) < 0) {
459 return -1;
462 if (debug)
463 printf("a balance record?\n");
464 } else {
465 if (debug)
466 printf("another a record?\n");
467 return -1;
470 free ($1);
471 free ($3);
472 free ($7);
475 STRING COMMA STRING COMMA NUMBER COMMA NUMBER COMMA STRING CRLF
477 if (strcasecmp($3, "mx") == 0) {
478 if (fill_mx($1, $3, $5, $7, $9) < 0) {
479 return -1;
482 if (debug)
483 printf("%s MX -> %d %s\n", $1, $7, $9);
485 } else {
486 if (debug)
487 printf("another record I don't know about?");
488 return (-1);
491 free ($1);
492 free ($3);
493 free ($9);
496 STRING COMMA STRING COMMA NUMBER COMMA QUOTEDSTRING CRLF
498 if (strcasecmp($3, "txt") == 0) {
499 if (fill_txt($1, $3, $5, $7) < 0) {
500 return -1;
503 if (debug)
504 printf(" %s TXT -> %s\n", $1, $7);
505 } else if (strcasecmp($3, "spf") == 0) {
506 if (fill_spf($1, $3, $5, $7) < 0) {
507 return -1;
510 if (debug)
511 printf(" %s SPF -> %s\n", $1, $7);
512 } else {
513 if (debug)
514 printf("another txt/spf like record I don't know?\n");
515 return (-1);
518 free ($1);
519 free ($3);
520 free ($7);
523 STRING COMMA STRING COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA QUOTEDSTRING COMMA QUOTEDSTRING COMMA QUOTEDSTRING COMMA STRING CRLF
525 if (strcasecmp($3, "naptr") == 0) {
526 if (fill_naptr($1, $3, $5, $7, $9, $11, $13, $15, $17) < 0) {
527 return -1;
530 if (debug)
531 printf(" %s NAPTR\n", $1);
532 } else {
533 if (debug)
534 printf("another naptr like record I don't know?\n");
535 return (-1);
538 free ($1);
539 free ($3);
540 free ($11);
541 free ($13);
542 free ($15);
543 free ($17);
545 | comment CRLF
549 options:
550 OPTIONS optionslabel optionscontent
552 if ((confstatus & CONFIG_VERSION) != CONFIG_VERSION) {
553 dolog(LOG_INFO, "There must be a version at the top of the first configfile\n");
554 return (-1);
559 optionslabel:
560 QUOTEDSTRING
563 optionscontent:
564 OBRACE optionsstatements EBRACE CRLF
565 | OBRACE CRLF optionsstatements EBRACE CRLF
568 optionsstatements:
569 optionsstatement
570 | optionsstatements optionsstatement
573 optionsstatement:
575 STRING SEMICOLON CRLF
577 if (strcasecmp($1, "recurse") == 0) {
578 dolog(LOG_DEBUG, "recursive server on\n");
579 rflag = 0; /* keep it off please! */
580 } else if (strcasecmp($1, "log") == 0) {
581 dolog(LOG_DEBUG, "logging on\n");
582 lflag = 1;
586 STRING QUOTEDSTRING SEMICOLON CRLF
588 if (strcasecmp($1, "interface") == 0) {
589 iflag = 1;
590 if (icount > 253) {
591 dolog(LOG_ERR, "too many interface keywords in options\n");
592 return (-1);
595 dolog(LOG_DEBUG, "interface \"%s\" added\n", $2);
596 interface_list[icount++] = $2;
601 STRING NUMBER SEMICOLON CRLF
603 if (strcasecmp($1, "fork") == 0) {
604 dolog(LOG_DEBUG, "forking %d times\n", $2);
605 nflag = $2;
606 } else if (strcasecmp($1, "port") == 0) {
607 port = $2 & 0xffff;
608 dolog(LOG_DEBUG, "listening on port %d\n", port);
609 } else if (strcasecmp($1, "ratelimit-pps") == 0) {
610 if ($2 > 127 || $2 < 1) {
611 dolog(LOG_ERR, "ratelimit packets per second must be between 1 and 127, or leave it off!\n");
612 return -1;
614 ratelimit = 1;
615 ratelimit_packets_per_second = $2;
616 dolog(LOG_DEBUG, "ratelimiting to %d packets per second", ratelimit_packets_per_second);
621 STRING ipcidr SEMICOLON CRLF
623 if (strcasecmp($1, "bind") == 0) {
624 bflag = 1;
625 if (bcount > 253) {
626 dolog(LOG_ERR, "too many bind keywords in options\n");
627 return (-1);
629 dolog(LOG_DEBUG, "binding to %s\n", $2);
630 bind_list[bcount++] = $2;
634 | comment CRLF
637 /* logging below */
639 logging:
640 LOGGING logginglabel loggingcontent
642 if ((confstatus & CONFIG_VERSION) != CONFIG_VERSION) {
643 dolog(LOG_INFO, "There must be a version at the top of the first configfile\n");
644 return (-1);
649 logginglabel:
650 QUOTEDSTRING
653 loggingcontent:
654 OBRACE loggingstatements EBRACE CRLF
655 | OBRACE CRLF loggingstatements EBRACE CRLF
658 loggingstatements:
659 loggingstatement CRLF
660 | loggingstatements loggingstatement CRLF
663 loggingstatement:
664 STRING STRING SEMICOLON
666 char buf[512];
668 if (strcasecmp($1, "logbind") == 0) {
669 logging.active = 1;
670 logging.bind = 0;
672 gethostname(buf, sizeof(buf));
673 logging.hostname = strdup(buf);
674 if (logging.hostname == NULL) {
675 dolog(LOG_ERR, "strdup failed\n");
676 return (-1);
679 if (strcmp($2, "yes") == 0) {
680 logging.bind = 1;
682 } else if (strcasecmp($1, "logpasswd") == 0) {
684 logging.logpasswd = strdup($2);
686 if (logging.logpasswd == NULL) {
687 dolog(LOG_ERR, "strdup failed\n");
688 return (-1);
691 } else {
692 if (debug)
693 printf("another logging statement I don't know?\n");
694 return (-1);
699 STRING NUMBER SEMICOLON
701 char buf[16];
703 if (strcasecmp($1, "logport") == 0) {
704 snprintf(buf, sizeof(buf), "%d", $2);
705 logging.logport = strdup(buf);
706 if (logging.logport == NULL) {
707 dolog(LOG_ERR, "strdup failed\n");
708 return (-1);
710 logging.logport2 = $2;
714 STRING ipcidr SEMICOLON
716 struct addrinfo hints, *res0;
717 struct sockaddr_in6 *psin6;
718 struct sockaddr_in *psin;
719 int error;
721 if (strcasecmp($1, "loghost") == 0) {
722 logging.loghost = strdup($2);
723 if (logging.loghost == NULL) {
724 dolog(LOG_ERR, "strdup failed\n");
726 return (-1);
729 if (strchr($2, ':') != NULL) {
730 memset(&hints, 0, sizeof(hints));
731 hints.ai_family = AF_INET6;
732 hints.ai_socktype = SOCK_STREAM;
733 hints.ai_flags = AI_NUMERICHOST;
735 error = getaddrinfo($2, "www", &hints, &res0);
736 if (error) {
737 dolog(LOG_ERR, "%s line %d: %s\n",
738 file->name, file->lineno,
739 gai_strerror(error));
741 return (-1);
744 if (res0 == NULL) {
745 dolog(LOG_ERR, "%s line %d: could not"
746 " determine IPv6 address\n"
747 , file->name, file->lineno);
748 return (-1);
751 psin6 = (struct sockaddr_in6 *)&logging.loghost2;
752 psin6->sin6_family = res0->ai_family;
753 memcpy(psin6, res0->ai_addr, res0->ai_addrlen);
754 freeaddrinfo(res0);
755 } else {
756 memset(&hints, 0, sizeof(hints));
758 hints.ai_family = AF_INET;
759 hints.ai_socktype = SOCK_STREAM;
760 hints.ai_flags = AI_NUMERICHOST;
762 error = getaddrinfo($2, "www", &hints, &res0);
763 if (error) {
764 dolog(LOG_ERR, "%s line %d: %s\n",
765 file->name, file->lineno,
766 gai_strerror(error));
768 return (-1);
771 if (res0 == NULL) {
772 dolog(LOG_ERR, "%s line %d: could not"
773 " determine IPv6 address\n"
774 , file->name, file->lineno);
775 return (-1);
778 psin = (struct sockaddr_in *)&logging.loghost2;
779 psin->sin_family = res0->ai_family;
780 memcpy(psin, res0->ai_addr, res0->ai_addrlen);
782 freeaddrinfo(res0);
784 } else {
785 if (debug)
786 printf("2 another logging statement I don't know?\n");
787 return (-1);
790 | comment CRLF
793 /* whitelist "these hosts" { .. } */
795 whitelist:
796 WHITELIST whitelistlabel whitelistcontent
798 if ((confstatus & CONFIG_VERSION) != CONFIG_VERSION) {
799 dolog(LOG_INFO, "There must be a version at the top of the first configfile\n");
800 return (-1);
805 whitelistlabel:
806 QUOTEDSTRING
809 whitelistcontent:
810 OBRACE whiteliststatements EBRACE
811 | OBRACE CRLF whiteliststatements EBRACE
814 whiteliststatements :
815 whiteliststatements whiteliststatement
816 | whiteliststatement
819 whiteliststatement : ipcidr SEMICOLON CRLF
821 char prefixlength[INET_ADDRSTRLEN];
822 char *dst;
825 if ((dst = get_prefixlen($1, (char *)&prefixlength, sizeof(prefixlength))) == NULL) {
826 return (-1);
829 if (insert_whitelist(dst, prefixlength) < 0) {
830 dolog(LOG_ERR, "insert_whitelist, line %d\n", file->lineno);
831 return (-1);
834 if (debug)
835 printf("recurse inserted %s address\n", $1);
837 whitelist = 1;
839 free (dst);
840 free ($1);
842 | comment CRLF
845 /* filter "these hosts" { .. } */
847 filter:
848 FILTER filterlabel filtercontent
850 if ((confstatus & CONFIG_VERSION) != CONFIG_VERSION) {
851 dolog(LOG_INFO, "There must be a version at the top of the first configfile\n");
852 return (-1);
857 filterlabel:
858 QUOTEDSTRING
861 filtercontent:
862 OBRACE filterstatements EBRACE
863 | OBRACE CRLF filterstatements EBRACE
866 filterstatements :
867 filterstatements filterstatement
868 | filterstatement
871 filterstatement : ipcidr SEMICOLON CRLF
873 char prefixlength[INET_ADDRSTRLEN];
874 char *dst;
877 if ((dst = get_prefixlen($1, (char *)&prefixlength, sizeof(prefixlength))) == NULL) {
878 return (-1);
881 if (insert_filter(dst, prefixlength) < 0) {
882 dolog(LOG_ERR, "insert_filter, line %d\n", file->lineno);
883 return (-1);
886 if (debug)
887 printf("recurse inserted %s address\n", $1);
889 free (dst);
890 free ($1);
892 | comment CRLF
896 /* notify "these hosts" { .. } */
898 notify:
899 NOTIFY notifylabel notifycontent
901 if ((confstatus & CONFIG_VERSION) != CONFIG_VERSION) {
902 dolog(LOG_INFO, "There must be a version at the top of the first configfile\n");
903 return (-1);
908 notifylabel:
909 QUOTEDSTRING
912 notifycontent:
913 OBRACE notifystatements EBRACE
914 | OBRACE CRLF notifystatements EBRACE
917 notifystatements :
918 notifystatements notifystatement
919 | notifystatement
922 notifystatement : ipcidr SEMICOLON CRLF
924 char prefixlength[INET_ADDRSTRLEN];
925 char *dst;
928 if ((dst = get_prefixlen($1, (char *)&prefixlength, sizeof(prefixlength))) == NULL) {
929 return (-1);
932 if (insert_notifyslave(dst, prefixlength) < 0) {
933 dolog(LOG_ERR, "insert_notifyslave, line %d\n", file->lineno);
934 return (-1);
937 notify++;
939 free (dst);
940 free ($1);
942 | comment CRLF
945 /* axfr-for "these hosts" { .. } */
947 axfr:
948 AXFRFOR axfrlabel axfrcontent
950 if ((confstatus & CONFIG_VERSION) != CONFIG_VERSION) {
951 dolog(LOG_INFO, "There must be a version at the top of the first configfile\n");
952 return (-1);
957 axfrlabel:
958 QUOTEDSTRING
961 axfrcontent:
962 OBRACE axfrstatements EBRACE
963 | OBRACE CRLF axfrstatements EBRACE
966 axfrstatements :
967 axfrstatements axfrstatement
968 | axfrstatement
971 axfrstatement : ipcidr SEMICOLON CRLF
973 char prefixlength[INET_ADDRSTRLEN];
974 char *dst;
977 if ((dst = get_prefixlen($1, (char *)&prefixlength, sizeof(prefixlength))) == NULL) {
978 return (-1);
981 if (insert_axfr(dst, prefixlength) < 0) {
982 dolog(LOG_ERR, "insert_axfr, line %d\n", file->lineno);
983 return (-1);
986 if (debug)
987 printf("recurse inserted %s address\n", $1);
989 free (dst);
990 free ($1);
992 | comment CRLF
995 /* recurse-for "these hosts" { .. } */
997 recurse:
998 RECURSEFOR recurselabel recursecontent
1000 if ((confstatus & CONFIG_VERSION) != CONFIG_VERSION) {
1001 dolog(LOG_INFO, "There must be a version at the top of the first configfile\n");
1002 return (-1);
1007 recurselabel:
1008 QUOTEDSTRING
1011 recursecontent:
1012 OBRACE recursestatements EBRACE
1013 | OBRACE CRLF recursestatements EBRACE
1016 recursestatements :
1017 recursestatements recursestatement
1018 | recursestatement
1021 recursestatement : ipcidr SEMICOLON CRLF
1023 char prefixlength[INET_ADDRSTRLEN];
1024 char *dst;
1026 if ((dst = get_prefixlen($1, (char *)&prefixlength, sizeof(prefixlength))) == NULL) {
1027 return (-1);
1030 if (insert_recurse(dst, prefixlength) < 0) {
1031 dolog(LOG_ERR, "insert_recurse, line %d\n", file->lineno);
1032 return (-1);
1035 if (debug)
1036 printf("recurse inserted %s address\n", $1);
1038 free (dst);
1039 free ($1);
1041 | comment CRLF
1045 /* wildcard-only-for "these hosts" { .. } */
1047 wof:
1048 WOF woflabel wofcontent
1050 if ((confstatus & CONFIG_VERSION) != CONFIG_VERSION) {
1051 dolog(LOG_INFO, "There must be a version at the top of the first configfile\n");
1052 return (-1);
1057 woflabel:
1058 QUOTEDSTRING
1061 wofcontent:
1062 OBRACE wofstatements EBRACE
1063 | OBRACE CRLF wofstatements EBRACE
1066 wofstatements :
1067 wofstatements wofstatement
1068 | wofstatement
1071 wofstatement : ipcidr SEMICOLON CRLF
1073 char prefixlength[INET_ADDRSTRLEN];
1074 char *dst;
1076 if ((dst = get_prefixlen($1, (char *)&prefixlength, sizeof(prefixlength))) == NULL) {
1078 return (-1);
1081 if (insert_wildcard(dst, prefixlength) < 0) {
1082 dolog(LOG_ERR, "insert_wildcard, line %d\n", file->lineno);
1083 return (-1);
1086 if (debug)
1087 printf("wildcard inserted %s address\n", $1);
1089 free (dst);
1090 free ($1);
1092 | comment CRLF
1096 /* region "lacnic" { .. } */
1098 region:
1099 REGION regionlabel regioncontent
1101 if ((confstatus & CONFIG_VERSION) != CONFIG_VERSION) {
1102 dolog(LOG_INFO, "There must be a version at the top of the first configfile\n");
1103 return (-1);
1106 region++;
1110 regionlabel:
1111 QUOTEDSTRING
1114 regioncontent:
1115 OBRACE regionstatements EBRACE
1116 | OBRACE CRLF regionstatements EBRACE
1119 regionstatements :
1120 regionstatements regionstatement
1121 | regionstatement
1124 regionstatement : ipcidr SEMICOLON CRLF
1126 char prefixlength[INET_ADDRSTRLEN];
1127 char *dst;
1129 if ((dst = get_prefixlen($1, (char *)&prefixlength, sizeof(prefixlength))) == NULL) {
1130 return (-1);
1133 if (insert_region(dst, prefixlength, region) < 0) {
1134 dolog(LOG_ERR, "insert_region, line %d\n", file->lineno);
1135 return (-1);
1138 if (debug)
1139 printf("%s ipv4 address\n", dst);
1141 free (dst);
1142 free ($1);
1144 | comment CRLF
1147 ipcidr:
1149 | IPV6
1155 struct tab {
1156 char *val;
1157 int num;
1158 int state;
1162 struct tab cmdtab[] = {
1163 { "axfrport", AXFRPORT, 0},
1164 { "axfr-for", AXFRFOR, STATE_IP },
1165 { "whitelist", WHITELIST, STATE_IP },
1166 { "filter", FILTER, STATE_IP },
1167 { "include", INCLUDE, 0 },
1168 { "logging", LOGGING, 0 },
1169 { "options", OPTIONS, 0 },
1170 { "recurse-for", RECURSEFOR, STATE_IP },
1171 { "region", REGION, STATE_IP },
1172 { "wildcard-only-for", WOF, STATE_IP },
1173 { "version", VERSION, 0 },
1174 { "zone", ZONE, 0 },
1175 { "notify", NOTIFY, STATE_IP },
1176 { NULL, 0, 0}};
1180 void
1181 yyerror(const char *str)
1183 dolog(LOG_ERR, "%s file: %s line: %d\n", str, file->name, file->lineno);
1184 slave_shutdown();
1185 exit (1);
1188 int
1189 yywrap()
1191 return 1;
1194 int
1195 parse_file(DB *db, char *filename)
1197 int errors;
1199 mydb = db;
1201 memset(&logging, 0, sizeof(struct logging));
1202 logging.active = 0;
1205 if ((file = pushfile(filename, 0)) == NULL) {
1206 return (-1);
1209 topfile = file;
1211 if (yyparse() < 0) {
1212 dolog(LOG_ERR, "error: %s line: %d\n", file->name, file->lineno);
1213 return (-1);
1215 errors = file->errors;
1216 popfile();
1218 dolog(LOG_INFO, "configuration file read\n");
1220 return 0;
1223 int
1224 yylex()
1226 struct tab *p;
1227 static char buf[512];
1228 static char dst[INET6_ADDRSTRLEN];
1229 char *cp = NULL;
1230 int c, cpos;
1231 static int setupstate = 0;
1234 do {
1235 c = lgetc(0);
1236 } while ((c == ' ') || (c == '\t'));
1238 if (c == EOF)
1239 return 0;
1241 if (c == '\n') {
1242 file->lineno++;
1244 while ((c = lgetc(0)) != EOF && (c == '\n' || c == '\t'))
1245 if (c == '\n')
1246 file->lineno++;
1247 lungetc(c);
1250 #ifdef LEXDEBUG
1251 if (debug)
1252 printf("returning %s\n", "crlf");
1253 #endif
1255 return CRLF;
1258 switch (state) {
1259 case STATE_IP:
1260 if (c == ':' || isalnum(c)) {
1261 lungetc(c);
1262 get_ip(buf, sizeof(buf) - 1);
1264 yylval.v.string = strdup(buf);
1265 if (yylval.v.string == NULL) {
1266 dolog(LOG_ERR, "yylex: %s\n", strerror(errno));
1267 slave_shutdown();
1268 exit(1);
1270 #ifdef LEXDEBUG
1271 if (debug)
1272 printf("returning %s\n", "IP");
1273 #endif
1274 return (IP);
1276 /* FALLTHROUGH */
1277 default:
1278 if (c == '}') {
1279 #ifdef LEXDEBUG
1280 if (debug)
1281 printf("returning %s\n", "ebrace");
1282 #endif
1283 setupstate = 0;
1284 state = 0;
1285 return EBRACE;
1288 if (c == '{') {
1289 if (setupstate)
1290 state = setupstate;
1291 #ifdef LEXDEBUG
1292 if (debug)
1293 printf("returning %s\n", "obrace");
1294 #endif
1295 return OBRACE;
1298 if (c == '/') {
1299 #ifdef LEXDEBUG
1300 if (debug)
1301 printf("returning %s\n", "slash");
1302 #endif
1303 return SLASH;
1306 if (c == ',') {
1307 #ifdef LEXDEBUG
1308 if (debug)
1309 printf("returning %s\n", "comma");
1310 #endif
1311 return COMMA;
1315 if (c == ';') {
1316 while ((c = lgetc(0)) != EOF && c != '\n');
1317 lungetc(c);
1318 #ifdef LEXDEBUG
1319 if (debug)
1320 printf("returning %s\n", "semicolon");
1321 #endif
1322 return SEMICOLON;
1325 if (c == '#') {
1326 while ((c = lgetc(0)) != EOF && c != '\n');
1327 lungetc(c);
1328 #ifdef LEXDEBUG
1329 if (debug)
1330 printf("returning %s\n", "pound");
1331 #endif
1332 return POUND;
1335 if (c == '"') {
1336 get_quotedstring(buf, sizeof(buf) - 1);
1338 if ((cp = strrchr(buf, '"'))) {
1339 cpos = cp - buf;
1340 c = buf[cpos];
1341 buf[cpos] = '\0';
1344 yylval.v.string = strdup(buf);
1345 if (yylval.v.string == NULL) {
1346 dolog(LOG_ERR, "yylex: %s\n", strerror(errno));
1347 slave_shutdown();
1348 exit(1);
1351 #ifdef LEXDEBUG
1352 if (debug)
1353 printf("returning %s\n", "quotedstring");
1354 #endif
1355 return QUOTEDSTRING;
1358 if (c == '*') {
1359 yylval.v.string = strdup("*");
1360 if (yylval.v.string == NULL) {
1361 dolog(LOG_ERR, "yylex: %s\n", strerror(errno));
1362 slave_shutdown();
1363 exit(1);
1365 #ifdef LEXDEBUG
1366 if (debug)
1367 printf("returning %s\n", "string");
1368 #endif
1369 return STRING;
1372 if (isalnum(c) || c == '.' || c == ':' || c == '-' || c == '_') {
1373 lungetc(c);
1374 get_string(buf, sizeof(buf) - 1);
1376 if ((cp = strpbrk(buf, " \n"))) {
1377 cpos = cp - buf;
1378 c = buf[cpos];
1379 buf[cpos] = '\0';
1382 p = lookup(cmdtab, buf);
1383 if (p != NULL) {
1384 #ifdef LEXDEBUG
1385 if (debug)
1386 printf("returning %s\n", p->val);
1387 #endif
1388 yylval.v.string = strdup(p->val);
1389 if (yylval.v.string == NULL) {
1390 dolog(LOG_ERR, "yylex: %s\n", strerror(errno));
1391 slave_shutdown();
1392 exit(1);
1394 setupstate = p->state;
1395 return (p->num);
1398 yylval.v.string = strdup(buf);
1399 if (yylval.v.string == NULL) {
1400 dolog(LOG_ERR, "yylex: %s\n", strerror(errno));
1401 slave_shutdown();
1402 exit(1);
1406 memset(&dst, 0, sizeof(dst));
1407 if (strchr(buf, ':') != NULL) {
1408 if (inet_net_pton(AF_INET6, buf, &dst, sizeof(dst)) == -1) {
1409 if (errno == EAFNOSUPPORT &&
1410 temp_inet_net_pton_ipv6(buf, &dst, sizeof(dst)) != -1)
1411 #if LEXDEBUG
1412 if (debug)
1413 printf("returning IPV6\n");
1414 #endif
1415 return IPV6;
1416 } else {
1418 #if LEXDEBUG
1419 if (debug)
1420 printf("returning IPV6\n");
1421 #endif
1422 return IPV6;
1426 memset(&dst, 0, sizeof(dst));
1427 if (strchr(buf, '.') != NULL &&
1428 inet_net_pton(AF_INET, buf, &dst, sizeof(dst)) != -1){
1429 #if LEXDEBUG
1430 if (debug)
1431 printf("returning %s\n", "IP");
1432 #endif
1433 return IP;
1436 for (cp = &buf[0]; *cp != '\0'; cp++) {
1437 if ((! isdigit((int)*cp)) && (*cp != '.'))
1438 break;
1441 if (*cp != '\0' || (buf[0] == '.' && buf[1] == '\0')) {
1442 #ifdef LEXDEBUG
1443 printf("returning %s (%s)\n", "STRING", buf);
1444 #endif
1445 return (STRING);
1448 #ifdef LEXDEBUG
1449 dolog(LOG_DEBUG, "returning %s\n", "NUMBER");
1450 #endif
1452 free (yylval.v.string);
1453 yylval.v.intval = atoi(buf);
1455 return (NUMBER);
1458 break;
1461 return (c);
1464 int
1465 get_quotedstring(char *buf, int n)
1467 int i, c;
1468 int stack = 0;
1469 char *cs;
1471 cs = buf;
1473 for (i = 0; --n > 0; ++i) {
1474 c = lgetc(0);
1475 if (c == '\n') {
1476 *cs = '\0';
1477 lungetc(c);
1478 return (0);
1479 } else if (c == '"') {
1480 if (stack == 0) {
1481 *cs++ = c;
1482 *cs = '\0';
1483 return (0);
1484 } else {
1485 stack--;
1487 } else if (c == '\\') {
1488 if (stack == 0) {
1489 stack++;
1490 continue;
1491 } else {
1492 stack--;
1494 } else
1495 stack = 0;
1498 *cs++ = c;
1501 return (1);
1504 int
1505 get_string(char *buf, int n)
1507 int i, c;
1508 char *cs;
1510 cs = buf;
1512 for (i = 0; --n > 0; ++i) {
1513 c = lgetc(0);
1514 if (c == '\n' || c == ' ' || c == ',' || c == ';' || ! (isprint(c) || c == '-' || c == '_')) {
1515 *cs = '\0';
1516 lungetc(c);
1517 return (0);
1520 *cs++ = c;
1523 return (1);
1526 struct rrtab *
1527 rrlookup(struct rrtab *p, char *keyword)
1530 for (; p->name != NULL; p++) {
1531 if (strcasecmp(p->name, keyword) == 0)
1532 return (p);
1535 return (NULL);
1538 struct tab *
1539 lookup(struct tab *cmdtab, char *keyword)
1541 struct tab *p;
1543 for (p = cmdtab; p->val != NULL; p++) {
1544 if (strcmp(p->val, keyword) == 0)
1545 return (p);
1548 return (NULL);
1551 int
1552 get_ip(char *buf, int n)
1554 int i, c;
1555 char *cs;
1557 cs = buf;
1559 for (i = 0; --n > 0; ++i) {
1560 c = lgetc(0);
1561 if (c == ',' || c == '\n' || ! (isalnum(c) || c == '/' || c == ':' || c == '.')) {
1562 *cs = '\0';
1563 lungetc(c);
1564 return (0);
1567 *cs++ = c;
1570 return (1);
1573 char *
1574 check_rr(char *domainname, char *mytype, int itype, int *converted_namelen)
1576 struct rrtab *rr;
1577 char *converted_name, *p;
1578 int i;
1581 if ((rr = rrlookup(myrrtab, mytype)) == NULL) {
1582 dolog(LOG_ERR, "error input line %d\n", file->lineno);
1583 slave_shutdown();
1584 exit(1);
1587 if (rr->type != itype) {
1588 dolog(LOG_ERR, "error input line %d, expected itype = %d, had %d\n", file->lineno, itype, rr->type);
1589 return NULL;
1592 if (strlen(domainname) > (DNS_MAXNAME - 2)) {
1593 dolog(LOG_ERR, "domain name too long, line %d\n", file->lineno);
1594 slave_shutdown();
1595 exit(1);
1598 for (i = 0, p = domainname; i < strlen(domainname); i++) {
1599 *p = tolower((int)*p);
1600 p++;
1603 if ((strlen(domainname) == 1) && (domainname[0] == '.')) {
1604 converted_name = malloc(1);
1605 if (converted_name == NULL) {
1606 dolog(LOG_ERR, "malloc failed\n");
1607 slave_shutdown();
1608 exit(1);
1611 *converted_namelen = 1;
1612 *converted_name = '\0';
1613 } else if ((strlen(domainname) == 1) && (domainname[0] == '*')) {
1614 converted_name = malloc(1);
1615 if (converted_name == NULL) {
1616 dolog(LOG_ERR, "malloc failed\n");
1617 slave_shutdown();
1618 exit(1);
1621 *converted_namelen = 1;
1622 *converted_name = '*';
1623 } else {
1624 converted_name = dns_label(domainname, converted_namelen);
1626 if (converted_name == NULL) {
1627 dolog(LOG_ERR, "error processing domain name line %d\n", file->lineno);
1628 slave_shutdown();
1629 exit(1);
1633 return (converted_name);
1636 int
1637 fill_cname(char *name, char *type, int myttl, char *hostname)
1639 struct domain sdomain;
1640 char *myname, *converted_name;
1641 int len, converted_namelen;
1642 int i ;
1644 for (i = 0; i < strlen(name); i++) {
1645 name[i] = tolower((int)name[i]);
1648 converted_name = check_rr(name, type, DNS_TYPE_CNAME, &converted_namelen);
1649 if (converted_name == NULL) {
1650 return -1;
1653 memset(&sdomain, 0, sizeof(sdomain));
1654 if (get_record(&sdomain, converted_name, converted_namelen) < 0) {
1655 return (-1);
1658 #ifdef __linux__
1659 strncpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
1660 sdomain.zonename[DNS_MAXNAME] = '\0';
1661 #else
1662 strlcpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
1663 #endif
1664 memcpy(sdomain.zone, converted_name, converted_namelen);
1665 sdomain.zonelen = converted_namelen;
1667 sdomain.ttl = myttl;
1669 myname = dns_label(hostname, (int *)&len);
1670 if (myname == NULL) {
1671 dolog(LOG_INFO, "illegal nameserver, skipping line %d\n", file->lineno);
1672 return 0;
1675 if (len > 0xff || len < 0) {
1676 dolog(LOG_INFO, "illegal len value , line %d\n", file->lineno);
1677 return -1;
1680 sdomain.cnamelen = len;
1681 memcpy((char *)&sdomain.cname[0], myname, len);
1683 free(myname);
1685 sdomain.flags |= DOMAIN_HAVE_CNAME;
1687 set_record(&sdomain, converted_name, converted_namelen);
1689 if (converted_name)
1690 free (converted_name);
1692 return (0);
1696 int
1697 fill_ptr(char *name, char *type, int myttl, char *hostname)
1699 struct domain sdomain;
1700 int len, converted_namelen;
1701 char *myname, *converted_name;
1702 int i;
1704 for (i = 0; i < strlen(name); i++) {
1705 name[i] = tolower((int)name[i]);
1708 converted_name = check_rr(name, type, DNS_TYPE_PTR, &converted_namelen);
1709 if (converted_name == NULL) {
1710 return -1;
1713 memset(&sdomain, 0, sizeof(sdomain));
1714 if (get_record(&sdomain, converted_name, converted_namelen) < 0) {
1715 return (-1);
1718 #ifdef __linux__
1719 strncpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
1720 sdomain.zonename[DNS_MAXNAME] = '\0';
1721 #else
1722 strlcpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
1723 #endif
1724 memcpy(sdomain.zone, converted_name, converted_namelen);
1725 sdomain.zonelen = converted_namelen;
1727 sdomain.ttl = myttl;
1729 myname = dns_label(hostname, (int *)&len);
1730 if (myname == NULL) {
1731 dolog(LOG_INFO, "illegal nameserver, skipping line %d\n", file->lineno);
1732 return 0;
1735 if (len > 0xff || len < 0) {
1736 dolog(LOG_INFO, "illegal len value , line %d\n", file->lineno);
1737 return -1;
1740 sdomain.ptrlen = len;
1741 memcpy((char *)&sdomain.ptr[0], myname, len);
1743 free(myname);
1745 sdomain.flags |= DOMAIN_HAVE_PTR;
1747 set_record(&sdomain, converted_name, converted_namelen);
1749 if (converted_name)
1750 free (converted_name);
1752 return (0);
1756 /* based on fill_txt */
1757 int
1758 fill_spf(char *name, char *type, int myttl, char *msg)
1760 struct domain sdomain;
1761 int converted_namelen;
1762 char *converted_name;
1763 int len, i;
1765 for (i = 0; i < strlen(name); i++) {
1766 name[i] = tolower((int)name[i]);
1769 if ((len = strlen(msg)) > 255) {
1770 dolog(LOG_ERR, "SPF record too long line %d\n", file->lineno);
1771 return (-1);
1774 converted_name = check_rr(name, type, DNS_TYPE_SPF, &converted_namelen);
1775 if (converted_name == NULL) {
1776 return -1;
1779 memset(&sdomain, 0, sizeof(sdomain));
1780 if (get_record(&sdomain, converted_name, converted_namelen) < 0) {
1781 return (-1);
1784 #ifdef __linux__
1785 strncpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
1786 sdomain.zonename[DNS_MAXNAME] = '\0';
1787 #else
1788 strlcpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
1789 #endif
1790 memcpy(sdomain.zone, converted_name, converted_namelen);
1791 sdomain.zonelen = converted_namelen;
1793 sdomain.ttl = myttl;
1795 memcpy(&sdomain.spf, msg, len);
1796 sdomain.spflen = len;
1798 sdomain.flags |= DOMAIN_HAVE_SPF;
1800 set_record(&sdomain, converted_name, converted_namelen);
1802 if (converted_name)
1803 free (converted_name);
1805 return (0);
1810 int
1811 fill_naptr(char *name, char *type, int myttl, int order, int preference, char *flags, char *services, char *regexp, char *replacement)
1813 struct domain sdomain;
1814 int converted_namelen;
1815 char *converted_name, *naptrname;
1816 int flagslen, serviceslen, regexplen, replacementlen;
1817 int i, naptr_namelen;
1819 for (i = 0; i < strlen(name); i++) {
1820 name[i] = tolower((int)name[i]);
1823 if ((flagslen = strlen(flags)) > 255 ||
1824 (serviceslen = strlen(services)) > 255 ||
1825 (regexplen = strlen(regexp)) > 255 ||
1826 (replacementlen = strlen(replacement)) > 255) {
1828 dolog(LOG_ERR, "NAPTR record too long line %d\n", file->lineno);
1829 return (-1);
1832 converted_name = check_rr(name, type, DNS_TYPE_NAPTR, &converted_namelen);
1833 if (converted_name == NULL) {
1834 return -1;
1837 memset(&sdomain, 0, sizeof(sdomain));
1838 if (get_record(&sdomain, converted_name, converted_namelen) < 0) {
1839 return (-1);
1842 #ifdef __linux__
1843 strncpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
1844 sdomain.zonename[DNS_MAXNAME] = '\0';
1845 #else
1846 strlcpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
1847 #endif
1848 memcpy(sdomain.zone, converted_name, converted_namelen);
1849 sdomain.zonelen = converted_namelen;
1851 sdomain.ttl = myttl;
1853 sdomain.naptr[sdomain.naptr_count].order = order;
1854 sdomain.naptr[sdomain.naptr_count].preference = preference;
1856 memcpy(&sdomain.naptr[sdomain.naptr_count].flags, flags, flagslen);
1857 sdomain.naptr[sdomain.naptr_count].flagslen = flagslen;
1859 memcpy(&sdomain.naptr[sdomain.naptr_count].services, services, serviceslen);
1860 sdomain.naptr[sdomain.naptr_count].serviceslen = serviceslen;
1862 memcpy(&sdomain.naptr[sdomain.naptr_count].regexp, regexp, regexplen);
1863 sdomain.naptr[sdomain.naptr_count].regexplen = regexplen;
1865 naptrname = check_rr(replacement, type, DNS_TYPE_NAPTR, &naptr_namelen);
1866 if (naptrname == NULL) {
1867 return -1;
1870 memcpy(&sdomain.naptr[sdomain.naptr_count].replacement, naptrname, naptr_namelen);
1871 sdomain.naptr[sdomain.naptr_count].replacementlen = naptr_namelen;
1873 sdomain.naptr_count++;
1875 sdomain.flags |= DOMAIN_HAVE_NAPTR;
1877 set_record(&sdomain, converted_name, converted_namelen);
1879 if (naptrname)
1880 free (naptrname);
1882 if (converted_name)
1883 free (converted_name);
1885 return (0);
1889 int
1890 fill_txt(char *name, char *type, int myttl, char *msg)
1892 struct domain sdomain;
1893 int converted_namelen;
1894 char *converted_name;
1895 int len, i;
1897 for (i = 0; i < strlen(name); i++) {
1898 name[i] = tolower((int)name[i]);
1901 if ((len = strlen(msg)) > 255) {
1902 dolog(LOG_ERR, "TXT record too long line %d\n", file->lineno);
1903 return (-1);
1906 converted_name = check_rr(name, type, DNS_TYPE_TXT, &converted_namelen);
1907 if (converted_name == NULL) {
1908 return -1;
1911 memset(&sdomain, 0, sizeof(sdomain));
1912 if (get_record(&sdomain, converted_name, converted_namelen) < 0) {
1913 return (-1);
1916 #ifdef __linux__
1917 strncpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
1918 sdomain.zonename[DNS_MAXNAME] = '\0';
1919 #else
1920 strlcpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
1921 #endif
1922 memcpy(sdomain.zone, converted_name, converted_namelen);
1923 sdomain.zonelen = converted_namelen;
1925 sdomain.ttl = myttl;
1927 memcpy(&sdomain.txt, msg, len);
1928 sdomain.txtlen = len;
1930 sdomain.flags |= DOMAIN_HAVE_TXT;
1932 set_record(&sdomain, converted_name, converted_namelen);
1934 if (converted_name)
1935 free (converted_name);
1937 return (0);
1941 /* based on fill_srv */
1942 int
1943 fill_sshfp(char *name, char *type, int myttl, int alg, int fptype, char *fingerprint)
1945 struct domain sdomain;
1946 int converted_namelen;
1947 char *converted_name;
1948 char *p, *ep, save;
1949 int len, i;
1951 for (i = 0; i < strlen(name); i++) {
1952 name[i] = tolower((int)name[i]);
1955 converted_name = check_rr(name, type, DNS_TYPE_SSHFP, &converted_namelen);
1956 if (converted_name == NULL) {
1957 return -1;
1960 memset(&sdomain, 0, sizeof(sdomain));
1961 if (get_record(&sdomain, converted_name, converted_namelen) < 0) {
1962 return (-1);
1965 #ifdef __linux__
1966 strncpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
1967 sdomain.zonename[DNS_MAXNAME] = '\0';
1968 #else
1969 strlcpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
1970 #endif
1971 memcpy(sdomain.zone, converted_name, converted_namelen);
1972 sdomain.zonelen = converted_namelen;
1974 if (sdomain.sshfp_count >= RECORD_COUNT) {
1975 dolog(LOG_INFO, "%s: too many SSHFP records for zone \"%s\", skipping line %d\n", file->name, name, file->lineno);
1976 return (-1);
1979 sdomain.ttl = myttl;
1981 sdomain.sshfp[sdomain.sshfp_count].algorithm = alg;
1982 sdomain.sshfp[sdomain.sshfp_count].fptype = fptype;
1984 switch (fptype) {
1985 case 1:
1986 len = sdomain.sshfp[sdomain.sshfp_count].fplen = DNS_SSHFP_SIZE_SHA1;
1987 break;
1988 case 2:
1989 len = sdomain.sshfp[sdomain.sshfp_count].fplen = DNS_SSHFP_SIZE_SHA256;
1990 break;
1991 default:
1992 dolog(LOG_ERR, "sshfp: unknown fingerprint type!\n");
1993 return -1;
1996 p = fingerprint;
1997 for (i = 0; i < len; i++) {
1998 save = p[2];
1999 p[2] = '\0';
2000 sdomain.sshfp[sdomain.sshfp_count].fingerprint[i] = strtol(p, &ep, 16);
2001 p[2] = save;
2002 p += 2;
2006 sdomain.sshfp_count++;
2008 sdomain.flags |= DOMAIN_HAVE_SSHFP;
2010 set_record(&sdomain, converted_name, converted_namelen);
2012 if (converted_name)
2013 free (converted_name);
2015 return (0);
2019 int
2020 fill_srv(char *name, char *type, int myttl, int priority, int weight, int port, char *srvhost)
2022 struct domain sdomain;
2023 int converted_namelen;
2024 char *converted_name;
2025 char *srvname;
2026 int len, i;
2028 for (i = 0; i < strlen(name); i++) {
2029 name[i] = tolower((int)name[i]);
2032 converted_name = check_rr(name, type, DNS_TYPE_SRV, &converted_namelen);
2033 if (converted_name == NULL) {
2034 return -1;
2037 memset(&sdomain, 0, sizeof(sdomain));
2038 if (get_record(&sdomain, converted_name, converted_namelen) < 0) {
2039 return (-1);
2042 #ifdef __linux__
2043 strncpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
2044 sdomain.zonename[DNS_MAXNAME] = '\0';
2045 #else
2046 strlcpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
2047 #endif
2048 memcpy(sdomain.zone, converted_name, converted_namelen);
2049 sdomain.zonelen = converted_namelen;
2051 if (sdomain.srv_count >= RECORD_COUNT) {
2052 dolog(LOG_INFO, "%s: too many SRV records for zone \"%s\", skipping line %d\n", file->name, name, file->lineno);
2053 return (-1);
2056 sdomain.ttl = myttl;
2058 sdomain.srv[sdomain.srv_count].priority = priority;
2059 sdomain.srv[sdomain.srv_count].weight = weight;
2060 sdomain.srv[sdomain.srv_count].port = port;
2062 srvname = dns_label(srvhost, &len);
2063 if (srvname == NULL) {
2064 dolog(LOG_INFO, "illegal srv server, skipping line %d\n", file->lineno);
2065 return (-1);
2069 sdomain.srv[sdomain.srv_count].targetlen = len;
2070 memcpy((char *)&sdomain.srv[sdomain.srv_count].target, srvname, len);
2072 /* bad hack workaround !!! */
2073 if (strcmp(srvhost, ".") == 0 && len > 1)
2074 sdomain.srv[sdomain.srv_count].targetlen = 1;
2076 free (srvname);
2078 sdomain.srv_count++;
2080 sdomain.flags |= DOMAIN_HAVE_SRV;
2082 set_record(&sdomain, converted_name, converted_namelen);
2084 if (converted_name)
2085 free (converted_name);
2087 return (0);
2091 int
2092 fill_mx(char *name, char *type, int myttl, int priority, char *mxhost)
2094 struct domain sdomain;
2095 int converted_namelen;
2096 char *converted_name;
2097 char *mxname;
2098 int len, i;
2100 for (i = 0; i < strlen(name); i++) {
2101 name[i] = tolower((int)name[i]);
2104 converted_name = check_rr(name, type, DNS_TYPE_MX, &converted_namelen);
2105 if (converted_name == NULL) {
2106 return -1;
2109 memset(&sdomain, 0, sizeof(sdomain));
2110 if (get_record(&sdomain, converted_name, converted_namelen) < 0) {
2111 return (-1);
2114 #ifdef __linux__
2115 strncpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
2116 sdomain.zonename[DNS_MAXNAME] = '\0';
2117 #else
2118 strlcpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
2119 #endif
2120 memcpy(sdomain.zone, converted_name, converted_namelen);
2121 sdomain.zonelen = converted_namelen;
2123 if (sdomain.mx_count >= RECORD_COUNT) {
2124 dolog(LOG_INFO, "%s: too many MX records for zone \"%s\", skipping line %d\n", file->name, name, file->lineno);
2125 return (-1);
2128 sdomain.ttl = myttl;
2129 sdomain.mx[sdomain.mx_count].preference = priority;
2131 mxname = dns_label(mxhost, &len);
2132 if (mxname == NULL) {
2133 dolog(LOG_INFO, "illegal mx server, skipping line %d\n", file->lineno);
2134 return (-1);
2137 sdomain.mx[sdomain.mx_count].exchangelen = len;
2138 memcpy((char *)&sdomain.mx[sdomain.mx_count].exchange, mxname, len);
2139 free (mxname);
2141 sdomain.mx_count++;
2143 sdomain.flags |= DOMAIN_HAVE_MX;
2145 set_record(&sdomain, converted_name, converted_namelen);
2147 if (converted_name)
2148 free (converted_name);
2150 return (0);
2154 int
2155 fill_balance(char *name, char *type, int myttl, char *a)
2157 struct domain sdomain;
2158 int converted_namelen;
2159 char *converted_name;
2160 struct sockaddr_in sin;
2161 in_addr_t *ia;
2162 int i;
2164 for (i = 0; i < strlen(name); i++) {
2165 name[i] = tolower((int)name[i]);
2168 converted_name = check_rr(name, type, DNS_TYPE_BALANCE, &converted_namelen);
2169 if (converted_name == NULL) {
2170 return -1;
2173 memset(&sdomain, 0, sizeof(sdomain));
2174 if (get_record(&sdomain, converted_name, converted_namelen) < 0) {
2175 return (-1);
2178 #ifdef __linux__
2179 strncpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
2180 sdomain.zonename[DNS_MAXNAME] = '\0';
2181 #else
2182 strlcpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
2183 #endif
2184 memcpy(sdomain.zone, converted_name, converted_namelen);
2185 sdomain.zonelen = converted_namelen;
2187 if (sdomain.a_count >= RECORD_COUNT) {
2188 dolog(LOG_INFO, "%s: too many BALANCE records for zone \"%s\", skipping line %d\n", file->name, name, file->lineno);
2189 return (-1);
2192 sdomain.ttl = myttl;
2193 ia = (in_addr_t *)&sdomain.a[sdomain.a_count];
2195 if ((*ia = inet_addr(a)) == INADDR_ANY) {
2196 dolog(LOG_INFO, "could not parse BALANCE record on line %d\n", file->lineno);
2197 return (-1);
2201 memset(&sin, 0, sizeof(sin));
2202 sin.sin_addr.s_addr = *ia;
2203 sin.sin_family = AF_INET;
2204 sdomain.region[sdomain.a_count] = find_region((struct sockaddr_storage *)&sin, AF_INET);
2206 sdomain.a_count++;
2207 sdomain.a_ptr = 0;
2209 sdomain.flags |= DOMAIN_HAVE_A;
2211 set_record(&sdomain, converted_name, converted_namelen);
2213 if (converted_name)
2214 free (converted_name);
2216 return (0);
2220 int
2221 fill_a(char *name, char *type, int myttl, char *a)
2223 struct domain sdomain;
2224 int converted_namelen;
2225 char *converted_name;
2226 in_addr_t *ia;
2227 int i;
2229 for (i = 0; i < strlen(name); i++) {
2230 name[i] = tolower((int)name[i]);
2233 converted_name = check_rr(name, type, DNS_TYPE_A, &converted_namelen);
2234 if (converted_name == NULL) {
2235 return -1;
2238 memset(&sdomain, 0, sizeof(sdomain));
2239 if (get_record(&sdomain, converted_name, converted_namelen) < 0) {
2240 return (-1);
2243 #ifdef __linux__
2244 strncpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
2245 sdomain.zonename[DNS_MAXNAME] = '\0';
2246 #else
2247 strlcpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
2248 #endif
2249 memcpy(sdomain.zone, converted_name, converted_namelen);
2250 sdomain.zonelen = converted_namelen;
2252 if (sdomain.a_count >= RECORD_COUNT) {
2253 dolog(LOG_INFO, "%s: too many A records for zone \"%s\", skipping line %d\n", file->name, name, file->lineno);
2254 return (-1);
2257 sdomain.ttl = myttl;
2258 ia = (in_addr_t *)&sdomain.a[sdomain.a_count];
2260 if ((*ia = inet_addr(a)) == INADDR_ANY) {
2261 dolog(LOG_INFO, "could not parse A record on line %d\n", file->lineno);
2262 return (-1);
2265 sdomain.region[sdomain.a_count] = 0xff;
2267 sdomain.a_count++;
2268 sdomain.a_ptr = 0;
2270 sdomain.flags |= DOMAIN_HAVE_A;
2272 set_record(&sdomain, converted_name, converted_namelen);
2274 if (converted_name)
2275 free (converted_name);
2277 return (0);
2282 int
2283 fill_aaaa(char *name, char *type, int myttl, char *aaaa)
2285 struct domain sdomain;
2286 int converted_namelen;
2287 char *converted_name;
2288 struct in6_addr *ia6;
2289 int i;
2292 for (i = 0; i < strlen(name); i++) {
2293 name[i] = tolower((int)name[i]);
2296 converted_name = check_rr(name, type, DNS_TYPE_AAAA, &converted_namelen);
2297 if (converted_name == NULL) {
2298 return -1;
2301 memset(&sdomain, 0, sizeof(sdomain));
2302 if (get_record(&sdomain, converted_name, converted_namelen) < 0) {
2303 return (-1);
2306 #ifdef __linux__
2307 strncpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
2308 sdomain.zonename[DNS_MAXNAME] = '\0';
2309 #else
2310 strlcpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
2311 #endif
2312 memcpy(sdomain.zone, converted_name, converted_namelen);
2313 sdomain.zonelen = converted_namelen;
2315 if (sdomain.aaaa_count >= RECORD_COUNT) {
2316 dolog(LOG_INFO, "%s: too many AAAA records for zone \"%s\", skipping line %d\n", file->name, name, file->lineno);
2317 return (-1);
2320 sdomain.ttl = myttl;
2321 ia6 = (struct in6_addr *)&sdomain.aaaa[sdomain.aaaa_count];
2322 if (inet_pton(AF_INET6, (char *)aaaa, (char *)ia6) != 1) {
2323 dolog(LOG_INFO, "AAAA \"%s\" unparseable line %d\n", aaaa, file->lineno);
2324 return -1;
2327 sdomain.aaaa_count++;
2328 sdomain.aaaa_ptr = 0;
2330 sdomain.flags |= DOMAIN_HAVE_AAAA;
2332 set_record(&sdomain, converted_name, converted_namelen);
2334 if (converted_name)
2335 free (converted_name);
2337 return (0);
2342 int
2343 fill_ns(char *name, char *type, int myttl, char *nameserver)
2345 struct domain sdomain;
2346 int len, converted_namelen;
2347 char *myname, *converted_name;
2348 char *n;
2349 int nstype, i;
2352 for (i = 0; i < strlen(name); i++) {
2353 name[i] = tolower((int)name[i]);
2356 if (strcasecmp(type, "ns") == 0) {
2357 converted_name = check_rr(name, type, DNS_TYPE_NS, &converted_namelen);
2358 nstype = 0;
2359 } else if (strcasecmp(type, "hint") == 0) {
2360 converted_name = check_rr(name, type, DNS_TYPE_HINT, &converted_namelen);
2361 nstype = NS_TYPE_HINT;
2362 } else {
2363 converted_name = check_rr(name, type, DNS_TYPE_DELEGATE, &converted_namelen);
2364 nstype = NS_TYPE_DELEGATE;
2367 if (converted_name == NULL) {
2368 return -1;
2371 memset(&sdomain, 0, sizeof(sdomain));
2372 if (get_record(&sdomain, converted_name, converted_namelen) < 0) {
2373 return (-1);
2376 #ifdef __linux__
2377 strncpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
2378 sdomain.zonename[DNS_MAXNAME] = '\0';
2379 #else
2380 strlcpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
2381 #endif
2382 memcpy(sdomain.zone, converted_name, converted_namelen);
2383 sdomain.zonelen = converted_namelen;
2385 if (sdomain.ns_count >= RECORD_COUNT) {
2386 dolog(LOG_INFO, "%s: too many NS records for zone \"%s\", skipping line %d\n", file->name, name, file->lineno);
2387 return (-1);
2390 sdomain.ttl = myttl;
2392 myname = dns_label(nameserver, (int *)&len);
2393 if (myname == NULL) {
2394 dolog(LOG_INFO, "illegal nameserver, skipping line %d\n", file->lineno);
2395 return 0;
2398 if (len > 0xff || len < 0) {
2399 dolog(LOG_INFO, "illegal len value , line %d\n", file->lineno);
2400 return -1;
2403 n = (char *)sdomain.ns[sdomain.ns_count].nsserver;
2404 sdomain.ns[sdomain.ns_count].nslen = len;
2405 memcpy((char *)n, myname, sdomain.ns[sdomain.ns_count].nslen);
2407 free(myname);
2409 sdomain.ns_count++;
2410 sdomain.ns_ptr = 0;
2411 sdomain.ns_type = nstype;
2413 sdomain.flags |= DOMAIN_HAVE_NS;
2415 set_record(&sdomain, converted_name, converted_namelen);
2417 if (converted_name)
2418 free (converted_name);
2420 return (0);
2425 /* centroid.eu,soa,3600,uranus.centroid.eu.,pjp.solarscale.de.,1258740680,3600,1800,7200,3600 */
2426 int
2427 fill_soa(char *name, char *type, int myttl, char *auth, char *contact, int serial, int retry, int refresh, int expire, int ttl)
2429 struct domain sdomain;
2430 int len, converted_namelen;
2431 char *myname, *converted_name;
2432 int i;
2434 for (i = 0; i < strlen(name); i++) {
2435 name[i] = tolower((int)name[i]);
2438 converted_name = check_rr(name, type, DNS_TYPE_SOA, &converted_namelen);
2439 if (converted_name == NULL) {
2440 dolog(LOG_ERR, "error input line %d\n", file->lineno);
2441 return (-1);
2444 memset(&sdomain, 0, sizeof(sdomain));
2445 if (get_record(&sdomain, converted_name, converted_namelen) < 0) {
2446 return (-1);
2449 #ifdef __linux__
2450 strncpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
2451 sdomain.zonename[DNS_MAXNAME] = '\0';
2452 #else
2453 strlcpy((char *)sdomain.zonename, (char *)name, DNS_MAXNAME + 1);
2454 #endif
2455 memcpy(sdomain.zone, converted_name, converted_namelen);
2456 sdomain.zonelen = converted_namelen;
2458 sdomain.ttl = myttl;
2460 myname = dns_label(auth, (int *)&len);
2461 if (myname == NULL) {
2462 dolog(LOG_INFO, "illegal nameserver, skipping line %d\n", file->lineno);
2463 return 0;
2466 if (len > 0xff || len < 0) {
2467 dolog(LOG_INFO, "illegal len value , line %d\n", file->lineno);
2468 return -1;
2471 sdomain.soa.nsserver_len = len;
2472 memcpy((char *)&sdomain.soa.nsserver[0], myname, len);
2474 free(myname);
2476 myname = dns_label(contact, (int *)&len);
2477 if (myname == NULL) {
2478 dolog(LOG_INFO, "illegal nameserver, skipping line %d\n", file->lineno);
2479 return 0;
2482 if (len > 0xff || len < 0) {
2483 dolog(LOG_INFO, "illegal len value , line %d\n", file->lineno);
2484 return -1;
2487 sdomain.soa.rp_len = len;
2488 memcpy((char *)&sdomain.soa.responsible_person[0], myname, len);
2490 free (myname);
2492 sdomain.soa.serial = serial;
2493 sdomain.soa.refresh = refresh;
2494 sdomain.soa.retry = retry;
2495 sdomain.soa.expire = expire;
2496 sdomain.soa.minttl = ttl;
2498 sdomain.flags |= DOMAIN_HAVE_SOA;
2500 set_record(&sdomain, converted_name, converted_namelen);
2502 if (converted_name)
2503 free (converted_name);
2505 return (0);
2510 int
2511 get_record(struct domain *sdomain, char *converted_name, int converted_namelen)
2513 DB *db = mydb; /* XXX */
2515 memset(&key, 0, sizeof(key));
2516 memset(&data, 0, sizeof(data));
2518 key.data = (char *)converted_name;
2519 key.size = converted_namelen;
2521 data.data = NULL;
2522 data.size = 0;
2524 if (db->get(db, NULL, &key, &data, 0) == 0) {
2526 if (data.size != sizeof(struct domain)) {
2527 dolog(LOG_INFO, "damaged btree database\n");
2528 return -1;
2531 memcpy((char *)sdomain, (char *)data.data, data.size);
2532 } else {
2533 if (debug)
2534 dolog(LOG_INFO, "db->get: %s\n", strerror(errno));
2537 return 0;
2541 void
2542 set_record(struct domain *sdomain, char *converted_name, int converted_namelen)
2544 DB *db = mydb; /* XXX */
2545 int ret;
2547 /* everythign in parse.y should get this flag! */
2548 sdomain->flags |= DOMAIN_STATIC_ZONE;
2550 memset(&key, 0, sizeof(key));
2551 memset(&data, 0, sizeof(data));
2553 key.data = (char *)converted_name;
2554 key.size = converted_namelen;
2556 data.data = (void*)sdomain;
2557 data.size = sizeof(struct domain);
2559 if ((ret = db->put(db, NULL, &key, &data, 0)) != 0) {
2560 dolog(LOG_INFO, "db->put: %s\n" , db_strerror(ret));
2561 return;
2564 return;
2568 struct file *
2569 pushfile(const char *name, int secret)
2571 struct stat sb;
2572 struct file *nfile;
2573 int fd;
2575 if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
2576 dolog(LOG_INFO, "warn: malloc\n");
2577 return (NULL);
2579 if ((nfile->name = strdup(name)) == NULL) {
2580 dolog(LOG_INFO, "warn: malloc\n");
2581 free(nfile);
2582 return (NULL);
2584 if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
2585 dolog(LOG_INFO, "warn: %s\n", nfile->name);
2586 free(nfile->name);
2587 free(nfile);
2588 return (NULL);
2591 fd = fileno(nfile->stream);
2592 if (fstat(fd, &sb) < 0) {
2593 dolog(LOG_INFO, "warn: %s\n", strerror(errno));
2596 /* get the highest time of all included files */
2597 if (time_changed < sb.st_ctime)
2598 time_changed = (time_t)sb.st_ctime; /* ufs1 is only 32 bits */
2600 nfile->lineno = 1;
2601 TAILQ_INSERT_TAIL(&files, nfile, entry);
2602 return (nfile);
2605 #define MAXPUSHBACK 128
2607 char *parsebuf;
2608 int parseindex;
2609 char pushback_buffer[MAXPUSHBACK];
2610 int pushback_index = 0;
2613 int
2614 lgetc(int quotec)
2616 int c;
2618 if (parsebuf) {
2619 /* Read character from the parsebuffer instead of input. */
2620 if (parseindex >= 0) {
2621 c = parsebuf[parseindex++];
2622 if (c != '\0')
2623 return (c);
2624 parsebuf = NULL;
2625 } else
2626 parseindex++;
2629 if (pushback_index)
2630 return (pushback_buffer[--pushback_index]);
2632 if (quotec) {
2633 if ((c = getc(file->stream)) == EOF) {
2634 yyerror("reached end of file while parsing "
2635 "quoted string");
2636 if (file == topfile || popfile() == EOF)
2637 return (EOF);
2638 return (quotec);
2640 return (c);
2643 while ((c = getc(file->stream)) == EOF) {
2644 if (file == topfile || popfile() == EOF)
2645 return (EOF);
2647 return (c);
2650 int
2651 popfile(void)
2653 struct file *prev;
2655 if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
2656 prev->errors += file->errors;
2658 TAILQ_REMOVE(&files, file, entry);
2659 fclose(file->stream);
2660 free(file->name);
2661 free(file);
2662 file = prev;
2663 return (file ? 0 : EOF);
2667 int
2668 lungetc(int c)
2670 if (c == EOF)
2671 return (EOF);
2672 if (parsebuf) {
2673 parseindex--;
2674 if (parseindex >= 0)
2675 return (c);
2677 if (pushback_index < MAXPUSHBACK-1)
2678 return (pushback_buffer[pushback_index++] = c);
2679 else
2680 return (EOF);
2683 int
2684 findeol(void)
2686 int c;
2688 parsebuf = NULL;
2689 pushback_index = 0;
2691 /* skip to either EOF or the first real EOL */
2692 while (1) {
2693 c = lgetc(0);
2694 if (c == '\n') {
2695 file->lineno++;
2696 break;
2698 if (c == EOF)
2699 break;
2701 return (ERROR);
2706 * from opensmtpd, the license at the top is compatible with this stuff
2709 static int
2710 temp_inet_net_pton_ipv6(const char *src, void *dst, size_t size)
2712 int ret;
2713 int bits;
2714 char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255:255:255:255/128")];
2715 char *sep;
2716 #if defined __OpenBSD__ || defined __FreeBSD__
2717 const char *errstr;
2718 #endif
2720 #ifndef __linux__
2721 if (strlcpy(buf, src, sizeof buf) >= sizeof buf) {
2722 errno = EMSGSIZE;
2723 return (-1);
2725 #else
2726 strncpy(buf, src, sizeof(buf));
2727 buf[sizeof(buf) - 1] = '\0';
2728 #endif
2730 sep = strchr(buf, '/');
2731 if (sep != NULL)
2732 *sep++ = '\0';
2734 ret = inet_pton(AF_INET6, buf, dst);
2735 if (ret != 1) {
2736 return (-1);
2739 if (sep == NULL)
2740 return 128;
2742 #if ! defined __linux__ && ! defined __APPLE__ && ! defined __NetBSD__
2743 bits = strtonum(sep, 0, 128, &errstr);
2744 if (errstr)
2745 return (-1);
2746 #else
2747 bits = atoi(sep);
2748 #endif
2750 return bits;
2754 char *
2755 get_prefixlen(char *input, char *prefixlength, int plsize)
2757 int af = AF_INET;
2758 int prefixlen;
2759 char *ret, *p;
2761 if (strchr(input, ':') != NULL)
2762 af = AF_INET6;
2764 prefixlen = inet_net_pton(af, input, prefixlength, plsize);
2765 if (prefixlen < 0) {
2766 if (errno == EAFNOSUPPORT) {
2767 prefixlen = temp_inet_net_pton_ipv6(input, prefixlength, plsize);
2768 } else {
2769 if (debug)
2770 printf("not address family %d (%s)\n", af, input);
2771 return (NULL);
2775 if ((p = strchr(input, '/')) != NULL) {
2776 *p++ = '\0';
2777 } else {
2778 if (af == AF_INET)
2779 p = "32";
2780 else
2781 p = "128";
2784 snprintf(prefixlength, plsize, "%s", p);
2785 ret = strdup(input);
2786 return (ret);