📄 nslint.c
字号:
/* * Copyright (c) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials * provided with the distribution, and (3) all advertising materials mentioning * features or use of this software display the following acknowledgement: * ``This product includes software developed by the University of California, * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of * the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */#ifndef lintstatic const char copyright[] = "@(#) Copyright (c) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001\n\The Regents of the University of California. All rights reserved.\n";static const char rcsid[] = "@(#) $Id: nslint.c,v 1.1 2001/12/21 04:12:04 marka Exp $ (LBL)";#endif/* * nslint - perform consistency checks on dns files */#include <sys/types.h>#include <sys/stat.h>#include <netinet/in.h>#include <arpa/inet.h>#include <ctype.h>#include <errno.h>#ifdef HAVE_FCNTL_H#include <fcntl.h>#endif#ifdef HAVE_MALLOC_H#include <malloc.h>#endif#ifdef HAVE_MEMORY_H#include <memory.h>#endif#include <netdb.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <unistd.h>#include "savestr.h"#include "gnuc.h"#ifdef HAVE_OS_PROTO_H#include "os-proto.h"#endif#define NSLINTBOOT "nslint.boot" /* default nslint.boot file */#define NSLINTCONF "nslint.conf" /* default nslint.conf file *//* item struct */struct item { char *host; /* pointer to hostname */ u_int32_t addr; /* ip address */ u_int ttl; /* ttl of A records */ int records; /* resource records seen */ int flags; /* flags word */};/* Resource records seen */#define REC_A 0x0001#define REC_PTR 0x0002#define REC_WKS 0x0004#define REC_HINFO 0x0008#define REC_MX 0x0010#define REC_CNAME 0x0020#define REC_NS 0x0040#define REC_SOA 0x0080#define REC_RP 0x0100#define REC_TXT 0x0200#define REC_SRV 0x0400/* These aren't real records */#define REC_OTHER 0x0800#define REC_REF 0x1000#define REC_UNKNOWN 0x2000/* Test for records we want to map to REC_OTHER */#define MASK_TEST_REC (REC_WKS | REC_HINFO | \ REC_MX | REC_SOA | REC_RP | REC_TXT | REC_SRV | REC_UNKNOWN)/* Mask away records we don't care about in the final processing to REC_OTHER */#define MASK_CHECK_REC \ (REC_A | REC_PTR | REC_CNAME | REC_REF | REC_OTHER)/* Test for records we want to check for duplicate name detection */#define MASK_TEST_DUP \ (REC_A | REC_HINFO)/* Flags */#define FLG_SELFMX 0x001 /* mx record refers to self */#define FLG_MXREF 0x002 /* this record referred to by a mx record */#define FLG_SMTPWKS 0x004 /* saw wks with smtp/tcp */#define FLG_ALLOWDUPA 0x008 /* allow duplicate a records *//* Test for smtp problems */#define MASK_TEST_SMTP \ (FLG_SELFMX | FLG_SMTPWKS)#define ITEMSIZE (1 << 17) /* power of two */#define ITEMHASH(str, h, p) \ for (p = str, h = 0; *p != '.' && *p != '\0';) h = (h << 5) - h + *p++struct item items[ITEMSIZE];int itemcnt; /* count of items *//* Hostname string storage */#define STRSIZE 8192; /* size to malloc when more space is needed */char *strptr; /* pointer to string pool */int strsize; /* size of space left in pool */int debug;int errors;char *bootfile = "/etc/named.boot";char *conffile = "/etc/named.conf";char *nslintboot;char *nslintconf;char *prog;char *cwd = ".";char **protoserv; /* valid protocol/service names */int protoserv_init;int protoserv_last;int protoserv_len;static char inaddr[] = ".in-addr.arpa.";/* SOA record */#define SOA_SERIAL 0#define SOA_REFRESH 1#define SOA_RETRY 2#define SOA_EXPIRE 3#define SOA_MINIMUM 4static u_int soaval[5];static int nsoaval;#define NSOAVAL (sizeof(soaval) / sizeof(soaval[0]))/* Forwards */static inline void add_domain(char *, const char *);int checkdots(const char *);void checkdups(struct item *, int);int checkserv(const char *, char **p);int checkwks(FILE *, char *, int *, char **);int cmpaddr(const void *, const void *);int cmphost(const void *, const void *);int doboot(const char *, int);int doconf(const char *, int);void initprotoserv(void);char *intoa(u_int32_t);int main(int, char **);int nslint(void);int parseinaddr(const char *, u_int32_t *, u_int32_t *);int parsenetwork(const char *, char **);u_int32_t parseptr(const char *, u_int32_t, u_int32_t, char **);char *parsequoted(char *);int parsesoa(const char *, char **);void process(const char *, const char *, const char *);int rfc1034host(const char *, int);int updateitem(const char *, u_int32_t, int, u_int, int);__dead void usage(void) __attribute__((volatile));extern char *optarg;extern int optind, opterr;/* add domain if necessary */static inline voidadd_domain(register char *name, register const char *domain){ register char *cp; /* Kill trailing white space and convert to lowercase */ for (cp = name; *cp != '\0' && !isspace(*cp); ++cp) if (isupper(*cp)) *cp = tolower(*cp); *cp-- = '\0'; /* If necessary, append domain */ if (cp >= name && *cp++ != '.') { if (*domain != '.') *cp++ = '.'; (void)strcpy(cp, domain); } /* XXX should we insure a trailing dot? */}intmain(int argc, char **argv){ register char *cp; register int op, status, i, donamedboot, donamedconf; if ((cp = strrchr(argv[0], '/')) != NULL) prog = cp + 1; else prog = argv[0]; donamedboot = 0; donamedconf = 0; while ((op = getopt(argc, argv, "b:c:B:C:d")) != -1) switch (op) { case 'b': bootfile = optarg; ++donamedboot; break; case 'c': conffile = optarg; ++donamedconf; break; case 'B': nslintboot = optarg; ++donamedboot; break; case 'C': nslintconf = optarg; ++donamedconf; break; case 'd': ++debug; break; default: usage(); } if (optind != argc || (donamedboot && donamedconf)) usage(); if (donamedboot) status = doboot(bootfile, 1); else if (donamedconf) status = doconf(conffile, 1); else { status = doconf(conffile, 0); if (status < 0) { status = doboot(bootfile, 1); ++donamedboot; } else ++donamedconf; } if (donamedboot) { if (nslintboot != NULL) status |= doboot(nslintboot, 1); else if ((i = doboot(NSLINTBOOT, 0)) > 0) status |= i; } else { if (nslintconf != NULL) status |= doconf(nslintconf, 1); else if ((i = doconf(NSLINTCONF, 0)) > 0) status |= i; } status |= nslint(); exit (status);}struct netlist { u_int32_t net; u_int32_t mask;};static struct netlist *netlist;static u_int netlistsize; /* size of array */static u_int netlistcnt; /* next free element */static u_int32_tfindmask(u_int32_t addr){ register int i; for (i = 0; i < netlistcnt; ++i) if ((addr & netlist[i].mask) == netlist[i].net) return (netlist[i].mask); return (0);}intparsenetwork(register const char *cp, register char **errstrp){ register int i, w; register u_int32_t net, mask; register u_int32_t o; register int shift; static char errstr[132]; while (isspace(*cp)) ++cp; net = 0; mask = 0; shift = 24; while (isdigit(*cp) && shift >= 0) { o = 0; do { o = o * 10 + (*cp++ - '0'); } while (isdigit(*cp)); net |= o << shift; shift -= 8; if (*cp != '.') break; ++cp; } if (isspace(*cp)) { ++cp; while (isspace(*cp)) ++cp; mask = htonl(inet_addr(cp)); if ((int)mask == -1) { *errstrp = errstr; (void)sprintf(errstr, "bad mask \"%s\"", cp); return (0); } i = 0; while (isdigit(*cp)) ++cp; for (i = 0; i < 3 && *cp == '.'; ++i) { ++cp; while (isdigit(*cp)) ++cp; } if (i != 3) { *errstrp = "wrong number of dots in mask"; return (0); } } else if (*cp == '/') { ++cp; w = atoi(cp); do { ++cp; } while (isdigit(*cp)); if (w < 1 || w > 32) { *errstrp = "bad mask width"; return (0); } mask = 0xffffffff << (32 - w); } else { *errstrp = "garbage after net"; return (0); } while (isspace(*cp)) ++cp; if (*cp != '\0') { *errstrp = "trailing garbage"; return (0); } /* Finaly sanity checks */ if ((net & ~ mask) != 0) { *errstrp = errstr; (void)sprintf(errstr, "host bits set in net \"%s\"", intoa(net)); return (0); } /* Make sure there's room */ if (netlistsize <= netlistcnt) { if (netlistsize == 0) { netlistsize = 32; netlist = (struct netlist *) malloc(netlistsize * sizeof(*netlist)); } else { netlistsize <<= 1; netlist = (struct netlist *) realloc(netlist, netlistsize * sizeof(*netlist)); } if (netlist == NULL) { fprintf(stderr, "%s: nslint: malloc/realloc: %s\n", prog, strerror(errno)); exit(1); } } /* Add to list */ netlist[netlistcnt].net = net; netlist[netlistcnt].mask = mask; ++netlistcnt; return (1);}intdoboot(register const char *file, register int mustexist){ register int n; register char *cp, *cp2; register FILE *f; char *errstr; char buf[1024], name[128]; errno = 0; f = fopen(file, "r"); if (f == NULL) { /* Not an error if it doesn't exist */ if (!mustexist && errno == ENOENT) { if (debug > 1) printf( "%s: doit: %s doesn't exist (ignoring)\n", prog, file); return (-1); } fprintf(stderr, "%s: %s: %s\n", prog, file, strerror(errno)); exit(1); } if (debug > 1) printf("%s: doit: opened %s\n", prog, file); n = 0; while (fgets(buf, sizeof(buf), f) != NULL) { ++n; /* Skip comments */ if (buf[0] == ';') continue; cp = strchr(buf, ';'); if (cp) *cp = '\0'; cp = buf + strlen(buf) - 1; if (cp >= buf && *cp == '\n') *cp = '\0'; cp = buf; /* Eat leading whitespace */ while (isspace(*cp)) ++cp; /* Skip blank lines */ if (*cp == '\n' || *cp == '\0') continue; /* Get name */ cp2 = cp; while (!isspace(*cp) && *cp != '\0') ++cp; *cp++ = '\0'; /* Find next keyword */ while (isspace(*cp)) ++cp; if (strcasecmp(cp2, "directory") == 0) { /* Terminate directory */ cp2 = cp; while (!isspace(*cp) && *cp != '\0') ++cp; *cp = '\0'; if (chdir(cp2) < 0) { ++errors; fprintf(stderr, "%s: can't chdir %s: %s\n", prog, cp2, strerror(errno)); exit(1); } cwd = savestr(cp2); continue; } if (strcasecmp(cp2, "primary") == 0) { /* Extract domain, converting to lowercase */ for (cp2 = name; !isspace(*cp) && *cp != '\0'; ++cp) if (isupper(*cp)) *cp2++ = tolower(*cp); else *cp2++ = *cp; /* Insure trailing dot */ if (cp2 > name && cp2[-1] != '.') *cp2++ = '.'; *cp2 = '\0'; /* Find file */ while (isspace(*cp)) ++cp; /* Terminate directory */ cp2 = cp; while (!isspace(*cp) && *cp != '\0') ++cp; *cp = '\0'; /* Process it! (zone is the same as the domain) */ nsoaval = -1; memset(soaval, 0, sizeof(soaval)); process(cp2, name, name); continue; } if (strcasecmp(cp2, "network") == 0) { if (!parsenetwork(cp, &errstr)) { ++errors; fprintf(stderr, "%s: %s:%d: bad network: %s\n", prog, file, n, errstr); } continue; } if (strcasecmp(cp2, "include") == 0) { /* Terminate include file */ cp2 = cp; while (!isspace(*cp) && *cp != '\0') ++cp; *cp = '\0'; errors += doboot(cp2, 1); continue; } /* Eat any other options */ } (void)fclose(f); return (errors != 0);}intdoconf(register const char *file, register int mustexist){ register int n, fd, cc, i, depth; register char *cp, *cp2, *buf; register char *name, *zonename, *filename, *typename; register int namelen, zonenamelen, filenamelen, typenamelen; char *errstr; struct stat sbuf; char zone[128], includefile[256]; errno = 0; fd = open(file, O_RDONLY, 0); if (fd < 0) { /* Not an error if it doesn't exist */ if (!mustexist && errno == ENOENT) { if (debug > 1) printf( "%s: doconf: %s doesn't exist (ignoring)\n", prog, file); return (-1); } fprintf(stderr, "%s: %s: %s\n", prog, file, strerror(errno)); exit(1); } if (debug > 1) printf("%s: doconf: opened %s\n", prog, file); if (fstat(fd, &sbuf) < 0) { fprintf(stderr, "%s: fstat(%s) %s\n", prog, file, strerror(errno)); exit(1); } buf = (char *)malloc(sbuf.st_size + 1); if (buf == NULL) { fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno)); exit(1); } /* Slurp entire config file */ n = sbuf.st_size; cp = buf; do { cc = read(fd, cp, n); if (cc < 0) { fprintf(stderr, "%s: read(%s) %s\n", prog, file, strerror(errno)); exit(1); } cp += cc; n -= cc; } while (cc != 0 && cc < n); buf[cc] = '\0';#define EATWHITESPACE \ while (isspace(*cp)) { \ if (*cp == '\n') \ ++n; \ ++cp; \ }/* Handle both to-end-of-line and C style comments */#define EATCOMMENTS \ { \ int sawcomment; \ do { \ EATWHITESPACE \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -