xref: /minix3/external/bsd/bind/dist/contrib/nslint-3.0a2/nslint.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
1*00b67f09SDavid van Moolenbroek /*	$NetBSD: nslint.c,v 1.1.1.3 2014/12/10 03:34:34 christos Exp $	*/
2*00b67f09SDavid van Moolenbroek 
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek  * Copyright (c) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2007, 2008, 2009
5*00b67f09SDavid van Moolenbroek  *	The Regents of the University of California.  All rights reserved.
6*00b67f09SDavid van Moolenbroek  *
7*00b67f09SDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
8*00b67f09SDavid van Moolenbroek  * modification, are permitted provided that: (1) source code distributions
9*00b67f09SDavid van Moolenbroek  * retain the above copyright notice and this paragraph in its entirety, (2)
10*00b67f09SDavid van Moolenbroek  * distributions including binary code include the above copyright notice and
11*00b67f09SDavid van Moolenbroek  * this paragraph in its entirety in the documentation or other materials
12*00b67f09SDavid van Moolenbroek  * provided with the distribution, and (3) all advertising materials mentioning
13*00b67f09SDavid van Moolenbroek  * features or use of this software display the following acknowledgement:
14*00b67f09SDavid van Moolenbroek  * ``This product includes software developed by the University of California,
15*00b67f09SDavid van Moolenbroek  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16*00b67f09SDavid van Moolenbroek  * the University nor the names of its contributors may be used to endorse
17*00b67f09SDavid van Moolenbroek  * or promote products derived from this software without specific prior
18*00b67f09SDavid van Moolenbroek  * written permission.
19*00b67f09SDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20*00b67f09SDavid van Moolenbroek  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21*00b67f09SDavid van Moolenbroek  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22*00b67f09SDavid van Moolenbroek  */
23*00b67f09SDavid van Moolenbroek #ifndef lint
24*00b67f09SDavid van Moolenbroek static const char copyright[] =
25*00b67f09SDavid van Moolenbroek     "@(#) Copyright (c) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2007, 2008, 2009\n\
26*00b67f09SDavid van Moolenbroek The Regents of the University of California.  All rights reserved.\n";
27*00b67f09SDavid van Moolenbroek static const char rcsid[] =
28*00b67f09SDavid van Moolenbroek     "@(#) Id: nslint.c 247 2009-10-14 17:54:05Z leres  (LBL)";
29*00b67f09SDavid van Moolenbroek #endif
30*00b67f09SDavid van Moolenbroek /*
31*00b67f09SDavid van Moolenbroek  * nslint - perform consistency checks on dns files
32*00b67f09SDavid van Moolenbroek  */
33*00b67f09SDavid van Moolenbroek 
34*00b67f09SDavid van Moolenbroek #include <sys/types.h>
35*00b67f09SDavid van Moolenbroek #include <sys/stat.h>
36*00b67f09SDavid van Moolenbroek #include <sys/socket.h>
37*00b67f09SDavid van Moolenbroek 
38*00b67f09SDavid van Moolenbroek #include <netinet/in.h>
39*00b67f09SDavid van Moolenbroek 
40*00b67f09SDavid van Moolenbroek #include <arpa/inet.h>
41*00b67f09SDavid van Moolenbroek 
42*00b67f09SDavid van Moolenbroek #include <ctype.h>
43*00b67f09SDavid van Moolenbroek #include <errno.h>
44*00b67f09SDavid van Moolenbroek #ifdef HAVE_FCNTL_H
45*00b67f09SDavid van Moolenbroek #include <fcntl.h>
46*00b67f09SDavid van Moolenbroek #endif
47*00b67f09SDavid van Moolenbroek #ifdef HAVE_MEMORY_H
48*00b67f09SDavid van Moolenbroek #include <memory.h>
49*00b67f09SDavid van Moolenbroek #endif
50*00b67f09SDavid van Moolenbroek #include <netdb.h>
51*00b67f09SDavid van Moolenbroek #include <stdio.h>
52*00b67f09SDavid van Moolenbroek #include <stdlib.h>
53*00b67f09SDavid van Moolenbroek #include <string.h>
54*00b67f09SDavid van Moolenbroek #include <time.h>
55*00b67f09SDavid van Moolenbroek #include <unistd.h>
56*00b67f09SDavid van Moolenbroek 
57*00b67f09SDavid van Moolenbroek #include "savestr.h"
58*00b67f09SDavid van Moolenbroek #include "version.h"
59*00b67f09SDavid van Moolenbroek 
60*00b67f09SDavid van Moolenbroek #include "gnuc.h"
61*00b67f09SDavid van Moolenbroek #ifdef HAVE_OS_PROTO_H
62*00b67f09SDavid van Moolenbroek #include "os-proto.h"
63*00b67f09SDavid van Moolenbroek #endif
64*00b67f09SDavid van Moolenbroek 
65*00b67f09SDavid van Moolenbroek #define NSLINTBOOT "nslint.boot"	/* default nslint.boot file */
66*00b67f09SDavid van Moolenbroek #define NSLINTCONF "nslint.conf"	/* default nslint.conf file */
67*00b67f09SDavid van Moolenbroek 
68*00b67f09SDavid van Moolenbroek /* Is the string just a dot by itself? */
69*00b67f09SDavid van Moolenbroek #define CHECKDOT(p) (p[0] == '.' && p[1] == '\0')
70*00b67f09SDavid van Moolenbroek 
71*00b67f09SDavid van Moolenbroek /* Address (network order) */
72*00b67f09SDavid van Moolenbroek struct addr {
73*00b67f09SDavid van Moolenbroek 	u_int family;
74*00b67f09SDavid van Moolenbroek 	union {
75*00b67f09SDavid van Moolenbroek 		struct in_addr _a_addr4;
76*00b67f09SDavid van Moolenbroek 		struct in6_addr _a_addr6;
77*00b67f09SDavid van Moolenbroek 	} addr;
78*00b67f09SDavid van Moolenbroek };
79*00b67f09SDavid van Moolenbroek #define a_addr4 addr._a_addr4.s_addr
80*00b67f09SDavid van Moolenbroek #define a_addr6 addr._a_addr6.s6_addr
81*00b67f09SDavid van Moolenbroek 
82*00b67f09SDavid van Moolenbroek /* Network */
83*00b67f09SDavid van Moolenbroek struct network {
84*00b67f09SDavid van Moolenbroek 	u_int family;
85*00b67f09SDavid van Moolenbroek 	union {
86*00b67f09SDavid van Moolenbroek 		struct in_addr _n_addr4;
87*00b67f09SDavid van Moolenbroek 		struct in6_addr _n_addr6;
88*00b67f09SDavid van Moolenbroek 	} addr;
89*00b67f09SDavid van Moolenbroek 	union {
90*00b67f09SDavid van Moolenbroek 		struct in_addr _n_mask4;
91*00b67f09SDavid van Moolenbroek 		struct in6_addr _n_mask6;
92*00b67f09SDavid van Moolenbroek 	} mask;
93*00b67f09SDavid van Moolenbroek };
94*00b67f09SDavid van Moolenbroek #define n_addr4 addr._n_addr4.s_addr
95*00b67f09SDavid van Moolenbroek #define n_mask4 mask._n_mask4.s_addr
96*00b67f09SDavid van Moolenbroek #define n_addr6 addr._n_addr6.s6_addr
97*00b67f09SDavid van Moolenbroek #define n_mask6 mask._n_mask6.s6_addr
98*00b67f09SDavid van Moolenbroek 
99*00b67f09SDavid van Moolenbroek /* Item struct */
100*00b67f09SDavid van Moolenbroek struct item {
101*00b67f09SDavid van Moolenbroek 	char *host;		/* pointer to hostname */
102*00b67f09SDavid van Moolenbroek 	struct addr addr;	/* ip address */
103*00b67f09SDavid van Moolenbroek 	u_int ttl;		/* ttl of A records */
104*00b67f09SDavid van Moolenbroek 	int records;		/* resource records seen */
105*00b67f09SDavid van Moolenbroek 	int flags;		/* flags word */
106*00b67f09SDavid van Moolenbroek };
107*00b67f09SDavid van Moolenbroek 
108*00b67f09SDavid van Moolenbroek /* Ignored zone struct */
109*00b67f09SDavid van Moolenbroek struct ignoredzone {
110*00b67f09SDavid van Moolenbroek 	char *zone;		/* zone name */
111*00b67f09SDavid van Moolenbroek 	int len;		/* length of zone */
112*00b67f09SDavid van Moolenbroek };
113*00b67f09SDavid van Moolenbroek 
114*00b67f09SDavid van Moolenbroek /* Resource records seen */
115*00b67f09SDavid van Moolenbroek #define REC_A		0x0001
116*00b67f09SDavid van Moolenbroek #define REC_AAAA	0x0002
117*00b67f09SDavid van Moolenbroek #define REC_PTR		0x0004
118*00b67f09SDavid van Moolenbroek #define REC_WKS		0x0008
119*00b67f09SDavid van Moolenbroek #define REC_HINFO	0x0010
120*00b67f09SDavid van Moolenbroek #define REC_MX		0x0020
121*00b67f09SDavid van Moolenbroek #define REC_CNAME	0x0040
122*00b67f09SDavid van Moolenbroek #define REC_NS		0x0080
123*00b67f09SDavid van Moolenbroek #define REC_SOA		0x0100
124*00b67f09SDavid van Moolenbroek #define REC_RP		0x0200
125*00b67f09SDavid van Moolenbroek #define REC_TXT		0x0400
126*00b67f09SDavid van Moolenbroek #define REC_SRV		0x0800
127*00b67f09SDavid van Moolenbroek 
128*00b67f09SDavid van Moolenbroek /* These aren't real records */
129*00b67f09SDavid van Moolenbroek #define REC_OTHER	0x1000
130*00b67f09SDavid van Moolenbroek #define REC_REF		0x2000
131*00b67f09SDavid van Moolenbroek #define REC_UNKNOWN	0x4000
132*00b67f09SDavid van Moolenbroek 
133*00b67f09SDavid van Moolenbroek /* resource record types for parsing */
134*00b67f09SDavid van Moolenbroek enum rrtype {
135*00b67f09SDavid van Moolenbroek 	RR_UNDEF = 0,
136*00b67f09SDavid van Moolenbroek 	RR_A,
137*00b67f09SDavid van Moolenbroek 	RR_AAAA,
138*00b67f09SDavid van Moolenbroek 	RR_ALLOWDUPA,
139*00b67f09SDavid van Moolenbroek 	RR_CNAME,
140*00b67f09SDavid van Moolenbroek 	RR_DNSKEY,
141*00b67f09SDavid van Moolenbroek 	RR_HINFO,
142*00b67f09SDavid van Moolenbroek 	RR_MX,
143*00b67f09SDavid van Moolenbroek 	RR_NS,
144*00b67f09SDavid van Moolenbroek 	RR_PTR,
145*00b67f09SDavid van Moolenbroek 	RR_RP,
146*00b67f09SDavid van Moolenbroek 	RR_SOA,
147*00b67f09SDavid van Moolenbroek 	RR_SRV,
148*00b67f09SDavid van Moolenbroek 	RR_TXT,
149*00b67f09SDavid van Moolenbroek 	RR_WKS,
150*00b67f09SDavid van Moolenbroek 	RR_RRSIG,
151*00b67f09SDavid van Moolenbroek 	RR_NSEC,
152*00b67f09SDavid van Moolenbroek };
153*00b67f09SDavid van Moolenbroek 
154*00b67f09SDavid van Moolenbroek /* Test for records we want to map to REC_OTHER */
155*00b67f09SDavid van Moolenbroek #define MASK_TEST_REC (REC_WKS | REC_HINFO | \
156*00b67f09SDavid van Moolenbroek     REC_MX | REC_SOA | REC_RP | REC_TXT | REC_SRV | REC_UNKNOWN)
157*00b67f09SDavid van Moolenbroek 
158*00b67f09SDavid van Moolenbroek /* Mask away records we don't care about in the final processing to REC_OTHER */
159*00b67f09SDavid van Moolenbroek #define MASK_CHECK_REC \
160*00b67f09SDavid van Moolenbroek     (REC_A | REC_AAAA | REC_PTR | REC_CNAME | REC_REF | REC_OTHER)
161*00b67f09SDavid van Moolenbroek 
162*00b67f09SDavid van Moolenbroek /* Test for records we want to check for duplicate name detection */
163*00b67f09SDavid van Moolenbroek #define MASK_TEST_DUP \
164*00b67f09SDavid van Moolenbroek     (REC_A | REC_AAAA | REC_HINFO | REC_CNAME)
165*00b67f09SDavid van Moolenbroek 
166*00b67f09SDavid van Moolenbroek /* Flags */
167*00b67f09SDavid van Moolenbroek #define FLG_SELFMX	0x001	/* mx record refers to self */
168*00b67f09SDavid van Moolenbroek #define FLG_MXREF	0x002	/* this record referred to by a mx record */
169*00b67f09SDavid van Moolenbroek #define FLG_SMTPWKS	0x004	/* saw wks with smtp/tcp */
170*00b67f09SDavid van Moolenbroek #define FLG_ALLOWDUPA	0x008	/* allow duplicate a records */
171*00b67f09SDavid van Moolenbroek 
172*00b67f09SDavid van Moolenbroek /* doconf() and doboot() flags */
173*00b67f09SDavid van Moolenbroek #define CONF_MUSTEXIST	0x001	/* fatal for files to not exist */
174*00b67f09SDavid van Moolenbroek #define CONF_NOZONE	0x002	/* do not parse zone files */
175*00b67f09SDavid van Moolenbroek 
176*00b67f09SDavid van Moolenbroek /* Test for smtp problems */
177*00b67f09SDavid van Moolenbroek #define MASK_TEST_SMTP \
178*00b67f09SDavid van Moolenbroek     (FLG_SELFMX | FLG_SMTPWKS)
179*00b67f09SDavid van Moolenbroek 
180*00b67f09SDavid van Moolenbroek #define ITEMSIZE (1 << 17)	/* power of two */
181*00b67f09SDavid van Moolenbroek 
182*00b67f09SDavid van Moolenbroek struct	item items[ITEMSIZE];
183*00b67f09SDavid van Moolenbroek int	itemcnt;		/* count of items */
184*00b67f09SDavid van Moolenbroek 
185*00b67f09SDavid van Moolenbroek /* Hostname string storage */
186*00b67f09SDavid van Moolenbroek #define STRSIZE 8192;		/* size to malloc when more space is needed */
187*00b67f09SDavid van Moolenbroek char	*strptr;		/* pointer to string pool */
188*00b67f09SDavid van Moolenbroek int	strsize;		/* size of space left in pool */
189*00b67f09SDavid van Moolenbroek 
190*00b67f09SDavid van Moolenbroek int	debug;
191*00b67f09SDavid van Moolenbroek int	errors;
192*00b67f09SDavid van Moolenbroek #ifdef __FreeBSD__
193*00b67f09SDavid van Moolenbroek char	*bootfile = "/etc/namedb/named.boot";
194*00b67f09SDavid van Moolenbroek char	*conffile = "/etc/namedb/named.conf";
195*00b67f09SDavid van Moolenbroek #else
196*00b67f09SDavid van Moolenbroek char	*bootfile = "/etc/named.boot";
197*00b67f09SDavid van Moolenbroek char	*conffile = "/etc/named.conf";
198*00b67f09SDavid van Moolenbroek #endif
199*00b67f09SDavid van Moolenbroek char	*nslintboot;
200*00b67f09SDavid van Moolenbroek char	*nslintconf;
201*00b67f09SDavid van Moolenbroek char	*prog;
202*00b67f09SDavid van Moolenbroek char	*cwd = ".";
203*00b67f09SDavid van Moolenbroek 
204*00b67f09SDavid van Moolenbroek static struct network *netlist;
205*00b67f09SDavid van Moolenbroek static u_int netlistsize;	/* size of array */
206*00b67f09SDavid van Moolenbroek static u_int netlistcnt;	/* next free element */
207*00b67f09SDavid van Moolenbroek 
208*00b67f09SDavid van Moolenbroek char **protoserv;		/* valid protocol/service names */
209*00b67f09SDavid van Moolenbroek int protoserv_init;
210*00b67f09SDavid van Moolenbroek int protoserv_last;
211*00b67f09SDavid van Moolenbroek int protoserv_len;
212*00b67f09SDavid van Moolenbroek 
213*00b67f09SDavid van Moolenbroek static char inaddr[] = ".in-addr.arpa.";
214*00b67f09SDavid van Moolenbroek static char inaddr6[] = ".ip6.arpa.";
215*00b67f09SDavid van Moolenbroek 
216*00b67f09SDavid van Moolenbroek /* XXX should be dynamic */
217*00b67f09SDavid van Moolenbroek static struct ignoredzone ignoredzones[10];
218*00b67f09SDavid van Moolenbroek static int numignoredzones = 0;
219*00b67f09SDavid van Moolenbroek #define SIZEIGNOREDZONES (sizeof(ignoredzones) / sizeof(ignoredzones[0]))
220*00b67f09SDavid van Moolenbroek 
221*00b67f09SDavid van Moolenbroek /* SOA record */
222*00b67f09SDavid van Moolenbroek #define SOA_SERIAL	0
223*00b67f09SDavid van Moolenbroek #define SOA_REFRESH	1
224*00b67f09SDavid van Moolenbroek #define SOA_RETRY	2
225*00b67f09SDavid van Moolenbroek #define SOA_EXPIRE	3
226*00b67f09SDavid van Moolenbroek #define SOA_MINIMUM	4
227*00b67f09SDavid van Moolenbroek 
228*00b67f09SDavid van Moolenbroek static u_int soaval[5];
229*00b67f09SDavid van Moolenbroek static int nsoaval;
230*00b67f09SDavid van Moolenbroek #define NSOAVAL (sizeof(soaval) / sizeof(soaval[0]))
231*00b67f09SDavid van Moolenbroek 
232*00b67f09SDavid van Moolenbroek /* Forwards */
233*00b67f09SDavid van Moolenbroek void add_domain(char *, const char *);
234*00b67f09SDavid van Moolenbroek const char *addr2str(struct addr *);
235*00b67f09SDavid van Moolenbroek int checkaddr(const char *);
236*00b67f09SDavid van Moolenbroek int checkdots(const char *);
237*00b67f09SDavid van Moolenbroek void checkdups(struct item *, int);
238*00b67f09SDavid van Moolenbroek int checkignoredzone(const char *);
239*00b67f09SDavid van Moolenbroek int checkserv(const char *, char **p);
240*00b67f09SDavid van Moolenbroek int checkwks(FILE *, char *, int *, char **);
241*00b67f09SDavid van Moolenbroek int cmpaddr(const void *, const void *);
242*00b67f09SDavid van Moolenbroek int cmpitemaddr(const void *, const void *);
243*00b67f09SDavid van Moolenbroek int cmpitemhost(const void *, const void *);
244*00b67f09SDavid van Moolenbroek int cmpnetwork(const void *, const void *);
245*00b67f09SDavid van Moolenbroek void doboot(const char *, int);
246*00b67f09SDavid van Moolenbroek void doconf(const char *, int);
247*00b67f09SDavid van Moolenbroek const char *extractaddr(const char *, struct addr *);
248*00b67f09SDavid van Moolenbroek const char *extractnetwork(const char *, struct network *);
249*00b67f09SDavid van Moolenbroek struct network *findnetwork(struct addr *);
250*00b67f09SDavid van Moolenbroek void initprotoserv(void);
251*00b67f09SDavid van Moolenbroek int main(int, char **);
252*00b67f09SDavid van Moolenbroek int maskwidth(struct network *);
253*00b67f09SDavid van Moolenbroek const char *network2str(struct network *);
254*00b67f09SDavid van Moolenbroek void nslint(void);
255*00b67f09SDavid van Moolenbroek const char *parsenetwork(const char *);
256*00b67f09SDavid van Moolenbroek const char *parseptr(const char *, struct addr *);
257*00b67f09SDavid van Moolenbroek char *parsequoted(char *);
258*00b67f09SDavid van Moolenbroek int parserrsig(const char *, char **);
259*00b67f09SDavid van Moolenbroek int parsesoa(const char *, char **);
260*00b67f09SDavid van Moolenbroek void process(const char *, const char *, const char *);
261*00b67f09SDavid van Moolenbroek int rfc1034host(const char *, int);
262*00b67f09SDavid van Moolenbroek enum rrtype txt2rrtype(const char *);
263*00b67f09SDavid van Moolenbroek int samesubnet(struct addr *, struct addr *, struct network *);
264*00b67f09SDavid van Moolenbroek void setmaskwidth(u_int w, struct network *);
265*00b67f09SDavid van Moolenbroek int updateitem(const char *, struct addr *, int, u_int, int);
266*00b67f09SDavid van Moolenbroek void usage(void) __attribute__((noreturn));
267*00b67f09SDavid van Moolenbroek 
268*00b67f09SDavid van Moolenbroek extern	char *optarg;
269*00b67f09SDavid van Moolenbroek extern	int optind, opterr;
270*00b67f09SDavid van Moolenbroek 
271*00b67f09SDavid van Moolenbroek int
main(int argc,char ** argv)272*00b67f09SDavid van Moolenbroek main(int argc, char **argv)
273*00b67f09SDavid van Moolenbroek {
274*00b67f09SDavid van Moolenbroek 	char *cp;
275*00b67f09SDavid van Moolenbroek 	int op, donamedboot, donamedconf;
276*00b67f09SDavid van Moolenbroek 
277*00b67f09SDavid van Moolenbroek 	if ((cp = strrchr(argv[0], '/')) != NULL)
278*00b67f09SDavid van Moolenbroek 		prog = cp + 1;
279*00b67f09SDavid van Moolenbroek 	else
280*00b67f09SDavid van Moolenbroek 		prog = argv[0];
281*00b67f09SDavid van Moolenbroek 
282*00b67f09SDavid van Moolenbroek 	donamedboot = 0;
283*00b67f09SDavid van Moolenbroek 	donamedconf = 0;
284*00b67f09SDavid van Moolenbroek 	while ((op = getopt(argc, argv, "b:c:B:C:d")) != -1)
285*00b67f09SDavid van Moolenbroek 		switch (op) {
286*00b67f09SDavid van Moolenbroek 
287*00b67f09SDavid van Moolenbroek 		case 'b':
288*00b67f09SDavid van Moolenbroek 			bootfile = optarg;
289*00b67f09SDavid van Moolenbroek 			++donamedboot;
290*00b67f09SDavid van Moolenbroek 			break;
291*00b67f09SDavid van Moolenbroek 
292*00b67f09SDavid van Moolenbroek 		case 'c':
293*00b67f09SDavid van Moolenbroek 			conffile = optarg;
294*00b67f09SDavid van Moolenbroek 			++donamedconf;
295*00b67f09SDavid van Moolenbroek 			break;
296*00b67f09SDavid van Moolenbroek 
297*00b67f09SDavid van Moolenbroek 		case 'B':
298*00b67f09SDavid van Moolenbroek 			nslintboot = optarg;
299*00b67f09SDavid van Moolenbroek 			++donamedboot;
300*00b67f09SDavid van Moolenbroek 			break;
301*00b67f09SDavid van Moolenbroek 
302*00b67f09SDavid van Moolenbroek 		case 'C':
303*00b67f09SDavid van Moolenbroek 			nslintconf = optarg;
304*00b67f09SDavid van Moolenbroek 			++donamedconf;
305*00b67f09SDavid van Moolenbroek 			break;
306*00b67f09SDavid van Moolenbroek 
307*00b67f09SDavid van Moolenbroek 		case 'd':
308*00b67f09SDavid van Moolenbroek 			++debug;
309*00b67f09SDavid van Moolenbroek 			break;
310*00b67f09SDavid van Moolenbroek 
311*00b67f09SDavid van Moolenbroek 		default:
312*00b67f09SDavid van Moolenbroek 			usage();
313*00b67f09SDavid van Moolenbroek 		}
314*00b67f09SDavid van Moolenbroek 	if (optind != argc || (donamedboot && donamedconf))
315*00b67f09SDavid van Moolenbroek 		usage();
316*00b67f09SDavid van Moolenbroek 
317*00b67f09SDavid van Moolenbroek 	/* Find config file if not manually specified */
318*00b67f09SDavid van Moolenbroek 	if (!donamedboot && !donamedconf) {
319*00b67f09SDavid van Moolenbroek 		if (access(conffile, R_OK) >= 0)
320*00b67f09SDavid van Moolenbroek 			++donamedconf;
321*00b67f09SDavid van Moolenbroek 		if (access(bootfile, R_OK) >= 0)
322*00b67f09SDavid van Moolenbroek 			++donamedboot;
323*00b67f09SDavid van Moolenbroek 
324*00b67f09SDavid van Moolenbroek 		if (donamedboot && donamedconf) {
325*00b67f09SDavid van Moolenbroek 			fprintf(stderr,
326*00b67f09SDavid van Moolenbroek 			    "%s: nslint: both %s and %s exist; use -b or -c\n",
327*00b67f09SDavid van Moolenbroek 			    prog, conffile, bootfile);
328*00b67f09SDavid van Moolenbroek 			exit(1);
329*00b67f09SDavid van Moolenbroek 		}
330*00b67f09SDavid van Moolenbroek 	}
331*00b67f09SDavid van Moolenbroek 
332*00b67f09SDavid van Moolenbroek 	if (donamedboot) {
333*00b67f09SDavid van Moolenbroek 		doboot(bootfile, CONF_MUSTEXIST | CONF_NOZONE);
334*00b67f09SDavid van Moolenbroek 		if (nslintboot != NULL)
335*00b67f09SDavid van Moolenbroek 			doboot(nslintboot, CONF_MUSTEXIST);
336*00b67f09SDavid van Moolenbroek 		else
337*00b67f09SDavid van Moolenbroek 			doboot(NSLINTBOOT, 0);
338*00b67f09SDavid van Moolenbroek 		doboot(bootfile, CONF_MUSTEXIST);
339*00b67f09SDavid van Moolenbroek 	} else {
340*00b67f09SDavid van Moolenbroek 		doconf(conffile, CONF_MUSTEXIST | CONF_NOZONE);
341*00b67f09SDavid van Moolenbroek 		if (nslintconf != NULL)
342*00b67f09SDavid van Moolenbroek 			doconf(nslintconf, CONF_MUSTEXIST);
343*00b67f09SDavid van Moolenbroek 		else
344*00b67f09SDavid van Moolenbroek 			doconf(NSLINTCONF, 0);
345*00b67f09SDavid van Moolenbroek 		doconf(conffile, CONF_MUSTEXIST);
346*00b67f09SDavid van Moolenbroek 	}
347*00b67f09SDavid van Moolenbroek 
348*00b67f09SDavid van Moolenbroek 	/* Sort network list */
349*00b67f09SDavid van Moolenbroek 	if (netlistcnt > 0)
350*00b67f09SDavid van Moolenbroek 		qsort(netlist, netlistcnt, sizeof(netlist[0]), cmpnetwork);
351*00b67f09SDavid van Moolenbroek 
352*00b67f09SDavid van Moolenbroek 	nslint();
353*00b67f09SDavid van Moolenbroek 	exit (errors != 0);
354*00b67f09SDavid van Moolenbroek }
355*00b67f09SDavid van Moolenbroek 
356*00b67f09SDavid van Moolenbroek /* add domain if necessary */
357*00b67f09SDavid van Moolenbroek void
add_domain(char * name,const char * domain)358*00b67f09SDavid van Moolenbroek add_domain(char *name, const char *domain)
359*00b67f09SDavid van Moolenbroek {
360*00b67f09SDavid van Moolenbroek 	char *cp;
361*00b67f09SDavid van Moolenbroek 
362*00b67f09SDavid van Moolenbroek 	/* Kill trailing white space and convert to lowercase */
363*00b67f09SDavid van Moolenbroek 	for (cp = name; *cp != '\0' && !isspace(*cp); ++cp)
364*00b67f09SDavid van Moolenbroek 		if (isupper(*cp))
365*00b67f09SDavid van Moolenbroek 			*cp = tolower(*cp);
366*00b67f09SDavid van Moolenbroek 	*cp-- = '\0';
367*00b67f09SDavid van Moolenbroek 	/* If necessary, append domain */
368*00b67f09SDavid van Moolenbroek 	if (cp >= name && *cp++ != '.') {
369*00b67f09SDavid van Moolenbroek 		if (*domain != '.')
370*00b67f09SDavid van Moolenbroek 			*cp++ = '.';
371*00b67f09SDavid van Moolenbroek 		(void)strcpy(cp, domain);
372*00b67f09SDavid van Moolenbroek 	}
373*00b67f09SDavid van Moolenbroek 	/* XXX should we insure a trailing dot? */
374*00b67f09SDavid van Moolenbroek }
375*00b67f09SDavid van Moolenbroek 
376*00b67f09SDavid van Moolenbroek const char *
addr2str(struct addr * ap)377*00b67f09SDavid van Moolenbroek addr2str(struct addr *ap)
378*00b67f09SDavid van Moolenbroek {
379*00b67f09SDavid van Moolenbroek 	struct network net;
380*00b67f09SDavid van Moolenbroek 
381*00b67f09SDavid van Moolenbroek 	memset(&net, 0, sizeof(net));
382*00b67f09SDavid van Moolenbroek 	net.family = ap->family;
383*00b67f09SDavid van Moolenbroek 	switch (ap->family) {
384*00b67f09SDavid van Moolenbroek 
385*00b67f09SDavid van Moolenbroek 	case AF_INET:
386*00b67f09SDavid van Moolenbroek 		net.n_addr4 = ap->a_addr4;
387*00b67f09SDavid van Moolenbroek 		setmaskwidth(32, &net);
388*00b67f09SDavid van Moolenbroek 		break;
389*00b67f09SDavid van Moolenbroek 
390*00b67f09SDavid van Moolenbroek 	case AF_INET6:
391*00b67f09SDavid van Moolenbroek 		memmove(net.n_addr6, &ap->a_addr6, sizeof(ap->a_addr6));
392*00b67f09SDavid van Moolenbroek 		setmaskwidth(128, &net);
393*00b67f09SDavid van Moolenbroek 		break;
394*00b67f09SDavid van Moolenbroek 
395*00b67f09SDavid van Moolenbroek 	default:
396*00b67f09SDavid van Moolenbroek 		return ("<nil>");
397*00b67f09SDavid van Moolenbroek 	}
398*00b67f09SDavid van Moolenbroek 	return (network2str(&net));
399*00b67f09SDavid van Moolenbroek }
400*00b67f09SDavid van Moolenbroek 
401*00b67f09SDavid van Moolenbroek /*
402*00b67f09SDavid van Moolenbroek  * Returns true if name is really an ip address.
403*00b67f09SDavid van Moolenbroek  */
404*00b67f09SDavid van Moolenbroek int
checkaddr(const char * name)405*00b67f09SDavid van Moolenbroek checkaddr(const char *name)
406*00b67f09SDavid van Moolenbroek {
407*00b67f09SDavid van Moolenbroek 	struct in_addr addr;
408*00b67f09SDavid van Moolenbroek 
409*00b67f09SDavid van Moolenbroek 	return (inet_pton(AF_INET, name, (char *)&addr));
410*00b67f09SDavid van Moolenbroek }
411*00b67f09SDavid van Moolenbroek 
412*00b67f09SDavid van Moolenbroek /*
413*00b67f09SDavid van Moolenbroek  * Returns true if name contains a dot but not a trailing dot.
414*00b67f09SDavid van Moolenbroek  * Special case: allow a single dot if the second part is not one
415*00b67f09SDavid van Moolenbroek  * of the 3 or 4 letter top level domains or is any 2 letter TLD
416*00b67f09SDavid van Moolenbroek  */
417*00b67f09SDavid van Moolenbroek int
checkdots(const char * name)418*00b67f09SDavid van Moolenbroek checkdots(const char *name)
419*00b67f09SDavid van Moolenbroek {
420*00b67f09SDavid van Moolenbroek 	const char *cp, *cp2;
421*00b67f09SDavid van Moolenbroek 
422*00b67f09SDavid van Moolenbroek 	if ((cp = strchr(name, '.')) == NULL)
423*00b67f09SDavid van Moolenbroek 		return (0);
424*00b67f09SDavid van Moolenbroek 	cp2 = name + strlen(name) - 1;
425*00b67f09SDavid van Moolenbroek 	if (cp2 >= name && *cp2 == '.')
426*00b67f09SDavid van Moolenbroek 		return (0);
427*00b67f09SDavid van Moolenbroek 
428*00b67f09SDavid van Moolenbroek 	/* Return true of more than one dot*/
429*00b67f09SDavid van Moolenbroek 	++cp;
430*00b67f09SDavid van Moolenbroek 	if (strchr(cp, '.') != NULL)
431*00b67f09SDavid van Moolenbroek 		return (1);
432*00b67f09SDavid van Moolenbroek 
433*00b67f09SDavid van Moolenbroek 	if (strlen(cp) == 2 ||
434*00b67f09SDavid van Moolenbroek 	    strcasecmp(cp, "gov") == 0 ||
435*00b67f09SDavid van Moolenbroek 	    strcasecmp(cp, "edu") == 0 ||
436*00b67f09SDavid van Moolenbroek 	    strcasecmp(cp, "com") == 0 ||
437*00b67f09SDavid van Moolenbroek 	    strcasecmp(cp, "net") == 0 ||
438*00b67f09SDavid van Moolenbroek 	    strcasecmp(cp, "org") == 0 ||
439*00b67f09SDavid van Moolenbroek 	    strcasecmp(cp, "mil") == 0 ||
440*00b67f09SDavid van Moolenbroek 	    strcasecmp(cp, "int") == 0 ||
441*00b67f09SDavid van Moolenbroek 	    strcasecmp(cp, "nato") == 0 ||
442*00b67f09SDavid van Moolenbroek 	    strcasecmp(cp, "arpa") == 0)
443*00b67f09SDavid van Moolenbroek 		return (1);
444*00b67f09SDavid van Moolenbroek 	return (0);
445*00b67f09SDavid van Moolenbroek }
446*00b67f09SDavid van Moolenbroek 
447*00b67f09SDavid van Moolenbroek /* Records we use to detect duplicates */
448*00b67f09SDavid van Moolenbroek static struct duprec {
449*00b67f09SDavid van Moolenbroek 	int record;
450*00b67f09SDavid van Moolenbroek 	char *name;
451*00b67f09SDavid van Moolenbroek } duprec[] = {
452*00b67f09SDavid van Moolenbroek 	{ REC_A, "a" },
453*00b67f09SDavid van Moolenbroek 	{ REC_AAAA, "aaaa" },
454*00b67f09SDavid van Moolenbroek 	{ REC_HINFO, "hinfo" },
455*00b67f09SDavid van Moolenbroek 	{ REC_CNAME, "cname" },
456*00b67f09SDavid van Moolenbroek 	{ 0, NULL },
457*00b67f09SDavid van Moolenbroek };
458*00b67f09SDavid van Moolenbroek 
459*00b67f09SDavid van Moolenbroek void
checkdups(struct item * ip,int records)460*00b67f09SDavid van Moolenbroek checkdups(struct item *ip, int records)
461*00b67f09SDavid van Moolenbroek {
462*00b67f09SDavid van Moolenbroek 	struct duprec *dp;
463*00b67f09SDavid van Moolenbroek 
464*00b67f09SDavid van Moolenbroek 	records &= (ip->records & MASK_TEST_DUP);
465*00b67f09SDavid van Moolenbroek 	if (records == 0)
466*00b67f09SDavid van Moolenbroek 		return;
467*00b67f09SDavid van Moolenbroek 	for (dp = duprec; dp->name != NULL; ++dp)
468*00b67f09SDavid van Moolenbroek 		if ((records & dp->record) != 0) {
469*00b67f09SDavid van Moolenbroek 			++errors;
470*00b67f09SDavid van Moolenbroek 			fprintf(stderr, "%s: multiple \"%s\" records for %s\n",
471*00b67f09SDavid van Moolenbroek 			    prog, dp->name, ip->host);
472*00b67f09SDavid van Moolenbroek 			records &= ~dp->record;
473*00b67f09SDavid van Moolenbroek 		}
474*00b67f09SDavid van Moolenbroek 	if (records != 0)
475*00b67f09SDavid van Moolenbroek 		fprintf(stderr, "%s: checkdups: records not zero %s (0x%x)\n",
476*00b67f09SDavid van Moolenbroek 		    prog, ip->host, records);
477*00b67f09SDavid van Moolenbroek }
478*00b67f09SDavid van Moolenbroek 
479*00b67f09SDavid van Moolenbroek /* Check for an "ignored zone" (usually dynamic dns) */
480*00b67f09SDavid van Moolenbroek int
checkignoredzone(const char * name)481*00b67f09SDavid van Moolenbroek checkignoredzone(const char *name)
482*00b67f09SDavid van Moolenbroek {
483*00b67f09SDavid van Moolenbroek 	int i, len, len2;
484*00b67f09SDavid van Moolenbroek 
485*00b67f09SDavid van Moolenbroek 	len = strlen(name);
486*00b67f09SDavid van Moolenbroek 	if (len > 1 && name[len - 1] == '.')
487*00b67f09SDavid van Moolenbroek 		--len;
488*00b67f09SDavid van Moolenbroek 	for (i = 0; i < numignoredzones; ++i) {
489*00b67f09SDavid van Moolenbroek 		len2 = len - ignoredzones[i].len;
490*00b67f09SDavid van Moolenbroek 		if (len2 >= 0 &&
491*00b67f09SDavid van Moolenbroek 		    strncasecmp(name + len2,
492*00b67f09SDavid van Moolenbroek 			ignoredzones[i].zone, len - len2) == 0)
493*00b67f09SDavid van Moolenbroek 			    return (1);
494*00b67f09SDavid van Moolenbroek 	}
495*00b67f09SDavid van Moolenbroek 	return (0);
496*00b67f09SDavid van Moolenbroek }
497*00b67f09SDavid van Moolenbroek 
498*00b67f09SDavid van Moolenbroek int
checkserv(const char * serv,char ** p)499*00b67f09SDavid van Moolenbroek checkserv(const char *serv, char **p)
500*00b67f09SDavid van Moolenbroek {
501*00b67f09SDavid van Moolenbroek 	for (; *p != NULL; ++p)
502*00b67f09SDavid van Moolenbroek 		if (*serv == **p && strcmp(serv, *p) == 0)
503*00b67f09SDavid van Moolenbroek 			return (1);
504*00b67f09SDavid van Moolenbroek 	return (0);
505*00b67f09SDavid van Moolenbroek }
506*00b67f09SDavid van Moolenbroek 
507*00b67f09SDavid van Moolenbroek int
checkwks(FILE * f,char * proto,int * smtpp,char ** errstrp)508*00b67f09SDavid van Moolenbroek checkwks(FILE *f, char *proto, int *smtpp, char **errstrp)
509*00b67f09SDavid van Moolenbroek {
510*00b67f09SDavid van Moolenbroek 	int n, sawparen;
511*00b67f09SDavid van Moolenbroek 	char *cp, *serv, **p;
512*00b67f09SDavid van Moolenbroek 	static char errstr[132];
513*00b67f09SDavid van Moolenbroek 	char buf[1024];
514*00b67f09SDavid van Moolenbroek 	char psbuf[512];
515*00b67f09SDavid van Moolenbroek 
516*00b67f09SDavid van Moolenbroek 	if (!protoserv_init) {
517*00b67f09SDavid van Moolenbroek 		initprotoserv();
518*00b67f09SDavid van Moolenbroek 		++protoserv_init;
519*00b67f09SDavid van Moolenbroek 	}
520*00b67f09SDavid van Moolenbroek 
521*00b67f09SDavid van Moolenbroek 	/* Line count */
522*00b67f09SDavid van Moolenbroek 	n = 0;
523*00b67f09SDavid van Moolenbroek 
524*00b67f09SDavid van Moolenbroek 	/* Terminate protocol */
525*00b67f09SDavid van Moolenbroek 	cp = proto;
526*00b67f09SDavid van Moolenbroek 	while (!isspace(*cp) && *cp != '\0')
527*00b67f09SDavid van Moolenbroek 		++cp;
528*00b67f09SDavid van Moolenbroek 	if (*cp != '\0')
529*00b67f09SDavid van Moolenbroek 		*cp++ = '\0';
530*00b67f09SDavid van Moolenbroek 
531*00b67f09SDavid van Moolenbroek 	/* Find services */
532*00b67f09SDavid van Moolenbroek 	*smtpp = 0;
533*00b67f09SDavid van Moolenbroek 	sawparen = 0;
534*00b67f09SDavid van Moolenbroek 	if (*cp == '(') {
535*00b67f09SDavid van Moolenbroek 		++sawparen;
536*00b67f09SDavid van Moolenbroek 		++cp;
537*00b67f09SDavid van Moolenbroek 		while (isspace(*cp))
538*00b67f09SDavid van Moolenbroek 			++cp;
539*00b67f09SDavid van Moolenbroek 	}
540*00b67f09SDavid van Moolenbroek 	for (;;) {
541*00b67f09SDavid van Moolenbroek 		if (*cp == '\0') {
542*00b67f09SDavid van Moolenbroek 			if (!sawparen)
543*00b67f09SDavid van Moolenbroek 				break;
544*00b67f09SDavid van Moolenbroek 			if (fgets(buf, sizeof(buf), f) == NULL) {
545*00b67f09SDavid van Moolenbroek 				*errstrp = "mismatched parens";
546*00b67f09SDavid van Moolenbroek 				return (n);
547*00b67f09SDavid van Moolenbroek 			}
548*00b67f09SDavid van Moolenbroek 			++n;
549*00b67f09SDavid van Moolenbroek 			cp = buf;
550*00b67f09SDavid van Moolenbroek 			while (isspace(*cp))
551*00b67f09SDavid van Moolenbroek 				++cp;
552*00b67f09SDavid van Moolenbroek 		}
553*00b67f09SDavid van Moolenbroek 		/* Find end of service, converting to lowercase */
554*00b67f09SDavid van Moolenbroek 		for (serv = cp; !isspace(*cp) && *cp != '\0'; ++cp)
555*00b67f09SDavid van Moolenbroek 			if (isupper(*cp))
556*00b67f09SDavid van Moolenbroek 				*cp = tolower(*cp);
557*00b67f09SDavid van Moolenbroek 		if (*cp != '\0')
558*00b67f09SDavid van Moolenbroek 			*cp++ = '\0';
559*00b67f09SDavid van Moolenbroek 		if (sawparen && *cp == ')') {
560*00b67f09SDavid van Moolenbroek 			/* XXX should check for trailing junk */
561*00b67f09SDavid van Moolenbroek 			break;
562*00b67f09SDavid van Moolenbroek 		}
563*00b67f09SDavid van Moolenbroek 
564*00b67f09SDavid van Moolenbroek 		(void)sprintf(psbuf, "%s/%s", serv, proto);
565*00b67f09SDavid van Moolenbroek 
566*00b67f09SDavid van Moolenbroek 		if (*serv == 's' && strcmp(psbuf, "tcp/smtp") == 0)
567*00b67f09SDavid van Moolenbroek 			++*smtpp;
568*00b67f09SDavid van Moolenbroek 
569*00b67f09SDavid van Moolenbroek 		for (p = protoserv; *p != NULL; ++p)
570*00b67f09SDavid van Moolenbroek 			if (*psbuf == **p && strcmp(psbuf, *p) == 0) {
571*00b67f09SDavid van Moolenbroek 				break;
572*00b67f09SDavid van Moolenbroek 			}
573*00b67f09SDavid van Moolenbroek 		if (*p == NULL) {
574*00b67f09SDavid van Moolenbroek 			sprintf(errstr, "%s unknown", psbuf);
575*00b67f09SDavid van Moolenbroek 			*errstrp = errstr;
576*00b67f09SDavid van Moolenbroek 			break;
577*00b67f09SDavid van Moolenbroek 		}
578*00b67f09SDavid van Moolenbroek 	}
579*00b67f09SDavid van Moolenbroek 
580*00b67f09SDavid van Moolenbroek 	return (n);
581*00b67f09SDavid van Moolenbroek }
582*00b67f09SDavid van Moolenbroek 
583*00b67f09SDavid van Moolenbroek int
cmpaddr(const void * arg1,const void * arg2)584*00b67f09SDavid van Moolenbroek cmpaddr(const void *arg1, const void *arg2)
585*00b67f09SDavid van Moolenbroek {
586*00b67f09SDavid van Moolenbroek 	int i, r1;
587*00b67f09SDavid van Moolenbroek 	const struct network *n1, *n2;
588*00b67f09SDavid van Moolenbroek 
589*00b67f09SDavid van Moolenbroek 	n1 = (const struct network *)arg1;
590*00b67f09SDavid van Moolenbroek 	n2 = (const struct network *)arg2;
591*00b67f09SDavid van Moolenbroek 
592*00b67f09SDavid van Moolenbroek 	/* IPv4 before IPv6 */
593*00b67f09SDavid van Moolenbroek 	if (n1->family != n2->family)
594*00b67f09SDavid van Moolenbroek 		return ((n1->family == AF_INET) ? -1 : 1);
595*00b67f09SDavid van Moolenbroek 
596*00b67f09SDavid van Moolenbroek 	switch (n1->family) {
597*00b67f09SDavid van Moolenbroek 
598*00b67f09SDavid van Moolenbroek 	case AF_INET:
599*00b67f09SDavid van Moolenbroek 		/* Address */
600*00b67f09SDavid van Moolenbroek 		if (ntohl(n1->n_addr4) < ntohl(n2->n_addr4))
601*00b67f09SDavid van Moolenbroek 			return (-1);
602*00b67f09SDavid van Moolenbroek 		else if (ntohl(n1->n_addr4) > ntohl(n2->n_addr4))
603*00b67f09SDavid van Moolenbroek 			return (1);
604*00b67f09SDavid van Moolenbroek 		return (0);
605*00b67f09SDavid van Moolenbroek 
606*00b67f09SDavid van Moolenbroek 	case AF_INET6:
607*00b67f09SDavid van Moolenbroek 		/* Address */
608*00b67f09SDavid van Moolenbroek 		r1 = 0;
609*00b67f09SDavid van Moolenbroek 		for (i = 0; i < 16; ++i) {
610*00b67f09SDavid van Moolenbroek 			if (ntohl(n1->n_addr6[i]) < ntohl(n2->n_addr6[i]))
611*00b67f09SDavid van Moolenbroek 				return (-1);
612*00b67f09SDavid van Moolenbroek 			if (ntohl(n1->n_addr6[i]) > ntohl(n2->n_addr6[i]))
613*00b67f09SDavid van Moolenbroek 				return (1);
614*00b67f09SDavid van Moolenbroek 		}
615*00b67f09SDavid van Moolenbroek 		return (0);
616*00b67f09SDavid van Moolenbroek 
617*00b67f09SDavid van Moolenbroek 	default:
618*00b67f09SDavid van Moolenbroek 		abort();
619*00b67f09SDavid van Moolenbroek 	}
620*00b67f09SDavid van Moolenbroek }
621*00b67f09SDavid van Moolenbroek 
622*00b67f09SDavid van Moolenbroek int
cmpitemaddr(const void * arg1,const void * arg2)623*00b67f09SDavid van Moolenbroek cmpitemaddr(const void *arg1, const void *arg2)
624*00b67f09SDavid van Moolenbroek {
625*00b67f09SDavid van Moolenbroek 	struct item *i1, *i2;
626*00b67f09SDavid van Moolenbroek 
627*00b67f09SDavid van Moolenbroek 	i1 = (struct item *)arg1;
628*00b67f09SDavid van Moolenbroek 	i2 = (struct item *)arg2;
629*00b67f09SDavid van Moolenbroek 
630*00b67f09SDavid van Moolenbroek 	return (cmpaddr(&i1->addr, &i2->addr));
631*00b67f09SDavid van Moolenbroek }
632*00b67f09SDavid van Moolenbroek 
633*00b67f09SDavid van Moolenbroek int
cmpitemhost(const void * arg1,const void * arg2)634*00b67f09SDavid van Moolenbroek cmpitemhost(const void *arg1, const void *arg2)
635*00b67f09SDavid van Moolenbroek {
636*00b67f09SDavid van Moolenbroek 	struct item *i1, *i2;
637*00b67f09SDavid van Moolenbroek 
638*00b67f09SDavid van Moolenbroek 	i1 = (struct item *)arg1;
639*00b67f09SDavid van Moolenbroek 	i2 = (struct item *)arg2;
640*00b67f09SDavid van Moolenbroek 
641*00b67f09SDavid van Moolenbroek 	return (strcasecmp(i1->host, i1->host));
642*00b67f09SDavid van Moolenbroek }
643*00b67f09SDavid van Moolenbroek 
644*00b67f09SDavid van Moolenbroek /* Sort by network number (use mask when networks are the same) */
645*00b67f09SDavid van Moolenbroek int
cmpnetwork(const void * arg1,const void * arg2)646*00b67f09SDavid van Moolenbroek cmpnetwork(const void *arg1, const void *arg2)
647*00b67f09SDavid van Moolenbroek {
648*00b67f09SDavid van Moolenbroek 	int i, r1, r2;
649*00b67f09SDavid van Moolenbroek 	const struct network *n1, *n2;
650*00b67f09SDavid van Moolenbroek 
651*00b67f09SDavid van Moolenbroek 	n1 = (const struct network *)arg1;
652*00b67f09SDavid van Moolenbroek 	n2 = (const struct network *)arg2;
653*00b67f09SDavid van Moolenbroek 
654*00b67f09SDavid van Moolenbroek 	/* IPv4 before IPv6 */
655*00b67f09SDavid van Moolenbroek 	if (n1->family != n2->family)
656*00b67f09SDavid van Moolenbroek 		return ((n1->family == AF_INET) ? -1 : 1);
657*00b67f09SDavid van Moolenbroek 
658*00b67f09SDavid van Moolenbroek 	switch (n1->family) {
659*00b67f09SDavid van Moolenbroek 
660*00b67f09SDavid van Moolenbroek 	case AF_INET:
661*00b67f09SDavid van Moolenbroek 		/* Address */
662*00b67f09SDavid van Moolenbroek 		if (ntohl(n1->n_addr4) < ntohl(n2->n_addr4))
663*00b67f09SDavid van Moolenbroek 			return (-1);
664*00b67f09SDavid van Moolenbroek 		else if (ntohl(n1->n_addr4) > ntohl(n2->n_addr4))
665*00b67f09SDavid van Moolenbroek 			return (1);
666*00b67f09SDavid van Moolenbroek 
667*00b67f09SDavid van Moolenbroek 		/* Mask */
668*00b67f09SDavid van Moolenbroek 		if (ntohl(n1->n_mask4) < ntohl(n2->n_mask4))
669*00b67f09SDavid van Moolenbroek 			return (1);
670*00b67f09SDavid van Moolenbroek 		else if (ntohl(n1->n_mask4) > ntohl(n2->n_mask4))
671*00b67f09SDavid van Moolenbroek 			return (-1);
672*00b67f09SDavid van Moolenbroek 		return (0);
673*00b67f09SDavid van Moolenbroek 
674*00b67f09SDavid van Moolenbroek 	case AF_INET6:
675*00b67f09SDavid van Moolenbroek 		/* Address */
676*00b67f09SDavid van Moolenbroek 		r1 = 0;
677*00b67f09SDavid van Moolenbroek 		for (i = 0; i < 16; ++i) {
678*00b67f09SDavid van Moolenbroek 			if (ntohl(n1->n_addr6[i]) < ntohl(n2->n_addr6[i]))
679*00b67f09SDavid van Moolenbroek 				return (-1);
680*00b67f09SDavid van Moolenbroek 			if (ntohl(n1->n_addr6[i]) > ntohl(n2->n_addr6[i]))
681*00b67f09SDavid van Moolenbroek 				return (1);
682*00b67f09SDavid van Moolenbroek 		}
683*00b67f09SDavid van Moolenbroek 
684*00b67f09SDavid van Moolenbroek 		/* Mask */
685*00b67f09SDavid van Moolenbroek 		r2 = 0;
686*00b67f09SDavid van Moolenbroek 		for (i = 0; i < 16; ++i) {
687*00b67f09SDavid van Moolenbroek 			if (n1->n_mask6[i] < n2->n_mask6[i])
688*00b67f09SDavid van Moolenbroek 				return (1);
689*00b67f09SDavid van Moolenbroek 			if (n1->n_mask6[i] > n2->n_mask6[i])
690*00b67f09SDavid van Moolenbroek 				return (-1);
691*00b67f09SDavid van Moolenbroek 		}
692*00b67f09SDavid van Moolenbroek 		return (0);
693*00b67f09SDavid van Moolenbroek 		break;
694*00b67f09SDavid van Moolenbroek 
695*00b67f09SDavid van Moolenbroek 	default:
696*00b67f09SDavid van Moolenbroek 		abort();
697*00b67f09SDavid van Moolenbroek 	}
698*00b67f09SDavid van Moolenbroek 	abort();
699*00b67f09SDavid van Moolenbroek }
700*00b67f09SDavid van Moolenbroek 
701*00b67f09SDavid van Moolenbroek void
doboot(const char * file,int flags)702*00b67f09SDavid van Moolenbroek doboot(const char *file, int flags)
703*00b67f09SDavid van Moolenbroek {
704*00b67f09SDavid van Moolenbroek 	int n;
705*00b67f09SDavid van Moolenbroek 	char *cp, *cp2;
706*00b67f09SDavid van Moolenbroek 	FILE *f;
707*00b67f09SDavid van Moolenbroek 	const char *errstr;
708*00b67f09SDavid van Moolenbroek 	char buf[1024], name[128];
709*00b67f09SDavid van Moolenbroek 
710*00b67f09SDavid van Moolenbroek 	errno = 0;
711*00b67f09SDavid van Moolenbroek 	f = fopen(file, "r");
712*00b67f09SDavid van Moolenbroek 	if (f == NULL) {
713*00b67f09SDavid van Moolenbroek 		/* Not an error if it doesn't exist */
714*00b67f09SDavid van Moolenbroek 		if ((flags & CONF_MUSTEXIST) == 0 && errno == ENOENT) {
715*00b67f09SDavid van Moolenbroek 			if (debug > 1)
716*00b67f09SDavid van Moolenbroek 				printf(
717*00b67f09SDavid van Moolenbroek 				    "%s: doit: %s doesn't exist (ignoring)\n",
718*00b67f09SDavid van Moolenbroek 				    prog, file);
719*00b67f09SDavid van Moolenbroek 			return;
720*00b67f09SDavid van Moolenbroek 		}
721*00b67f09SDavid van Moolenbroek 		fprintf(stderr, "%s: %s: %s\n", prog, file, strerror(errno));
722*00b67f09SDavid van Moolenbroek 		exit(1);
723*00b67f09SDavid van Moolenbroek 	}
724*00b67f09SDavid van Moolenbroek 	if (debug > 1)
725*00b67f09SDavid van Moolenbroek 		printf("%s: doit: opened %s\n", prog, file);
726*00b67f09SDavid van Moolenbroek 
727*00b67f09SDavid van Moolenbroek 	n = 0;
728*00b67f09SDavid van Moolenbroek 	while (fgets(buf, sizeof(buf), f) != NULL) {
729*00b67f09SDavid van Moolenbroek 		++n;
730*00b67f09SDavid van Moolenbroek 
731*00b67f09SDavid van Moolenbroek 		/* Skip comments */
732*00b67f09SDavid van Moolenbroek 		if (buf[0] == ';')
733*00b67f09SDavid van Moolenbroek 			continue;
734*00b67f09SDavid van Moolenbroek 		cp = strchr(buf, ';');
735*00b67f09SDavid van Moolenbroek 		if (cp)
736*00b67f09SDavid van Moolenbroek 			*cp = '\0';
737*00b67f09SDavid van Moolenbroek 		cp = buf + strlen(buf) - 1;
738*00b67f09SDavid van Moolenbroek 		if (cp >= buf && *cp == '\n')
739*00b67f09SDavid van Moolenbroek 			*cp = '\0';
740*00b67f09SDavid van Moolenbroek 		cp = buf;
741*00b67f09SDavid van Moolenbroek 
742*00b67f09SDavid van Moolenbroek 		/* Eat leading whitespace */
743*00b67f09SDavid van Moolenbroek 		while (isspace(*cp))
744*00b67f09SDavid van Moolenbroek 			++cp;
745*00b67f09SDavid van Moolenbroek 
746*00b67f09SDavid van Moolenbroek 		/* Skip blank lines */
747*00b67f09SDavid van Moolenbroek 		if (*cp == '\n' || *cp == '\0')
748*00b67f09SDavid van Moolenbroek 			continue;
749*00b67f09SDavid van Moolenbroek 
750*00b67f09SDavid van Moolenbroek 		/* Get name */
751*00b67f09SDavid van Moolenbroek 		cp2 = cp;
752*00b67f09SDavid van Moolenbroek 		while (!isspace(*cp) && *cp != '\0')
753*00b67f09SDavid van Moolenbroek 			++cp;
754*00b67f09SDavid van Moolenbroek 		*cp++ = '\0';
755*00b67f09SDavid van Moolenbroek 
756*00b67f09SDavid van Moolenbroek 		/* Find next keyword */
757*00b67f09SDavid van Moolenbroek 		while (isspace(*cp))
758*00b67f09SDavid van Moolenbroek 			++cp;
759*00b67f09SDavid van Moolenbroek 		if (strcasecmp(cp2, "directory") == 0) {
760*00b67f09SDavid van Moolenbroek 			/* Terminate directory */
761*00b67f09SDavid van Moolenbroek 			cp2 = cp;
762*00b67f09SDavid van Moolenbroek 			while (!isspace(*cp) && *cp != '\0')
763*00b67f09SDavid van Moolenbroek 				++cp;
764*00b67f09SDavid van Moolenbroek 			*cp = '\0';
765*00b67f09SDavid van Moolenbroek 			if (chdir(cp2) < 0) {
766*00b67f09SDavid van Moolenbroek 				++errors;
767*00b67f09SDavid van Moolenbroek 				fprintf(stderr, "%s: can't chdir %s: %s\n",
768*00b67f09SDavid van Moolenbroek 				    prog, cp2, strerror(errno));
769*00b67f09SDavid van Moolenbroek 				exit(1);
770*00b67f09SDavid van Moolenbroek 			}
771*00b67f09SDavid van Moolenbroek 			cwd = savestr(cp2);
772*00b67f09SDavid van Moolenbroek 			continue;
773*00b67f09SDavid van Moolenbroek 		}
774*00b67f09SDavid van Moolenbroek 		if (strcasecmp(cp2, "primary") == 0) {
775*00b67f09SDavid van Moolenbroek 			/* Extract domain, converting to lowercase */
776*00b67f09SDavid van Moolenbroek 			for (cp2 = name; !isspace(*cp) && *cp != '\0'; ++cp)
777*00b67f09SDavid van Moolenbroek 				if (isupper(*cp))
778*00b67f09SDavid van Moolenbroek 					*cp2++ = tolower(*cp);
779*00b67f09SDavid van Moolenbroek 				else
780*00b67f09SDavid van Moolenbroek 					*cp2++ = *cp;
781*00b67f09SDavid van Moolenbroek 			/* Insure trailing dot */
782*00b67f09SDavid van Moolenbroek 			if (cp2 > name && cp2[-1] != '.')
783*00b67f09SDavid van Moolenbroek 				*cp2++ = '.';
784*00b67f09SDavid van Moolenbroek 			*cp2 = '\0';
785*00b67f09SDavid van Moolenbroek 
786*00b67f09SDavid van Moolenbroek 			/* Find file */
787*00b67f09SDavid van Moolenbroek 			while (isspace(*cp))
788*00b67f09SDavid van Moolenbroek 				++cp;
789*00b67f09SDavid van Moolenbroek 
790*00b67f09SDavid van Moolenbroek 			/* Terminate directory */
791*00b67f09SDavid van Moolenbroek 			cp2 = cp;
792*00b67f09SDavid van Moolenbroek 			while (!isspace(*cp) && *cp != '\0')
793*00b67f09SDavid van Moolenbroek 				++cp;
794*00b67f09SDavid van Moolenbroek 			*cp = '\0';
795*00b67f09SDavid van Moolenbroek 
796*00b67f09SDavid van Moolenbroek 			/* Process it! (zone is the same as the domain) */
797*00b67f09SDavid van Moolenbroek 			nsoaval = -1;
798*00b67f09SDavid van Moolenbroek 			memset(soaval, 0, sizeof(soaval));
799*00b67f09SDavid van Moolenbroek 			if ((flags & CONF_NOZONE) == 0)
800*00b67f09SDavid van Moolenbroek 				process(cp2, name, name);
801*00b67f09SDavid van Moolenbroek 			continue;
802*00b67f09SDavid van Moolenbroek 		}
803*00b67f09SDavid van Moolenbroek 		if (strcasecmp(cp2, "network") == 0) {
804*00b67f09SDavid van Moolenbroek 			errstr = parsenetwork(cp);
805*00b67f09SDavid van Moolenbroek 			if (errstr != NULL) {
806*00b67f09SDavid van Moolenbroek 				++errors;
807*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
808*00b67f09SDavid van Moolenbroek 				    "%s: %s:%d: bad network: %s\n",
809*00b67f09SDavid van Moolenbroek 				    prog, file, n, errstr);
810*00b67f09SDavid van Moolenbroek 			}
811*00b67f09SDavid van Moolenbroek 			continue;
812*00b67f09SDavid van Moolenbroek 		}
813*00b67f09SDavid van Moolenbroek 		if (strcasecmp(cp2, "include") == 0) {
814*00b67f09SDavid van Moolenbroek 			/* Terminate include file */
815*00b67f09SDavid van Moolenbroek 			cp2 = cp;
816*00b67f09SDavid van Moolenbroek 			while (!isspace(*cp) && *cp != '\0')
817*00b67f09SDavid van Moolenbroek 				++cp;
818*00b67f09SDavid van Moolenbroek 			*cp = '\0';
819*00b67f09SDavid van Moolenbroek 			doboot(cp2, 1);
820*00b67f09SDavid van Moolenbroek 			continue;
821*00b67f09SDavid van Moolenbroek 		}
822*00b67f09SDavid van Moolenbroek 		/* Eat any other options */
823*00b67f09SDavid van Moolenbroek 	}
824*00b67f09SDavid van Moolenbroek 	(void)fclose(f);
825*00b67f09SDavid van Moolenbroek }
826*00b67f09SDavid van Moolenbroek 
827*00b67f09SDavid van Moolenbroek void
doconf(const char * file,int flags)828*00b67f09SDavid van Moolenbroek doconf(const char *file, int flags)
829*00b67f09SDavid van Moolenbroek {
830*00b67f09SDavid van Moolenbroek 	int n, fd, cc, i, depth;
831*00b67f09SDavid van Moolenbroek 	char *cp, *cp2, *buf;
832*00b67f09SDavid van Moolenbroek 	const char *p;
833*00b67f09SDavid van Moolenbroek 	char *name, *zonename, *filename, *typename;
834*00b67f09SDavid van Moolenbroek 	int namelen, zonenamelen, filenamelen, typenamelen;
835*00b67f09SDavid van Moolenbroek 	struct stat sbuf;
836*00b67f09SDavid van Moolenbroek 	char zone[128], includefile[256];
837*00b67f09SDavid van Moolenbroek 
838*00b67f09SDavid van Moolenbroek 	errno = 0;
839*00b67f09SDavid van Moolenbroek 	fd = open(file, O_RDONLY, 0);
840*00b67f09SDavid van Moolenbroek 	if (fd < 0) {
841*00b67f09SDavid van Moolenbroek 		/* Not an error if it doesn't exist */
842*00b67f09SDavid van Moolenbroek 		if ((flags & CONF_MUSTEXIST) == 0 && errno == ENOENT) {
843*00b67f09SDavid van Moolenbroek 			if (debug > 1)
844*00b67f09SDavid van Moolenbroek 				printf(
845*00b67f09SDavid van Moolenbroek 				    "%s: doconf: %s doesn't exist (ignoring)\n",
846*00b67f09SDavid van Moolenbroek 				    prog, file);
847*00b67f09SDavid van Moolenbroek 			return;
848*00b67f09SDavid van Moolenbroek 		}
849*00b67f09SDavid van Moolenbroek 		fprintf(stderr, "%s: %s: %s\n", prog, file, strerror(errno));
850*00b67f09SDavid van Moolenbroek 		exit(1);
851*00b67f09SDavid van Moolenbroek 	}
852*00b67f09SDavid van Moolenbroek 	if (debug > 1)
853*00b67f09SDavid van Moolenbroek 		printf("%s: doconf: opened %s\n", prog, file);
854*00b67f09SDavid van Moolenbroek 
855*00b67f09SDavid van Moolenbroek 	if (fstat(fd, &sbuf) < 0) {
856*00b67f09SDavid van Moolenbroek 		fprintf(stderr, "%s: fstat(%s) %s\n",
857*00b67f09SDavid van Moolenbroek 		    prog, file, strerror(errno));
858*00b67f09SDavid van Moolenbroek 		exit(1);
859*00b67f09SDavid van Moolenbroek 	}
860*00b67f09SDavid van Moolenbroek 	buf = (char *)malloc(sbuf.st_size + 1);
861*00b67f09SDavid van Moolenbroek 	if (buf == NULL) {
862*00b67f09SDavid van Moolenbroek 		fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno));
863*00b67f09SDavid van Moolenbroek 		exit(1);
864*00b67f09SDavid van Moolenbroek 	}
865*00b67f09SDavid van Moolenbroek 
866*00b67f09SDavid van Moolenbroek 	/* Slurp entire config file */
867*00b67f09SDavid van Moolenbroek 	n = sbuf.st_size;
868*00b67f09SDavid van Moolenbroek 	cp = buf;
869*00b67f09SDavid van Moolenbroek 	do {
870*00b67f09SDavid van Moolenbroek 		cc = read(fd, cp, n);
871*00b67f09SDavid van Moolenbroek 		if (cc < 0) {
872*00b67f09SDavid van Moolenbroek 			fprintf(stderr, "%s: read(%s) %s\n",
873*00b67f09SDavid van Moolenbroek 			    prog, file, strerror(errno));
874*00b67f09SDavid van Moolenbroek 			exit(1);
875*00b67f09SDavid van Moolenbroek 		}
876*00b67f09SDavid van Moolenbroek 		cp += cc;
877*00b67f09SDavid van Moolenbroek 		n -= cc;
878*00b67f09SDavid van Moolenbroek 	} while (cc != 0 && cc < n);
879*00b67f09SDavid van Moolenbroek 	buf[cc] = '\0';
880*00b67f09SDavid van Moolenbroek 
881*00b67f09SDavid van Moolenbroek #define EATWHITESPACE \
882*00b67f09SDavid van Moolenbroek 	while (isspace(*cp)) { \
883*00b67f09SDavid van Moolenbroek 		if (*cp == '\n') \
884*00b67f09SDavid van Moolenbroek 			++n; \
885*00b67f09SDavid van Moolenbroek 		++cp; \
886*00b67f09SDavid van Moolenbroek 	}
887*00b67f09SDavid van Moolenbroek 
888*00b67f09SDavid van Moolenbroek /* Handle both to-end-of-line and C style comments */
889*00b67f09SDavid van Moolenbroek #define EATCOMMENTS \
890*00b67f09SDavid van Moolenbroek 	{ \
891*00b67f09SDavid van Moolenbroek 	int sawcomment; \
892*00b67f09SDavid van Moolenbroek 	do { \
893*00b67f09SDavid van Moolenbroek 		EATWHITESPACE \
894*00b67f09SDavid van Moolenbroek 		sawcomment = 0; \
895*00b67f09SDavid van Moolenbroek 		if (*cp == '#') { \
896*00b67f09SDavid van Moolenbroek 			sawcomment = 1; \
897*00b67f09SDavid van Moolenbroek 			++cp; \
898*00b67f09SDavid van Moolenbroek 			while (*cp != '\n' && *cp != '\0') \
899*00b67f09SDavid van Moolenbroek 				++cp; \
900*00b67f09SDavid van Moolenbroek 		} \
901*00b67f09SDavid van Moolenbroek 		else if (strncmp(cp, "//", 2) == 0) { \
902*00b67f09SDavid van Moolenbroek 			sawcomment = 1; \
903*00b67f09SDavid van Moolenbroek 			cp += 2; \
904*00b67f09SDavid van Moolenbroek 			while (*cp != '\n' && *cp != '\0') \
905*00b67f09SDavid van Moolenbroek 				++cp; \
906*00b67f09SDavid van Moolenbroek 		} \
907*00b67f09SDavid van Moolenbroek 		else if (strncmp(cp, "/*", 2) == 0) { \
908*00b67f09SDavid van Moolenbroek 			sawcomment = 1; \
909*00b67f09SDavid van Moolenbroek 			for (cp += 2; *cp != '\0'; ++cp) { \
910*00b67f09SDavid van Moolenbroek 				if (*cp == '\n') \
911*00b67f09SDavid van Moolenbroek 					++n; \
912*00b67f09SDavid van Moolenbroek 				else if (strncmp(cp, "*/", 2) == 0) { \
913*00b67f09SDavid van Moolenbroek 					cp += 2; \
914*00b67f09SDavid van Moolenbroek 					break; \
915*00b67f09SDavid van Moolenbroek 				} \
916*00b67f09SDavid van Moolenbroek 			} \
917*00b67f09SDavid van Moolenbroek 		} \
918*00b67f09SDavid van Moolenbroek 	} while (sawcomment); \
919*00b67f09SDavid van Moolenbroek 	}
920*00b67f09SDavid van Moolenbroek 
921*00b67f09SDavid van Moolenbroek #define GETNAME(name, len) \
922*00b67f09SDavid van Moolenbroek 	{ \
923*00b67f09SDavid van Moolenbroek 	(name) = cp; \
924*00b67f09SDavid van Moolenbroek 	(len) = 0; \
925*00b67f09SDavid van Moolenbroek 	while (!isspace(*cp) && *cp != ';' && *cp != '\0') { \
926*00b67f09SDavid van Moolenbroek 		++(len); \
927*00b67f09SDavid van Moolenbroek 		++cp; \
928*00b67f09SDavid van Moolenbroek 	} \
929*00b67f09SDavid van Moolenbroek 	}
930*00b67f09SDavid van Moolenbroek 
931*00b67f09SDavid van Moolenbroek #define GETQUOTEDNAME(name, len) \
932*00b67f09SDavid van Moolenbroek 	{ \
933*00b67f09SDavid van Moolenbroek 	if (*cp != '"') { \
934*00b67f09SDavid van Moolenbroek 		++errors; \
935*00b67f09SDavid van Moolenbroek 		fprintf(stderr, "%s: %s:%d missing left quote\n", \
936*00b67f09SDavid van Moolenbroek 		    prog, file, n); \
937*00b67f09SDavid van Moolenbroek 	} else \
938*00b67f09SDavid van Moolenbroek 		++cp; \
939*00b67f09SDavid van Moolenbroek 	(name) = cp; \
940*00b67f09SDavid van Moolenbroek 	(len) = 0; \
941*00b67f09SDavid van Moolenbroek 	while (*cp != '"' && *cp != '\n' && *cp != '\0') { \
942*00b67f09SDavid van Moolenbroek 		++(len); \
943*00b67f09SDavid van Moolenbroek 		++cp; \
944*00b67f09SDavid van Moolenbroek 	} \
945*00b67f09SDavid van Moolenbroek 	if (*cp != '"') { \
946*00b67f09SDavid van Moolenbroek 		++errors; \
947*00b67f09SDavid van Moolenbroek 		fprintf(stderr, "%s: %s:%d missing right quote\n", \
948*00b67f09SDavid van Moolenbroek 		    prog, file, n); \
949*00b67f09SDavid van Moolenbroek 	} else \
950*00b67f09SDavid van Moolenbroek 		++cp; \
951*00b67f09SDavid van Moolenbroek 	}
952*00b67f09SDavid van Moolenbroek 
953*00b67f09SDavid van Moolenbroek /* Eat everything to the next semicolon, perhaps eating matching qbraces */
954*00b67f09SDavid van Moolenbroek #define EATSEMICOLON \
955*00b67f09SDavid van Moolenbroek 	{ \
956*00b67f09SDavid van Moolenbroek 	int depth = 0; \
957*00b67f09SDavid van Moolenbroek 	while (*cp != '\0') { \
958*00b67f09SDavid van Moolenbroek 		EATCOMMENTS \
959*00b67f09SDavid van Moolenbroek 		if (*cp == ';') { \
960*00b67f09SDavid van Moolenbroek 			++cp; \
961*00b67f09SDavid van Moolenbroek 			if (depth == 0) \
962*00b67f09SDavid van Moolenbroek 				break; \
963*00b67f09SDavid van Moolenbroek 			continue; \
964*00b67f09SDavid van Moolenbroek 		} \
965*00b67f09SDavid van Moolenbroek 		if (*cp == '{') { \
966*00b67f09SDavid van Moolenbroek 			++depth; \
967*00b67f09SDavid van Moolenbroek 			++cp; \
968*00b67f09SDavid van Moolenbroek 			continue; \
969*00b67f09SDavid van Moolenbroek 		} \
970*00b67f09SDavid van Moolenbroek 		if (*cp == '}') { \
971*00b67f09SDavid van Moolenbroek 			--depth; \
972*00b67f09SDavid van Moolenbroek 			++cp; \
973*00b67f09SDavid van Moolenbroek 			continue; \
974*00b67f09SDavid van Moolenbroek 		} \
975*00b67f09SDavid van Moolenbroek 		++cp; \
976*00b67f09SDavid van Moolenbroek 	} \
977*00b67f09SDavid van Moolenbroek 	}
978*00b67f09SDavid van Moolenbroek 
979*00b67f09SDavid van Moolenbroek /* Eat everything to the next left qbrace */
980*00b67f09SDavid van Moolenbroek #define EATSLEFTBRACE \
981*00b67f09SDavid van Moolenbroek 	while (*cp != '\0') { \
982*00b67f09SDavid van Moolenbroek 		EATCOMMENTS \
983*00b67f09SDavid van Moolenbroek 		if (*cp == '{') { \
984*00b67f09SDavid van Moolenbroek 			++cp; \
985*00b67f09SDavid van Moolenbroek 			break; \
986*00b67f09SDavid van Moolenbroek 		} \
987*00b67f09SDavid van Moolenbroek 		++cp; \
988*00b67f09SDavid van Moolenbroek 	}
989*00b67f09SDavid van Moolenbroek 
990*00b67f09SDavid van Moolenbroek 	n = 1;
991*00b67f09SDavid van Moolenbroek 	zone[0] = '\0';
992*00b67f09SDavid van Moolenbroek 	cp = buf;
993*00b67f09SDavid van Moolenbroek 	while (*cp != '\0') {
994*00b67f09SDavid van Moolenbroek 		EATCOMMENTS
995*00b67f09SDavid van Moolenbroek 		if (*cp == '\0')
996*00b67f09SDavid van Moolenbroek 			break;
997*00b67f09SDavid van Moolenbroek 		GETNAME(name, namelen)
998*00b67f09SDavid van Moolenbroek 		if (namelen == 0) {
999*00b67f09SDavid van Moolenbroek 			++errors;
1000*00b67f09SDavid van Moolenbroek 			fprintf(stderr, "%s: %s:%d garbage char '%c' (1)\n",
1001*00b67f09SDavid van Moolenbroek 			    prog, file, n, *cp);
1002*00b67f09SDavid van Moolenbroek 			++cp;
1003*00b67f09SDavid van Moolenbroek 			continue;
1004*00b67f09SDavid van Moolenbroek 		}
1005*00b67f09SDavid van Moolenbroek 		EATCOMMENTS
1006*00b67f09SDavid van Moolenbroek 		if (strncasecmp(name, "options", namelen) == 0) {
1007*00b67f09SDavid van Moolenbroek 			EATCOMMENTS
1008*00b67f09SDavid van Moolenbroek 			if (*cp != '{')  {
1009*00b67f09SDavid van Moolenbroek 				++errors;
1010*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
1011*00b67f09SDavid van Moolenbroek 			    "%s: %s:%d missing left qbrace in options\n",
1012*00b67f09SDavid van Moolenbroek 				    prog, file, n);
1013*00b67f09SDavid van Moolenbroek 			} else
1014*00b67f09SDavid van Moolenbroek 				++cp;
1015*00b67f09SDavid van Moolenbroek 			EATCOMMENTS
1016*00b67f09SDavid van Moolenbroek 			while (*cp != '}' && *cp != '\0') {
1017*00b67f09SDavid van Moolenbroek 				EATCOMMENTS
1018*00b67f09SDavid van Moolenbroek 				GETNAME(name, namelen)
1019*00b67f09SDavid van Moolenbroek 				if (namelen == 0) {
1020*00b67f09SDavid van Moolenbroek 					++errors;
1021*00b67f09SDavid van Moolenbroek 					fprintf(stderr,
1022*00b67f09SDavid van Moolenbroek 					    "%s: %s:%d garbage char '%c' (2)\n",
1023*00b67f09SDavid van Moolenbroek 					    prog, file, n, *cp);
1024*00b67f09SDavid van Moolenbroek 					++cp;
1025*00b67f09SDavid van Moolenbroek 					break;
1026*00b67f09SDavid van Moolenbroek 				}
1027*00b67f09SDavid van Moolenbroek 
1028*00b67f09SDavid van Moolenbroek 				/* If not the "directory" option, just eat it */
1029*00b67f09SDavid van Moolenbroek 				if (strncasecmp(name, "directory",
1030*00b67f09SDavid van Moolenbroek 				    namelen) == 0) {
1031*00b67f09SDavid van Moolenbroek 					EATCOMMENTS
1032*00b67f09SDavid van Moolenbroek 					GETQUOTEDNAME(cp2, i)
1033*00b67f09SDavid van Moolenbroek 					cp2[i] = '\0';
1034*00b67f09SDavid van Moolenbroek 					if (chdir(cp2) < 0) {
1035*00b67f09SDavid van Moolenbroek 						++errors;
1036*00b67f09SDavid van Moolenbroek 						fprintf(stderr,
1037*00b67f09SDavid van Moolenbroek 					    "%s: %s:.%d can't chdir %s: %s\n",
1038*00b67f09SDavid van Moolenbroek 						    prog, file, n, cp2,
1039*00b67f09SDavid van Moolenbroek 						    strerror(errno));
1040*00b67f09SDavid van Moolenbroek 						exit(1);
1041*00b67f09SDavid van Moolenbroek 					}
1042*00b67f09SDavid van Moolenbroek 					cwd = savestr(cp2);
1043*00b67f09SDavid van Moolenbroek 				}
1044*00b67f09SDavid van Moolenbroek 				EATSEMICOLON
1045*00b67f09SDavid van Moolenbroek 				EATCOMMENTS
1046*00b67f09SDavid van Moolenbroek 			}
1047*00b67f09SDavid van Moolenbroek 			++cp;
1048*00b67f09SDavid van Moolenbroek 			EATCOMMENTS
1049*00b67f09SDavid van Moolenbroek 			if (*cp != ';')  {
1050*00b67f09SDavid van Moolenbroek 				++errors;
1051*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
1052*00b67f09SDavid van Moolenbroek 				    "%s: %s:%d missing options semi\n",
1053*00b67f09SDavid van Moolenbroek 				    prog, file, n);
1054*00b67f09SDavid van Moolenbroek 			} else
1055*00b67f09SDavid van Moolenbroek 				++cp;
1056*00b67f09SDavid van Moolenbroek 			continue;
1057*00b67f09SDavid van Moolenbroek 		}
1058*00b67f09SDavid van Moolenbroek 		if (strncasecmp(name, "zone", namelen) == 0) {
1059*00b67f09SDavid van Moolenbroek 			EATCOMMENTS
1060*00b67f09SDavid van Moolenbroek 			GETQUOTEDNAME(zonename, zonenamelen)
1061*00b67f09SDavid van Moolenbroek 			typename = NULL;
1062*00b67f09SDavid van Moolenbroek 			filename = NULL;
1063*00b67f09SDavid van Moolenbroek 			typenamelen = 0;
1064*00b67f09SDavid van Moolenbroek 			filenamelen = 0;
1065*00b67f09SDavid van Moolenbroek 			EATCOMMENTS
1066*00b67f09SDavid van Moolenbroek 			if (strncasecmp(cp, "in", 2) == 0) {
1067*00b67f09SDavid van Moolenbroek 				cp += 2;
1068*00b67f09SDavid van Moolenbroek 				EATWHITESPACE
1069*00b67f09SDavid van Moolenbroek 			} else if (strncasecmp(cp, "chaos", 5) == 0) {
1070*00b67f09SDavid van Moolenbroek 				cp += 5;
1071*00b67f09SDavid van Moolenbroek 				EATWHITESPACE
1072*00b67f09SDavid van Moolenbroek 			}
1073*00b67f09SDavid van Moolenbroek 			if (*cp != '{')  {	/* } */
1074*00b67f09SDavid van Moolenbroek 				++errors;
1075*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
1076*00b67f09SDavid van Moolenbroek 			    "%s: %s:%d missing left qbrace in zone\n",
1077*00b67f09SDavid van Moolenbroek 				    prog, file, n);
1078*00b67f09SDavid van Moolenbroek 				continue;
1079*00b67f09SDavid van Moolenbroek 			}
1080*00b67f09SDavid van Moolenbroek 			depth = 0;
1081*00b67f09SDavid van Moolenbroek 			EATCOMMENTS
1082*00b67f09SDavid van Moolenbroek 			while (*cp != '\0') {
1083*00b67f09SDavid van Moolenbroek 				if (*cp == '{') {
1084*00b67f09SDavid van Moolenbroek 					++cp;
1085*00b67f09SDavid van Moolenbroek 					++depth;
1086*00b67f09SDavid van Moolenbroek 				} else if (*cp == '}') {
1087*00b67f09SDavid van Moolenbroek 					if (--depth <= 1)
1088*00b67f09SDavid van Moolenbroek 						break;
1089*00b67f09SDavid van Moolenbroek 					++cp;
1090*00b67f09SDavid van Moolenbroek 				}
1091*00b67f09SDavid van Moolenbroek 				EATCOMMENTS
1092*00b67f09SDavid van Moolenbroek 				GETNAME(name, namelen)
1093*00b67f09SDavid van Moolenbroek 				if (namelen == 0) {
1094*00b67f09SDavid van Moolenbroek 					++errors;
1095*00b67f09SDavid van Moolenbroek 					fprintf(stderr,
1096*00b67f09SDavid van Moolenbroek 					    "%s: %s:%d garbage char '%c' (3)\n",
1097*00b67f09SDavid van Moolenbroek 					    prog, file, n, *cp);
1098*00b67f09SDavid van Moolenbroek 					++cp;
1099*00b67f09SDavid van Moolenbroek 					break;
1100*00b67f09SDavid van Moolenbroek 				}
1101*00b67f09SDavid van Moolenbroek 				if (strncasecmp(name, "type",
1102*00b67f09SDavid van Moolenbroek 				    namelen) == 0) {
1103*00b67f09SDavid van Moolenbroek 					EATCOMMENTS
1104*00b67f09SDavid van Moolenbroek 					GETNAME(typename, typenamelen)
1105*00b67f09SDavid van Moolenbroek 					if (namelen == 0) {
1106*00b67f09SDavid van Moolenbroek 						++errors;
1107*00b67f09SDavid van Moolenbroek 						fprintf(stderr,
1108*00b67f09SDavid van Moolenbroek 					    "%s: %s:%d garbage char '%c' (4)\n",
1109*00b67f09SDavid van Moolenbroek 						    prog, file, n, *cp);
1110*00b67f09SDavid van Moolenbroek 						++cp;
1111*00b67f09SDavid van Moolenbroek 						break;
1112*00b67f09SDavid van Moolenbroek 					}
1113*00b67f09SDavid van Moolenbroek 				} else if (strncasecmp(name, "file",
1114*00b67f09SDavid van Moolenbroek 				    namelen) == 0) {
1115*00b67f09SDavid van Moolenbroek 					EATCOMMENTS
1116*00b67f09SDavid van Moolenbroek 					GETQUOTEDNAME(filename, filenamelen)
1117*00b67f09SDavid van Moolenbroek 				}
1118*00b67f09SDavid van Moolenbroek 				/* Just ignore keywords we don't understand */
1119*00b67f09SDavid van Moolenbroek 				EATSEMICOLON
1120*00b67f09SDavid van Moolenbroek 				EATCOMMENTS
1121*00b67f09SDavid van Moolenbroek 			}
1122*00b67f09SDavid van Moolenbroek 			/* { */
1123*00b67f09SDavid van Moolenbroek 			if (*cp != '}')  {
1124*00b67f09SDavid van Moolenbroek 				++errors;
1125*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
1126*00b67f09SDavid van Moolenbroek 				    "%s: %s:%d missing zone right qbrace\n",
1127*00b67f09SDavid van Moolenbroek 				    prog, file, n);
1128*00b67f09SDavid van Moolenbroek 			} else
1129*00b67f09SDavid van Moolenbroek 				++cp;
1130*00b67f09SDavid van Moolenbroek 			if (*cp != ';')  {
1131*00b67f09SDavid van Moolenbroek 				++errors;
1132*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
1133*00b67f09SDavid van Moolenbroek 				    "%s: %s:%d missing zone semi\n",
1134*00b67f09SDavid van Moolenbroek 				    prog, file, n);
1135*00b67f09SDavid van Moolenbroek 			} else
1136*00b67f09SDavid van Moolenbroek 				++cp;
1137*00b67f09SDavid van Moolenbroek 			EATCOMMENTS
1138*00b67f09SDavid van Moolenbroek 			/* If we got something interesting, process it */
1139*00b67f09SDavid van Moolenbroek 			if (typenamelen == 0) {
1140*00b67f09SDavid van Moolenbroek 				++errors;
1141*00b67f09SDavid van Moolenbroek 				fprintf(stderr, "%s: missing zone type!\n",
1142*00b67f09SDavid van Moolenbroek 				    prog);
1143*00b67f09SDavid van Moolenbroek 				continue;
1144*00b67f09SDavid van Moolenbroek 			}
1145*00b67f09SDavid van Moolenbroek 			if (strncasecmp(typename, "master", typenamelen) == 0) {
1146*00b67f09SDavid van Moolenbroek 				if (filenamelen == 0) {
1147*00b67f09SDavid van Moolenbroek 					++errors;
1148*00b67f09SDavid van Moolenbroek 					fprintf(stderr,
1149*00b67f09SDavid van Moolenbroek 					    "%s: missing zone filename!\n",
1150*00b67f09SDavid van Moolenbroek 					    prog);
1151*00b67f09SDavid van Moolenbroek 					continue;
1152*00b67f09SDavid van Moolenbroek 				}
1153*00b67f09SDavid van Moolenbroek 				strncpy(zone, zonename, zonenamelen);
1154*00b67f09SDavid van Moolenbroek 				zone[zonenamelen] = '\0';
1155*00b67f09SDavid van Moolenbroek 				for (cp2 = zone; *cp2 != '\0'; ++cp2)
1156*00b67f09SDavid van Moolenbroek 					if (isupper(*cp2))
1157*00b67f09SDavid van Moolenbroek 						*cp2 = tolower(*cp2);
1158*00b67f09SDavid van Moolenbroek 				/* Insure trailing dot */
1159*00b67f09SDavid van Moolenbroek 				if (cp2 > zone && cp2[-1] != '.') {
1160*00b67f09SDavid van Moolenbroek 					*cp2++ = '.';
1161*00b67f09SDavid van Moolenbroek 					*cp2 = '\0';
1162*00b67f09SDavid van Moolenbroek 				}
1163*00b67f09SDavid van Moolenbroek 				filename[filenamelen] = '\0';
1164*00b67f09SDavid van Moolenbroek 				nsoaval = -1;
1165*00b67f09SDavid van Moolenbroek 				memset(soaval, 0, sizeof(soaval));
1166*00b67f09SDavid van Moolenbroek 				if ((flags & CONF_NOZONE) == 0)
1167*00b67f09SDavid van Moolenbroek 					process(filename, zone, zone);
1168*00b67f09SDavid van Moolenbroek 			}
1169*00b67f09SDavid van Moolenbroek 			continue;
1170*00b67f09SDavid van Moolenbroek 		}
1171*00b67f09SDavid van Moolenbroek 		if (strncasecmp(name, "nslint", namelen) == 0) {
1172*00b67f09SDavid van Moolenbroek 			EATCOMMENTS
1173*00b67f09SDavid van Moolenbroek 			if (*cp != '{')  {
1174*00b67f09SDavid van Moolenbroek 				++errors;
1175*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
1176*00b67f09SDavid van Moolenbroek 			    "%s: %s:%d missing left qbrace in nslint\n",
1177*00b67f09SDavid van Moolenbroek 				    prog, file, n);
1178*00b67f09SDavid van Moolenbroek 			} else
1179*00b67f09SDavid van Moolenbroek 				++cp;
1180*00b67f09SDavid van Moolenbroek 			++cp;
1181*00b67f09SDavid van Moolenbroek 			EATCOMMENTS
1182*00b67f09SDavid van Moolenbroek 			while (*cp != '}' && *cp != '\0') {
1183*00b67f09SDavid van Moolenbroek 				EATCOMMENTS
1184*00b67f09SDavid van Moolenbroek 				GETNAME(name, namelen)
1185*00b67f09SDavid van Moolenbroek 				if (strncasecmp(name, "network",
1186*00b67f09SDavid van Moolenbroek 				    namelen) == 0) {
1187*00b67f09SDavid van Moolenbroek 					EATCOMMENTS
1188*00b67f09SDavid van Moolenbroek 					GETQUOTEDNAME(cp2, i)
1189*00b67f09SDavid van Moolenbroek 
1190*00b67f09SDavid van Moolenbroek 					cp2[i] = '\0';
1191*00b67f09SDavid van Moolenbroek 					p = parsenetwork(cp2);
1192*00b67f09SDavid van Moolenbroek 					if (p != NULL) {
1193*00b67f09SDavid van Moolenbroek 						++errors;
1194*00b67f09SDavid van Moolenbroek 						fprintf(stderr,
1195*00b67f09SDavid van Moolenbroek 					    "%s: %s:%d: bad network: %s\n",
1196*00b67f09SDavid van Moolenbroek 						    prog, file, n, p);
1197*00b67f09SDavid van Moolenbroek 					}
1198*00b67f09SDavid van Moolenbroek 				} else if (strncasecmp(name, "ignorezone",
1199*00b67f09SDavid van Moolenbroek 				    namelen) == 0) {
1200*00b67f09SDavid van Moolenbroek 					EATCOMMENTS
1201*00b67f09SDavid van Moolenbroek 					GETQUOTEDNAME(cp2, i)
1202*00b67f09SDavid van Moolenbroek 					cp2[i] = '\0';
1203*00b67f09SDavid van Moolenbroek 					if (numignoredzones + 1 <
1204*00b67f09SDavid van Moolenbroek 					    sizeof(ignoredzones) /
1205*00b67f09SDavid van Moolenbroek 					    sizeof(ignoredzones[0])) {
1206*00b67f09SDavid van Moolenbroek 						ignoredzones[numignoredzones].zone =
1207*00b67f09SDavid van Moolenbroek 						    savestr(cp2);
1208*00b67f09SDavid van Moolenbroek 						if (ignoredzones[numignoredzones].zone != NULL) {
1209*00b67f09SDavid van Moolenbroek 							ignoredzones[numignoredzones].len = strlen(cp2);
1210*00b67f09SDavid van Moolenbroek 							++numignoredzones;
1211*00b67f09SDavid van Moolenbroek 						}
1212*00b67f09SDavid van Moolenbroek 					}
1213*00b67f09SDavid van Moolenbroek 				} else {
1214*00b67f09SDavid van Moolenbroek 					++errors;
1215*00b67f09SDavid van Moolenbroek 					fprintf(stderr,
1216*00b67f09SDavid van Moolenbroek 					    "%s: unknown nslint \"%.*s\"\n",
1217*00b67f09SDavid van Moolenbroek 					    prog, namelen, name);
1218*00b67f09SDavid van Moolenbroek 				}
1219*00b67f09SDavid van Moolenbroek 				EATSEMICOLON
1220*00b67f09SDavid van Moolenbroek 				EATCOMMENTS
1221*00b67f09SDavid van Moolenbroek 			}
1222*00b67f09SDavid van Moolenbroek 			++cp;
1223*00b67f09SDavid van Moolenbroek 			EATCOMMENTS
1224*00b67f09SDavid van Moolenbroek 			if (*cp != ';')  {
1225*00b67f09SDavid van Moolenbroek 				++errors;
1226*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
1227*00b67f09SDavid van Moolenbroek 				    "%s: %s:%d: missing nslint semi\n",
1228*00b67f09SDavid van Moolenbroek 				    prog, file, n);
1229*00b67f09SDavid van Moolenbroek 			} else
1230*00b67f09SDavid van Moolenbroek 				++cp;
1231*00b67f09SDavid van Moolenbroek 			continue;
1232*00b67f09SDavid van Moolenbroek 		}
1233*00b67f09SDavid van Moolenbroek 		if (strncasecmp(name, "include", namelen) == 0) {
1234*00b67f09SDavid van Moolenbroek 			EATCOMMENTS
1235*00b67f09SDavid van Moolenbroek 			GETQUOTEDNAME(filename, filenamelen)
1236*00b67f09SDavid van Moolenbroek 			strncpy(includefile, filename, filenamelen);
1237*00b67f09SDavid van Moolenbroek 			includefile[filenamelen] = '\0';
1238*00b67f09SDavid van Moolenbroek 			doconf(includefile, 1);
1239*00b67f09SDavid van Moolenbroek 			EATSEMICOLON
1240*00b67f09SDavid van Moolenbroek 			continue;
1241*00b67f09SDavid van Moolenbroek 		}
1242*00b67f09SDavid van Moolenbroek 		if (strncasecmp(name, "view", namelen) == 0) {
1243*00b67f09SDavid van Moolenbroek 			EATSLEFTBRACE
1244*00b67f09SDavid van Moolenbroek 			continue;
1245*00b67f09SDavid van Moolenbroek 		}
1246*00b67f09SDavid van Moolenbroek 
1247*00b67f09SDavid van Moolenbroek 		/* Skip over statements we don't understand */
1248*00b67f09SDavid van Moolenbroek 		EATSEMICOLON
1249*00b67f09SDavid van Moolenbroek 	}
1250*00b67f09SDavid van Moolenbroek 
1251*00b67f09SDavid van Moolenbroek 	free(buf);
1252*00b67f09SDavid van Moolenbroek 	close(fd);
1253*00b67f09SDavid van Moolenbroek }
1254*00b67f09SDavid van Moolenbroek 
1255*00b67f09SDavid van Moolenbroek const char *
extractaddr(const char * str,struct addr * ap)1256*00b67f09SDavid van Moolenbroek extractaddr(const char *str, struct addr *ap)
1257*00b67f09SDavid van Moolenbroek {
1258*00b67f09SDavid van Moolenbroek 
1259*00b67f09SDavid van Moolenbroek 	memset(ap, 0, sizeof(*ap));
1260*00b67f09SDavid van Moolenbroek 
1261*00b67f09SDavid van Moolenbroek 	/* Let's see what we've got here */
1262*00b67f09SDavid van Moolenbroek 	if (strchr(str, '.') != NULL) {
1263*00b67f09SDavid van Moolenbroek 		ap->family = AF_INET;
1264*00b67f09SDavid van Moolenbroek 	} else if (strchr(str, ':') != NULL) {
1265*00b67f09SDavid van Moolenbroek 		ap->family = AF_INET6;
1266*00b67f09SDavid van Moolenbroek 	} else
1267*00b67f09SDavid van Moolenbroek 		return ("unrecognized address type");
1268*00b67f09SDavid van Moolenbroek 
1269*00b67f09SDavid van Moolenbroek 	switch (ap->family) {
1270*00b67f09SDavid van Moolenbroek 
1271*00b67f09SDavid van Moolenbroek 	case AF_INET:
1272*00b67f09SDavid van Moolenbroek 		if (!inet_pton(ap->family, str, &ap->a_addr4))
1273*00b67f09SDavid van Moolenbroek 			return ("cannot parse IPv4 address");
1274*00b67f09SDavid van Moolenbroek 
1275*00b67f09SDavid van Moolenbroek 		break;
1276*00b67f09SDavid van Moolenbroek 
1277*00b67f09SDavid van Moolenbroek 	case AF_INET6:
1278*00b67f09SDavid van Moolenbroek 		if (!inet_pton(ap->family, str, &ap->a_addr6))
1279*00b67f09SDavid van Moolenbroek 			return ("cannot parse IPv6 address");
1280*00b67f09SDavid van Moolenbroek 		break;
1281*00b67f09SDavid van Moolenbroek 
1282*00b67f09SDavid van Moolenbroek 	default:
1283*00b67f09SDavid van Moolenbroek 		abort();
1284*00b67f09SDavid van Moolenbroek 	}
1285*00b67f09SDavid van Moolenbroek 
1286*00b67f09SDavid van Moolenbroek 	return (NULL);
1287*00b67f09SDavid van Moolenbroek }
1288*00b67f09SDavid van Moolenbroek 
1289*00b67f09SDavid van Moolenbroek const char *
extractnetwork(const char * str,struct network * np)1290*00b67f09SDavid van Moolenbroek extractnetwork(const char *str, struct network *np)
1291*00b67f09SDavid van Moolenbroek {
1292*00b67f09SDavid van Moolenbroek 	int i;
1293*00b67f09SDavid van Moolenbroek 	long w;
1294*00b67f09SDavid van Moolenbroek 	char *cp, *ep;
1295*00b67f09SDavid van Moolenbroek 	const char *p;
1296*00b67f09SDavid van Moolenbroek 	char temp[64];
1297*00b67f09SDavid van Moolenbroek 
1298*00b67f09SDavid van Moolenbroek 	memset(np, 0, sizeof(*np));
1299*00b67f09SDavid van Moolenbroek 
1300*00b67f09SDavid van Moolenbroek 	/* Let's see what we've got here */
1301*00b67f09SDavid van Moolenbroek 	if (strchr(str, '.') != NULL) {
1302*00b67f09SDavid van Moolenbroek 		np->family = AF_INET;
1303*00b67f09SDavid van Moolenbroek 		w = 32;
1304*00b67f09SDavid van Moolenbroek 	} else if (strchr(str, ':') != NULL) {
1305*00b67f09SDavid van Moolenbroek 		np->family = AF_INET6;
1306*00b67f09SDavid van Moolenbroek 		w = 128;
1307*00b67f09SDavid van Moolenbroek 	} else
1308*00b67f09SDavid van Moolenbroek 		return ("unrecognized address type");
1309*00b67f09SDavid van Moolenbroek 
1310*00b67f09SDavid van Moolenbroek 	p = strchr(str, '/');
1311*00b67f09SDavid van Moolenbroek 	if (p != NULL) {
1312*00b67f09SDavid van Moolenbroek 		/* Mask length was specified */
1313*00b67f09SDavid van Moolenbroek 		strncpy(temp, str, sizeof(temp));
1314*00b67f09SDavid van Moolenbroek 		temp[sizeof(temp) - 1] = '\0';
1315*00b67f09SDavid van Moolenbroek 		cp = strchr(temp, '/');
1316*00b67f09SDavid van Moolenbroek 		if (cp == NULL)
1317*00b67f09SDavid van Moolenbroek 			abort();
1318*00b67f09SDavid van Moolenbroek 		*cp++ = '\0';
1319*00b67f09SDavid van Moolenbroek 		ep = NULL;
1320*00b67f09SDavid van Moolenbroek 		w = strtol(cp, &ep, 10);
1321*00b67f09SDavid van Moolenbroek 		if (*ep != '\0')
1322*00b67f09SDavid van Moolenbroek 			return ("garbage following mask width");
1323*00b67f09SDavid van Moolenbroek 		str = temp;
1324*00b67f09SDavid van Moolenbroek 	}
1325*00b67f09SDavid van Moolenbroek 
1326*00b67f09SDavid van Moolenbroek 	switch (np->family) {
1327*00b67f09SDavid van Moolenbroek 
1328*00b67f09SDavid van Moolenbroek 	case AF_INET:
1329*00b67f09SDavid van Moolenbroek 		if (!inet_pton(np->family, str, &np->n_addr4))
1330*00b67f09SDavid van Moolenbroek 			return ("cannot parse IPv4 address");
1331*00b67f09SDavid van Moolenbroek 
1332*00b67f09SDavid van Moolenbroek 		if (w > 32)
1333*00b67f09SDavid van Moolenbroek 			return ("mask length must be <= 32");
1334*00b67f09SDavid van Moolenbroek 		setmaskwidth(w, np);
1335*00b67f09SDavid van Moolenbroek 
1336*00b67f09SDavid van Moolenbroek 		if ((np->n_addr4 & ~np->n_mask4) != 0)
1337*00b67f09SDavid van Moolenbroek 			return ("non-network bits set in addr");
1338*00b67f09SDavid van Moolenbroek 
1339*00b67f09SDavid van Moolenbroek #ifdef notdef
1340*00b67f09SDavid van Moolenbroek 		if ((ntohl(np->n_addr4) & 0xff000000) == 0)
1341*00b67f09SDavid van Moolenbroek 			return ("high octet must be non-zero");
1342*00b67f09SDavid van Moolenbroek #endif
1343*00b67f09SDavid van Moolenbroek 		break;
1344*00b67f09SDavid van Moolenbroek 
1345*00b67f09SDavid van Moolenbroek 	case AF_INET6:
1346*00b67f09SDavid van Moolenbroek 		if (!inet_pton(np->family, str, &np->n_addr6))
1347*00b67f09SDavid van Moolenbroek 			return ("cannot parse IPv6 address");
1348*00b67f09SDavid van Moolenbroek 		if (w > 128)
1349*00b67f09SDavid van Moolenbroek 			return ("mask length must be <= 128");
1350*00b67f09SDavid van Moolenbroek 		setmaskwidth(w, np);
1351*00b67f09SDavid van Moolenbroek 
1352*00b67f09SDavid van Moolenbroek 		for (i = 0; i < 16; ++i) {
1353*00b67f09SDavid van Moolenbroek 			if ((np->n_addr6[i] & ~np->n_mask6[i]) != 0)
1354*00b67f09SDavid van Moolenbroek 				return ("non-network bits set in addr");
1355*00b67f09SDavid van Moolenbroek 		}
1356*00b67f09SDavid van Moolenbroek 		break;
1357*00b67f09SDavid van Moolenbroek 
1358*00b67f09SDavid van Moolenbroek 	default:
1359*00b67f09SDavid van Moolenbroek 		abort();
1360*00b67f09SDavid van Moolenbroek 	}
1361*00b67f09SDavid van Moolenbroek 
1362*00b67f09SDavid van Moolenbroek 	return (NULL);
1363*00b67f09SDavid van Moolenbroek }
1364*00b67f09SDavid van Moolenbroek 
1365*00b67f09SDavid van Moolenbroek struct network *
findnetwork(struct addr * ap)1366*00b67f09SDavid van Moolenbroek findnetwork(struct addr *ap)
1367*00b67f09SDavid van Moolenbroek {
1368*00b67f09SDavid van Moolenbroek 	int i, j;
1369*00b67f09SDavid van Moolenbroek 	struct network *np;
1370*00b67f09SDavid van Moolenbroek 
1371*00b67f09SDavid van Moolenbroek 	switch (ap->family) {
1372*00b67f09SDavid van Moolenbroek 
1373*00b67f09SDavid van Moolenbroek 	case AF_INET:
1374*00b67f09SDavid van Moolenbroek 		for (i = 0, np = netlist; i < netlistcnt; ++i, ++np)
1375*00b67f09SDavid van Moolenbroek 			if ((ap->a_addr4 & np->n_mask4) == np->n_addr4)
1376*00b67f09SDavid van Moolenbroek 				return (np);
1377*00b67f09SDavid van Moolenbroek 		break;
1378*00b67f09SDavid van Moolenbroek 
1379*00b67f09SDavid van Moolenbroek 	case AF_INET6:
1380*00b67f09SDavid van Moolenbroek 		for (i = 0, np = netlist; i < netlistcnt; ++i, ++np) {
1381*00b67f09SDavid van Moolenbroek 			for (j = 0; j < sizeof(ap->a_addr6); ++j) {
1382*00b67f09SDavid van Moolenbroek 				if ((ap->a_addr6[j] & np->n_mask6[j]) !=
1383*00b67f09SDavid van Moolenbroek 				    np->n_addr6[j])
1384*00b67f09SDavid van Moolenbroek 					break;
1385*00b67f09SDavid van Moolenbroek 			}
1386*00b67f09SDavid van Moolenbroek 			if (j >= sizeof(ap->a_addr6))
1387*00b67f09SDavid van Moolenbroek 				return (np);
1388*00b67f09SDavid van Moolenbroek 		}
1389*00b67f09SDavid van Moolenbroek 		break;
1390*00b67f09SDavid van Moolenbroek 
1391*00b67f09SDavid van Moolenbroek 	default:
1392*00b67f09SDavid van Moolenbroek 		abort();
1393*00b67f09SDavid van Moolenbroek 	}
1394*00b67f09SDavid van Moolenbroek 	return (NULL);
1395*00b67f09SDavid van Moolenbroek }
1396*00b67f09SDavid van Moolenbroek 
1397*00b67f09SDavid van Moolenbroek void
initprotoserv(void)1398*00b67f09SDavid van Moolenbroek initprotoserv(void)
1399*00b67f09SDavid van Moolenbroek {
1400*00b67f09SDavid van Moolenbroek 	char *cp;
1401*00b67f09SDavid van Moolenbroek 	struct servent *sp;
1402*00b67f09SDavid van Moolenbroek 	char psbuf[512];
1403*00b67f09SDavid van Moolenbroek 
1404*00b67f09SDavid van Moolenbroek 	protoserv_len = 256;
1405*00b67f09SDavid van Moolenbroek 	protoserv = (char **)malloc(protoserv_len * sizeof(*protoserv));
1406*00b67f09SDavid van Moolenbroek 	if (protoserv == NULL) {
1407*00b67f09SDavid van Moolenbroek 		fprintf(stderr, "%s: nslint: malloc: %s\n",
1408*00b67f09SDavid van Moolenbroek 		    prog, strerror(errno));
1409*00b67f09SDavid van Moolenbroek 		exit(1);
1410*00b67f09SDavid van Moolenbroek 	}
1411*00b67f09SDavid van Moolenbroek 
1412*00b67f09SDavid van Moolenbroek 	while ((sp = getservent()) != NULL) {
1413*00b67f09SDavid van Moolenbroek 		(void)sprintf(psbuf, "%s/%s", sp->s_name, sp->s_proto);
1414*00b67f09SDavid van Moolenbroek 
1415*00b67f09SDavid van Moolenbroek 		/* Convert to lowercase */
1416*00b67f09SDavid van Moolenbroek 		for (cp = psbuf; *cp != '\0'; ++cp)
1417*00b67f09SDavid van Moolenbroek 			if (isupper(*cp))
1418*00b67f09SDavid van Moolenbroek 				*cp = tolower(*cp);
1419*00b67f09SDavid van Moolenbroek 
1420*00b67f09SDavid van Moolenbroek 		if (protoserv_last + 1 >= protoserv_len) {
1421*00b67f09SDavid van Moolenbroek 			protoserv_len <<= 1;
1422*00b67f09SDavid van Moolenbroek 			protoserv = realloc(protoserv,
1423*00b67f09SDavid van Moolenbroek 			    protoserv_len * sizeof(*protoserv));
1424*00b67f09SDavid van Moolenbroek 			if (protoserv == NULL) {
1425*00b67f09SDavid van Moolenbroek 				fprintf(stderr, "%s: nslint: realloc: %s\n",
1426*00b67f09SDavid van Moolenbroek 				    prog, strerror(errno));
1427*00b67f09SDavid van Moolenbroek 				exit(1);
1428*00b67f09SDavid van Moolenbroek 			}
1429*00b67f09SDavid van Moolenbroek 		}
1430*00b67f09SDavid van Moolenbroek 		protoserv[protoserv_last] = savestr(psbuf);
1431*00b67f09SDavid van Moolenbroek 		++protoserv_last;
1432*00b67f09SDavid van Moolenbroek 	}
1433*00b67f09SDavid van Moolenbroek 	protoserv[protoserv_last] = NULL;
1434*00b67f09SDavid van Moolenbroek }
1435*00b67f09SDavid van Moolenbroek 
1436*00b67f09SDavid van Moolenbroek int
maskwidth(struct network * np)1437*00b67f09SDavid van Moolenbroek maskwidth(struct network *np)
1438*00b67f09SDavid van Moolenbroek {
1439*00b67f09SDavid van Moolenbroek 	int w;
1440*00b67f09SDavid van Moolenbroek 	int i, j;
1441*00b67f09SDavid van Moolenbroek 	u_int32_t m, tm;
1442*00b67f09SDavid van Moolenbroek 
1443*00b67f09SDavid van Moolenbroek 	/* Work backwards until we find a set bit */
1444*00b67f09SDavid van Moolenbroek 	switch (np->family) {
1445*00b67f09SDavid van Moolenbroek 
1446*00b67f09SDavid van Moolenbroek 	case AF_INET:
1447*00b67f09SDavid van Moolenbroek 		m = ntohl(np->n_mask4);
1448*00b67f09SDavid van Moolenbroek 		for (w = 32; w > 0; --w) {
1449*00b67f09SDavid van Moolenbroek 			tm = 0xffffffff << (32 - w);
1450*00b67f09SDavid van Moolenbroek 			if (tm == m)
1451*00b67f09SDavid van Moolenbroek 				break;
1452*00b67f09SDavid van Moolenbroek 		}
1453*00b67f09SDavid van Moolenbroek 		break;
1454*00b67f09SDavid van Moolenbroek 
1455*00b67f09SDavid van Moolenbroek 	case AF_INET6:
1456*00b67f09SDavid van Moolenbroek 		w = 128;
1457*00b67f09SDavid van Moolenbroek 		for (j = 15; j >= 0; --j) {
1458*00b67f09SDavid van Moolenbroek 			m = np->n_mask6[j];
1459*00b67f09SDavid van Moolenbroek 			for (i = 8; i > 0; --w, --i) {
1460*00b67f09SDavid van Moolenbroek 				tm = (0xff << (8 - i)) & 0xff;
1461*00b67f09SDavid van Moolenbroek 				if (tm == m)
1462*00b67f09SDavid van Moolenbroek 					return (w);
1463*00b67f09SDavid van Moolenbroek 			}
1464*00b67f09SDavid van Moolenbroek 		}
1465*00b67f09SDavid van Moolenbroek 		break;
1466*00b67f09SDavid van Moolenbroek 
1467*00b67f09SDavid van Moolenbroek 	default:
1468*00b67f09SDavid van Moolenbroek 		abort();
1469*00b67f09SDavid van Moolenbroek 	}
1470*00b67f09SDavid van Moolenbroek 	return (w);
1471*00b67f09SDavid van Moolenbroek }
1472*00b67f09SDavid van Moolenbroek 
1473*00b67f09SDavid van Moolenbroek const char *
network2str(struct network * np)1474*00b67f09SDavid van Moolenbroek network2str(struct network *np)
1475*00b67f09SDavid van Moolenbroek {
1476*00b67f09SDavid van Moolenbroek 	int w;
1477*00b67f09SDavid van Moolenbroek 	size_t len, size;
1478*00b67f09SDavid van Moolenbroek 	char *cp;
1479*00b67f09SDavid van Moolenbroek 	static char buf[128];
1480*00b67f09SDavid van Moolenbroek 
1481*00b67f09SDavid van Moolenbroek 	w = maskwidth(np);
1482*00b67f09SDavid van Moolenbroek 	switch (np->family) {
1483*00b67f09SDavid van Moolenbroek 
1484*00b67f09SDavid van Moolenbroek 	case AF_INET:
1485*00b67f09SDavid van Moolenbroek 		if (inet_ntop(np->family, &np->n_addr4,
1486*00b67f09SDavid van Moolenbroek 		    buf, sizeof(buf)) == NULL) {
1487*00b67f09SDavid van Moolenbroek 			fprintf(stderr, "network2str: v4 botch");
1488*00b67f09SDavid van Moolenbroek 			abort();
1489*00b67f09SDavid van Moolenbroek 		}
1490*00b67f09SDavid van Moolenbroek 		if (w == 32)
1491*00b67f09SDavid van Moolenbroek 			return (buf);
1492*00b67f09SDavid van Moolenbroek 		break;
1493*00b67f09SDavid van Moolenbroek 
1494*00b67f09SDavid van Moolenbroek 	case AF_INET6:
1495*00b67f09SDavid van Moolenbroek 		if (inet_ntop(np->family, &np->n_addr6,
1496*00b67f09SDavid van Moolenbroek 		    buf, sizeof(buf)) == NULL) {
1497*00b67f09SDavid van Moolenbroek 			fprintf(stderr, "network2str: v6 botch");
1498*00b67f09SDavid van Moolenbroek 			abort();
1499*00b67f09SDavid van Moolenbroek 		}
1500*00b67f09SDavid van Moolenbroek 		if (w == 128)
1501*00b67f09SDavid van Moolenbroek 			return (buf);
1502*00b67f09SDavid van Moolenbroek 		break;
1503*00b67f09SDavid van Moolenbroek 
1504*00b67f09SDavid van Moolenbroek 	default:
1505*00b67f09SDavid van Moolenbroek 		return ("<nil>");
1506*00b67f09SDavid van Moolenbroek 	}
1507*00b67f09SDavid van Moolenbroek 
1508*00b67f09SDavid van Moolenbroek 	/* Append address mask width */
1509*00b67f09SDavid van Moolenbroek 	cp = buf;
1510*00b67f09SDavid van Moolenbroek 	len = strlen(cp);
1511*00b67f09SDavid van Moolenbroek 	cp += len;
1512*00b67f09SDavid van Moolenbroek 	size = sizeof(buf) - len;
1513*00b67f09SDavid van Moolenbroek 	(void)snprintf(cp, size, "/%d", w);
1514*00b67f09SDavid van Moolenbroek 	return (buf);
1515*00b67f09SDavid van Moolenbroek }
1516*00b67f09SDavid van Moolenbroek 
1517*00b67f09SDavid van Moolenbroek void
nslint(void)1518*00b67f09SDavid van Moolenbroek nslint(void)
1519*00b67f09SDavid van Moolenbroek {
1520*00b67f09SDavid van Moolenbroek 	int n, records, flags;
1521*00b67f09SDavid van Moolenbroek 	struct item *ip, *lastaip, **ipp, **itemlist;
1522*00b67f09SDavid van Moolenbroek 	struct addr addr, lastaddr;
1523*00b67f09SDavid van Moolenbroek 	struct network *np;
1524*00b67f09SDavid van Moolenbroek 
1525*00b67f09SDavid van Moolenbroek 	itemlist = (struct item **)calloc(itemcnt, sizeof(*ipp));
1526*00b67f09SDavid van Moolenbroek 	if (itemlist == NULL) {
1527*00b67f09SDavid van Moolenbroek 		fprintf(stderr, "%s: nslint: calloc: %s\n",
1528*00b67f09SDavid van Moolenbroek 		    prog, strerror(errno));
1529*00b67f09SDavid van Moolenbroek 		exit(1);
1530*00b67f09SDavid van Moolenbroek 	}
1531*00b67f09SDavid van Moolenbroek 	ipp = itemlist;
1532*00b67f09SDavid van Moolenbroek 	for (n = 0, ip = items; n < ITEMSIZE; ++n, ++ip) {
1533*00b67f09SDavid van Moolenbroek 		if (ip->host == NULL)
1534*00b67f09SDavid van Moolenbroek 			continue;
1535*00b67f09SDavid van Moolenbroek 		/* Save entries with addresses for later check */
1536*00b67f09SDavid van Moolenbroek 		if (ip->addr.family != 0)
1537*00b67f09SDavid van Moolenbroek 			*ipp++ = ip;
1538*00b67f09SDavid van Moolenbroek 
1539*00b67f09SDavid van Moolenbroek 		if (debug > 1) {
1540*00b67f09SDavid van Moolenbroek 			if (debug > 2)
1541*00b67f09SDavid van Moolenbroek 				printf("%d\t", n);
1542*00b67f09SDavid van Moolenbroek 			printf("%s\t%s\t0x%x\t0x%x\n",
1543*00b67f09SDavid van Moolenbroek 			    ip->host, addr2str(&ip->addr),
1544*00b67f09SDavid van Moolenbroek 			    ip->records, ip->flags);
1545*00b67f09SDavid van Moolenbroek 		}
1546*00b67f09SDavid van Moolenbroek 
1547*00b67f09SDavid van Moolenbroek 		/* Check for illegal hostnames (rfc1034) */
1548*00b67f09SDavid van Moolenbroek 		if (rfc1034host(ip->host, ip->records))
1549*00b67f09SDavid van Moolenbroek 			++errors;
1550*00b67f09SDavid van Moolenbroek 
1551*00b67f09SDavid van Moolenbroek 		/* Check for missing ptr records (ok if also an ns record) */
1552*00b67f09SDavid van Moolenbroek 		records = ip->records & MASK_CHECK_REC;
1553*00b67f09SDavid van Moolenbroek 		if ((ip->records & MASK_TEST_REC) != 0)
1554*00b67f09SDavid van Moolenbroek 			records |= REC_OTHER;
1555*00b67f09SDavid van Moolenbroek 		switch (records) {
1556*00b67f09SDavid van Moolenbroek 
1557*00b67f09SDavid van Moolenbroek 		case REC_A | REC_OTHER | REC_PTR | REC_REF:
1558*00b67f09SDavid van Moolenbroek 		case REC_A | REC_OTHER | REC_PTR:
1559*00b67f09SDavid van Moolenbroek 		case REC_A | REC_PTR | REC_REF:
1560*00b67f09SDavid van Moolenbroek 		case REC_A | REC_PTR:
1561*00b67f09SDavid van Moolenbroek 		case REC_AAAA | REC_OTHER | REC_PTR | REC_REF:
1562*00b67f09SDavid van Moolenbroek 		case REC_AAAA | REC_OTHER | REC_PTR:
1563*00b67f09SDavid van Moolenbroek 		case REC_AAAA | REC_PTR | REC_REF:
1564*00b67f09SDavid van Moolenbroek 		case REC_AAAA | REC_PTR:
1565*00b67f09SDavid van Moolenbroek 		case REC_CNAME:
1566*00b67f09SDavid van Moolenbroek 			/* These are O.K. */
1567*00b67f09SDavid van Moolenbroek 			break;
1568*00b67f09SDavid van Moolenbroek 
1569*00b67f09SDavid van Moolenbroek 		case REC_CNAME | REC_REF:
1570*00b67f09SDavid van Moolenbroek 			++errors;
1571*00b67f09SDavid van Moolenbroek 			fprintf(stderr, "%s: \"cname\" referenced by other"
1572*00b67f09SDavid van Moolenbroek 			    " \"cname\" or \"mx\": %s\n", prog, ip->host);
1573*00b67f09SDavid van Moolenbroek 			break;
1574*00b67f09SDavid van Moolenbroek 
1575*00b67f09SDavid van Moolenbroek 		case REC_OTHER | REC_REF:
1576*00b67f09SDavid van Moolenbroek 		case REC_OTHER:
1577*00b67f09SDavid van Moolenbroek 			/*
1578*00b67f09SDavid van Moolenbroek 			 * This is only an error if there is an address
1579*00b67f09SDavid van Moolenbroek 			 * associated with the hostname; this means
1580*00b67f09SDavid van Moolenbroek 			 * there was a wks entry with bogus address.
1581*00b67f09SDavid van Moolenbroek 			 * Otherwise, we have an mx or hinfo.
1582*00b67f09SDavid van Moolenbroek 			 *
1583*00b67f09SDavid van Moolenbroek 			 * XXX ignore localhost for now
1584*00b67f09SDavid van Moolenbroek 			 * (use flag to indicate loopback?)
1585*00b67f09SDavid van Moolenbroek 			 */
1586*00b67f09SDavid van Moolenbroek 			if (ip->addr.family == AF_INET &&
1587*00b67f09SDavid van Moolenbroek 			    ip->addr.a_addr4 != htonl(INADDR_LOOPBACK)) {
1588*00b67f09SDavid van Moolenbroek 				++errors;
1589*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
1590*00b67f09SDavid van Moolenbroek 			    "%s: \"wks\" without \"a\" and \"ptr\": %s -> %s\n",
1591*00b67f09SDavid van Moolenbroek 				    prog, ip->host, addr2str(&ip->addr));
1592*00b67f09SDavid van Moolenbroek 			}
1593*00b67f09SDavid van Moolenbroek 			break;
1594*00b67f09SDavid van Moolenbroek 
1595*00b67f09SDavid van Moolenbroek 		case REC_REF:
1596*00b67f09SDavid van Moolenbroek 			if (!checkignoredzone(ip->host)) {
1597*00b67f09SDavid van Moolenbroek 				++errors;
1598*00b67f09SDavid van Moolenbroek 				fprintf(stderr, "%s: Name referenced without"
1599*00b67f09SDavid van Moolenbroek 				    " other records: %s\n", prog, ip->host);
1600*00b67f09SDavid van Moolenbroek 			}
1601*00b67f09SDavid van Moolenbroek 			break;
1602*00b67f09SDavid van Moolenbroek 
1603*00b67f09SDavid van Moolenbroek 		case REC_A | REC_OTHER | REC_REF:
1604*00b67f09SDavid van Moolenbroek 		case REC_A | REC_OTHER:
1605*00b67f09SDavid van Moolenbroek 		case REC_A | REC_REF:
1606*00b67f09SDavid van Moolenbroek 		case REC_A:
1607*00b67f09SDavid van Moolenbroek 		case REC_AAAA | REC_OTHER | REC_REF:
1608*00b67f09SDavid van Moolenbroek 		case REC_AAAA | REC_OTHER:
1609*00b67f09SDavid van Moolenbroek 		case REC_AAAA | REC_REF:
1610*00b67f09SDavid van Moolenbroek 		case REC_AAAA:
1611*00b67f09SDavid van Moolenbroek 			++errors;
1612*00b67f09SDavid van Moolenbroek 			fprintf(stderr, "%s: Missing \"ptr\": %s -> %s\n",
1613*00b67f09SDavid van Moolenbroek 			    prog, ip->host, addr2str(&ip->addr));
1614*00b67f09SDavid van Moolenbroek 			break;
1615*00b67f09SDavid van Moolenbroek 
1616*00b67f09SDavid van Moolenbroek 		case REC_OTHER | REC_PTR | REC_REF:
1617*00b67f09SDavid van Moolenbroek 		case REC_OTHER | REC_PTR:
1618*00b67f09SDavid van Moolenbroek 		case REC_PTR | REC_REF:
1619*00b67f09SDavid van Moolenbroek 		case REC_PTR:
1620*00b67f09SDavid van Moolenbroek 			++errors;
1621*00b67f09SDavid van Moolenbroek 			fprintf(stderr, "%s: Missing \"a\": %s -> %s\n",
1622*00b67f09SDavid van Moolenbroek 			    prog, ip->host, addr2str(&ip->addr));
1623*00b67f09SDavid van Moolenbroek 			break;
1624*00b67f09SDavid van Moolenbroek 
1625*00b67f09SDavid van Moolenbroek 		case REC_A | REC_CNAME | REC_OTHER | REC_PTR | REC_REF:
1626*00b67f09SDavid van Moolenbroek 		case REC_A | REC_CNAME | REC_OTHER | REC_PTR:
1627*00b67f09SDavid van Moolenbroek 		case REC_A | REC_CNAME | REC_OTHER | REC_REF:
1628*00b67f09SDavid van Moolenbroek 		case REC_A | REC_CNAME | REC_OTHER:
1629*00b67f09SDavid van Moolenbroek 		case REC_A | REC_CNAME | REC_PTR | REC_REF:
1630*00b67f09SDavid van Moolenbroek 		case REC_A | REC_CNAME | REC_PTR:
1631*00b67f09SDavid van Moolenbroek 		case REC_A | REC_CNAME | REC_REF:
1632*00b67f09SDavid van Moolenbroek 		case REC_A | REC_CNAME:
1633*00b67f09SDavid van Moolenbroek 		case REC_AAAA | REC_CNAME | REC_OTHER | REC_PTR | REC_REF:
1634*00b67f09SDavid van Moolenbroek 		case REC_AAAA | REC_CNAME | REC_OTHER | REC_PTR:
1635*00b67f09SDavid van Moolenbroek 		case REC_AAAA | REC_CNAME | REC_OTHER | REC_REF:
1636*00b67f09SDavid van Moolenbroek 		case REC_AAAA | REC_CNAME | REC_OTHER:
1637*00b67f09SDavid van Moolenbroek 		case REC_AAAA | REC_CNAME | REC_PTR | REC_REF:
1638*00b67f09SDavid van Moolenbroek 		case REC_AAAA | REC_CNAME | REC_PTR:
1639*00b67f09SDavid van Moolenbroek 		case REC_AAAA | REC_CNAME | REC_REF:
1640*00b67f09SDavid van Moolenbroek 		case REC_AAAA | REC_CNAME:
1641*00b67f09SDavid van Moolenbroek 		case REC_CNAME | REC_OTHER | REC_PTR | REC_REF:
1642*00b67f09SDavid van Moolenbroek 		case REC_CNAME | REC_OTHER | REC_PTR:
1643*00b67f09SDavid van Moolenbroek 		case REC_CNAME | REC_OTHER | REC_REF:
1644*00b67f09SDavid van Moolenbroek 		case REC_CNAME | REC_OTHER:
1645*00b67f09SDavid van Moolenbroek 		case REC_CNAME | REC_PTR | REC_REF:
1646*00b67f09SDavid van Moolenbroek 		case REC_CNAME | REC_PTR:
1647*00b67f09SDavid van Moolenbroek 			++errors;
1648*00b67f09SDavid van Moolenbroek 			fprintf(stderr, "%s: \"cname\" %s has other records\n",
1649*00b67f09SDavid van Moolenbroek 			    prog, ip->host);
1650*00b67f09SDavid van Moolenbroek 			break;
1651*00b67f09SDavid van Moolenbroek 
1652*00b67f09SDavid van Moolenbroek 		case 0:
1653*00b67f09SDavid van Moolenbroek 			/* Second level test */
1654*00b67f09SDavid van Moolenbroek 			if ((ip->records & ~(REC_NS | REC_TXT)) == 0)
1655*00b67f09SDavid van Moolenbroek 				break;
1656*00b67f09SDavid van Moolenbroek 			/* Fall through... */
1657*00b67f09SDavid van Moolenbroek 
1658*00b67f09SDavid van Moolenbroek 		default:
1659*00b67f09SDavid van Moolenbroek 			++errors;
1660*00b67f09SDavid van Moolenbroek 			fprintf(stderr,
1661*00b67f09SDavid van Moolenbroek 			    "%s: records == 0x%x: can't happen (%s 0x%x)\n",
1662*00b67f09SDavid van Moolenbroek 			    prog, records, ip->host, ip->records);
1663*00b67f09SDavid van Moolenbroek 			break;
1664*00b67f09SDavid van Moolenbroek 		}
1665*00b67f09SDavid van Moolenbroek 
1666*00b67f09SDavid van Moolenbroek 		/* Check for smtp problems */
1667*00b67f09SDavid van Moolenbroek 		flags = ip->flags & MASK_TEST_SMTP;
1668*00b67f09SDavid van Moolenbroek 
1669*00b67f09SDavid van Moolenbroek 		if ((flags & FLG_SELFMX) != 0 &&
1670*00b67f09SDavid van Moolenbroek 		    (ip->records & (REC_A | REC_AAAA)) == 0) {
1671*00b67f09SDavid van Moolenbroek 			++errors;
1672*00b67f09SDavid van Moolenbroek 			fprintf(stderr,
1673*00b67f09SDavid van Moolenbroek 			    "%s: Self \"mx\" for %s missing"
1674*00b67f09SDavid van Moolenbroek 			    " \"a\" or \"aaaa\" record\n",
1675*00b67f09SDavid van Moolenbroek 			    prog, ip->host);
1676*00b67f09SDavid van Moolenbroek 		}
1677*00b67f09SDavid van Moolenbroek 
1678*00b67f09SDavid van Moolenbroek 		switch (flags) {
1679*00b67f09SDavid van Moolenbroek 
1680*00b67f09SDavid van Moolenbroek 		case 0:
1681*00b67f09SDavid van Moolenbroek 		case FLG_SELFMX | FLG_SMTPWKS:
1682*00b67f09SDavid van Moolenbroek 			/* These are O.K. */
1683*00b67f09SDavid van Moolenbroek 			break;
1684*00b67f09SDavid van Moolenbroek 
1685*00b67f09SDavid van Moolenbroek 		case FLG_SELFMX:
1686*00b67f09SDavid van Moolenbroek 			if ((ip->records & REC_WKS) != 0) {
1687*00b67f09SDavid van Moolenbroek 				++errors;
1688*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
1689*00b67f09SDavid van Moolenbroek 				    "%s: smtp/tcp missing from \"wks\": %s\n",
1690*00b67f09SDavid van Moolenbroek 				    prog, ip->host);
1691*00b67f09SDavid van Moolenbroek 			}
1692*00b67f09SDavid van Moolenbroek 			break;
1693*00b67f09SDavid van Moolenbroek 
1694*00b67f09SDavid van Moolenbroek 		case FLG_SMTPWKS:
1695*00b67f09SDavid van Moolenbroek 			++errors;
1696*00b67f09SDavid van Moolenbroek 			fprintf(stderr,
1697*00b67f09SDavid van Moolenbroek 			    "%s: Saw smtp/tcp without self \"mx\": %s\n",
1698*00b67f09SDavid van Moolenbroek 			    prog, ip->host);
1699*00b67f09SDavid van Moolenbroek 			break;
1700*00b67f09SDavid van Moolenbroek 
1701*00b67f09SDavid van Moolenbroek 		default:
1702*00b67f09SDavid van Moolenbroek 			++errors;
1703*00b67f09SDavid van Moolenbroek 			fprintf(stderr,
1704*00b67f09SDavid van Moolenbroek 			    "%s: flags == 0x%x: can't happen (%s)\n",
1705*00b67f09SDavid van Moolenbroek 			    prog, flags, ip->host);
1706*00b67f09SDavid van Moolenbroek 		}
1707*00b67f09SDavid van Moolenbroek 
1708*00b67f09SDavid van Moolenbroek 		/* Check for chained MX records */
1709*00b67f09SDavid van Moolenbroek 		if ((ip->flags & (FLG_SELFMX | FLG_MXREF)) == FLG_MXREF &&
1710*00b67f09SDavid van Moolenbroek 		    (ip->records & REC_MX) != 0) {
1711*00b67f09SDavid van Moolenbroek 			++errors;
1712*00b67f09SDavid van Moolenbroek 			fprintf(stderr, "%s: \"mx\" referenced by other"
1713*00b67f09SDavid van Moolenbroek 			    " \"mx\" record: %s\n", prog, ip->host);
1714*00b67f09SDavid van Moolenbroek 		}
1715*00b67f09SDavid van Moolenbroek 	}
1716*00b67f09SDavid van Moolenbroek 
1717*00b67f09SDavid van Moolenbroek 	/* Check for doubly booked addresses */
1718*00b67f09SDavid van Moolenbroek 	n = ipp - itemlist;
1719*00b67f09SDavid van Moolenbroek 	qsort(itemlist, n, sizeof(itemlist[0]), cmpaddr);
1720*00b67f09SDavid van Moolenbroek 	memset(&lastaddr, 0, sizeof(lastaddr));
1721*00b67f09SDavid van Moolenbroek 	ip = NULL;
1722*00b67f09SDavid van Moolenbroek 	for (ipp = itemlist; n > 0; ++ipp, --n) {
1723*00b67f09SDavid van Moolenbroek 		addr = (*ipp)->addr;
1724*00b67f09SDavid van Moolenbroek 		if (cmpaddr(&lastaddr, &addr) == 0 &&
1725*00b67f09SDavid van Moolenbroek 		    ((*ipp)->flags & FLG_ALLOWDUPA) == 0 &&
1726*00b67f09SDavid van Moolenbroek 		    (ip->flags & FLG_ALLOWDUPA) == 0) {
1727*00b67f09SDavid van Moolenbroek 			++errors;
1728*00b67f09SDavid van Moolenbroek 			fprintf(stderr, "%s: %s in use by %s and %s\n",
1729*00b67f09SDavid van Moolenbroek 			    prog, addr2str(&addr), (*ipp)->host, ip->host);
1730*00b67f09SDavid van Moolenbroek 		}
1731*00b67f09SDavid van Moolenbroek 		memmove(&lastaddr, &addr, sizeof(addr));
1732*00b67f09SDavid van Moolenbroek 		ip = *ipp;
1733*00b67f09SDavid van Moolenbroek 	}
1734*00b67f09SDavid van Moolenbroek 
1735*00b67f09SDavid van Moolenbroek 	/* Check for hosts with multiple addresses on the same subnet */
1736*00b67f09SDavid van Moolenbroek 	n = ipp - itemlist;
1737*00b67f09SDavid van Moolenbroek 	qsort(itemlist, n, sizeof(itemlist[0]), cmpitemhost);
1738*00b67f09SDavid van Moolenbroek 	if (netlistcnt > 0) {
1739*00b67f09SDavid van Moolenbroek 		n = ipp - itemlist;
1740*00b67f09SDavid van Moolenbroek 		lastaip = NULL;
1741*00b67f09SDavid van Moolenbroek 		for (ipp = itemlist; n > 0; ++ipp, --n) {
1742*00b67f09SDavid van Moolenbroek 			ip = *ipp;
1743*00b67f09SDavid van Moolenbroek 			if ((ip->records & (REC_A | REC_AAAA)) == 0 ||
1744*00b67f09SDavid van Moolenbroek 			    (ip->flags & FLG_ALLOWDUPA) != 0)
1745*00b67f09SDavid van Moolenbroek 				continue;
1746*00b67f09SDavid van Moolenbroek 			if (lastaip != NULL &&
1747*00b67f09SDavid van Moolenbroek 			    strcasecmp(ip->host, lastaip->host) == 0) {
1748*00b67f09SDavid van Moolenbroek 				np = findnetwork(&ip->addr);
1749*00b67f09SDavid van Moolenbroek 				if (np == NULL) {
1750*00b67f09SDavid van Moolenbroek 					++errors;
1751*00b67f09SDavid van Moolenbroek 					fprintf(stderr,
1752*00b67f09SDavid van Moolenbroek 					    "%s: Can't find subnet mask"
1753*00b67f09SDavid van Moolenbroek 					    " for %s (%s)\n",
1754*00b67f09SDavid van Moolenbroek 					    prog, ip->host,
1755*00b67f09SDavid van Moolenbroek 					    addr2str(&ip->addr));
1756*00b67f09SDavid van Moolenbroek 				} else if (samesubnet(&lastaip->addr,
1757*00b67f09SDavid van Moolenbroek 				    &ip->addr, np)) {
1758*00b67f09SDavid van Moolenbroek 					++errors;
1759*00b67f09SDavid van Moolenbroek 					fprintf(stderr,
1760*00b67f09SDavid van Moolenbroek 			    "%s: Multiple \"a\" records for %s on subnet %s",
1761*00b67f09SDavid van Moolenbroek 					    prog, ip->host,
1762*00b67f09SDavid van Moolenbroek 					    network2str(np));
1763*00b67f09SDavid van Moolenbroek 					fprintf(stderr, "\n\t(%s",
1764*00b67f09SDavid van Moolenbroek 					    addr2str(&lastaip->addr));
1765*00b67f09SDavid van Moolenbroek 					fprintf(stderr, " and %s)\n",
1766*00b67f09SDavid van Moolenbroek 					    addr2str(&ip->addr));
1767*00b67f09SDavid van Moolenbroek 				}
1768*00b67f09SDavid van Moolenbroek 			}
1769*00b67f09SDavid van Moolenbroek 			lastaip = ip;
1770*00b67f09SDavid van Moolenbroek 		}
1771*00b67f09SDavid van Moolenbroek 	}
1772*00b67f09SDavid van Moolenbroek 
1773*00b67f09SDavid van Moolenbroek 	if (debug)
1774*00b67f09SDavid van Moolenbroek 		printf("%s: %d/%d items used, %d error%s\n", prog, itemcnt,
1775*00b67f09SDavid van Moolenbroek 		    ITEMSIZE, errors, errors == 1 ? "" : "s");
1776*00b67f09SDavid van Moolenbroek }
1777*00b67f09SDavid van Moolenbroek 
1778*00b67f09SDavid van Moolenbroek const char *
parsenetwork(const char * cp)1779*00b67f09SDavid van Moolenbroek parsenetwork(const char *cp)
1780*00b67f09SDavid van Moolenbroek {
1781*00b67f09SDavid van Moolenbroek 	const char *p;
1782*00b67f09SDavid van Moolenbroek 	struct network net;
1783*00b67f09SDavid van Moolenbroek 
1784*00b67f09SDavid van Moolenbroek 	while (isspace(*cp))
1785*00b67f09SDavid van Moolenbroek 		++cp;
1786*00b67f09SDavid van Moolenbroek 
1787*00b67f09SDavid van Moolenbroek 	p = extractnetwork(cp, &net);
1788*00b67f09SDavid van Moolenbroek 	if (p != NULL)
1789*00b67f09SDavid van Moolenbroek 		return (p);
1790*00b67f09SDavid van Moolenbroek 
1791*00b67f09SDavid van Moolenbroek 	while (isspace(*cp))
1792*00b67f09SDavid van Moolenbroek 		++cp;
1793*00b67f09SDavid van Moolenbroek 
1794*00b67f09SDavid van Moolenbroek 	/* Make sure there's room */
1795*00b67f09SDavid van Moolenbroek 	if (netlistsize <= netlistcnt) {
1796*00b67f09SDavid van Moolenbroek 		if (netlistsize == 0) {
1797*00b67f09SDavid van Moolenbroek 			netlistsize = 32;
1798*00b67f09SDavid van Moolenbroek 			netlist = (struct network *)
1799*00b67f09SDavid van Moolenbroek 			    malloc(netlistsize * sizeof(*netlist));
1800*00b67f09SDavid van Moolenbroek 		} else {
1801*00b67f09SDavid van Moolenbroek 			netlistsize <<= 1;
1802*00b67f09SDavid van Moolenbroek 			netlist = (struct network *)
1803*00b67f09SDavid van Moolenbroek 			    realloc(netlist, netlistsize * sizeof(*netlist));
1804*00b67f09SDavid van Moolenbroek 		}
1805*00b67f09SDavid van Moolenbroek 		if (netlist == NULL) {
1806*00b67f09SDavid van Moolenbroek 			fprintf(stderr,
1807*00b67f09SDavid van Moolenbroek 			    "%s: parsenetwork: malloc/realloc: %s\n",
1808*00b67f09SDavid van Moolenbroek 			    prog, strerror(errno));
1809*00b67f09SDavid van Moolenbroek 			exit(1);
1810*00b67f09SDavid van Moolenbroek 		}
1811*00b67f09SDavid van Moolenbroek 	}
1812*00b67f09SDavid van Moolenbroek 
1813*00b67f09SDavid van Moolenbroek 	/* Add to list */
1814*00b67f09SDavid van Moolenbroek 	memmove(netlist + netlistcnt, &net, sizeof(net));
1815*00b67f09SDavid van Moolenbroek 	++netlistcnt;
1816*00b67f09SDavid van Moolenbroek 
1817*00b67f09SDavid van Moolenbroek 	return (NULL);
1818*00b67f09SDavid van Moolenbroek }
1819*00b67f09SDavid van Moolenbroek 
1820*00b67f09SDavid van Moolenbroek const char *
parseptr(const char * str,struct addr * ap)1821*00b67f09SDavid van Moolenbroek parseptr(const char *str, struct addr *ap)
1822*00b67f09SDavid van Moolenbroek {
1823*00b67f09SDavid van Moolenbroek 	int i, n, base;
1824*00b67f09SDavid van Moolenbroek 	u_long v, v2;
1825*00b67f09SDavid van Moolenbroek 	char *cp;
1826*00b67f09SDavid van Moolenbroek 	const char *p;
1827*00b67f09SDavid van Moolenbroek 	u_char *up;
1828*00b67f09SDavid van Moolenbroek 
1829*00b67f09SDavid van Moolenbroek 	memset(ap, 0, sizeof(*ap));
1830*00b67f09SDavid van Moolenbroek 	base = -1;
1831*00b67f09SDavid van Moolenbroek 
1832*00b67f09SDavid van Moolenbroek 	/* IPv4 */
1833*00b67f09SDavid van Moolenbroek 	p = str + strlen(str) - sizeof(inaddr) + 1;
1834*00b67f09SDavid van Moolenbroek 	if (p >= str && strcasecmp(p, inaddr) == 0) {
1835*00b67f09SDavid van Moolenbroek 		ap->family = AF_INET;
1836*00b67f09SDavid van Moolenbroek 		n = 4;
1837*00b67f09SDavid van Moolenbroek 		base = 10;
1838*00b67f09SDavid van Moolenbroek 	} else {
1839*00b67f09SDavid van Moolenbroek 		/* IPv6 */
1840*00b67f09SDavid van Moolenbroek 		p = str + strlen(str) - sizeof(inaddr6) + 1;
1841*00b67f09SDavid van Moolenbroek 		if (p >= str && strcasecmp(p, inaddr6) == 0) {
1842*00b67f09SDavid van Moolenbroek 			ap->family = AF_INET6;
1843*00b67f09SDavid van Moolenbroek 			n = 16;
1844*00b67f09SDavid van Moolenbroek 			base = 16;
1845*00b67f09SDavid van Moolenbroek 		}
1846*00b67f09SDavid van Moolenbroek 	}
1847*00b67f09SDavid van Moolenbroek 
1848*00b67f09SDavid van Moolenbroek 	if (base < 0)
1849*00b67f09SDavid van Moolenbroek 		return ("Not a IPv4 or IPv6 \"ptr\" record");
1850*00b67f09SDavid van Moolenbroek 
1851*00b67f09SDavid van Moolenbroek 	up = (u_char *)&ap->addr;
1852*00b67f09SDavid van Moolenbroek 	for (i = 0; i < n; ++i) {
1853*00b67f09SDavid van Moolenbroek 		/* Back up to previous dot or beginning of string */
1854*00b67f09SDavid van Moolenbroek 		while (p > str && p[-1] != '.')
1855*00b67f09SDavid van Moolenbroek 			--p;
1856*00b67f09SDavid van Moolenbroek 		v = strtoul(p, &cp, base);
1857*00b67f09SDavid van Moolenbroek 
1858*00b67f09SDavid van Moolenbroek 		if (base == 10) {
1859*00b67f09SDavid van Moolenbroek 			if (v > 0xff)
1860*00b67f09SDavid van Moolenbroek 				return ("Octet larger than 8 bits");
1861*00b67f09SDavid van Moolenbroek 		} else {
1862*00b67f09SDavid van Moolenbroek 			if (v > 0xf)
1863*00b67f09SDavid van Moolenbroek 				return ("Octet larger than 4 bits");
1864*00b67f09SDavid van Moolenbroek 			if (*cp != '.')
1865*00b67f09SDavid van Moolenbroek 				return ("Junk in \"ptr\" record");
1866*00b67f09SDavid van Moolenbroek 
1867*00b67f09SDavid van Moolenbroek 			/* Back up over dot */
1868*00b67f09SDavid van Moolenbroek 			if (p > str)
1869*00b67f09SDavid van Moolenbroek 				--p;
1870*00b67f09SDavid van Moolenbroek 
1871*00b67f09SDavid van Moolenbroek 			/* Back up to previous dot or beginning of string */
1872*00b67f09SDavid van Moolenbroek 			while (p > str && p[-1] != '.')
1873*00b67f09SDavid van Moolenbroek 				--p;
1874*00b67f09SDavid van Moolenbroek 			v2 = strtoul(p, &cp, base);
1875*00b67f09SDavid van Moolenbroek 			if (v2 > 0xf)
1876*00b67f09SDavid van Moolenbroek 				return ("Octet larger than 4 bits");
1877*00b67f09SDavid van Moolenbroek 			if (*cp != '.')
1878*00b67f09SDavid van Moolenbroek 				return ("Junk in \"ptr\" record");
1879*00b67f09SDavid van Moolenbroek 			v = (v << 4) | v2;
1880*00b67f09SDavid van Moolenbroek 		}
1881*00b67f09SDavid van Moolenbroek 		if (*cp != '.')
1882*00b67f09SDavid van Moolenbroek 			return ("Junk in \"ptr\" record");
1883*00b67f09SDavid van Moolenbroek 
1884*00b67f09SDavid van Moolenbroek 		*up++ = v & 0xff;
1885*00b67f09SDavid van Moolenbroek 
1886*00b67f09SDavid van Moolenbroek 		/* Back up over dot */
1887*00b67f09SDavid van Moolenbroek 		if (p > str)
1888*00b67f09SDavid van Moolenbroek 			--p;
1889*00b67f09SDavid van Moolenbroek 		else if (p == str)
1890*00b67f09SDavid van Moolenbroek 			break;
1891*00b67f09SDavid van Moolenbroek 	}
1892*00b67f09SDavid van Moolenbroek 	if (i < n - 1)
1893*00b67f09SDavid van Moolenbroek 		return ("Too many octets in \"ptr\" record");
1894*00b67f09SDavid van Moolenbroek 	if (p != str)
1895*00b67f09SDavid van Moolenbroek 		return ("Not enough octets in \"ptr\" record");
1896*00b67f09SDavid van Moolenbroek 
1897*00b67f09SDavid van Moolenbroek 	return (NULL);
1898*00b67f09SDavid van Moolenbroek }
1899*00b67f09SDavid van Moolenbroek 
1900*00b67f09SDavid van Moolenbroek /* Returns a pointer after the next token or quoted string, else NULL */
1901*00b67f09SDavid van Moolenbroek char *
parsequoted(char * cp)1902*00b67f09SDavid van Moolenbroek parsequoted(char *cp)
1903*00b67f09SDavid van Moolenbroek {
1904*00b67f09SDavid van Moolenbroek 
1905*00b67f09SDavid van Moolenbroek 	if (*cp == '"') {
1906*00b67f09SDavid van Moolenbroek 		++cp;
1907*00b67f09SDavid van Moolenbroek 		while (*cp != '"' && *cp != '\0')
1908*00b67f09SDavid van Moolenbroek 			++cp;
1909*00b67f09SDavid van Moolenbroek 		if (*cp != '"')
1910*00b67f09SDavid van Moolenbroek 			return (NULL);
1911*00b67f09SDavid van Moolenbroek 		++cp;
1912*00b67f09SDavid van Moolenbroek 	} else {
1913*00b67f09SDavid van Moolenbroek 		while (!isspace(*cp) && *cp != '\0')
1914*00b67f09SDavid van Moolenbroek 			++cp;
1915*00b67f09SDavid van Moolenbroek 	}
1916*00b67f09SDavid van Moolenbroek 	return (cp);
1917*00b67f09SDavid van Moolenbroek }
1918*00b67f09SDavid van Moolenbroek 
1919*00b67f09SDavid van Moolenbroek /* Return true when done */
1920*00b67f09SDavid van Moolenbroek int
parserrsig(const char * str,char ** errstrp)1921*00b67f09SDavid van Moolenbroek parserrsig(const char *str, char **errstrp)
1922*00b67f09SDavid van Moolenbroek {
1923*00b67f09SDavid van Moolenbroek 	const char *cp;
1924*00b67f09SDavid van Moolenbroek 
1925*00b67f09SDavid van Moolenbroek 	/* XXX just look for closing paren */
1926*00b67f09SDavid van Moolenbroek 	cp = str + strlen(str) - 1;
1927*00b67f09SDavid van Moolenbroek 	while (cp >= str)
1928*00b67f09SDavid van Moolenbroek 		if (*cp-- == ')')
1929*00b67f09SDavid van Moolenbroek 		return (1);
1930*00b67f09SDavid van Moolenbroek 	return (0);
1931*00b67f09SDavid van Moolenbroek }
1932*00b67f09SDavid van Moolenbroek 
1933*00b67f09SDavid van Moolenbroek /* Return true when done */
1934*00b67f09SDavid van Moolenbroek int
parsesoa(const char * cp,char ** errstrp)1935*00b67f09SDavid van Moolenbroek parsesoa(const char *cp, char **errstrp)
1936*00b67f09SDavid van Moolenbroek {
1937*00b67f09SDavid van Moolenbroek 	char ch, *garbage;
1938*00b67f09SDavid van Moolenbroek 	static char errstr[132];
1939*00b67f09SDavid van Moolenbroek 
1940*00b67f09SDavid van Moolenbroek 	/* Eat leading whitespace */
1941*00b67f09SDavid van Moolenbroek 	while (isspace(*cp))
1942*00b67f09SDavid van Moolenbroek 		++cp;
1943*00b67f09SDavid van Moolenbroek 
1944*00b67f09SDavid van Moolenbroek 	/* Find opening paren */
1945*00b67f09SDavid van Moolenbroek 	if (nsoaval < 0) {
1946*00b67f09SDavid van Moolenbroek 		cp = strchr(cp, '(');
1947*00b67f09SDavid van Moolenbroek 		if (cp == NULL)
1948*00b67f09SDavid van Moolenbroek 			return (0);
1949*00b67f09SDavid van Moolenbroek 		++cp;
1950*00b67f09SDavid van Moolenbroek 		while (isspace(*cp))
1951*00b67f09SDavid van Moolenbroek 			++cp;
1952*00b67f09SDavid van Moolenbroek 		nsoaval = 0;
1953*00b67f09SDavid van Moolenbroek 	}
1954*00b67f09SDavid van Moolenbroek 
1955*00b67f09SDavid van Moolenbroek 	/* Grab any numbers we find */
1956*00b67f09SDavid van Moolenbroek 	garbage = "leading garbage";
1957*00b67f09SDavid van Moolenbroek 	while (isdigit(*cp) && nsoaval < NSOAVAL) {
1958*00b67f09SDavid van Moolenbroek 		soaval[nsoaval] = atoi(cp);
1959*00b67f09SDavid van Moolenbroek 		do {
1960*00b67f09SDavid van Moolenbroek 			++cp;
1961*00b67f09SDavid van Moolenbroek 		} while (isdigit(*cp));
1962*00b67f09SDavid van Moolenbroek 		if (nsoaval == SOA_SERIAL && *cp == '.' && isdigit(cp[1])) {
1963*00b67f09SDavid van Moolenbroek 			do {
1964*00b67f09SDavid van Moolenbroek 				++cp;
1965*00b67f09SDavid van Moolenbroek 			} while (isdigit(*cp));
1966*00b67f09SDavid van Moolenbroek 		} else {
1967*00b67f09SDavid van Moolenbroek 			ch = *cp;
1968*00b67f09SDavid van Moolenbroek 			if (isupper(ch))
1969*00b67f09SDavid van Moolenbroek 				ch = tolower(ch);
1970*00b67f09SDavid van Moolenbroek 			switch (ch) {
1971*00b67f09SDavid van Moolenbroek 
1972*00b67f09SDavid van Moolenbroek 			case 'w':
1973*00b67f09SDavid van Moolenbroek 				soaval[nsoaval] *= 7;
1974*00b67f09SDavid van Moolenbroek 				/* fall through */
1975*00b67f09SDavid van Moolenbroek 
1976*00b67f09SDavid van Moolenbroek 			case 'd':
1977*00b67f09SDavid van Moolenbroek 				soaval[nsoaval] *= 24;
1978*00b67f09SDavid van Moolenbroek 				/* fall through */
1979*00b67f09SDavid van Moolenbroek 
1980*00b67f09SDavid van Moolenbroek 			case 'h':
1981*00b67f09SDavid van Moolenbroek 				soaval[nsoaval] *= 60;
1982*00b67f09SDavid van Moolenbroek 				/* fall through */
1983*00b67f09SDavid van Moolenbroek 
1984*00b67f09SDavid van Moolenbroek 			case 'm':
1985*00b67f09SDavid van Moolenbroek 				soaval[nsoaval] *= 60;
1986*00b67f09SDavid van Moolenbroek 				/* fall through */
1987*00b67f09SDavid van Moolenbroek 
1988*00b67f09SDavid van Moolenbroek 			case 's':
1989*00b67f09SDavid van Moolenbroek 				++cp;
1990*00b67f09SDavid van Moolenbroek 				break;
1991*00b67f09SDavid van Moolenbroek 
1992*00b67f09SDavid van Moolenbroek 			default:
1993*00b67f09SDavid van Moolenbroek 				;	/* none */
1994*00b67f09SDavid van Moolenbroek 			}
1995*00b67f09SDavid van Moolenbroek 		}
1996*00b67f09SDavid van Moolenbroek 		while (isspace(*cp))
1997*00b67f09SDavid van Moolenbroek 			++cp;
1998*00b67f09SDavid van Moolenbroek 		garbage = "trailing garbage";
1999*00b67f09SDavid van Moolenbroek 		++nsoaval;
2000*00b67f09SDavid van Moolenbroek 	}
2001*00b67f09SDavid van Moolenbroek 
2002*00b67f09SDavid van Moolenbroek 	/* If we're done, do some sanity checks */
2003*00b67f09SDavid van Moolenbroek 	if (nsoaval >= NSOAVAL && *cp == ')') {
2004*00b67f09SDavid van Moolenbroek 		++cp;
2005*00b67f09SDavid van Moolenbroek 		if (*cp != '\0')
2006*00b67f09SDavid van Moolenbroek 			*errstrp = garbage;
2007*00b67f09SDavid van Moolenbroek 		else if (soaval[SOA_EXPIRE] <
2008*00b67f09SDavid van Moolenbroek 		    soaval[SOA_REFRESH] + 10 * soaval[SOA_RETRY]) {
2009*00b67f09SDavid van Moolenbroek 			(void)sprintf(errstr,
2010*00b67f09SDavid van Moolenbroek 		    "expire less than refresh + 10 * retry (%u < %u + 10 * %u)",
2011*00b67f09SDavid van Moolenbroek 			    soaval[SOA_EXPIRE],
2012*00b67f09SDavid van Moolenbroek 			    soaval[SOA_REFRESH],
2013*00b67f09SDavid van Moolenbroek 			    soaval[SOA_RETRY]);
2014*00b67f09SDavid van Moolenbroek 			*errstrp = errstr;
2015*00b67f09SDavid van Moolenbroek 		} else if (soaval[SOA_REFRESH] < 2 * soaval[SOA_RETRY]) {
2016*00b67f09SDavid van Moolenbroek 			(void)sprintf(errstr,
2017*00b67f09SDavid van Moolenbroek 			    "refresh less than 2 * retry (%u < 2 * %u)",
2018*00b67f09SDavid van Moolenbroek 			    soaval[SOA_REFRESH],
2019*00b67f09SDavid van Moolenbroek 			    soaval[SOA_RETRY]);
2020*00b67f09SDavid van Moolenbroek 			*errstrp = errstr;
2021*00b67f09SDavid van Moolenbroek 		}
2022*00b67f09SDavid van Moolenbroek 		return (1);
2023*00b67f09SDavid van Moolenbroek 	}
2024*00b67f09SDavid van Moolenbroek 
2025*00b67f09SDavid van Moolenbroek 	if (*cp != '\0') {
2026*00b67f09SDavid van Moolenbroek 		*errstrp = garbage;
2027*00b67f09SDavid van Moolenbroek 		return (1);
2028*00b67f09SDavid van Moolenbroek 	}
2029*00b67f09SDavid van Moolenbroek 
2030*00b67f09SDavid van Moolenbroek 	return (0);
2031*00b67f09SDavid van Moolenbroek }
2032*00b67f09SDavid van Moolenbroek 
2033*00b67f09SDavid van Moolenbroek void
process(const char * file,const char * domain,const char * zone)2034*00b67f09SDavid van Moolenbroek process(const char *file, const char *domain, const char *zone)
2035*00b67f09SDavid van Moolenbroek {
2036*00b67f09SDavid van Moolenbroek 	FILE *f;
2037*00b67f09SDavid van Moolenbroek 	char ch, *cp, *cp2, *cp3, *rtype;
2038*00b67f09SDavid van Moolenbroek 	const char *p;
2039*00b67f09SDavid van Moolenbroek 	int n, sawsoa, sawrrsig, flags, i;
2040*00b67f09SDavid van Moolenbroek 	u_int ttl;
2041*00b67f09SDavid van Moolenbroek 	enum rrtype rrtype;
2042*00b67f09SDavid van Moolenbroek 	struct addr *ap;
2043*00b67f09SDavid van Moolenbroek 	struct addr addr;
2044*00b67f09SDavid van Moolenbroek 	// struct network *net;
2045*00b67f09SDavid van Moolenbroek 	int smtp;
2046*00b67f09SDavid van Moolenbroek 	char buf[2048], name[256], lastname[256], odomain[256];
2047*00b67f09SDavid van Moolenbroek 	char *errstr;
2048*00b67f09SDavid van Moolenbroek 	const char *addrfmt =
2049*00b67f09SDavid van Moolenbroek 	    "%s: %s/%s:%d \"%s\" target is an ip address: %s\n";
2050*00b67f09SDavid van Moolenbroek 	const char *dotfmt =
2051*00b67f09SDavid van Moolenbroek 	    "%s: %s/%s:%d \"%s\" target missing trailing dot: %s\n";
2052*00b67f09SDavid van Moolenbroek 
2053*00b67f09SDavid van Moolenbroek 	/* Check for an "ignored zone" (usually dynamic dns) */
2054*00b67f09SDavid van Moolenbroek 	if (checkignoredzone(zone))
2055*00b67f09SDavid van Moolenbroek 		return;
2056*00b67f09SDavid van Moolenbroek 
2057*00b67f09SDavid van Moolenbroek 	f = fopen(file, "r");
2058*00b67f09SDavid van Moolenbroek 	if (f == NULL) {
2059*00b67f09SDavid van Moolenbroek 		fprintf(stderr, "%s: %s/%s: %s\n",
2060*00b67f09SDavid van Moolenbroek 		    prog, cwd, file, strerror(errno));
2061*00b67f09SDavid van Moolenbroek 		++errors;
2062*00b67f09SDavid van Moolenbroek 		return;
2063*00b67f09SDavid van Moolenbroek 	}
2064*00b67f09SDavid van Moolenbroek 	if (debug > 1)
2065*00b67f09SDavid van Moolenbroek 		printf("%s: process: opened %s/%s\n", prog, cwd, file);
2066*00b67f09SDavid van Moolenbroek 
2067*00b67f09SDavid van Moolenbroek 	/* Line number */
2068*00b67f09SDavid van Moolenbroek 	n = 0;
2069*00b67f09SDavid van Moolenbroek 
2070*00b67f09SDavid van Moolenbroek 	ap = &addr;
2071*00b67f09SDavid van Moolenbroek 
2072*00b67f09SDavid van Moolenbroek 	lastname[0] = '\0';
2073*00b67f09SDavid van Moolenbroek 	sawsoa = 0;
2074*00b67f09SDavid van Moolenbroek 	sawrrsig = 0;
2075*00b67f09SDavid van Moolenbroek 	while (fgets(buf, sizeof(buf), f) != NULL) {
2076*00b67f09SDavid van Moolenbroek 		++n;
2077*00b67f09SDavid van Moolenbroek 		cp = buf;
2078*00b67f09SDavid van Moolenbroek 		while (*cp != '\0') {
2079*00b67f09SDavid van Moolenbroek 			/* Handle quoted strings (but don't report errors) */
2080*00b67f09SDavid van Moolenbroek 			if (*cp == '"') {
2081*00b67f09SDavid van Moolenbroek 				++cp;
2082*00b67f09SDavid van Moolenbroek 				while (*cp != '"' && *cp != '\n' && *cp != '\0')
2083*00b67f09SDavid van Moolenbroek 					++cp;
2084*00b67f09SDavid van Moolenbroek 				continue;
2085*00b67f09SDavid van Moolenbroek 			}
2086*00b67f09SDavid van Moolenbroek 			if (*cp == '\n' || *cp == ';')
2087*00b67f09SDavid van Moolenbroek 				break;
2088*00b67f09SDavid van Moolenbroek 			++cp;
2089*00b67f09SDavid van Moolenbroek 		}
2090*00b67f09SDavid van Moolenbroek 		*cp-- = '\0';
2091*00b67f09SDavid van Moolenbroek 
2092*00b67f09SDavid van Moolenbroek 		/* Nuke trailing white space */
2093*00b67f09SDavid van Moolenbroek 		while (cp >= buf && isspace(*cp))
2094*00b67f09SDavid van Moolenbroek 			*cp-- = '\0';
2095*00b67f09SDavid van Moolenbroek 
2096*00b67f09SDavid van Moolenbroek 		cp = buf;
2097*00b67f09SDavid van Moolenbroek 		if (*cp == '\0')
2098*00b67f09SDavid van Moolenbroek 			continue;
2099*00b67f09SDavid van Moolenbroek 
2100*00b67f09SDavid van Moolenbroek 		/* Handle multi-line soa records */
2101*00b67f09SDavid van Moolenbroek 		if (sawsoa) {
2102*00b67f09SDavid van Moolenbroek 			errstr = NULL;
2103*00b67f09SDavid van Moolenbroek 			if (parsesoa(cp, &errstr))
2104*00b67f09SDavid van Moolenbroek 				sawsoa = 0;
2105*00b67f09SDavid van Moolenbroek 			if (errstr != NULL) {
2106*00b67f09SDavid van Moolenbroek 				++errors;
2107*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2108*00b67f09SDavid van Moolenbroek 				    "%s: %s/%s:%d Bad \"soa\" record (%s)\n",
2109*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, errstr);
2110*00b67f09SDavid van Moolenbroek 			}
2111*00b67f09SDavid van Moolenbroek 			continue;
2112*00b67f09SDavid van Moolenbroek 		}
2113*00b67f09SDavid van Moolenbroek 
2114*00b67f09SDavid van Moolenbroek 		/* Handle multi-line rrsig records */
2115*00b67f09SDavid van Moolenbroek 		if (sawrrsig) {
2116*00b67f09SDavid van Moolenbroek 			errstr = NULL;
2117*00b67f09SDavid van Moolenbroek 			if (parserrsig(cp, &errstr))
2118*00b67f09SDavid van Moolenbroek 				sawsoa = 0;
2119*00b67f09SDavid van Moolenbroek 			if (errstr != NULL) {
2120*00b67f09SDavid van Moolenbroek 				++errors;
2121*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2122*00b67f09SDavid van Moolenbroek 				    "%s: %s/%s:%d Bad \"rrsig\" record (%s)\n",
2123*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, errstr);
2124*00b67f09SDavid van Moolenbroek 			}
2125*00b67f09SDavid van Moolenbroek 			continue;
2126*00b67f09SDavid van Moolenbroek 		}
2127*00b67f09SDavid van Moolenbroek 
2128*00b67f09SDavid van Moolenbroek 		if (debug > 3)
2129*00b67f09SDavid van Moolenbroek 			printf(">%s<\n", cp);
2130*00b67f09SDavid van Moolenbroek 
2131*00b67f09SDavid van Moolenbroek 		/* Look for name */
2132*00b67f09SDavid van Moolenbroek 		if (isspace(*cp)) {
2133*00b67f09SDavid van Moolenbroek 			/* Same name as last record */
2134*00b67f09SDavid van Moolenbroek 			if (lastname[0] == '\0') {
2135*00b67f09SDavid van Moolenbroek 				++errors;
2136*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2137*00b67f09SDavid van Moolenbroek 				    "%s: %s/%s:%d No default name\n",
2138*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n);
2139*00b67f09SDavid van Moolenbroek 				continue;
2140*00b67f09SDavid van Moolenbroek 			}
2141*00b67f09SDavid van Moolenbroek 			(void)strcpy(name, lastname);
2142*00b67f09SDavid van Moolenbroek 		} else {
2143*00b67f09SDavid van Moolenbroek 			/* Extract name, converting to lowercase */
2144*00b67f09SDavid van Moolenbroek 			for (cp2 = name; !isspace(*cp) && *cp != '\0'; ++cp)
2145*00b67f09SDavid van Moolenbroek 				if (isupper(*cp))
2146*00b67f09SDavid van Moolenbroek 					*cp2++ = tolower(*cp);
2147*00b67f09SDavid van Moolenbroek 				else
2148*00b67f09SDavid van Moolenbroek 					*cp2++ = *cp;
2149*00b67f09SDavid van Moolenbroek 			*cp2 = '\0';
2150*00b67f09SDavid van Moolenbroek 
2151*00b67f09SDavid van Moolenbroek 			/* Check for domain shorthand */
2152*00b67f09SDavid van Moolenbroek 			if (name[0] == '@' && name[1] == '\0')
2153*00b67f09SDavid van Moolenbroek 				(void)strcpy(name, domain);
2154*00b67f09SDavid van Moolenbroek 		}
2155*00b67f09SDavid van Moolenbroek 
2156*00b67f09SDavid van Moolenbroek 		/* Find next token */
2157*00b67f09SDavid van Moolenbroek 		while (isspace(*cp))
2158*00b67f09SDavid van Moolenbroek 			++cp;
2159*00b67f09SDavid van Moolenbroek 
2160*00b67f09SDavid van Moolenbroek 		/* Handle includes (gag) */
2161*00b67f09SDavid van Moolenbroek 		if (name[0] == '$' && strcasecmp(name, "$include") == 0) {
2162*00b67f09SDavid van Moolenbroek 			/* Extract filename */
2163*00b67f09SDavid van Moolenbroek 			cp2 = name;
2164*00b67f09SDavid van Moolenbroek 			while (!isspace(*cp) && *cp != '\0')
2165*00b67f09SDavid van Moolenbroek 				*cp2++ = *cp++;
2166*00b67f09SDavid van Moolenbroek 			*cp2 = '\0';
2167*00b67f09SDavid van Moolenbroek 
2168*00b67f09SDavid van Moolenbroek 			/* Look for optional domain */
2169*00b67f09SDavid van Moolenbroek 			while (isspace(*cp))
2170*00b67f09SDavid van Moolenbroek 				++cp;
2171*00b67f09SDavid van Moolenbroek 			if (*cp == '\0')
2172*00b67f09SDavid van Moolenbroek 				process(name, domain, zone);
2173*00b67f09SDavid van Moolenbroek 			else {
2174*00b67f09SDavid van Moolenbroek 				cp2 = cp;
2175*00b67f09SDavid van Moolenbroek 				/* Convert optional domain to lowercase */
2176*00b67f09SDavid van Moolenbroek 				for (; !isspace(*cp) && *cp != '\0'; ++cp)
2177*00b67f09SDavid van Moolenbroek 					if (isupper(*cp))
2178*00b67f09SDavid van Moolenbroek 						*cp = tolower(*cp);
2179*00b67f09SDavid van Moolenbroek 				*cp = '\0';
2180*00b67f09SDavid van Moolenbroek 				process(name, cp2, cp2);
2181*00b67f09SDavid van Moolenbroek 			}
2182*00b67f09SDavid van Moolenbroek 			continue;
2183*00b67f09SDavid van Moolenbroek 		}
2184*00b67f09SDavid van Moolenbroek 
2185*00b67f09SDavid van Moolenbroek 		/* Handle $origin */
2186*00b67f09SDavid van Moolenbroek 		if (name[0] == '$' && strcasecmp(name, "$origin") == 0) {
2187*00b67f09SDavid van Moolenbroek 			/* Extract domain, converting to lowercase */
2188*00b67f09SDavid van Moolenbroek 			for (cp2 = odomain; !isspace(*cp) && *cp != '\0'; ++cp)
2189*00b67f09SDavid van Moolenbroek 				if (isupper(*cp))
2190*00b67f09SDavid van Moolenbroek 					*cp2++ = tolower(*cp);
2191*00b67f09SDavid van Moolenbroek 				else
2192*00b67f09SDavid van Moolenbroek 					*cp2++ = *cp;
2193*00b67f09SDavid van Moolenbroek 			*cp2 = '\0';
2194*00b67f09SDavid van Moolenbroek 			domain = odomain;
2195*00b67f09SDavid van Moolenbroek 			lastname[0] = '\0';
2196*00b67f09SDavid van Moolenbroek 			continue;
2197*00b67f09SDavid van Moolenbroek 		}
2198*00b67f09SDavid van Moolenbroek 
2199*00b67f09SDavid van Moolenbroek 		/* Handle ttl */
2200*00b67f09SDavid van Moolenbroek 		if (name[0] == '$' && strcasecmp(name, "$ttl") == 0) {
2201*00b67f09SDavid van Moolenbroek 			cp2 = cp;
2202*00b67f09SDavid van Moolenbroek 			while (isdigit(*cp))
2203*00b67f09SDavid van Moolenbroek 				++cp;
2204*00b67f09SDavid van Moolenbroek 			ch = *cp;
2205*00b67f09SDavid van Moolenbroek 			if (isupper(ch))
2206*00b67f09SDavid van Moolenbroek 				ch = tolower(ch);
2207*00b67f09SDavid van Moolenbroek 			if (strchr("wdhms", ch) != NULL)
2208*00b67f09SDavid van Moolenbroek 				++cp;
2209*00b67f09SDavid van Moolenbroek 			while (isspace(*cp))
2210*00b67f09SDavid van Moolenbroek 				++cp;
2211*00b67f09SDavid van Moolenbroek 			if (*cp != '\0') {
2212*00b67f09SDavid van Moolenbroek 				++errors;
2213*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2214*00b67f09SDavid van Moolenbroek 				    "%s: %s/%s:%d Bad $ttl \"%s\"\n",
2215*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, cp2);
2216*00b67f09SDavid van Moolenbroek 			}
2217*00b67f09SDavid van Moolenbroek 			(void)strcpy(name, lastname);
2218*00b67f09SDavid van Moolenbroek 			continue;
2219*00b67f09SDavid van Moolenbroek 		}
2220*00b67f09SDavid van Moolenbroek 
2221*00b67f09SDavid van Moolenbroek 		/* Parse ttl or use default  */
2222*00b67f09SDavid van Moolenbroek 		if (isdigit(*cp)) {
2223*00b67f09SDavid van Moolenbroek 			ttl = atoi(cp);
2224*00b67f09SDavid van Moolenbroek 			do {
2225*00b67f09SDavid van Moolenbroek 				++cp;
2226*00b67f09SDavid van Moolenbroek 			} while (isdigit(*cp));
2227*00b67f09SDavid van Moolenbroek 
2228*00b67f09SDavid van Moolenbroek 			ch = *cp;
2229*00b67f09SDavid van Moolenbroek 			if (isupper(ch))
2230*00b67f09SDavid van Moolenbroek 				ch = tolower(ch);
2231*00b67f09SDavid van Moolenbroek 			switch (ch) {
2232*00b67f09SDavid van Moolenbroek 
2233*00b67f09SDavid van Moolenbroek 			case 'w':
2234*00b67f09SDavid van Moolenbroek 				ttl *= 7;
2235*00b67f09SDavid van Moolenbroek 				/* fall through */
2236*00b67f09SDavid van Moolenbroek 
2237*00b67f09SDavid van Moolenbroek 			case 'd':
2238*00b67f09SDavid van Moolenbroek 				ttl *= 24;
2239*00b67f09SDavid van Moolenbroek 				/* fall through */
2240*00b67f09SDavid van Moolenbroek 
2241*00b67f09SDavid van Moolenbroek 			case 'h':
2242*00b67f09SDavid van Moolenbroek 				ttl *= 60;
2243*00b67f09SDavid van Moolenbroek 				/* fall through */
2244*00b67f09SDavid van Moolenbroek 
2245*00b67f09SDavid van Moolenbroek 			case 'm':
2246*00b67f09SDavid van Moolenbroek 				ttl *= 60;
2247*00b67f09SDavid van Moolenbroek 				/* fall through */
2248*00b67f09SDavid van Moolenbroek 
2249*00b67f09SDavid van Moolenbroek 			case 's':
2250*00b67f09SDavid van Moolenbroek 				++cp;
2251*00b67f09SDavid van Moolenbroek 				break;
2252*00b67f09SDavid van Moolenbroek 
2253*00b67f09SDavid van Moolenbroek 			default:
2254*00b67f09SDavid van Moolenbroek 				;	/* none */
2255*00b67f09SDavid van Moolenbroek 			}
2256*00b67f09SDavid van Moolenbroek 
2257*00b67f09SDavid van Moolenbroek 			if (!isspace(*cp)) {
2258*00b67f09SDavid van Moolenbroek 				++errors;
2259*00b67f09SDavid van Moolenbroek 				fprintf(stderr, "%s: %s/%s:%d Bad ttl\n",
2260*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n);
2261*00b67f09SDavid van Moolenbroek 				continue;
2262*00b67f09SDavid van Moolenbroek 			}
2263*00b67f09SDavid van Moolenbroek 
2264*00b67f09SDavid van Moolenbroek 			/* Find next token */
2265*00b67f09SDavid van Moolenbroek 			++cp;
2266*00b67f09SDavid van Moolenbroek 			while (isspace(*cp))
2267*00b67f09SDavid van Moolenbroek 				++cp;
2268*00b67f09SDavid van Moolenbroek 		} else
2269*00b67f09SDavid van Moolenbroek 			ttl = soaval[SOA_MINIMUM];
2270*00b67f09SDavid van Moolenbroek 
2271*00b67f09SDavid van Moolenbroek 		/* Eat optional "in" */
2272*00b67f09SDavid van Moolenbroek 		if ((cp[0] == 'i' || cp[0] == 'I') &&
2273*00b67f09SDavid van Moolenbroek 		    (cp[1] == 'n' || cp[1] == 'N') && isspace(cp[2])) {
2274*00b67f09SDavid van Moolenbroek 			/* Find next token */
2275*00b67f09SDavid van Moolenbroek 			cp += 3;
2276*00b67f09SDavid van Moolenbroek 			while (isspace(*cp))
2277*00b67f09SDavid van Moolenbroek 				++cp;
2278*00b67f09SDavid van Moolenbroek 		} else if ((cp[0] == 'c' || cp[0] == 'C') &&
2279*00b67f09SDavid van Moolenbroek 		    isspace(cp[5]) && strncasecmp(cp, "chaos", 5) == 0) {
2280*00b67f09SDavid van Moolenbroek 			/* Find next token */
2281*00b67f09SDavid van Moolenbroek 			cp += 5;
2282*00b67f09SDavid van Moolenbroek 			while (isspace(*cp))
2283*00b67f09SDavid van Moolenbroek 				++cp;
2284*00b67f09SDavid van Moolenbroek 		}
2285*00b67f09SDavid van Moolenbroek 
2286*00b67f09SDavid van Moolenbroek 		/* Find end of record type, converting to lowercase */
2287*00b67f09SDavid van Moolenbroek 		rtype = cp;
2288*00b67f09SDavid van Moolenbroek 		for (rtype = cp; !isspace(*cp) && *cp != '\0'; ++cp)
2289*00b67f09SDavid van Moolenbroek 			if (isupper(*cp))
2290*00b67f09SDavid van Moolenbroek 				*cp = tolower(*cp);
2291*00b67f09SDavid van Moolenbroek 		*cp++ = '\0';
2292*00b67f09SDavid van Moolenbroek 
2293*00b67f09SDavid van Moolenbroek 		/* Find "the rest" */
2294*00b67f09SDavid van Moolenbroek 		while (isspace(*cp))
2295*00b67f09SDavid van Moolenbroek 			++cp;
2296*00b67f09SDavid van Moolenbroek 
2297*00b67f09SDavid van Moolenbroek 		/* Check for non-ptr names with dots but no trailing dot */
2298*00b67f09SDavid van Moolenbroek 		if (!isdigit(*name) &&
2299*00b67f09SDavid van Moolenbroek 		    checkdots(name) && strcmp(domain, ".") != 0) {
2300*00b67f09SDavid van Moolenbroek 			++errors;
2301*00b67f09SDavid van Moolenbroek 			fprintf(stderr,
2302*00b67f09SDavid van Moolenbroek 			  "%s: %s/%s:%d \"%s\" name missing trailing dot: %s\n",
2303*00b67f09SDavid van Moolenbroek 			    prog, cwd, file, n, rtype, name);
2304*00b67f09SDavid van Moolenbroek 		}
2305*00b67f09SDavid van Moolenbroek 
2306*00b67f09SDavid van Moolenbroek 		/* Check for FQDNs outside the zone */
2307*00b67f09SDavid van Moolenbroek 		cp2 = name + strlen(name) - 1;
2308*00b67f09SDavid van Moolenbroek 		if (cp2 >= name && *cp2 == '.' && strchr(name, '.') != NULL) {
2309*00b67f09SDavid van Moolenbroek 			cp2 = name + strlen(name) - strlen(zone);
2310*00b67f09SDavid van Moolenbroek 			if (cp2 >= name && strcasecmp(cp2, zone) != 0) {
2311*00b67f09SDavid van Moolenbroek 				++errors;
2312*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2313*00b67f09SDavid van Moolenbroek 				    "%s: %s/%s:%d \"%s\" outside zone %s\n",
2314*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, name, zone);
2315*00b67f09SDavid van Moolenbroek 			}
2316*00b67f09SDavid van Moolenbroek 		}
2317*00b67f09SDavid van Moolenbroek 
2318*00b67f09SDavid van Moolenbroek 		rrtype = txt2rrtype(rtype);
2319*00b67f09SDavid van Moolenbroek 		switch (rrtype) {
2320*00b67f09SDavid van Moolenbroek 
2321*00b67f09SDavid van Moolenbroek 		case RR_A:
2322*00b67f09SDavid van Moolenbroek 			/* Handle "a" record */
2323*00b67f09SDavid van Moolenbroek 			add_domain(name, domain);
2324*00b67f09SDavid van Moolenbroek 			p = extractaddr(cp, ap);
2325*00b67f09SDavid van Moolenbroek 			if (p != NULL) {
2326*00b67f09SDavid van Moolenbroek 				++errors;
2327*00b67f09SDavid van Moolenbroek 				cp2 = cp + strlen(cp) - 1;
2328*00b67f09SDavid van Moolenbroek 				if (cp2 >= cp && *cp2 == '\n')
2329*00b67f09SDavid van Moolenbroek 					*cp2 = '\0';
2330*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2331*00b67f09SDavid van Moolenbroek 			    "%s: %s/%s:%d Bad \"a\" record ip addr \"%s\"\n",
2332*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, cp);
2333*00b67f09SDavid van Moolenbroek 				continue;
2334*00b67f09SDavid van Moolenbroek 			}
2335*00b67f09SDavid van Moolenbroek 			if (ap->family != AF_INET) {
2336*00b67f09SDavid van Moolenbroek 				++errors;
2337*00b67f09SDavid van Moolenbroek 				cp2 = cp + strlen(cp) - 1;
2338*00b67f09SDavid van Moolenbroek 				if (cp2 >= cp && *cp2 == '\n')
2339*00b67f09SDavid van Moolenbroek 					*cp2 = '\0';
2340*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2341*00b67f09SDavid van Moolenbroek 			    "%s: %s/%s:%d \"a\"record not AF_INET \"%s\"\n",
2342*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, cp);
2343*00b67f09SDavid van Moolenbroek 				continue;
2344*00b67f09SDavid van Moolenbroek 			}
2345*00b67f09SDavid van Moolenbroek 			errors += updateitem(name, ap, REC_A, ttl, 0);
2346*00b67f09SDavid van Moolenbroek 			break;
2347*00b67f09SDavid van Moolenbroek 
2348*00b67f09SDavid van Moolenbroek 		case RR_AAAA:
2349*00b67f09SDavid van Moolenbroek 			/* Handle "aaaa" record */
2350*00b67f09SDavid van Moolenbroek 			add_domain(name, domain);
2351*00b67f09SDavid van Moolenbroek 			p = extractaddr(cp, ap);
2352*00b67f09SDavid van Moolenbroek 			if (p != NULL) {
2353*00b67f09SDavid van Moolenbroek 				++errors;
2354*00b67f09SDavid van Moolenbroek 				cp2 = cp + strlen(cp) - 1;
2355*00b67f09SDavid van Moolenbroek 				if (cp2 >= cp && *cp2 == '\n')
2356*00b67f09SDavid van Moolenbroek 					*cp2 = '\0';
2357*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2358*00b67f09SDavid van Moolenbroek 			    "%s: %s/%s:%d Bad \"aaaa\" record ip addr \"%s\"\n",
2359*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, cp);
2360*00b67f09SDavid van Moolenbroek 				continue;
2361*00b67f09SDavid van Moolenbroek 			}
2362*00b67f09SDavid van Moolenbroek 			if (ap->family != AF_INET6) {
2363*00b67f09SDavid van Moolenbroek 				++errors;
2364*00b67f09SDavid van Moolenbroek 				cp2 = cp + strlen(cp) - 1;
2365*00b67f09SDavid van Moolenbroek 				if (cp2 >= cp && *cp2 == '\n')
2366*00b67f09SDavid van Moolenbroek 					*cp2 = '\0';
2367*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2368*00b67f09SDavid van Moolenbroek 			    "%s: %s/%s:%d \"aaaa\"record not AF_INET6 \"%s\"\n",
2369*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, cp);
2370*00b67f09SDavid van Moolenbroek 				continue;
2371*00b67f09SDavid van Moolenbroek 			}
2372*00b67f09SDavid van Moolenbroek 			errors += updateitem(name, ap, REC_AAAA, ttl, 0);
2373*00b67f09SDavid van Moolenbroek 			break;
2374*00b67f09SDavid van Moolenbroek 
2375*00b67f09SDavid van Moolenbroek 		case RR_PTR:
2376*00b67f09SDavid van Moolenbroek 			/* Handle "ptr" record */
2377*00b67f09SDavid van Moolenbroek 			add_domain(name, domain);
2378*00b67f09SDavid van Moolenbroek 			if (strcmp(cp, "@") == 0)
2379*00b67f09SDavid van Moolenbroek 				(void)strcpy(cp, zone);
2380*00b67f09SDavid van Moolenbroek 			if (checkdots(cp)) {
2381*00b67f09SDavid van Moolenbroek 				++errors;
2382*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2383*00b67f09SDavid van Moolenbroek 				    checkaddr(cp) ? addrfmt : dotfmt,
2384*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, rtype, cp);
2385*00b67f09SDavid van Moolenbroek 			}
2386*00b67f09SDavid van Moolenbroek 			add_domain(cp, domain);
2387*00b67f09SDavid van Moolenbroek 			p = parseptr(name, ap);
2388*00b67f09SDavid van Moolenbroek 			if (p != NULL) {
2389*00b67f09SDavid van Moolenbroek 				++errors;
2390*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2391*00b67f09SDavid van Moolenbroek 			"%s: %s/%s:%d Bad \"ptr\" record (%s) ip addr \"%s\"\n",
2392*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, p, name);
2393*00b67f09SDavid van Moolenbroek 				continue;
2394*00b67f09SDavid van Moolenbroek 			}
2395*00b67f09SDavid van Moolenbroek 			errors += updateitem(cp, ap, REC_PTR, 0, 0);
2396*00b67f09SDavid van Moolenbroek 			break;
2397*00b67f09SDavid van Moolenbroek 
2398*00b67f09SDavid van Moolenbroek 		case RR_SOA:
2399*00b67f09SDavid van Moolenbroek 			/* Handle "soa" record */
2400*00b67f09SDavid van Moolenbroek 			if (!CHECKDOT(name)) {
2401*00b67f09SDavid van Moolenbroek 				add_domain(name, domain);
2402*00b67f09SDavid van Moolenbroek 				errors += updateitem(name, NULL, REC_SOA, 0, 0);
2403*00b67f09SDavid van Moolenbroek 			}
2404*00b67f09SDavid van Moolenbroek 			errstr = NULL;
2405*00b67f09SDavid van Moolenbroek 			if (!parsesoa(cp, &errstr))
2406*00b67f09SDavid van Moolenbroek 				++sawsoa;
2407*00b67f09SDavid van Moolenbroek 			if (errstr != NULL) {
2408*00b67f09SDavid van Moolenbroek 				++errors;
2409*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2410*00b67f09SDavid van Moolenbroek 				    "%s: %s/%s:%d Bad \"soa\" record (%s)\n",
2411*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, errstr);
2412*00b67f09SDavid van Moolenbroek 				continue;
2413*00b67f09SDavid van Moolenbroek 			}
2414*00b67f09SDavid van Moolenbroek 			break;
2415*00b67f09SDavid van Moolenbroek 
2416*00b67f09SDavid van Moolenbroek 		case RR_WKS:
2417*00b67f09SDavid van Moolenbroek 			/* Handle "wks" record */
2418*00b67f09SDavid van Moolenbroek 			p = extractaddr(cp, ap);
2419*00b67f09SDavid van Moolenbroek 			if (p != NULL) {
2420*00b67f09SDavid van Moolenbroek 				++errors;
2421*00b67f09SDavid van Moolenbroek 				cp2 = cp;
2422*00b67f09SDavid van Moolenbroek 				while (!isspace(*cp2) && *cp2 != '\0')
2423*00b67f09SDavid van Moolenbroek 					++cp2;
2424*00b67f09SDavid van Moolenbroek 				*cp2 = '\0';
2425*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2426*00b67f09SDavid van Moolenbroek 			    "%s: %s/%s:%d Bad \"wks\" record ip addr \"%s\"\n",
2427*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, cp);
2428*00b67f09SDavid van Moolenbroek 				continue;
2429*00b67f09SDavid van Moolenbroek 			}
2430*00b67f09SDavid van Moolenbroek 			/* Step over ip address */
2431*00b67f09SDavid van Moolenbroek 			while (*cp == '.' || isdigit(*cp))
2432*00b67f09SDavid van Moolenbroek 				++cp;
2433*00b67f09SDavid van Moolenbroek 			while (isspace(*cp))
2434*00b67f09SDavid van Moolenbroek 				*cp++ = '\0';
2435*00b67f09SDavid van Moolenbroek 			/* Make sure services are legit */
2436*00b67f09SDavid van Moolenbroek 			errstr = NULL;
2437*00b67f09SDavid van Moolenbroek 			n += checkwks(f, cp, &smtp, &errstr);
2438*00b67f09SDavid van Moolenbroek 			if (errstr != NULL) {
2439*00b67f09SDavid van Moolenbroek 				++errors;
2440*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2441*00b67f09SDavid van Moolenbroek 				    "%s: %s/%s:%d Bad \"wks\" record (%s)\n",
2442*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, errstr);
2443*00b67f09SDavid van Moolenbroek 				continue;
2444*00b67f09SDavid van Moolenbroek 			}
2445*00b67f09SDavid van Moolenbroek 			add_domain(name, domain);
2446*00b67f09SDavid van Moolenbroek 			errors += updateitem(name, ap, REC_WKS,
2447*00b67f09SDavid van Moolenbroek 			    0, smtp ? FLG_SMTPWKS : 0);
2448*00b67f09SDavid van Moolenbroek 			/* XXX check to see if ip address records exists? */
2449*00b67f09SDavid van Moolenbroek 			break;
2450*00b67f09SDavid van Moolenbroek 
2451*00b67f09SDavid van Moolenbroek 		case RR_HINFO:
2452*00b67f09SDavid van Moolenbroek 			/* Handle "hinfo" record */
2453*00b67f09SDavid van Moolenbroek 			add_domain(name, domain);
2454*00b67f09SDavid van Moolenbroek 			errors += updateitem(name, NULL, REC_HINFO, 0, 0);
2455*00b67f09SDavid van Moolenbroek 			cp2 = cp;
2456*00b67f09SDavid van Moolenbroek 			cp = parsequoted(cp);
2457*00b67f09SDavid van Moolenbroek 			if (cp == NULL) {
2458*00b67f09SDavid van Moolenbroek 				++errors;
2459*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2460*00b67f09SDavid van Moolenbroek 			    "%s: %s/%s:%d \"hinfo\" missing quote: %s\n",
2461*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, cp2);
2462*00b67f09SDavid van Moolenbroek 				continue;
2463*00b67f09SDavid van Moolenbroek 			}
2464*00b67f09SDavid van Moolenbroek 			if (!isspace(*cp)) {
2465*00b67f09SDavid van Moolenbroek 				++errors;
2466*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2467*00b67f09SDavid van Moolenbroek 			    "%s: %s/%s:%d \"hinfo\" missing white space: %s\n",
2468*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, cp2);
2469*00b67f09SDavid van Moolenbroek 				continue;
2470*00b67f09SDavid van Moolenbroek 			}
2471*00b67f09SDavid van Moolenbroek 			++cp;
2472*00b67f09SDavid van Moolenbroek 			while (isspace(*cp))
2473*00b67f09SDavid van Moolenbroek 				++cp;
2474*00b67f09SDavid van Moolenbroek 			if (*cp == '\0') {
2475*00b67f09SDavid van Moolenbroek 				++errors;
2476*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2477*00b67f09SDavid van Moolenbroek 			    "%s: %s/%s:%d \"hinfo\" missing keyword: %s\n",
2478*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, cp2);
2479*00b67f09SDavid van Moolenbroek 				continue;
2480*00b67f09SDavid van Moolenbroek 			}
2481*00b67f09SDavid van Moolenbroek 			cp = parsequoted(cp);
2482*00b67f09SDavid van Moolenbroek 			if (cp == NULL) {
2483*00b67f09SDavid van Moolenbroek 				++errors;
2484*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2485*00b67f09SDavid van Moolenbroek 			    "%s: %s/%s:%d \"hinfo\" missing quote: %s\n",
2486*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, cp2);
2487*00b67f09SDavid van Moolenbroek 				continue;
2488*00b67f09SDavid van Moolenbroek 			}
2489*00b67f09SDavid van Moolenbroek 			if (*cp != '\0') {
2490*00b67f09SDavid van Moolenbroek 				++errors;
2491*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2492*00b67f09SDavid van Moolenbroek 			"%s: %s/%s:%d \"hinfo\" garbage after keywords: %s\n",
2493*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, cp2);
2494*00b67f09SDavid van Moolenbroek 				continue;
2495*00b67f09SDavid van Moolenbroek 			}
2496*00b67f09SDavid van Moolenbroek 			break;
2497*00b67f09SDavid van Moolenbroek 
2498*00b67f09SDavid van Moolenbroek 		case RR_MX:
2499*00b67f09SDavid van Moolenbroek 			/* Handle "mx" record */
2500*00b67f09SDavid van Moolenbroek 			add_domain(name, domain);
2501*00b67f09SDavid van Moolenbroek 			errors += updateitem(name, NULL, REC_MX, ttl, 0);
2502*00b67f09SDavid van Moolenbroek 
2503*00b67f09SDavid van Moolenbroek 			/* Look for priority */
2504*00b67f09SDavid van Moolenbroek 			if (!isdigit(*cp)) {
2505*00b67f09SDavid van Moolenbroek 				++errors;
2506*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2507*00b67f09SDavid van Moolenbroek 				    "%s: %s/%s:%d Bad \"mx\" priority: %s\n",
2508*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, cp);
2509*00b67f09SDavid van Moolenbroek 			}
2510*00b67f09SDavid van Moolenbroek 
2511*00b67f09SDavid van Moolenbroek 			/* Skip over priority */
2512*00b67f09SDavid van Moolenbroek 			++cp;
2513*00b67f09SDavid van Moolenbroek 			while (isdigit(*cp))
2514*00b67f09SDavid van Moolenbroek 				++cp;
2515*00b67f09SDavid van Moolenbroek 			while (isspace(*cp))
2516*00b67f09SDavid van Moolenbroek 				++cp;
2517*00b67f09SDavid van Moolenbroek 			if (*cp == '\0') {
2518*00b67f09SDavid van Moolenbroek 				++errors;
2519*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2520*00b67f09SDavid van Moolenbroek 				    "%s: %s/%s:%d Missing \"mx\" hostname\n",
2521*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n);
2522*00b67f09SDavid van Moolenbroek 			}
2523*00b67f09SDavid van Moolenbroek 			if (strcmp(cp, "@") == 0)
2524*00b67f09SDavid van Moolenbroek 				(void)strcpy(cp, zone);
2525*00b67f09SDavid van Moolenbroek 			if (checkdots(cp)) {
2526*00b67f09SDavid van Moolenbroek 				++errors;
2527*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2528*00b67f09SDavid van Moolenbroek 				    checkaddr(cp) ? addrfmt : dotfmt,
2529*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, rtype, cp);
2530*00b67f09SDavid van Moolenbroek 			}
2531*00b67f09SDavid van Moolenbroek 
2532*00b67f09SDavid van Moolenbroek 			/* Check to see if mx host exists */
2533*00b67f09SDavid van Moolenbroek 			add_domain(cp, domain);
2534*00b67f09SDavid van Moolenbroek 			flags = FLG_MXREF;
2535*00b67f09SDavid van Moolenbroek 			if (*name == *cp && strcmp(name, cp) == 0)
2536*00b67f09SDavid van Moolenbroek 				flags |= FLG_SELFMX;
2537*00b67f09SDavid van Moolenbroek 			errors += updateitem(cp, NULL, REC_REF, 0, flags);
2538*00b67f09SDavid van Moolenbroek 			break;
2539*00b67f09SDavid van Moolenbroek 
2540*00b67f09SDavid van Moolenbroek 		case RR_CNAME:
2541*00b67f09SDavid van Moolenbroek 			/* Handle "cname" record */
2542*00b67f09SDavid van Moolenbroek 			add_domain(name, domain);
2543*00b67f09SDavid van Moolenbroek 			errors += updateitem(name, NULL, REC_CNAME, 0, 0);
2544*00b67f09SDavid van Moolenbroek 			if (checkdots(cp)) {
2545*00b67f09SDavid van Moolenbroek 				++errors;
2546*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2547*00b67f09SDavid van Moolenbroek 				    checkaddr(cp) ? addrfmt : dotfmt,
2548*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, rtype, cp);
2549*00b67f09SDavid van Moolenbroek 			}
2550*00b67f09SDavid van Moolenbroek 
2551*00b67f09SDavid van Moolenbroek 			/* Make sure cname points somewhere */
2552*00b67f09SDavid van Moolenbroek 			if (strcmp(cp, "@") == 0)
2553*00b67f09SDavid van Moolenbroek 				(void)strcpy(cp, zone);
2554*00b67f09SDavid van Moolenbroek 			add_domain(cp, domain);
2555*00b67f09SDavid van Moolenbroek 			errors += updateitem(cp, NULL, REC_REF, 0, 0);
2556*00b67f09SDavid van Moolenbroek 			break;
2557*00b67f09SDavid van Moolenbroek 
2558*00b67f09SDavid van Moolenbroek 		case RR_SRV:
2559*00b67f09SDavid van Moolenbroek 			/* Handle "srv" record */
2560*00b67f09SDavid van Moolenbroek 			add_domain(name, domain);
2561*00b67f09SDavid van Moolenbroek 			errors += updateitem(name, NULL, REC_SRV, 0, 0);
2562*00b67f09SDavid van Moolenbroek 			cp2 = cp;
2563*00b67f09SDavid van Moolenbroek 
2564*00b67f09SDavid van Moolenbroek 			/* Skip over three values */
2565*00b67f09SDavid van Moolenbroek 			for (i = 0; i < 3; ++i) {
2566*00b67f09SDavid van Moolenbroek 				if (!isdigit(*cp)) {
2567*00b67f09SDavid van Moolenbroek 					++errors;
2568*00b67f09SDavid van Moolenbroek 					fprintf(stderr, "%s: %s/%s:%d"
2569*00b67f09SDavid van Moolenbroek 					    " Bad \"srv\" value: %s\n",
2570*00b67f09SDavid van Moolenbroek 					    prog, cwd, file, n, cp);
2571*00b67f09SDavid van Moolenbroek 				}
2572*00b67f09SDavid van Moolenbroek 
2573*00b67f09SDavid van Moolenbroek 				/* Skip over value */
2574*00b67f09SDavid van Moolenbroek 				++cp;
2575*00b67f09SDavid van Moolenbroek 				while (isdigit(*cp))
2576*00b67f09SDavid van Moolenbroek 					++cp;
2577*00b67f09SDavid van Moolenbroek 				while (isspace(*cp))
2578*00b67f09SDavid van Moolenbroek 					++cp;
2579*00b67f09SDavid van Moolenbroek 			}
2580*00b67f09SDavid van Moolenbroek 
2581*00b67f09SDavid van Moolenbroek 			/* Check to see if mx host exists */
2582*00b67f09SDavid van Moolenbroek 			add_domain(cp, domain);
2583*00b67f09SDavid van Moolenbroek 			errors += updateitem(cp, NULL, REC_REF, 0, 0);
2584*00b67f09SDavid van Moolenbroek 			break;
2585*00b67f09SDavid van Moolenbroek 
2586*00b67f09SDavid van Moolenbroek 		case RR_TXT:
2587*00b67f09SDavid van Moolenbroek 			/* Handle "txt" record */
2588*00b67f09SDavid van Moolenbroek 			add_domain(name, domain);
2589*00b67f09SDavid van Moolenbroek 			errors += updateitem(name, NULL, REC_TXT, 0, 0);
2590*00b67f09SDavid van Moolenbroek 			cp2 = cp;
2591*00b67f09SDavid van Moolenbroek 			cp = parsequoted(cp);
2592*00b67f09SDavid van Moolenbroek 			if (cp == NULL) {
2593*00b67f09SDavid van Moolenbroek 				++errors;
2594*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2595*00b67f09SDavid van Moolenbroek 				    "%s: %s/%s:%d \"txt\" missing quote: %s\n",
2596*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, cp2);
2597*00b67f09SDavid van Moolenbroek 				continue;
2598*00b67f09SDavid van Moolenbroek 			}
2599*00b67f09SDavid van Moolenbroek 			while (isspace(*cp))
2600*00b67f09SDavid van Moolenbroek 				++cp;
2601*00b67f09SDavid van Moolenbroek 			if (*cp != '\0') {
2602*00b67f09SDavid van Moolenbroek 				++errors;
2603*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2604*00b67f09SDavid van Moolenbroek 			    "%s: %s/%s:%d \"txt\" garbage after text: %s\n",
2605*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, cp2);
2606*00b67f09SDavid van Moolenbroek 				continue;
2607*00b67f09SDavid van Moolenbroek 			}
2608*00b67f09SDavid van Moolenbroek 			break;
2609*00b67f09SDavid van Moolenbroek 
2610*00b67f09SDavid van Moolenbroek 		case RR_NS:
2611*00b67f09SDavid van Moolenbroek 			/* Handle "ns" record */
2612*00b67f09SDavid van Moolenbroek 			errors += updateitem(zone, NULL, REC_NS, 0, 0);
2613*00b67f09SDavid van Moolenbroek 			if (strcmp(cp, "@") == 0)
2614*00b67f09SDavid van Moolenbroek 				(void)strcpy(cp, zone);
2615*00b67f09SDavid van Moolenbroek 			if (checkdots(cp)) {
2616*00b67f09SDavid van Moolenbroek 				++errors;
2617*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2618*00b67f09SDavid van Moolenbroek 				    checkaddr(cp) ? addrfmt : dotfmt,
2619*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, rtype, cp);
2620*00b67f09SDavid van Moolenbroek 			}
2621*00b67f09SDavid van Moolenbroek 			add_domain(cp, domain);
2622*00b67f09SDavid van Moolenbroek 			errors += updateitem(cp, NULL, REC_REF, 0, 0);
2623*00b67f09SDavid van Moolenbroek 			break;
2624*00b67f09SDavid van Moolenbroek 
2625*00b67f09SDavid van Moolenbroek 		case RR_RP:
2626*00b67f09SDavid van Moolenbroek 			/* Handle "rp" record */
2627*00b67f09SDavid van Moolenbroek 			add_domain(name, domain);
2628*00b67f09SDavid van Moolenbroek 			errors += updateitem(name, NULL, REC_RP, 0, 0);
2629*00b67f09SDavid van Moolenbroek 			cp2 = cp;
2630*00b67f09SDavid van Moolenbroek 
2631*00b67f09SDavid van Moolenbroek 			/* Step over mailbox name */
2632*00b67f09SDavid van Moolenbroek 			/* XXX could add_domain() and check further */
2633*00b67f09SDavid van Moolenbroek 			while (!isspace(*cp) && *cp != '\0')
2634*00b67f09SDavid van Moolenbroek 				++cp;
2635*00b67f09SDavid van Moolenbroek 			if (*cp == '\0') {
2636*00b67f09SDavid van Moolenbroek 				++errors;
2637*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2638*00b67f09SDavid van Moolenbroek 			    "%s: %s/%s:%d \"rp\" missing text name: %s\n",
2639*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, cp2);
2640*00b67f09SDavid van Moolenbroek 				continue;
2641*00b67f09SDavid van Moolenbroek 			}
2642*00b67f09SDavid van Moolenbroek 			++cp;
2643*00b67f09SDavid van Moolenbroek 			cp3 = cp;
2644*00b67f09SDavid van Moolenbroek 
2645*00b67f09SDavid van Moolenbroek 			/* Step over text name */
2646*00b67f09SDavid van Moolenbroek 			while (!isspace(*cp) && *cp != '\0')
2647*00b67f09SDavid van Moolenbroek 				++cp;
2648*00b67f09SDavid van Moolenbroek 
2649*00b67f09SDavid van Moolenbroek 			if (*cp != '\0') {
2650*00b67f09SDavid van Moolenbroek 				++errors;
2651*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2652*00b67f09SDavid van Moolenbroek 			    "%s: %s/%s:%d \"rp\" garbage after text name: %s\n",
2653*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, cp2);
2654*00b67f09SDavid van Moolenbroek 				continue;
2655*00b67f09SDavid van Moolenbroek 			}
2656*00b67f09SDavid van Moolenbroek 
2657*00b67f09SDavid van Moolenbroek 			/* Make sure text name points somewhere (if not ".") */
2658*00b67f09SDavid van Moolenbroek 			if (!CHECKDOT(cp3)) {
2659*00b67f09SDavid van Moolenbroek 				add_domain(cp3, domain);
2660*00b67f09SDavid van Moolenbroek 				errors += updateitem(cp3, NULL, REC_REF, 0, 0);
2661*00b67f09SDavid van Moolenbroek 			}
2662*00b67f09SDavid van Moolenbroek 			break;
2663*00b67f09SDavid van Moolenbroek 
2664*00b67f09SDavid van Moolenbroek 		case RR_ALLOWDUPA:
2665*00b67f09SDavid van Moolenbroek 			/* Handle "allow duplicate a" record */
2666*00b67f09SDavid van Moolenbroek 			add_domain(name, domain);
2667*00b67f09SDavid van Moolenbroek 			p = extractaddr(cp, ap);
2668*00b67f09SDavid van Moolenbroek 			if (p != NULL) {
2669*00b67f09SDavid van Moolenbroek 				++errors;
2670*00b67f09SDavid van Moolenbroek 				cp2 = cp + strlen(cp) - 1;
2671*00b67f09SDavid van Moolenbroek 				if (cp2 >= cp && *cp2 == '\n')
2672*00b67f09SDavid van Moolenbroek 					*cp2 = '\0';
2673*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2674*00b67f09SDavid van Moolenbroek 		    "%s: %s/%s:%d Bad \"allowdupa\" record ip addr \"%s\"\n",
2675*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, cp);
2676*00b67f09SDavid van Moolenbroek 				continue;
2677*00b67f09SDavid van Moolenbroek 			}
2678*00b67f09SDavid van Moolenbroek 			errors += updateitem(name, ap, 0, 0, FLG_ALLOWDUPA);
2679*00b67f09SDavid van Moolenbroek 			break;
2680*00b67f09SDavid van Moolenbroek 
2681*00b67f09SDavid van Moolenbroek 		case RR_DNSKEY:
2682*00b67f09SDavid van Moolenbroek 			/* Handle "dnskey" record */
2683*00b67f09SDavid van Moolenbroek 			add_domain(name, domain);
2684*00b67f09SDavid van Moolenbroek 			errors += updateitem(name, NULL, REC_CNAME, 0, 0);
2685*00b67f09SDavid van Moolenbroek 			if (checkdots(cp)) {
2686*00b67f09SDavid van Moolenbroek 				++errors;
2687*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2688*00b67f09SDavid van Moolenbroek 				    checkaddr(cp) ? addrfmt : dotfmt,
2689*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, rtype, cp);
2690*00b67f09SDavid van Moolenbroek 			}
2691*00b67f09SDavid van Moolenbroek 
2692*00b67f09SDavid van Moolenbroek 			/* Make sure cname points somewhere */
2693*00b67f09SDavid van Moolenbroek 			if (strcmp(cp, "@") == 0)
2694*00b67f09SDavid van Moolenbroek 				(void)strcpy(cp, zone);
2695*00b67f09SDavid van Moolenbroek 			add_domain(cp, domain);
2696*00b67f09SDavid van Moolenbroek 			errors += updateitem(cp, NULL, REC_REF, 0, 0);
2697*00b67f09SDavid van Moolenbroek 			break;
2698*00b67f09SDavid van Moolenbroek 
2699*00b67f09SDavid van Moolenbroek 		case RR_RRSIG:
2700*00b67f09SDavid van Moolenbroek 			errstr = NULL;
2701*00b67f09SDavid van Moolenbroek 			if (!parserrsig(cp, &errstr))
2702*00b67f09SDavid van Moolenbroek 				++sawrrsig;
2703*00b67f09SDavid van Moolenbroek 			if (errstr != NULL) {
2704*00b67f09SDavid van Moolenbroek 				++errors;
2705*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2706*00b67f09SDavid van Moolenbroek 				    "%s: %s/%s:%d Bad \"rrsig\" record (%s)\n",
2707*00b67f09SDavid van Moolenbroek 				    prog, cwd, file, n, errstr);
2708*00b67f09SDavid van Moolenbroek 				continue;
2709*00b67f09SDavid van Moolenbroek 			}
2710*00b67f09SDavid van Moolenbroek 			break;
2711*00b67f09SDavid van Moolenbroek 
2712*00b67f09SDavid van Moolenbroek 		case RR_NSEC:
2713*00b67f09SDavid van Moolenbroek 			/* XXX */
2714*00b67f09SDavid van Moolenbroek 			continue;
2715*00b67f09SDavid van Moolenbroek 
2716*00b67f09SDavid van Moolenbroek 		default:
2717*00b67f09SDavid van Moolenbroek 			/* Unknown record type */
2718*00b67f09SDavid van Moolenbroek 			++errors;
2719*00b67f09SDavid van Moolenbroek 			fprintf(stderr,
2720*00b67f09SDavid van Moolenbroek 			    "%s: %s/%s:%d Unknown record type \"%s\"\n",
2721*00b67f09SDavid van Moolenbroek 			    prog, cwd, file, n, rtype);
2722*00b67f09SDavid van Moolenbroek 			add_domain(name, domain);
2723*00b67f09SDavid van Moolenbroek 			errors += updateitem(name, NULL, REC_UNKNOWN, 0, 0);
2724*00b67f09SDavid van Moolenbroek 			break;
2725*00b67f09SDavid van Moolenbroek 		}
2726*00b67f09SDavid van Moolenbroek 		(void)strcpy(lastname, name);
2727*00b67f09SDavid van Moolenbroek 	}
2728*00b67f09SDavid van Moolenbroek 	(void)fclose(f);
2729*00b67f09SDavid van Moolenbroek 	return;
2730*00b67f09SDavid van Moolenbroek }
2731*00b67f09SDavid van Moolenbroek 
2732*00b67f09SDavid van Moolenbroek static const char *microlist[] = {
2733*00b67f09SDavid van Moolenbroek 	"_tcp",
2734*00b67f09SDavid van Moolenbroek 	"_udp",
2735*00b67f09SDavid van Moolenbroek 	"_msdcs",
2736*00b67f09SDavid van Moolenbroek 	"_sites",
2737*00b67f09SDavid van Moolenbroek 	NULL
2738*00b67f09SDavid van Moolenbroek };
2739*00b67f09SDavid van Moolenbroek 
2740*00b67f09SDavid van Moolenbroek int
rfc1034host(const char * host,int recs)2741*00b67f09SDavid van Moolenbroek rfc1034host(const char *host, int recs)
2742*00b67f09SDavid van Moolenbroek {
2743*00b67f09SDavid van Moolenbroek 	const char *cp, **p;
2744*00b67f09SDavid van Moolenbroek 	int underok;
2745*00b67f09SDavid van Moolenbroek 
2746*00b67f09SDavid van Moolenbroek 	underok = 0;
2747*00b67f09SDavid van Moolenbroek 	for (p = microlist; *p != NULL ;++p)
2748*00b67f09SDavid van Moolenbroek 		if ((cp = strstr(host, *p)) != NULL &&
2749*00b67f09SDavid van Moolenbroek 		    cp > host &&
2750*00b67f09SDavid van Moolenbroek 		    cp[-1] == '.' &&
2751*00b67f09SDavid van Moolenbroek 		    cp[strlen(*p)] == '.') {
2752*00b67f09SDavid van Moolenbroek 			++underok;
2753*00b67f09SDavid van Moolenbroek 			break;
2754*00b67f09SDavid van Moolenbroek 		}
2755*00b67f09SDavid van Moolenbroek 
2756*00b67f09SDavid van Moolenbroek 	cp = host;
2757*00b67f09SDavid van Moolenbroek 	if (!(isalpha(*cp) || isdigit(*cp) || (*cp == '_' && underok))) {
2758*00b67f09SDavid van Moolenbroek 		fprintf(stderr,
2759*00b67f09SDavid van Moolenbroek 	    "%s: illegal hostname \"%s\" (starts with non-alpha/numeric)\n",
2760*00b67f09SDavid van Moolenbroek 		    prog, host);
2761*00b67f09SDavid van Moolenbroek 		return (1);
2762*00b67f09SDavid van Moolenbroek 	}
2763*00b67f09SDavid van Moolenbroek 	for (++cp; *cp != '.' && *cp != '\0'; ++cp)
2764*00b67f09SDavid van Moolenbroek 		if (!(isalpha(*cp) || isdigit(*cp) || *cp == '-' ||
2765*00b67f09SDavid van Moolenbroek 		    (*cp == '/' && (recs & REC_SOA) != 0))) {
2766*00b67f09SDavid van Moolenbroek 			fprintf(stderr,
2767*00b67f09SDavid van Moolenbroek 		    "%s: Illegal hostname \"%s\" ('%c' illegal character)\n",
2768*00b67f09SDavid van Moolenbroek 			    prog, host, *cp);
2769*00b67f09SDavid van Moolenbroek 			return (1);
2770*00b67f09SDavid van Moolenbroek 		}
2771*00b67f09SDavid van Moolenbroek 	if (--cp >= host && *cp == '-') {
2772*00b67f09SDavid van Moolenbroek 		fprintf(stderr, "%s: Illegal hostname \"%s\" (ends with '-')\n",
2773*00b67f09SDavid van Moolenbroek 		    prog, host);
2774*00b67f09SDavid van Moolenbroek 		return (1);
2775*00b67f09SDavid van Moolenbroek 	}
2776*00b67f09SDavid van Moolenbroek 	return (0);
2777*00b67f09SDavid van Moolenbroek }
2778*00b67f09SDavid van Moolenbroek 
2779*00b67f09SDavid van Moolenbroek enum rrtype
txt2rrtype(const char * str)2780*00b67f09SDavid van Moolenbroek txt2rrtype(const char *str)
2781*00b67f09SDavid van Moolenbroek {
2782*00b67f09SDavid van Moolenbroek 	if (strcasecmp(str, "aaaa") == 0)
2783*00b67f09SDavid van Moolenbroek 		return (RR_AAAA);
2784*00b67f09SDavid van Moolenbroek 	if (strcasecmp(str, "a") == 0)
2785*00b67f09SDavid van Moolenbroek 		return (RR_A);
2786*00b67f09SDavid van Moolenbroek 	if (strcasecmp(str, "allowdupa") == 0)
2787*00b67f09SDavid van Moolenbroek 		return (RR_ALLOWDUPA);
2788*00b67f09SDavid van Moolenbroek 	if (strcasecmp(str, "cname") == 0)
2789*00b67f09SDavid van Moolenbroek 		return (RR_CNAME);
2790*00b67f09SDavid van Moolenbroek 	if (strcasecmp(str, "dnskey") == 0)
2791*00b67f09SDavid van Moolenbroek 		return (RR_DNSKEY);
2792*00b67f09SDavid van Moolenbroek 	if (strcasecmp(str, "hinfo") == 0)
2793*00b67f09SDavid van Moolenbroek 		return (RR_HINFO);
2794*00b67f09SDavid van Moolenbroek 	if (strcasecmp(str, "mx") == 0)
2795*00b67f09SDavid van Moolenbroek 		return (RR_MX);
2796*00b67f09SDavid van Moolenbroek 	if (strcasecmp(str, "ns") == 0)
2797*00b67f09SDavid van Moolenbroek 		return (RR_NS);
2798*00b67f09SDavid van Moolenbroek 	if (strcasecmp(str, "ptr") == 0)
2799*00b67f09SDavid van Moolenbroek 		return (RR_PTR);
2800*00b67f09SDavid van Moolenbroek 	if (strcasecmp(str, "rp") == 0)
2801*00b67f09SDavid van Moolenbroek 		return (RR_RP);
2802*00b67f09SDavid van Moolenbroek 	if (strcasecmp(str, "soa") == 0)
2803*00b67f09SDavid van Moolenbroek 		return (RR_SOA);
2804*00b67f09SDavid van Moolenbroek 	if (strcasecmp(str, "srv") == 0)
2805*00b67f09SDavid van Moolenbroek 		return (RR_SRV);
2806*00b67f09SDavid van Moolenbroek 	if (strcasecmp(str, "txt") == 0)
2807*00b67f09SDavid van Moolenbroek 		return (RR_TXT);
2808*00b67f09SDavid van Moolenbroek 	if (strcasecmp(str, "wks") == 0)
2809*00b67f09SDavid van Moolenbroek 		return (RR_WKS);
2810*00b67f09SDavid van Moolenbroek 	if (strcasecmp(str, "RRSIG") == 0)
2811*00b67f09SDavid van Moolenbroek 		return (RR_RRSIG);
2812*00b67f09SDavid van Moolenbroek 	if (strcasecmp(str, "NSEC") == 0)
2813*00b67f09SDavid van Moolenbroek 		return (RR_NSEC);
2814*00b67f09SDavid van Moolenbroek 	return (RR_UNDEF);
2815*00b67f09SDavid van Moolenbroek }
2816*00b67f09SDavid van Moolenbroek 
2817*00b67f09SDavid van Moolenbroek int
samesubnet(struct addr * a1,struct addr * a2,struct network * np)2818*00b67f09SDavid van Moolenbroek samesubnet(struct addr *a1, struct addr *a2, struct network *np)
2819*00b67f09SDavid van Moolenbroek {
2820*00b67f09SDavid van Moolenbroek 	int i;
2821*00b67f09SDavid van Moolenbroek 	u_int32_t v1, v2;
2822*00b67f09SDavid van Moolenbroek 
2823*00b67f09SDavid van Moolenbroek 	/* IPv4 before IPv6 */
2824*00b67f09SDavid van Moolenbroek 	if (a1->family != a2->family)
2825*00b67f09SDavid van Moolenbroek 		return (0);
2826*00b67f09SDavid van Moolenbroek 
2827*00b67f09SDavid van Moolenbroek 	switch (a1->family) {
2828*00b67f09SDavid van Moolenbroek 
2829*00b67f09SDavid van Moolenbroek 	case AF_INET:
2830*00b67f09SDavid van Moolenbroek 		/* Apply the mask to both values */
2831*00b67f09SDavid van Moolenbroek 		v1 = a1->a_addr4 & np->n_mask4;
2832*00b67f09SDavid van Moolenbroek 		v2 = a2->a_addr4 & np->n_mask4;
2833*00b67f09SDavid van Moolenbroek 		return (v1 == v2);
2834*00b67f09SDavid van Moolenbroek 
2835*00b67f09SDavid van Moolenbroek 	case AF_INET6:
2836*00b67f09SDavid van Moolenbroek 		/* Apply the mask to both values */
2837*00b67f09SDavid van Moolenbroek 		for (i = 0; i < 16; ++i) {
2838*00b67f09SDavid van Moolenbroek 			v1 = a1->a_addr6[i] & np->n_mask6[i];
2839*00b67f09SDavid van Moolenbroek 			v2 = a2->a_addr6[i] & np->n_mask6[i];
2840*00b67f09SDavid van Moolenbroek 			if (v1 != v2)
2841*00b67f09SDavid van Moolenbroek 				return (0);
2842*00b67f09SDavid van Moolenbroek 		}
2843*00b67f09SDavid van Moolenbroek 		break;
2844*00b67f09SDavid van Moolenbroek 
2845*00b67f09SDavid van Moolenbroek 	default:
2846*00b67f09SDavid van Moolenbroek 		abort();
2847*00b67f09SDavid van Moolenbroek 	}
2848*00b67f09SDavid van Moolenbroek 	return (1);
2849*00b67f09SDavid van Moolenbroek }
2850*00b67f09SDavid van Moolenbroek 
2851*00b67f09SDavid van Moolenbroek /* Set address mask in network order */
2852*00b67f09SDavid van Moolenbroek void
setmaskwidth(u_int w,struct network * np)2853*00b67f09SDavid van Moolenbroek setmaskwidth(u_int w, struct network *np)
2854*00b67f09SDavid van Moolenbroek {
2855*00b67f09SDavid van Moolenbroek 	int i, j;
2856*00b67f09SDavid van Moolenbroek 
2857*00b67f09SDavid van Moolenbroek 	switch (np->family) {
2858*00b67f09SDavid van Moolenbroek 
2859*00b67f09SDavid van Moolenbroek 	case AF_INET:
2860*00b67f09SDavid van Moolenbroek 		if (w <= 0)
2861*00b67f09SDavid van Moolenbroek 			np->n_mask4 = 0;
2862*00b67f09SDavid van Moolenbroek 		else
2863*00b67f09SDavid van Moolenbroek 			np->n_mask4 = htonl(0xffffffff << (32 - w));
2864*00b67f09SDavid van Moolenbroek 		break;
2865*00b67f09SDavid van Moolenbroek 
2866*00b67f09SDavid van Moolenbroek 	case AF_INET6:
2867*00b67f09SDavid van Moolenbroek 		/* XXX is this right? */
2868*00b67f09SDavid van Moolenbroek 		memset(np->n_mask6, 0, sizeof(np->n_mask6));
2869*00b67f09SDavid van Moolenbroek 		for (i = 0; i < w / 8; ++i)
2870*00b67f09SDavid van Moolenbroek 			np->n_mask6[i] = 0xff;
2871*00b67f09SDavid van Moolenbroek 		i = w / 8;
2872*00b67f09SDavid van Moolenbroek 		j = w % 8;
2873*00b67f09SDavid van Moolenbroek 		if (j > 0 && i < 16)
2874*00b67f09SDavid van Moolenbroek 			np->n_mask6[i] = 0xff << (8 - j);
2875*00b67f09SDavid van Moolenbroek 		break;
2876*00b67f09SDavid van Moolenbroek 
2877*00b67f09SDavid van Moolenbroek 	default:
2878*00b67f09SDavid van Moolenbroek 		abort();
2879*00b67f09SDavid van Moolenbroek 	}
2880*00b67f09SDavid van Moolenbroek }
2881*00b67f09SDavid van Moolenbroek 
2882*00b67f09SDavid van Moolenbroek int
updateitem(const char * host,struct addr * ap,int records,u_int ttl,int flags)2883*00b67f09SDavid van Moolenbroek updateitem(const char *host, struct addr *ap, int records, u_int ttl, int flags)
2884*00b67f09SDavid van Moolenbroek {
2885*00b67f09SDavid van Moolenbroek 	const char *ccp;
2886*00b67f09SDavid van Moolenbroek 	int n, errs;
2887*00b67f09SDavid van Moolenbroek 	u_int i;
2888*00b67f09SDavid van Moolenbroek 	struct item *ip;
2889*00b67f09SDavid van Moolenbroek 	int foundsome;
2890*00b67f09SDavid van Moolenbroek 
2891*00b67f09SDavid van Moolenbroek 	n = 0;
2892*00b67f09SDavid van Moolenbroek 	foundsome = 0;
2893*00b67f09SDavid van Moolenbroek 	errs = 0;
2894*00b67f09SDavid van Moolenbroek 
2895*00b67f09SDavid van Moolenbroek 	/* Hash the host name */
2896*00b67f09SDavid van Moolenbroek 	i = 0;
2897*00b67f09SDavid van Moolenbroek 	ccp = host;
2898*00b67f09SDavid van Moolenbroek 	while (*ccp != '\0')
2899*00b67f09SDavid van Moolenbroek 		i = i * 37 + *ccp++;
2900*00b67f09SDavid van Moolenbroek 	ip = &items[i & (ITEMSIZE - 1)];
2901*00b67f09SDavid van Moolenbroek 
2902*00b67f09SDavid van Moolenbroek 	/* Look for a match or any empty slot */
2903*00b67f09SDavid van Moolenbroek 	while (n < ITEMSIZE && ip->host != NULL) {
2904*00b67f09SDavid van Moolenbroek 
2905*00b67f09SDavid van Moolenbroek 		if ((ap == NULL || ip->addr.family == 0 ||
2906*00b67f09SDavid van Moolenbroek 		    cmpaddr(ap, &ip->addr) == 0) &&
2907*00b67f09SDavid van Moolenbroek 		    *host == *ip->host && strcmp(host, ip->host) == 0) {
2908*00b67f09SDavid van Moolenbroek 			++foundsome;
2909*00b67f09SDavid van Moolenbroek 			if (ip->addr.family == 0 && ap != NULL)
2910*00b67f09SDavid van Moolenbroek 				memmove(&ip->addr, ap, sizeof(*ap));
2911*00b67f09SDavid van Moolenbroek 			if ((records & MASK_TEST_DUP) != 0)
2912*00b67f09SDavid van Moolenbroek 				checkdups(ip, records);
2913*00b67f09SDavid van Moolenbroek 			ip->records |= records;
2914*00b67f09SDavid van Moolenbroek 			/* Only check differing ttl's for A and MX records */
2915*00b67f09SDavid van Moolenbroek 			if (ip->ttl == 0)
2916*00b67f09SDavid van Moolenbroek 				ip->ttl = ttl;
2917*00b67f09SDavid van Moolenbroek 			else if (ttl != 0 && ip->ttl != ttl) {
2918*00b67f09SDavid van Moolenbroek 				fprintf(stderr,
2919*00b67f09SDavid van Moolenbroek 				    "%s: Differing ttls for %s (%u != %u)\n",
2920*00b67f09SDavid van Moolenbroek 				    prog, ip->host, ttl, ip->ttl);
2921*00b67f09SDavid van Moolenbroek 				++errs;
2922*00b67f09SDavid van Moolenbroek 			}
2923*00b67f09SDavid van Moolenbroek 			ip->flags |= flags;
2924*00b67f09SDavid van Moolenbroek 			/* Not done if we wildcard matched the name */
2925*00b67f09SDavid van Moolenbroek 			if (ap != NULL)
2926*00b67f09SDavid van Moolenbroek 				return (errs);
2927*00b67f09SDavid van Moolenbroek 		}
2928*00b67f09SDavid van Moolenbroek 		++n;
2929*00b67f09SDavid van Moolenbroek 		++ip;
2930*00b67f09SDavid van Moolenbroek 		if (ip >= &items[ITEMSIZE])
2931*00b67f09SDavid van Moolenbroek 			ip = items;
2932*00b67f09SDavid van Moolenbroek 	}
2933*00b67f09SDavid van Moolenbroek 
2934*00b67f09SDavid van Moolenbroek 	if (n >= ITEMSIZE) {
2935*00b67f09SDavid van Moolenbroek 		fprintf(stderr, "%s: Out of item slots (max %d)\n",
2936*00b67f09SDavid van Moolenbroek 		    prog, ITEMSIZE);
2937*00b67f09SDavid van Moolenbroek 		exit(1);
2938*00b67f09SDavid van Moolenbroek 	}
2939*00b67f09SDavid van Moolenbroek 
2940*00b67f09SDavid van Moolenbroek 	/* Done if we were wildcarding the name (and found entries for it) */
2941*00b67f09SDavid van Moolenbroek 	if (ap == NULL && foundsome) {
2942*00b67f09SDavid van Moolenbroek 		return (errs);
2943*00b67f09SDavid van Moolenbroek 	}
2944*00b67f09SDavid van Moolenbroek 
2945*00b67f09SDavid van Moolenbroek 	/* Didn't find it, make new entry */
2946*00b67f09SDavid van Moolenbroek 	++itemcnt;
2947*00b67f09SDavid van Moolenbroek 	if (ip->host) {
2948*00b67f09SDavid van Moolenbroek 		fprintf(stderr, "%s: Reusing bucket!\n", prog);
2949*00b67f09SDavid van Moolenbroek 		exit(1);
2950*00b67f09SDavid van Moolenbroek 	}
2951*00b67f09SDavid van Moolenbroek 	if (ap != NULL)
2952*00b67f09SDavid van Moolenbroek 		memmove(&ip->addr, ap, sizeof(*ap));
2953*00b67f09SDavid van Moolenbroek 	ip->host = savestr(host);
2954*00b67f09SDavid van Moolenbroek 	if ((records & MASK_TEST_DUP) != 0)
2955*00b67f09SDavid van Moolenbroek 		checkdups(ip, records);
2956*00b67f09SDavid van Moolenbroek 	ip->records |= records;
2957*00b67f09SDavid van Moolenbroek 	if (ttl != 0)
2958*00b67f09SDavid van Moolenbroek 		ip->ttl = ttl;
2959*00b67f09SDavid van Moolenbroek 	ip->flags |= flags;
2960*00b67f09SDavid van Moolenbroek 	return (errs);
2961*00b67f09SDavid van Moolenbroek }
2962*00b67f09SDavid van Moolenbroek 
2963*00b67f09SDavid van Moolenbroek void
usage(void)2964*00b67f09SDavid van Moolenbroek usage(void)
2965*00b67f09SDavid van Moolenbroek {
2966*00b67f09SDavid van Moolenbroek 
2967*00b67f09SDavid van Moolenbroek 	fprintf(stderr, "Version %s\n", version);
2968*00b67f09SDavid van Moolenbroek 	fprintf(stderr, "usage: %s [-d] [-b named.boot] [-B nslint.boot]\n",
2969*00b67f09SDavid van Moolenbroek 	    prog);
2970*00b67f09SDavid van Moolenbroek 	fprintf(stderr, "       %s [-d] [-c named.conf] [-C nslint.conf]\n",
2971*00b67f09SDavid van Moolenbroek 	    prog);
2972*00b67f09SDavid van Moolenbroek 	exit(1);
2973*00b67f09SDavid van Moolenbroek }
2974