inetd.c revision 1.137
1/*	$NetBSD: inetd.c,v 1.137 2021/10/12 19:08:04 christos Exp $	*/
2
3/*-
4 * Copyright (c) 1998, 2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center and by Matthias Scheler.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/*
34 * Copyright (c) 1983, 1991, 1993, 1994
35 *	The Regents of the University of California.  All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 *    notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 *    notice, this list of conditions and the following disclaimer in the
44 *    documentation and/or other materials provided with the distribution.
45 * 3. Neither the name of the University nor the names of its contributors
46 *    may be used to endorse or promote products derived from this software
47 *    without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 */
61
62#include <sys/cdefs.h>
63#ifndef lint
64__COPYRIGHT("@(#) Copyright (c) 1983, 1991, 1993, 1994\
65 The Regents of the University of California.  All rights reserved.");
66#if 0
67static char sccsid[] = "@(#)inetd.c	8.4 (Berkeley) 4/13/94";
68#else
69__RCSID("$NetBSD: inetd.c,v 1.137 2021/10/12 19:08:04 christos Exp $");
70#endif
71#endif /* not lint */
72
73/*
74 * Inetd - Internet super-server
75 *
76 * This program invokes all internet services as needed.  Connection-oriented
77 * services are invoked each time a connection is made, by creating a process.
78 * This process is passed the connection as file descriptor 0 and is expected
79 * to do a getpeername to find out the source host and port.
80 *
81 * Datagram oriented services are invoked when a datagram
82 * arrives; a process is created and passed a pending message
83 * on file descriptor 0.  Datagram servers may either connect
84 * to their peer, freeing up the original socket for inetd
85 * to receive further messages on, or ``take over the socket'',
86 * processing all arriving datagrams and, eventually, timing
87 * out.	 The first type of server is said to be ``multi-threaded'';
88 * the second type of server ``single-threaded''.
89 *
90 * Inetd uses a configuration file which is read at startup
91 * and, possibly, at some later time in response to a hangup signal.
92 * The configuration file is ``free format'' with fields given in the
93 * order shown below.  Continuation lines for an entry must being with
94 * a space or tab.  All fields must be present in each entry.
95 *
96 *	service name			must be in /etc/services or must
97 *					name a tcpmux service
98 *	socket type[:accf[,arg]]	stream/dgram/raw/rdm/seqpacket,
99					only stream can name an accept filter
100 *	protocol			must be in /etc/protocols
101 *	wait/nowait[:max]		single-threaded/multi-threaded, max #
102 *	user[:group]			user/group to run daemon as
103 *	server program			full path name
104 *	server program arguments	maximum of MAXARGV (64)
105 *
106 * For RPC services
107 *	service name/version		must be in /etc/rpc
108 *	socket type			stream/dgram/raw/rdm/seqpacket
109 *	protocol			must be in /etc/protocols
110 *	wait/nowait[:max]		single-threaded/multi-threaded
111 *	user[:group]			user to run daemon as
112 *	server program			full path name
113 *	server program arguments	maximum of MAXARGV (64)
114 *
115 * For non-RPC services, the "service name" can be of the form
116 * hostaddress:servicename, in which case the hostaddress is used
117 * as the host portion of the address to listen on.  If hostaddress
118 * consists of a single `*' character, INADDR_ANY is used.
119 *
120 * A line can also consist of just
121 *	hostaddress:
122 * where hostaddress is as in the preceding paragraph.  Such a line must
123 * have no further fields; the specified hostaddress is remembered and
124 * used for all further lines that have no hostaddress specified,
125 * until the next such line (or EOF).  (This is why * is provided to
126 * allow explicit specification of INADDR_ANY.)  A line
127 *	*:
128 * is implicitly in effect at the beginning of the file.
129 *
130 * The hostaddress specifier may (and often will) contain dots;
131 * the service name must not.
132 *
133 * For RPC services, host-address specifiers are accepted and will
134 * work to some extent; however, because of limitations in the
135 * portmapper interface, it will not work to try to give more than
136 * one line for any given RPC service, even if the host-address
137 * specifiers are different.
138 *
139 * TCP services without official port numbers are handled with the
140 * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for
141 * requests. When a connection is made from a foreign host, the service
142 * requested is passed to tcpmux, which looks it up in the servtab list
143 * and returns the proper entry for the service. Tcpmux returns a
144 * negative reply if the service doesn't exist, otherwise the invoked
145 * server is expected to return the positive reply if the service type in
146 * inetd.conf file has the prefix "tcpmux/". If the service type has the
147 * prefix "tcpmux/+", tcpmux will return the positive reply for the
148 * process; this is for compatibility with older server code, and also
149 * allows you to invoke programs that use stdin/stdout without putting any
150 * special server code in them. Services that use tcpmux are "nowait"
151 * because they do not have a well-known port and hence cannot listen
152 * for new requests.
153 *
154 * Comment lines are indicated by a `#' in column 1.
155 *
156 * #ifdef IPSEC
157 * Comment lines that start with "#@" denote IPsec policy string, as described
158 * in ipsec_set_policy(3).  This will affect all the following items in
159 * inetd.conf(8).  To reset the policy, just use "#@" line.  By default,
160 * there's no IPsec policy.
161 * #endif
162 */
163
164/*
165 * Here's the scoop concerning the user:group feature:
166 *
167 * 1) set-group-option off.
168 *
169 * 	a) user = root:	NO setuid() or setgid() is done
170 *
171 * 	b) other:	setuid()
172 * 			setgid(primary group as found in passwd)
173 * 			initgroups(name, primary group)
174 *
175 * 2) set-group-option on.
176 *
177 * 	a) user = root:	NO setuid()
178 * 			setgid(specified group)
179 * 			NO initgroups()
180 *
181 * 	b) other:	setuid()
182 * 			setgid(specified group)
183 * 			initgroups(name, specified group)
184 *
185 */
186
187#include <sys/param.h>
188#include <sys/stat.h>
189#include <sys/ioctl.h>
190#include <sys/wait.h>
191#include <sys/resource.h>
192#include <sys/event.h>
193#include <sys/socket.h>
194#include <sys/queue.h>
195
196
197#ifndef NO_RPC
198#define RPC
199#endif
200
201#include <net/if.h>
202
203#ifdef RPC
204#include <rpc/rpc.h>
205#include <rpc/rpcb_clnt.h>
206#include <netconfig.h>
207#endif
208
209#include <ctype.h>
210#include <err.h>
211#include <errno.h>
212#include <fcntl.h>
213#include <glob.h>
214#include <grp.h>
215#include <libgen.h>
216#include <pwd.h>
217#include <signal.h>
218#include <stdio.h>
219#include <stdlib.h>
220#include <string.h>
221#include <syslog.h>
222#include <unistd.h>
223#include <util.h>
224#include <ifaddrs.h>
225
226#include "inetd.h"
227
228#ifdef LIBWRAP
229# include <tcpd.h>
230#ifndef LIBWRAP_ALLOW_FACILITY
231# define LIBWRAP_ALLOW_FACILITY LOG_AUTH
232#endif
233#ifndef LIBWRAP_ALLOW_SEVERITY
234# define LIBWRAP_ALLOW_SEVERITY LOG_INFO
235#endif
236#ifndef LIBWRAP_DENY_FACILITY
237# define LIBWRAP_DENY_FACILITY LOG_AUTH
238#endif
239#ifndef LIBWRAP_DENY_SEVERITY
240# define LIBWRAP_DENY_SEVERITY LOG_WARNING
241#endif
242int allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY;
243int deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY;
244#endif
245
246static bool foreground;
247int	debug;
248#ifdef LIBWRAP
249int	lflag;
250#endif
251int	maxsock;
252int	kq;
253int	options;
254int	timingout;
255const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
256
257#ifndef OPEN_MAX
258#define OPEN_MAX	64
259#endif
260
261/* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
262#define FD_MARGIN	(8)
263rlim_t		rlim_ofile_cur = OPEN_MAX;
264
265struct rlimit	rlim_ofile;
266
267struct kevent	changebuf[64];
268size_t		changes;
269
270struct servtab *servtab;
271
272static void	chargen_dg(int, struct servtab *);
273static void	chargen_stream(int, struct servtab *);
274static void	daytime_dg(int, struct servtab *);
275static void	daytime_stream(int, struct servtab *);
276static void	discard_dg(int, struct servtab *);
277static void	discard_stream(int, struct servtab *);
278static void	echo_dg(int, struct servtab *);
279static void	echo_stream(int, struct servtab *);
280__dead static void	goaway(void);
281static void	machtime_dg(int, struct servtab *);
282static void	machtime_stream(int, struct servtab *);
283static void	reapchild(void);
284static void	retry(void);
285static void	run_service(int, struct servtab *, int);
286static void	tcpmux(int, struct servtab *);
287__dead static void	usage(void);
288static void	bump_nofile(void);
289static void	inetd_setproctitle(char *, int);
290static void	initring(void);
291static uint32_t	machtime(void);
292static int	port_good_dg(struct sockaddr *);
293static int	dg_broadcast(struct in_addr *);
294static int	my_kevent(const struct kevent *, size_t, struct kevent *, size_t);
295static struct kevent	*allocchange(void);
296static int	get_line(int, char *, int);
297static void	spawn(struct servtab *, int);
298
299struct biltin {
300	const char *bi_service;		/* internally provided service name */
301	int	bi_socktype;		/* type of socket supported */
302	short	bi_fork;		/* 1 if should fork before call */
303	short	bi_wait;		/* 1 if should wait for child */
304	void	(*bi_fn)(int, struct servtab *);
305					/* function which performs it */
306} biltins[] = {
307	/* Echo received data */
308	{ "echo",	SOCK_STREAM,	true, false,	echo_stream },
309	{ "echo",	SOCK_DGRAM,	false, false,	echo_dg },
310
311	/* Internet /dev/null */
312	{ "discard",	SOCK_STREAM,	true, false,	discard_stream },
313	{ "discard",	SOCK_DGRAM,	false, false,	discard_dg },
314
315	/* Return 32 bit time since 1970 */
316	{ "time",	SOCK_STREAM,	false, false,	machtime_stream },
317	{ "time",	SOCK_DGRAM,	false, false,	machtime_dg },
318
319	/* Return human-readable time */
320	{ "daytime",	SOCK_STREAM,	false, false,	daytime_stream },
321	{ "daytime",	SOCK_DGRAM,	false, false,	daytime_dg },
322
323	/* Familiar character generator */
324	{ "chargen",	SOCK_STREAM,	true, false,	chargen_stream },
325	{ "chargen",	SOCK_DGRAM,	false, false,	chargen_dg },
326
327	{ "tcpmux",	SOCK_STREAM,	true, false,	tcpmux }
328};
329
330/* list of "bad" ports. I.e. ports that are most obviously used for
331 * "cycling packets" denial of service attacks. See /etc/services.
332 * List must end with port number "0".
333 */
334
335u_int16_t bad_ports[] =  { 7, 9, 13, 19, 37, 0 };
336
337
338#define NUMINT	(sizeof(intab) / sizeof(struct inent))
339const char	*CONFIG = _PATH_INETDCONF;
340
341static int my_signals[] =
342    { SIGALRM, SIGHUP, SIGCHLD, SIGTERM, SIGINT, SIGPIPE };
343
344int
345main(int argc, char *argv[])
346{
347	int		ch, n, reload = 1;
348
349	while ((ch = getopt(argc, argv,
350#ifdef LIBWRAP
351					"dfl"
352#else
353					"df"
354#endif
355					   )) != -1)
356		switch(ch) {
357		case 'd':
358			foreground = true;
359			debug = true;
360			options |= SO_DEBUG;
361			break;
362		case 'f':
363			foreground = true;
364			break;
365#ifdef LIBWRAP
366		case 'l':
367			lflag = true;
368			break;
369#endif
370		case '?':
371		default:
372			usage();
373		}
374	argc -= optind;
375	argv += optind;
376
377	if (argc > 0)
378		CONFIG = argv[0];
379
380	if (!foreground)
381		daemon(0, 0);
382	openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
383	pidfile(NULL);
384
385	kq = kqueue();
386	if (kq < 0) {
387		syslog(LOG_ERR, "kqueue: %m");
388		return (EXIT_FAILURE);
389	}
390
391	if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {
392		syslog(LOG_ERR, "getrlimit: %m");
393	} else {
394		rlim_ofile_cur = rlim_ofile.rlim_cur;
395		if (rlim_ofile_cur == RLIM_INFINITY)	/* ! */
396			rlim_ofile_cur = OPEN_MAX;
397	}
398
399	for (n = 0; n < (int)__arraycount(my_signals); n++) {
400		int	signum;
401
402		signum = my_signals[n];
403		if (signum != SIGCHLD)
404			(void) signal(signum, SIG_IGN);
405
406		if (signum != SIGPIPE) {
407			struct kevent	*ev;
408
409			ev = allocchange();
410			EV_SET(ev, signum, EVFILT_SIGNAL, EV_ADD | EV_ENABLE,
411			    0, 0, 0);
412		}
413	}
414
415	for (;;) {
416		int		ctrl;
417		struct kevent	eventbuf[64], *ev;
418		struct servtab	*sep;
419
420		if (reload) {
421			reload = false;
422			config_root();
423		}
424
425		n = my_kevent(changebuf, changes, eventbuf, __arraycount(eventbuf));
426		changes = 0;
427
428		for (ev = eventbuf; n > 0; ev++, n--) {
429			if (ev->filter == EVFILT_SIGNAL) {
430				switch (ev->ident) {
431				case SIGALRM:
432					retry();
433					break;
434				case SIGCHLD:
435					reapchild();
436					break;
437				case SIGTERM:
438				case SIGINT:
439					goaway();
440					break;
441				case SIGHUP:
442					reload = true;
443					break;
444				}
445				continue;
446			}
447			if (ev->filter != EVFILT_READ)
448				continue;
449			sep = (struct servtab *)ev->udata;
450			/* Paranoia */
451			if ((int)ev->ident != sep->se_fd)
452				continue;
453			DPRINTF(SERV_FMT ": service requested" , SERV_PARAMS(sep));
454			if (sep->se_wait == 0 && sep->se_socktype == SOCK_STREAM) {
455				/* XXX here do the libwrap check-before-accept*/
456				ctrl = accept(sep->se_fd, NULL, NULL);
457				DPRINTF(SERV_FMT ": accept, ctrl fd %d",
458				    SERV_PARAMS(sep), ctrl);
459				if (ctrl < 0) {
460					if (errno != EINTR)
461						syslog(LOG_WARNING,
462						    SERV_FMT ": accept: %m",
463						    SERV_PARAMS(sep));
464					continue;
465				}
466			} else
467				ctrl = sep->se_fd;
468			spawn(sep, ctrl);
469		}
470	}
471}
472
473static void
474spawn(struct servtab *sep, int ctrl)
475{
476	int dofork;
477	pid_t pid;
478
479	pid = 0;
480#ifdef LIBWRAP_INTERNAL
481	dofork = true;
482#else
483	dofork = (sep->se_bi == NULL || sep->se_bi->bi_fork);
484#endif
485	if (dofork) {
486		if (rl_process(sep, ctrl)) {
487			return;
488		}
489		pid = fork();
490		if (pid < 0) {
491			syslog(LOG_ERR, "fork: %m");
492			if (sep->se_wait == 0 && sep->se_socktype == SOCK_STREAM)
493				close(ctrl);
494			sleep(1);
495			return;
496		}
497		if (pid != 0 && sep->se_wait != 0) {
498			struct kevent	*ev;
499
500			sep->se_wait = pid;
501			ev = allocchange();
502			EV_SET(ev, sep->se_fd, EVFILT_READ,
503			    EV_DELETE, 0, 0, 0);
504		}
505		if (pid == 0) {
506			size_t	n;
507
508			for (n = 0; n < __arraycount(my_signals); n++)
509				(void) signal(my_signals[n], SIG_DFL);
510			/* Don't put services in terminal session */
511			if (foreground)
512				setsid();
513		}
514	}
515	if (pid == 0) {
516		run_service(ctrl, sep, dofork);
517		if (dofork)
518			exit(EXIT_SUCCESS);
519	}
520	if (sep->se_wait == 0 && sep->se_socktype == SOCK_STREAM)
521		close(ctrl);
522}
523
524static void
525run_service(int ctrl, struct servtab *sep, int didfork)
526{
527	struct passwd *pwd;
528	struct group *grp = NULL;	/* XXX gcc */
529	char buf[NI_MAXSERV];
530	struct servtab *s;
531#ifdef LIBWRAP
532	char abuf[BUFSIZ];
533	struct request_info req;
534	int denied;
535	char *service = NULL;	/* XXX gcc */
536#endif
537
538#ifdef LIBWRAP
539#ifndef LIBWRAP_INTERNAL
540	if (sep->se_bi == 0)
541#endif
542	if (sep->se_wait == 0 && sep->se_socktype == SOCK_STREAM) {
543		request_init(&req, RQ_DAEMON, sep->se_argv[0] != NULL ?
544		    sep->se_argv[0] : sep->se_service, RQ_FILE, ctrl, NULL);
545		fromhost(&req);
546		denied = hosts_access(&req) == 0;
547		if (denied || lflag) {
548			if (getnameinfo(&sep->se_ctrladdr,
549			    (socklen_t)sep->se_ctrladdr.sa_len, NULL, 0,
550			    buf, sizeof(buf), 0) != 0) {
551				/* shouldn't happen */
552				(void)snprintf(buf, sizeof buf, "%d",
553				    ntohs(sep->se_ctrladdr_in.sin_port));
554			}
555			service = buf;
556			if (req.client->sin != NULL) {
557				sockaddr_snprintf(abuf, sizeof(abuf), "%a",
558				    req.client->sin);
559			} else {
560				strcpy(abuf, "(null)");
561			}
562		}
563		if (denied) {
564			syslog(deny_severity,
565			    "refused connection from %.500s(%s), service %s (%s)",
566			    eval_client(&req), abuf, service, sep->se_proto);
567			goto reject;
568		}
569		if (lflag) {
570			syslog(allow_severity,
571			    "connection from %.500s(%s), service %s (%s)",
572			    eval_client(&req), abuf, service, sep->se_proto);
573		}
574	}
575#endif /* LIBWRAP */
576
577	if (sep->se_bi != NULL) {
578		if (didfork) {
579			for (s = servtab; s != NULL; s = s->se_next)
580				if (s->se_fd != -1 && s->se_fd != ctrl) {
581					close(s->se_fd);
582					s->se_fd = -1;
583				}
584		}
585		(*sep->se_bi->bi_fn)(ctrl, sep);
586	} else {
587		if ((pwd = getpwnam(sep->se_user)) == NULL) {
588			syslog(LOG_ERR, "%s/%s: %s: No such user",
589			    sep->se_service, sep->se_proto, sep->se_user);
590			goto reject;
591		}
592		if (sep->se_group != NULL &&
593		    (grp = getgrnam(sep->se_group)) == NULL) {
594			syslog(LOG_ERR, "%s/%s: %s: No such group",
595			    sep->se_service, sep->se_proto, sep->se_group);
596			goto reject;
597		}
598		if (pwd->pw_uid != 0) {
599			if (sep->se_group != NULL)
600				pwd->pw_gid = grp->gr_gid;
601			if (setgid(pwd->pw_gid) < 0) {
602				syslog(LOG_ERR,
603				 "%s/%s: can't set gid %d: %m", sep->se_service,
604				    sep->se_proto, pwd->pw_gid);
605				goto reject;
606			}
607			(void) initgroups(pwd->pw_name,
608			    pwd->pw_gid);
609			if (setuid(pwd->pw_uid) < 0) {
610				syslog(LOG_ERR,
611				 "%s/%s: can't set uid %d: %m", sep->se_service,
612				    sep->se_proto, pwd->pw_uid);
613				goto reject;
614			}
615		} else if (sep->se_group != NULL) {
616			(void) setgid((gid_t)grp->gr_gid);
617		}
618		DPRINTF("%d execl %s",
619		    getpid(), sep->se_server);
620		/* Set our control descriptor to not close-on-exec... */
621		if (fcntl(ctrl, F_SETFD, 0) < 0)
622			syslog(LOG_ERR, "fcntl (%d, F_SETFD, 0): %m", ctrl);
623		/* ...and dup it to stdin, stdout, and stderr. */
624		if (ctrl != 0) {
625			dup2(ctrl, 0);
626			close(ctrl);
627			ctrl = 0;
628		}
629		dup2(0, 1);
630		dup2(0, 2);
631		if (rlim_ofile.rlim_cur != rlim_ofile_cur &&
632		    setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0)
633			syslog(LOG_ERR, "setrlimit: %m");
634		execv(sep->se_server, sep->se_argv);
635		syslog(LOG_ERR, "cannot execute %s: %m", sep->se_server);
636	reject:
637		if (sep->se_socktype != SOCK_STREAM)
638			recv(ctrl, buf, sizeof (buf), 0);
639		_exit(EXIT_FAILURE);
640	}
641}
642
643static void
644reapchild(void)
645{
646	int status;
647	pid_t pid;
648	struct servtab *sep;
649
650	for (;;) {
651		pid = wait3(&status, WNOHANG, NULL);
652		if (pid <= 0)
653			break;
654		DPRINTF("%d reaped, status %#x", pid, status);
655		for (sep = servtab; sep != NULL; sep = sep->se_next)
656			if (sep->se_wait == pid) {
657				struct kevent	*ev;
658
659				if (WIFEXITED(status) && WEXITSTATUS(status))
660					syslog(LOG_WARNING,
661					    "%s: exit status %u",
662					    sep->se_server, WEXITSTATUS(status));
663				else if (WIFSIGNALED(status))
664					syslog(LOG_WARNING,
665					    "%s: exit signal %u",
666					    sep->se_server, WTERMSIG(status));
667				sep->se_wait = 1;
668				ev = allocchange();
669				EV_SET(ev, sep->se_fd, EVFILT_READ,
670				    EV_ADD | EV_ENABLE, 0, 0, (intptr_t)sep);
671				DPRINTF("restored %s, fd %d",
672				    sep->se_service, sep->se_fd);
673			}
674	}
675}
676
677static void
678retry(void)
679{
680	struct servtab *sep;
681
682	timingout = false;
683	for (sep = servtab; sep != NULL; sep = sep->se_next) {
684		if (sep->se_fd == -1 && !ISMUX(sep)) {
685			switch (sep->se_family) {
686			case AF_LOCAL:
687			case AF_INET:
688#ifdef INET6
689			case AF_INET6:
690#endif
691				setup(sep);
692				if (sep->se_fd >= 0 && isrpcservice(sep))
693					register_rpc(sep);
694				break;
695			}
696		}
697	}
698}
699
700static void
701goaway(void)
702{
703	struct servtab *sep;
704
705	for (sep = servtab; sep != NULL; sep = sep->se_next) {
706		if (sep->se_fd == -1)
707			continue;
708
709		switch (sep->se_family) {
710		case AF_LOCAL:
711			(void)unlink(sep->se_service);
712			break;
713		case AF_INET:
714#ifdef INET6
715		case AF_INET6:
716#endif
717			if (sep->se_wait == 1 && isrpcservice(sep))
718				unregister_rpc(sep);
719			break;
720		}
721		(void)close(sep->se_fd);
722		sep->se_fd = -1;
723	}
724
725	DPRINTF("Going away.");
726
727	exit(EXIT_SUCCESS);
728}
729
730void
731setup(struct servtab *sep)
732{
733	int		on = 1;
734#ifdef INET6
735	int		off = 0;
736#endif
737	struct kevent	*ev;
738
739	if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
740		DPRINTF("socket failed on " SERV_FMT ": %s",
741		    SERV_PARAMS(sep), strerror(errno));
742		syslog(LOG_ERR, "%s/%s: socket: %m",
743		    sep->se_service, sep->se_proto);
744		return;
745	}
746	/* Set all listening sockets to close-on-exec. */
747	if (fcntl(sep->se_fd, F_SETFD, FD_CLOEXEC) < 0) {
748		syslog(LOG_ERR, SERV_FMT ": fcntl(F_SETFD, FD_CLOEXEC): %m",
749		    SERV_PARAMS(sep));
750		close(sep->se_fd);
751		sep->se_fd = -1;
752		return;
753	}
754
755#define	turnon(fd, opt) \
756setsockopt(fd, SOL_SOCKET, opt, &on, (socklen_t)sizeof(on))
757	if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
758	    turnon(sep->se_fd, SO_DEBUG) < 0)
759		syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
760	if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
761		syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
762#undef turnon
763
764	/* Set the socket buffer sizes, if specified. */
765	if (sep->se_sndbuf != 0 && setsockopt(sep->se_fd, SOL_SOCKET,
766	    SO_SNDBUF, &sep->se_sndbuf, (socklen_t)sizeof(sep->se_sndbuf)) < 0)
767		syslog(LOG_ERR, "setsockopt (SO_SNDBUF %d): %m",
768		    sep->se_sndbuf);
769	if (sep->se_rcvbuf != 0 && setsockopt(sep->se_fd, SOL_SOCKET,
770	    SO_RCVBUF, &sep->se_rcvbuf, (socklen_t)sizeof(sep->se_rcvbuf)) < 0)
771		syslog(LOG_ERR, "setsockopt (SO_RCVBUF %d): %m",
772		    sep->se_rcvbuf);
773#ifdef INET6
774	if (sep->se_family == AF_INET6) {
775		int *v;
776		v = (sep->se_type == FAITH_TYPE) ? &on : &off;
777		if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_FAITH,
778		    v, (socklen_t)sizeof(*v)) < 0)
779			syslog(LOG_ERR, "setsockopt (IPV6_FAITH): %m");
780	}
781#endif
782#ifdef IPSEC
783	/* Avoid setting a policy if a policy specifier doesn't exist. */
784	if (sep->se_policy != NULL) {
785		int e = ipsecsetup(sep->se_family, sep->se_fd, sep->se_policy);
786		if (e < 0) {
787			syslog(LOG_ERR, SERV_FMT ": ipsec setup failed",
788			    SERV_PARAMS(sep));
789			(void)close(sep->se_fd);
790			sep->se_fd = -1;
791			return;
792		}
793	}
794#endif
795
796	if (bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size) < 0) {
797		DPRINTF(SERV_FMT ": bind failed: %s",
798			SERV_PARAMS(sep), strerror(errno));
799		syslog(LOG_ERR, SERV_FMT ": bind: %m",
800		    SERV_PARAMS(sep));
801		(void) close(sep->se_fd);
802		sep->se_fd = -1;
803		if (!timingout) {
804			timingout = true;
805			alarm(RETRYTIME);
806		}
807		return;
808	}
809	if (sep->se_socktype == SOCK_STREAM)
810		listen(sep->se_fd, 10);
811
812	/* Set the accept filter, if specified. To be done after listen.*/
813	if (sep->se_accf.af_name[0] != 0 && setsockopt(sep->se_fd, SOL_SOCKET,
814	    SO_ACCEPTFILTER, &sep->se_accf,
815	    (socklen_t)sizeof(sep->se_accf)) < 0)
816		syslog(LOG_ERR, "setsockopt(SO_ACCEPTFILTER %s): %m",
817		    sep->se_accf.af_name);
818
819	ev = allocchange();
820	EV_SET(ev, sep->se_fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0,
821	    (intptr_t)sep);
822	if (sep->se_fd > maxsock) {
823		maxsock = sep->se_fd;
824		if (maxsock > (int)(rlim_ofile_cur - FD_MARGIN))
825			bump_nofile();
826	}
827	DPRINTF(SERV_FMT ": registered on fd %d", SERV_PARAMS(sep), sep->se_fd);
828}
829
830/*
831 * Finish with a service and its socket.
832 */
833void
834close_sep(struct servtab *sep)
835{
836
837	if (sep->se_fd >= 0) {
838		(void) close(sep->se_fd);
839		sep->se_fd = -1;
840	}
841	sep->se_count = 0;
842	if (sep->se_ip_max != SERVTAB_UNSPEC_SIZE_T) {
843		rl_clear_ip_list(sep);
844	}
845}
846
847void
848register_rpc(struct servtab *sep)
849{
850#ifdef RPC
851	struct netbuf nbuf;
852	struct sockaddr_storage ss;
853	struct netconfig *nconf;
854	socklen_t socklen;
855	int n;
856
857	if ((nconf = getnetconfigent(sep->se_proto+4)) == NULL) {
858		syslog(LOG_ERR, "%s: getnetconfigent failed",
859		    sep->se_proto);
860		return;
861	}
862	socklen = sizeof ss;
863	if (getsockname(sep->se_fd, (struct sockaddr *)(void *)&ss, &socklen) < 0) {
864		syslog(LOG_ERR, SERV_FMT ": getsockname: %m",
865		    SERV_PARAMS(sep));
866		return;
867	}
868
869	nbuf.buf = &ss;
870	nbuf.len = ss.ss_len;
871	nbuf.maxlen = sizeof (struct sockaddr_storage);
872	for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
873		DPRINTF("rpcb_set: %u %d %s %s",
874		    sep->se_rpcprog, n, nconf->nc_netid,
875		    taddr2uaddr(nconf, &nbuf));
876		(void)rpcb_unset((unsigned int)sep->se_rpcprog, (unsigned int)n, nconf);
877		if (rpcb_set((unsigned int)sep->se_rpcprog, (unsigned int)n, nconf, &nbuf) == 0)
878			syslog(LOG_ERR, "rpcb_set: %u %d %s %s%s",
879			    sep->se_rpcprog, n, nconf->nc_netid,
880			    taddr2uaddr(nconf, &nbuf), clnt_spcreateerror(""));
881	}
882#endif /* RPC */
883}
884
885void
886unregister_rpc(struct servtab *sep)
887{
888#ifdef RPC
889	int n;
890	struct netconfig *nconf;
891
892	if ((nconf = getnetconfigent(sep->se_proto+4)) == NULL) {
893		syslog(LOG_ERR, "%s: getnetconfigent failed",
894		    sep->se_proto);
895		return;
896	}
897
898	for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
899		DPRINTF("rpcb_unset(%u, %d, %s)",
900		    sep->se_rpcprog, n, nconf->nc_netid);
901		if (rpcb_unset((unsigned int)sep->se_rpcprog, (unsigned int)n, nconf) == 0)
902			syslog(LOG_ERR, "rpcb_unset(%u, %d, %s) failed\n",
903			    sep->se_rpcprog, n, nconf->nc_netid);
904	}
905#endif /* RPC */
906}
907
908static void
909inetd_setproctitle(char *a, int s)
910{
911	socklen_t size;
912	struct sockaddr_storage ss;
913	char hbuf[NI_MAXHOST];
914	const char *hp;
915	struct sockaddr *sa;
916
917	size = sizeof(ss);
918	sa = (struct sockaddr *)(void *)&ss;
919	if (getpeername(s, sa, &size) == 0) {
920		if (getnameinfo(sa, size, hbuf, (socklen_t)sizeof(hbuf), NULL,
921		    0, niflags) != 0)
922			hp = "?";
923		else
924			hp = hbuf;
925		setproctitle("-%s [%s]", a, hp);
926	} else
927		setproctitle("-%s", a);
928}
929
930static void
931bump_nofile(void)
932{
933#define FD_CHUNK	32
934	struct rlimit rl;
935
936	if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
937		syslog(LOG_ERR, "getrlimit: %m");
938		return;
939	}
940	rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
941	if (rl.rlim_cur <= rlim_ofile_cur) {
942		syslog(LOG_ERR,
943		    "bump_nofile: cannot extend file limit, max = %d",
944		    (int)rl.rlim_cur);
945		return;
946	}
947
948	if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
949		syslog(LOG_ERR, "setrlimit: %m");
950		return;
951	}
952
953	rlim_ofile_cur = rl.rlim_cur;
954	return;
955}
956
957/*
958 * Internet services provided internally by inetd:
959 */
960#define	BUFSIZE	4096
961
962/* ARGSUSED */
963static void
964echo_stream(int s, struct servtab *sep)	/* Echo service -- echo data back */
965{
966	char buffer[BUFSIZE];
967	ssize_t i;
968
969	inetd_setproctitle(sep->se_service, s);
970	while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
971	    write(s, buffer, (size_t)i) > 0)
972		continue;
973}
974
975/* ARGSUSED */
976static void
977echo_dg(int s, struct servtab *sep)	/* Echo service -- echo data back */
978{
979	char buffer[BUFSIZE];
980	ssize_t i;
981	socklen_t size;
982	struct sockaddr_storage ss;
983	struct sockaddr *sa;
984
985	sa = (struct sockaddr *)(void *)&ss;
986	size = sizeof(ss);
987	if ((i = recvfrom(s, buffer, sizeof(buffer), 0, sa, &size)) < 0)
988		return;
989	if (port_good_dg(sa))
990		(void) sendto(s, buffer, (size_t)i, 0, sa, size);
991}
992
993/* ARGSUSED */
994static void
995discard_stream(int s, struct servtab *sep) /* Discard service -- ignore data */
996{
997	char buffer[BUFSIZE];
998
999	inetd_setproctitle(sep->se_service, s);
1000	while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
1001			errno == EINTR)
1002		;
1003}
1004
1005/* ARGSUSED */
1006static void
1007discard_dg(int s, struct servtab *sep)	/* Discard service -- ignore data */
1008
1009{
1010	char buffer[BUFSIZE];
1011
1012	(void) read(s, buffer, sizeof(buffer));
1013}
1014
1015#define LINESIZ 72
1016char ring[128];
1017char *endring;
1018
1019static void
1020initring(void)
1021{
1022	int i;
1023
1024	endring = ring;
1025
1026	for (i = 0; i <= 128; ++i)
1027		if (isprint(i))
1028			*endring++ = (char)i;
1029}
1030
1031/* ARGSUSED */
1032static void
1033chargen_stream(int s, struct servtab *sep)	/* Character generator */
1034{
1035	size_t len;
1036	char *rs, text[LINESIZ+2];
1037
1038	inetd_setproctitle(sep->se_service, s);
1039
1040	if (endring == NULL) {
1041		initring();
1042		rs = ring;
1043	}
1044
1045	text[LINESIZ] = '\r';
1046	text[LINESIZ + 1] = '\n';
1047	for (rs = ring;;) {
1048		if ((len = (size_t)(endring - rs)) >= LINESIZ)
1049			memmove(text, rs, LINESIZ);
1050		else {
1051			memmove(text, rs, len);
1052			memmove(text + len, ring, LINESIZ - len);
1053		}
1054		if (++rs == endring)
1055			rs = ring;
1056		if (write(s, text, sizeof(text)) != sizeof(text))
1057			break;
1058	}
1059}
1060
1061/* ARGSUSED */
1062static void
1063chargen_dg(int s, struct servtab *sep)		/* Character generator */
1064{
1065	struct sockaddr_storage ss;
1066	struct sockaddr *sa;
1067	static char *rs;
1068	size_t len;
1069	socklen_t size;
1070	char text[LINESIZ+2];
1071
1072	if (endring == 0) {
1073		initring();
1074		rs = ring;
1075	}
1076
1077	sa = (struct sockaddr *)(void *)&ss;
1078	size = sizeof(ss);
1079	if (recvfrom(s, text, sizeof(text), 0, sa, &size) < 0)
1080		return;
1081
1082	if (!port_good_dg(sa))
1083		return;
1084
1085	if ((len = (size_t)(endring - rs)) >= LINESIZ)
1086		memmove(text, rs, LINESIZ);
1087	else {
1088		memmove(text, rs, len);
1089		memmove(text + len, ring, LINESIZ - len);
1090	}
1091	if (++rs == endring)
1092		rs = ring;
1093	text[LINESIZ] = '\r';
1094	text[LINESIZ + 1] = '\n';
1095	(void) sendto(s, text, sizeof(text), 0, sa, size);
1096}
1097
1098/*
1099 * Return a machine readable date and time, in the form of the
1100 * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
1101 * returns the number of seconds since midnight, Jan 1, 1970,
1102 * we must add 2208988800 seconds to this figure to make up for
1103 * some seventy years Bell Labs was asleep.
1104 */
1105
1106static uint32_t
1107machtime(void)
1108{
1109	struct timeval tv;
1110
1111	if (gettimeofday(&tv, NULL) < 0) {
1112		DPRINTF("Unable to get time of day");
1113		return (0);
1114	}
1115#define	OFFSET ((uint32_t)25567 * 24*60*60)
1116	return (htonl((uint32_t)(tv.tv_sec + OFFSET)));
1117#undef OFFSET
1118}
1119
1120/* ARGSUSED */
1121static void
1122machtime_stream(int s, struct servtab *sep)
1123{
1124	uint32_t result;
1125
1126	result = machtime();
1127	(void) write(s, &result, sizeof(result));
1128}
1129
1130/* ARGSUSED */
1131void
1132machtime_dg(int s, struct servtab *sep)
1133{
1134	uint32_t result;
1135	struct sockaddr_storage ss;
1136	struct sockaddr *sa;
1137	socklen_t size;
1138
1139	sa = (struct sockaddr *)(void *)&ss;
1140	size = sizeof(ss);
1141	if (recvfrom(s, &result, sizeof(result), 0, sa, &size) < 0)
1142		return;
1143	if (!port_good_dg(sa))
1144		return;
1145	result = machtime();
1146	(void)sendto(s, &result, sizeof(result), 0, sa, size);
1147}
1148
1149/* ARGSUSED */
1150static void
1151daytime_stream(int s,struct servtab *sep)
1152/* Return human-readable time of day */
1153{
1154	char buffer[256];
1155	time_t clk;
1156	int len;
1157
1158	clk = time((time_t *) 0);
1159
1160	len = snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clk));
1161	(void) write(s, buffer, (size_t)len);
1162}
1163
1164/* ARGSUSED */
1165void
1166daytime_dg(int s, struct servtab *sep)
1167/* Return human-readable time of day */
1168{
1169	char buffer[256];
1170	time_t clk;
1171	struct sockaddr_storage ss;
1172	struct sockaddr *sa;
1173	socklen_t size;
1174	int len;
1175
1176	clk = time((time_t *) 0);
1177
1178	sa = (struct sockaddr *)(void *)&ss;
1179	size = sizeof(ss);
1180	if (recvfrom(s, buffer, sizeof(buffer), 0, sa, &size) < 0)
1181		return;
1182	if (!port_good_dg(sa))
1183		return;
1184	len = snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clk));
1185	(void) sendto(s, buffer, (size_t)len, 0, sa, size);
1186}
1187
1188static void
1189usage(void)
1190{
1191#ifdef LIBWRAP
1192	(void)fprintf(stderr, "usage: %s [-dl] [conf]\n", getprogname());
1193#else
1194	(void)fprintf(stderr, "usage: %s [-d] [conf]\n", getprogname());
1195#endif
1196	exit(EXIT_FAILURE);
1197}
1198
1199
1200/*
1201 *  Based on TCPMUX.C by Mark K. Lottor November 1988
1202 *  sri-nic::ps:<mkl>tcpmux.c
1203 */
1204
1205static int		/* # of characters upto \r,\n or \0 */
1206get_line(int fd,	char *buf, int len)
1207{
1208	int count = 0;
1209	ssize_t n;
1210
1211	do {
1212		n = read(fd, buf, (size_t)(len - count));
1213		if (n == 0)
1214			return (count);
1215		if (n < 0)
1216			return (-1);
1217		while (--n >= 0) {
1218			if (*buf == '\r' || *buf == '\n' || *buf == '\0')
1219				return (count);
1220			count++;
1221			buf++;
1222		}
1223	} while (count < len);
1224	return (count);
1225}
1226
1227#define MAX_SERV_LEN	(256+2)		/* 2 bytes for \r\n */
1228
1229#define strwrite(fd, buf)	(void) write(fd, buf, sizeof(buf)-1)
1230
1231static void
1232tcpmux(int ctrl, struct servtab *sep)
1233{
1234	char service[MAX_SERV_LEN+1];
1235	int len;
1236
1237	/* Get requested service name */
1238	if ((len = get_line(ctrl, service, MAX_SERV_LEN)) < 0) {
1239		strwrite(ctrl, "-Error reading service name\r\n");
1240		goto reject;
1241	}
1242	service[len] = '\0';
1243
1244	DPRINTF("tcpmux: %s: service requested", service);
1245
1246	/*
1247	 * Help is a required command, and lists available services,
1248	 * one per line.
1249	 */
1250	if (strcasecmp(service, "help") == 0) {
1251		strwrite(ctrl, "+Available services:\r\n");
1252		strwrite(ctrl, "help\r\n");
1253		for (sep = servtab; sep != NULL; sep = sep->se_next) {
1254			if (!ISMUX(sep))
1255				continue;
1256			(void)write(ctrl, sep->se_service,
1257			    strlen(sep->se_service));
1258			strwrite(ctrl, "\r\n");
1259		}
1260		goto reject;
1261	}
1262
1263	/* Try matching a service in inetd.conf with the request */
1264	for (sep = servtab; sep != NULL; sep = sep->se_next) {
1265		if (!ISMUX(sep))
1266			continue;
1267		if (strcasecmp(service, sep->se_service) == 0) {
1268			if (ISMUXPLUS(sep))
1269				strwrite(ctrl, "+Go\r\n");
1270			run_service(ctrl, sep, true /* forked */);
1271			return;
1272		}
1273	}
1274	strwrite(ctrl, "-Service not available\r\n");
1275reject:
1276	_exit(EXIT_FAILURE);
1277}
1278
1279/*
1280 * check if the address/port where send data to is one of the obvious ports
1281 * that are used for denial of service attacks like two echo ports
1282 * just echoing data between them
1283 */
1284static int
1285port_good_dg(struct sockaddr *sa)
1286{
1287	struct in_addr in;
1288	struct sockaddr_in *sin;
1289#ifdef INET6
1290	struct in6_addr *in6;
1291	struct sockaddr_in6 *sin6;
1292#endif
1293	u_int16_t port;
1294	int i;
1295	char hbuf[NI_MAXHOST];
1296
1297	switch (sa->sa_family) {
1298	case AF_INET:
1299		sin = (struct sockaddr_in *)(void *)sa;
1300		in.s_addr = ntohl(sin->sin_addr.s_addr);
1301		port = ntohs(sin->sin_port);
1302#ifdef INET6
1303	v4chk:
1304#endif
1305		if (IN_MULTICAST(in.s_addr))
1306			goto bad;
1307		switch ((in.s_addr & 0xff000000) >> 24) {
1308		case 0: case 127: case 255:
1309			goto bad;
1310		}
1311		if (dg_broadcast(&in))
1312			goto bad;
1313		break;
1314#ifdef INET6
1315	case AF_INET6:
1316		sin6 = (struct sockaddr_in6 *)(void *)sa;
1317		in6 = &sin6->sin6_addr;
1318		port = ntohs(sin6->sin6_port);
1319		if (IN6_IS_ADDR_MULTICAST(in6) || IN6_IS_ADDR_UNSPECIFIED(in6))
1320			goto bad;
1321		if (IN6_IS_ADDR_V4MAPPED(in6) || IN6_IS_ADDR_V4COMPAT(in6)) {
1322			memcpy(&in, &in6->s6_addr[12], sizeof(in));
1323			in.s_addr = ntohl(in.s_addr);
1324			goto v4chk;
1325		}
1326		break;
1327#endif
1328	default:
1329		/* XXX unsupported af, is it safe to assume it to be safe? */
1330		return true;
1331	}
1332
1333	for (i = 0; bad_ports[i] != 0; i++) {
1334		if (port == bad_ports[i])
1335			goto bad;
1336	}
1337
1338	return true;
1339
1340bad:
1341	if (getnameinfo(sa, sa->sa_len, hbuf, (socklen_t)sizeof(hbuf), NULL, 0,
1342	    niflags) != 0)
1343		strlcpy(hbuf, "?", sizeof(hbuf));
1344	syslog(LOG_WARNING,"Possible DoS attack from %s, Port %d",
1345		hbuf, port);
1346	return false;
1347}
1348
1349/* XXX need optimization */
1350static int
1351dg_broadcast(struct in_addr *in)
1352{
1353	struct ifaddrs *ifa, *ifap;
1354	struct sockaddr_in *sin;
1355
1356	if (getifaddrs(&ifap) < 0)
1357		return false;
1358	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
1359		if (ifa->ifa_addr->sa_family != AF_INET ||
1360		    (ifa->ifa_flags & IFF_BROADCAST) == 0)
1361			continue;
1362		sin = (struct sockaddr_in *)(void *)ifa->ifa_broadaddr;
1363		if (sin->sin_addr.s_addr == in->s_addr) {
1364			freeifaddrs(ifap);
1365			return true;
1366		}
1367	}
1368	freeifaddrs(ifap);
1369	return false;
1370}
1371
1372static int
1373my_kevent(const struct kevent *changelist, size_t nchanges,
1374    struct kevent *eventlist, size_t nevents)
1375{
1376	int	result;
1377
1378	while ((result = kevent(kq, changelist, nchanges, eventlist, nevents,
1379	    NULL)) < 0)
1380		if (errno != EINTR) {
1381			syslog(LOG_ERR, "kevent: %m");
1382			exit(EXIT_FAILURE);
1383		}
1384
1385	return (result);
1386}
1387
1388static struct kevent *
1389allocchange(void)
1390{
1391	if (changes == __arraycount(changebuf)) {
1392		(void) my_kevent(changebuf, __arraycount(changebuf), NULL, 0);
1393		changes = 0;
1394	}
1395
1396	return (&changebuf[changes++]);
1397}
1398
1399bool
1400try_biltin(struct servtab *sep)
1401{
1402	for(size_t i = 0; i < __arraycount(biltins); i++) {
1403		if (biltins[i].bi_socktype == sep->se_socktype &&
1404		    strcmp(biltins[i].bi_service, sep->se_service) == 0) {
1405			sep->se_bi = &biltins[i];
1406			sep->se_wait = biltins[i].bi_wait;
1407			return true;
1408		}
1409	}
1410	return false;
1411}
1412