144743Smarkm /*
244743Smarkm  * tcpdchk - examine all tcpd access control rules and inetd.conf entries
344743Smarkm  *
444743Smarkm  * Usage: tcpdchk [-a] [-d] [-i inet_conf] [-v]
544743Smarkm  *
644743Smarkm  * -a: complain about implicit "allow" at end of rule.
744743Smarkm  *
844743Smarkm  * -d: rules in current directory.
944743Smarkm  *
1044743Smarkm  * -i: location of inetd.conf file.
1144743Smarkm  *
1244743Smarkm  * -v: show all rules.
1344743Smarkm  *
1444743Smarkm  * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
1551495Ssheldonh  *
1651495Ssheldonh  * $FreeBSD: releng/10.3/contrib/tcp_wrappers/tcpdchk.c 63158 2000-07-14 17:15:34Z ume $
1744743Smarkm  */
1844743Smarkm
1944743Smarkm#ifndef lint
2044743Smarkmstatic char sccsid[] = "@(#) tcpdchk.c 1.8 97/02/12 02:13:25";
2144743Smarkm#endif
2244743Smarkm
2344743Smarkm/* System libraries. */
2444743Smarkm
2544743Smarkm#include <sys/types.h>
2644743Smarkm#include <sys/stat.h>
2756977Sshin#ifdef INET6
2856977Sshin#include <sys/socket.h>
2956977Sshin#endif
3044743Smarkm#include <netinet/in.h>
3144743Smarkm#include <arpa/inet.h>
3244743Smarkm#include <stdio.h>
3344743Smarkm#include <syslog.h>
3444743Smarkm#include <setjmp.h>
3544743Smarkm#include <errno.h>
3644743Smarkm#include <netdb.h>
3744743Smarkm#include <string.h>
3844743Smarkm
3944743Smarkmextern int errno;
4044743Smarkmextern void exit();
4144743Smarkmextern int optind;
4244743Smarkmextern char *optarg;
4344743Smarkm
4444743Smarkm#ifndef INADDR_NONE
4544743Smarkm#define INADDR_NONE     (-1)		/* XXX should be 0xffffffff */
4644743Smarkm#endif
4744743Smarkm
4844743Smarkm#ifndef S_ISDIR
4944743Smarkm#define S_ISDIR(m)	(((m) & S_IFMT) == S_IFDIR)
5044743Smarkm#endif
5144743Smarkm
5244743Smarkm/* Application-specific. */
5344743Smarkm
5444743Smarkm#include "tcpd.h"
5544743Smarkm#include "inetcf.h"
5644743Smarkm#include "scaffold.h"
5744743Smarkm
5844743Smarkm /*
5944743Smarkm  * Stolen from hosts_access.c...
6044743Smarkm  */
6144743Smarkmstatic char sep[] = ", \t\n";
6244743Smarkm
6344743Smarkm#define	BUFLEN 2048
6444743Smarkm
6544743Smarkmint     resident = 0;
6644743Smarkmint     hosts_access_verbose = 0;
6744743Smarkmchar   *hosts_allow_table = HOSTS_ALLOW;
6844743Smarkmchar   *hosts_deny_table = HOSTS_DENY;
6944743Smarkmextern jmp_buf tcpd_buf;
7044743Smarkm
7144743Smarkm /*
7244743Smarkm  * Local stuff.
7344743Smarkm  */
7444743Smarkmstatic void usage();
7544743Smarkmstatic void parse_table();
7644743Smarkmstatic void print_list();
7744743Smarkmstatic void check_daemon_list();
7844743Smarkmstatic void check_client_list();
7944743Smarkmstatic void check_daemon();
8044743Smarkmstatic void check_user();
8144743Smarkmstatic int check_host();
8244743Smarkmstatic int reserved_name();
8344743Smarkm
8444743Smarkm#define PERMIT	1
8544743Smarkm#define DENY	0
8644743Smarkm
8744743Smarkm#define YES	1
8844743Smarkm#define	NO	0
8944743Smarkm
9044743Smarkmstatic int defl_verdict;
9144743Smarkmstatic char *myname;
9244743Smarkmstatic int allow_check;
9344743Smarkmstatic char *inetcf;
9444743Smarkm
9544743Smarkmint     main(argc, argv)
9644743Smarkmint     argc;
9744743Smarkmchar  **argv;
9844743Smarkm{
9944743Smarkm    struct request_info request;
10044743Smarkm    struct stat st;
10144743Smarkm    int     c;
10244743Smarkm
10344743Smarkm    myname = argv[0];
10444743Smarkm
10544743Smarkm    /*
10644743Smarkm     * Parse the JCL.
10744743Smarkm     */
10844743Smarkm    while ((c = getopt(argc, argv, "adi:v")) != EOF) {
10944743Smarkm	switch (c) {
11044743Smarkm	case 'a':
11144743Smarkm	    allow_check = 1;
11244743Smarkm	    break;
11344743Smarkm	case 'd':
11444743Smarkm	    hosts_allow_table = "hosts.allow";
11544743Smarkm	    hosts_deny_table = "hosts.deny";
11644743Smarkm	    break;
11744743Smarkm	case 'i':
11844743Smarkm	    inetcf = optarg;
11944743Smarkm	    break;
12044743Smarkm	case 'v':
12144743Smarkm	    hosts_access_verbose++;
12244743Smarkm	    break;
12344743Smarkm	default:
12444743Smarkm	    usage();
12544743Smarkm	    /* NOTREACHED */
12644743Smarkm	}
12744743Smarkm    }
12844743Smarkm    if (argc != optind)
12944743Smarkm	usage();
13044743Smarkm
13144743Smarkm    /*
13244743Smarkm     * When confusion really strikes...
13344743Smarkm     */
13444743Smarkm    if (check_path(REAL_DAEMON_DIR, &st) < 0) {
13544743Smarkm	tcpd_warn("REAL_DAEMON_DIR %s: %m", REAL_DAEMON_DIR);
13644743Smarkm    } else if (!S_ISDIR(st.st_mode)) {
13744743Smarkm	tcpd_warn("REAL_DAEMON_DIR %s is not a directory", REAL_DAEMON_DIR);
13844743Smarkm    }
13944743Smarkm
14044743Smarkm    /*
14144743Smarkm     * Process the inet configuration file (or its moral equivalent). This
14244743Smarkm     * information is used later to find references in hosts.allow/deny to
14344743Smarkm     * unwrapped services, and other possible problems.
14444743Smarkm     */
14544743Smarkm    inetcf = inet_cfg(inetcf);
14644743Smarkm    if (hosts_access_verbose)
14744743Smarkm	printf("Using network configuration file: %s\n", inetcf);
14844743Smarkm
14944743Smarkm    /*
15044743Smarkm     * These are not run from inetd but may have built-in access control.
15144743Smarkm     */
15244743Smarkm    inet_set("portmap", WR_NOT);
15344743Smarkm    inet_set("rpcbind", WR_NOT);
15444743Smarkm
15544743Smarkm    /*
15644743Smarkm     * Check accessibility of access control files.
15744743Smarkm     */
15844743Smarkm    (void) check_path(hosts_allow_table, &st);
15944743Smarkm    (void) check_path(hosts_deny_table, &st);
16044743Smarkm
16144743Smarkm    /*
16244743Smarkm     * Fake up an arbitrary service request.
16344743Smarkm     */
16444743Smarkm    request_init(&request,
16544743Smarkm		 RQ_DAEMON, "daemon_name",
16644743Smarkm		 RQ_SERVER_NAME, "server_hostname",
16744743Smarkm		 RQ_SERVER_ADDR, "server_addr",
16844743Smarkm		 RQ_USER, "user_name",
16944743Smarkm		 RQ_CLIENT_NAME, "client_hostname",
17044743Smarkm		 RQ_CLIENT_ADDR, "client_addr",
17144743Smarkm		 RQ_FILE, 1,
17244743Smarkm		 0);
17344743Smarkm
17444743Smarkm    /*
17544743Smarkm     * Examine all access-control rules.
17644743Smarkm     */
17744743Smarkm    defl_verdict = PERMIT;
17844743Smarkm    parse_table(hosts_allow_table, &request);
17944743Smarkm    defl_verdict = DENY;
18044743Smarkm    parse_table(hosts_deny_table, &request);
18144743Smarkm    return (0);
18244743Smarkm}
18344743Smarkm
18444743Smarkm/* usage - explain */
18544743Smarkm
18644743Smarkmstatic void usage()
18744743Smarkm{
18844743Smarkm    fprintf(stderr, "usage: %s [-a] [-d] [-i inet_conf] [-v]\n", myname);
18944743Smarkm    fprintf(stderr, "	-a: report rules with implicit \"ALLOW\" at end\n");
19044743Smarkm    fprintf(stderr, "	-d: use allow/deny files in current directory\n");
19144743Smarkm    fprintf(stderr, "	-i: location of inetd.conf file\n");
19244743Smarkm    fprintf(stderr, "	-v: list all rules\n");
19344743Smarkm    exit(1);
19444743Smarkm}
19544743Smarkm
19644743Smarkm/* parse_table - like table_match(), but examines _all_ entries */
19744743Smarkm
19844743Smarkmstatic void parse_table(table, request)
19944743Smarkmchar   *table;
20044743Smarkmstruct request_info *request;
20144743Smarkm{
20244743Smarkm    FILE   *fp;
20344743Smarkm    int     real_verdict;
20444743Smarkm    char    sv_list[BUFLEN];		/* becomes list of daemons */
20544743Smarkm    char   *cl_list;			/* becomes list of requests */
20644743Smarkm    char   *sh_cmd;			/* becomes optional shell command */
20744743Smarkm    char    buf[BUFSIZ];
20844743Smarkm    int     verdict;
20944743Smarkm    struct tcpd_context saved_context;
21044743Smarkm
21144743Smarkm    saved_context = tcpd_context;		/* stupid compilers */
21244743Smarkm
21344743Smarkm    if (fp = fopen(table, "r")) {
21444743Smarkm	tcpd_context.file = table;
21544743Smarkm	tcpd_context.line = 0;
21644743Smarkm	while (xgets(sv_list, sizeof(sv_list), fp)) {
21744743Smarkm	    if (sv_list[strlen(sv_list) - 1] != '\n') {
21844743Smarkm		tcpd_warn("missing newline or line too long");
21944743Smarkm		continue;
22044743Smarkm	    }
22144743Smarkm	    if (sv_list[0] == '#' || sv_list[strspn(sv_list, " \t\r\n")] == 0)
22244743Smarkm		continue;
22344743Smarkm	    if ((cl_list = split_at(sv_list, ':')) == 0) {
22444743Smarkm		tcpd_warn("missing \":\" separator");
22544743Smarkm		continue;
22644743Smarkm	    }
22744743Smarkm	    sh_cmd = split_at(cl_list, ':');
22844743Smarkm
22944743Smarkm	    if (hosts_access_verbose)
23044743Smarkm		printf("\n>>> Rule %s line %d:\n",
23144743Smarkm		       tcpd_context.file, tcpd_context.line);
23244743Smarkm
23344743Smarkm	    if (hosts_access_verbose)
23444743Smarkm		print_list("daemons:  ", sv_list);
23544743Smarkm	    check_daemon_list(sv_list);
23644743Smarkm
23744743Smarkm	    if (hosts_access_verbose)
23844743Smarkm		print_list("clients:  ", cl_list);
23944743Smarkm	    check_client_list(cl_list);
24044743Smarkm
24144743Smarkm#ifdef PROCESS_OPTIONS
24244743Smarkm	    real_verdict = defl_verdict;
24344743Smarkm	    if (sh_cmd) {
24444743Smarkm		verdict = setjmp(tcpd_buf);
24544743Smarkm		if (verdict != 0) {
24644743Smarkm		    real_verdict = (verdict == AC_PERMIT);
24744743Smarkm		} else {
24844743Smarkm		    dry_run = 1;
24944743Smarkm		    process_options(sh_cmd, request);
25044743Smarkm		    if (dry_run == 1 && real_verdict && allow_check)
25144743Smarkm			tcpd_warn("implicit \"allow\" at end of rule");
25244743Smarkm		}
25344743Smarkm	    } else if (defl_verdict && allow_check) {
25444743Smarkm		tcpd_warn("implicit \"allow\" at end of rule");
25544743Smarkm	    }
25644743Smarkm	    if (hosts_access_verbose)
25744743Smarkm		printf("access:   %s\n", real_verdict ? "granted" : "denied");
25844743Smarkm#else
25944743Smarkm	    if (sh_cmd)
26044743Smarkm		shell_cmd(percent_x(buf, sizeof(buf), sh_cmd, request));
26144743Smarkm	    if (hosts_access_verbose)
26244743Smarkm		printf("access:   %s\n", defl_verdict ? "granted" : "denied");
26344743Smarkm#endif
26444743Smarkm	}
26544743Smarkm	(void) fclose(fp);
26644743Smarkm    } else if (errno != ENOENT) {
26744743Smarkm	tcpd_warn("cannot open %s: %m", table);
26844743Smarkm    }
26944743Smarkm    tcpd_context = saved_context;
27044743Smarkm}
27144743Smarkm
27244743Smarkm/* print_list - pretty-print a list */
27344743Smarkm
27444743Smarkmstatic void print_list(title, list)
27544743Smarkmchar   *title;
27644743Smarkmchar   *list;
27744743Smarkm{
27844743Smarkm    char    buf[BUFLEN];
27944743Smarkm    char   *cp;
28044743Smarkm    char   *next;
28144743Smarkm
28244743Smarkm    fputs(title, stdout);
28344743Smarkm    strcpy(buf, list);
28444743Smarkm
28544743Smarkm    for (cp = strtok(buf, sep); cp != 0; cp = next) {
28644743Smarkm	fputs(cp, stdout);
28744743Smarkm	next = strtok((char *) 0, sep);
28844743Smarkm	if (next != 0)
28944743Smarkm	    fputs(" ", stdout);
29044743Smarkm    }
29144743Smarkm    fputs("\n", stdout);
29244743Smarkm}
29344743Smarkm
29444743Smarkm/* check_daemon_list - criticize daemon list */
29544743Smarkm
29644743Smarkmstatic void check_daemon_list(list)
29744743Smarkmchar   *list;
29844743Smarkm{
29944743Smarkm    char    buf[BUFLEN];
30044743Smarkm    char   *cp;
30144743Smarkm    char   *host;
30244743Smarkm    int     daemons = 0;
30344743Smarkm
30444743Smarkm    strcpy(buf, list);
30544743Smarkm
30644743Smarkm    for (cp = strtok(buf, sep); cp != 0; cp = strtok((char *) 0, sep)) {
30744743Smarkm	if (STR_EQ(cp, "EXCEPT")) {
30844743Smarkm	    daemons = 0;
30944743Smarkm	} else {
31044743Smarkm	    daemons++;
31144743Smarkm	    if ((host = split_at(cp + 1, '@')) != 0 && check_host(host) > 1) {
31244743Smarkm		tcpd_warn("host %s has more than one address", host);
31344743Smarkm		tcpd_warn("(consider using an address instead)");
31444743Smarkm	    }
31544743Smarkm	    check_daemon(cp);
31644743Smarkm	}
31744743Smarkm    }
31844743Smarkm    if (daemons == 0)
31944743Smarkm	tcpd_warn("daemon list is empty or ends in EXCEPT");
32044743Smarkm}
32144743Smarkm
32244743Smarkm/* check_client_list - criticize client list */
32344743Smarkm
32444743Smarkmstatic void check_client_list(list)
32544743Smarkmchar   *list;
32644743Smarkm{
32744743Smarkm    char    buf[BUFLEN];
32844743Smarkm    char   *cp;
32944743Smarkm    char   *host;
33044743Smarkm    int     clients = 0;
33144743Smarkm
33244743Smarkm    strcpy(buf, list);
33344743Smarkm
33444743Smarkm    for (cp = strtok(buf, sep); cp != 0; cp = strtok((char *) 0, sep)) {
33544743Smarkm	if (STR_EQ(cp, "EXCEPT")) {
33644743Smarkm	    clients = 0;
33744743Smarkm	} else {
33844743Smarkm	    clients++;
33944743Smarkm	    if (host = split_at(cp + 1, '@')) {	/* user@host */
34044743Smarkm		check_user(cp);
34144743Smarkm		check_host(host);
34244743Smarkm	    } else {
34344743Smarkm		check_host(cp);
34444743Smarkm	    }
34544743Smarkm	}
34644743Smarkm    }
34744743Smarkm    if (clients == 0)
34844743Smarkm	tcpd_warn("client list is empty or ends in EXCEPT");
34944743Smarkm}
35044743Smarkm
35144743Smarkm/* check_daemon - criticize daemon pattern */
35244743Smarkm
35344743Smarkmstatic void check_daemon(pat)
35444743Smarkmchar   *pat;
35544743Smarkm{
35644743Smarkm    if (pat[0] == '@') {
35744743Smarkm	tcpd_warn("%s: daemon name begins with \"@\"", pat);
35851495Ssheldonh    } else if (pat[0] == '/') {
35951495Ssheldonh	tcpd_warn("%s: daemon name begins with \"/\"", pat);
36044743Smarkm    } else if (pat[0] == '.') {
36144743Smarkm	tcpd_warn("%s: daemon name begins with dot", pat);
36244743Smarkm    } else if (pat[strlen(pat) - 1] == '.') {
36344743Smarkm	tcpd_warn("%s: daemon name ends in dot", pat);
36444743Smarkm    } else if (STR_EQ(pat, "ALL") || STR_EQ(pat, unknown)) {
36544743Smarkm	 /* void */ ;
36644743Smarkm    } else if (STR_EQ(pat, "FAIL")) {		/* obsolete */
36744743Smarkm	tcpd_warn("FAIL is no longer recognized");
36844743Smarkm	tcpd_warn("(use EXCEPT or DENY instead)");
36944743Smarkm    } else if (reserved_name(pat)) {
37044743Smarkm	tcpd_warn("%s: daemon name may be reserved word", pat);
37144743Smarkm    } else {
37244743Smarkm	switch (inet_get(pat)) {
37344743Smarkm	case WR_UNKNOWN:
37444743Smarkm	    tcpd_warn("%s: no such process name in %s", pat, inetcf);
37544743Smarkm	    inet_set(pat, WR_YES);		/* shut up next time */
37644743Smarkm	    break;
37744743Smarkm	case WR_NOT:
37844743Smarkm	    tcpd_warn("%s: service possibly not wrapped", pat);
37944743Smarkm	    inet_set(pat, WR_YES);
38044743Smarkm	    break;
38144743Smarkm	}
38244743Smarkm    }
38344743Smarkm}
38444743Smarkm
38544743Smarkm/* check_user - criticize user pattern */
38644743Smarkm
38744743Smarkmstatic void check_user(pat)
38844743Smarkmchar   *pat;
38944743Smarkm{
39044743Smarkm    if (pat[0] == '@') {			/* @netgroup */
39144743Smarkm	tcpd_warn("%s: user name begins with \"@\"", pat);
39251495Ssheldonh    } else if (pat[0] == '/') {
39351495Ssheldonh	tcpd_warn("%s: user name begins with \"/\"", pat);
39444743Smarkm    } else if (pat[0] == '.') {
39544743Smarkm	tcpd_warn("%s: user name begins with dot", pat);
39644743Smarkm    } else if (pat[strlen(pat) - 1] == '.') {
39744743Smarkm	tcpd_warn("%s: user name ends in dot", pat);
39844743Smarkm    } else if (STR_EQ(pat, "ALL") || STR_EQ(pat, unknown)
39944743Smarkm	       || STR_EQ(pat, "KNOWN")) {
40044743Smarkm	 /* void */ ;
40144743Smarkm    } else if (STR_EQ(pat, "FAIL")) {		/* obsolete */
40244743Smarkm	tcpd_warn("FAIL is no longer recognized");
40344743Smarkm	tcpd_warn("(use EXCEPT or DENY instead)");
40444743Smarkm    } else if (reserved_name(pat)) {
40544743Smarkm	tcpd_warn("%s: user name may be reserved word", pat);
40644743Smarkm    }
40744743Smarkm}
40844743Smarkm
40956977Sshin#ifdef INET6
41056977Sshinstatic int is_inet6_addr(pat)
41156977Sshin    char *pat;
41256977Sshin{
41363158Sume    struct addrinfo hints, *res;
41456977Sshin    int len, ret;
41556977Sshin    char ch;
41656977Sshin
41756977Sshin    if (*pat != '[')
41856977Sshin	return (0);
41956977Sshin    len = strlen(pat);
42056977Sshin    if ((ch = pat[len - 1]) != ']')
42156977Sshin	return (0);
42256977Sshin    pat[len - 1] = '\0';
42363158Sume    memset(&hints, 0, sizeof(hints));
42463158Sume    hints.ai_family = AF_INET6;
42563158Sume    hints.ai_socktype = SOCK_STREAM;
42663158Sume    hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
42763158Sume    if ((ret = getaddrinfo(pat + 1, NULL, &hints, &res)) == 0)
42863158Sume	freeaddrinfo(res);
42956977Sshin    pat[len - 1] = ch;
43063158Sume    return (ret == 0);
43156977Sshin}
43256977Sshin#endif
43356977Sshin
43444743Smarkm/* check_host - criticize host pattern */
43544743Smarkm
43644743Smarkmstatic int check_host(pat)
43744743Smarkmchar   *pat;
43844743Smarkm{
43951495Ssheldonh    char    buf[BUFSIZ];
44044743Smarkm    char   *mask;
44144743Smarkm    int     addr_count = 1;
44251495Ssheldonh    FILE   *fp;
44351495Ssheldonh    struct tcpd_context saved_context;
44451495Ssheldonh    char   *cp;
44551495Ssheldonh    char   *wsp = " \t\r\n";
44644743Smarkm
44744743Smarkm    if (pat[0] == '@') {			/* @netgroup */
44844743Smarkm#ifdef NO_NETGRENT
44944743Smarkm	/* SCO has no *netgrent() support */
45044743Smarkm#else
45144743Smarkm#ifdef NETGROUP
45244743Smarkm	char   *machinep;
45344743Smarkm	char   *userp;
45444743Smarkm	char   *domainp;
45544743Smarkm
45644743Smarkm	setnetgrent(pat + 1);
45744743Smarkm	if (getnetgrent(&machinep, &userp, &domainp) == 0)
45844743Smarkm	    tcpd_warn("%s: unknown or empty netgroup", pat + 1);
45944743Smarkm	endnetgrent();
46044743Smarkm#else
46144743Smarkm	tcpd_warn("netgroup support disabled");
46244743Smarkm#endif
46344743Smarkm#endif
46451495Ssheldonh    } else if (pat[0] == '/') {			/* /path/name */
46551495Ssheldonh	if ((fp = fopen(pat, "r")) != 0) {
46651495Ssheldonh	    saved_context = tcpd_context;
46751495Ssheldonh	    tcpd_context.file = pat;
46851495Ssheldonh	    tcpd_context.line = 0;
46951495Ssheldonh	    while (fgets(buf, sizeof(buf), fp)) {
47051495Ssheldonh		tcpd_context.line++;
47151495Ssheldonh		for (cp = strtok(buf, wsp); cp; cp = strtok((char *) 0, wsp))
47251495Ssheldonh		    check_host(cp);
47351495Ssheldonh	    }
47451495Ssheldonh	    tcpd_context = saved_context;
47551495Ssheldonh	    fclose(fp);
47651495Ssheldonh	} else if (errno != ENOENT) {
47751495Ssheldonh	    tcpd_warn("open %s: %m", pat);
47851495Ssheldonh	}
47944743Smarkm    } else if (mask = split_at(pat, '/')) {	/* network/netmask */
48056977Sshin#ifdef INET6
48156977Sshin	int mask_len;
48256977Sshin
48356977Sshin	if ((dot_quad_addr(pat) == INADDR_NONE
48456977Sshin	    || dot_quad_addr(mask) == INADDR_NONE)
48556977Sshin	    && (!is_inet6_addr(pat)
48656977Sshin		|| ((mask_len = atoi(mask)) < 0 || mask_len > 128)))
48756977Sshin#else
48844743Smarkm	if (dot_quad_addr(pat) == INADDR_NONE
48944743Smarkm	    || dot_quad_addr(mask) == INADDR_NONE)
49056977Sshin#endif
49144743Smarkm	    tcpd_warn("%s/%s: bad net/mask pattern", pat, mask);
49244743Smarkm    } else if (STR_EQ(pat, "FAIL")) {		/* obsolete */
49344743Smarkm	tcpd_warn("FAIL is no longer recognized");
49444743Smarkm	tcpd_warn("(use EXCEPT or DENY instead)");
49544743Smarkm    } else if (reserved_name(pat)) {		/* other reserved */
49644743Smarkm	 /* void */ ;
49756977Sshin#ifdef INET6
49856977Sshin    } else if (is_inet6_addr(pat)) { /* IPv6 address */
49956977Sshin	addr_count = 1;
50056977Sshin#endif
50144743Smarkm    } else if (NOT_INADDR(pat)) {		/* internet name */
50244743Smarkm	if (pat[strlen(pat) - 1] == '.') {
50344743Smarkm	    tcpd_warn("%s: domain or host name ends in dot", pat);
50444743Smarkm	} else if (pat[0] != '.') {
50544743Smarkm	    addr_count = check_dns(pat);
50644743Smarkm	}
50744743Smarkm    } else {					/* numeric form */
50844743Smarkm	if (STR_EQ(pat, "0.0.0.0") || STR_EQ(pat, "255.255.255.255")) {
50944743Smarkm	    /* void */ ;
51044743Smarkm	} else if (pat[0] == '.') {
51144743Smarkm	    tcpd_warn("%s: network number begins with dot", pat);
51244743Smarkm	} else if (pat[strlen(pat) - 1] != '.') {
51344743Smarkm	    check_dns(pat);
51444743Smarkm	}
51544743Smarkm    }
51644743Smarkm    return (addr_count);
51744743Smarkm}
51844743Smarkm
51944743Smarkm/* reserved_name - determine if name is reserved */
52044743Smarkm
52144743Smarkmstatic int reserved_name(pat)
52244743Smarkmchar   *pat;
52344743Smarkm{
52444743Smarkm    return (STR_EQ(pat, unknown)
52544743Smarkm	    || STR_EQ(pat, "KNOWN")
52644743Smarkm	    || STR_EQ(pat, paranoid)
52744743Smarkm	    || STR_EQ(pat, "ALL")
52844743Smarkm	    || STR_EQ(pat, "LOCAL"));
52944743Smarkm}
530