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