1/*	$NetBSD: faithd.c,v 1.35 2011/09/16 15:39:37 joerg Exp $	*/
2/*	$KAME: faithd.c,v 1.62 2003/08/19 21:20:33 itojun Exp $	*/
3
4/*
5 * Copyright (C) 1997 and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33/*
34 * User level translator from IPv6 to IPv4.
35 *
36 * Usage: faithd [<port> <progpath> <arg1(progname)> <arg2> ...]
37 *   e.g. faithd telnet /usr/local/v6/sbin/telnetd telnetd
38 */
39
40#include <sys/cdefs.h>
41#include <sys/param.h>
42#include <sys/types.h>
43#include <sys/sysctl.h>
44#include <sys/socket.h>
45#include <sys/wait.h>
46#include <sys/stat.h>
47#include <sys/time.h>
48#include <sys/ioctl.h>
49
50#include <poll.h>
51#include <stdio.h>
52#include <stdlib.h>
53#include <stdarg.h>
54#include <string.h>
55#include <syslog.h>
56#include <unistd.h>
57#include <errno.h>
58#include <signal.h>
59#include <fcntl.h>
60#include <termios.h>
61
62#include <net/if_types.h>
63#ifdef IFT_FAITH
64# define USE_ROUTE
65# include <net/if.h>
66# include <net/route.h>
67# include <net/if_dl.h>
68#endif
69
70#include <netinet/in.h>
71#include <arpa/inet.h>
72#include <netdb.h>
73#include <ifaddrs.h>
74
75#include "faithd.h"
76#include "prefix.h"
77
78char *serverpath = NULL;
79char *serverarg[MAXARGV + 1];
80char logname[BUFSIZ];
81char procname[BUFSIZ];
82struct myaddrs {
83	struct myaddrs *next;
84	struct sockaddr *addr;
85};
86struct myaddrs *myaddrs = NULL;
87static const char *service;
88#ifdef USE_ROUTE
89static int sockfd = 0;
90#endif
91int dflag = 0;
92static int pflag = 0;
93static int inetd = 0;
94static char *configfile = NULL;
95
96static int inetd_main(int, char **);
97static int daemon_main(int, char **);
98static void play_service(int) __dead;
99static void play_child(int, struct sockaddr *) __dead;
100static int faith_prefix(struct sockaddr *);
101static int map6to4(struct sockaddr_in6 *, struct sockaddr_in *);
102static void sig_child(int);
103static void sig_terminate(int) __dead;
104static void start_daemon(void);
105static void exit_stderr(const char *, ...) __printflike(1, 2) __dead;
106static void grab_myaddrs(void);
107static void free_myaddrs(void);
108static void update_myaddrs(void);
109static void usage(void) __dead;
110
111int
112main(int argc, char **argv)
113{
114
115	/*
116	 * Initializing stuff
117	 */
118
119	setprogname(argv[0]);
120
121	if (strcmp(getprogname(), "faithd") != 0) {
122		inetd = 1;
123		return inetd_main(argc, argv);
124	} else
125		return daemon_main(argc, argv);
126}
127
128static int
129inetd_main(int argc, char **argv)
130{
131	char path[MAXPATHLEN];
132	struct sockaddr_storage me;
133	struct sockaddr_storage from;
134	socklen_t melen, fromlen;
135	int i;
136	int error;
137	const int on = 1;
138	char sbuf[NI_MAXSERV], snum[NI_MAXSERV];
139
140	if (config_load(configfile) < 0 && configfile) {
141		exit_failure("could not load config file");
142		/*NOTREACHED*/
143	}
144
145	if (strrchr(argv[0], '/') == NULL)
146		(void)snprintf(path, sizeof(path), "%s/%s", DEFAULT_DIR,
147		    argv[0]);
148	else
149		(void)snprintf(path, sizeof(path), "%s", argv[0]);
150
151#ifdef USE_ROUTE
152	grab_myaddrs();
153
154	sockfd = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC);
155	if (sockfd < 0) {
156		exit_failure("socket(PF_ROUTE): %s", strerror(errno));
157		/*NOTREACHED*/
158	}
159#endif
160
161	melen = sizeof(me);
162	if (getsockname(STDIN_FILENO, (void *)&me, &melen) == -1) {
163		exit_failure("getsockname: %s", strerror(errno));
164		/*NOTREACHED*/
165	}
166	fromlen = sizeof(from);
167	if (getpeername(STDIN_FILENO, (void *)&from, &fromlen) == -1) {
168		exit_failure("getpeername: %s", strerror(errno));
169		/*NOTREACHED*/
170	}
171	if (getnameinfo((void *)&me, melen, NULL, 0,
172	    sbuf, (socklen_t)sizeof(sbuf), NI_NUMERICHOST) == 0)
173		service = sbuf;
174	else
175		service = DEFAULT_PORT_NAME;
176	if (getnameinfo((void *)&me, melen, NULL, 0,
177	    snum, (socklen_t)sizeof(snum), NI_NUMERICHOST) != 0)
178		(void)snprintf(snum, sizeof(snum), "?");
179
180	(void)snprintf(logname, sizeof(logname), "faithd %s", snum);
181	(void)snprintf(procname, sizeof(procname), "accepting port %s", snum);
182	openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
183
184	if (argc >= MAXARGV) {
185		exit_failure("too many arguments");
186		/*NOTREACHED*/
187	}
188	serverarg[0] = serverpath = path;
189	for (i = 1; i < argc; i++)
190		serverarg[i] = argv[i];
191	serverarg[i] = NULL;
192
193	error = setsockopt(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE, &on,
194	    (socklen_t)sizeof(on));
195	if (error < 0) {
196		exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno));
197		/*NOTREACHED*/
198	}
199
200	play_child(STDIN_FILENO, (void *)&from);
201	exit_failure("should not reach here");
202	return 0;	/*dummy!*/
203}
204
205static int
206daemon_main(int argc, char **argv)
207{
208	struct addrinfo hints, *res;
209	int s_wld, error, i, serverargc, on = 1;
210	int family = AF_INET6;
211	int c;
212
213	while ((c = getopt(argc, argv, "df:p")) != -1) {
214		switch (c) {
215		case 'd':
216			dflag++;
217			break;
218		case 'f':
219			configfile = optarg;
220			break;
221		case 'p':
222			pflag++;
223			break;
224		default:
225			usage();
226			/*NOTREACHED*/
227		}
228	}
229	argc -= optind;
230	argv += optind;
231
232	if (config_load(configfile) < 0 && configfile) {
233		exit_failure("could not load config file");
234		/*NOTREACHED*/
235	}
236
237
238#ifdef USE_ROUTE
239	grab_myaddrs();
240#endif
241
242	switch (argc) {
243	case 0:
244		usage();
245		/*NOTREACHED*/
246	default:
247		serverargc = argc - NUMARG;
248		if (serverargc >= MAXARGV)
249			exit_stderr("too many arguments");
250
251		serverpath = strdup(argv[NUMPRG]);
252		if (!serverpath)
253			exit_stderr("not enough core");
254		for (i = 0; i < serverargc; i++) {
255			serverarg[i] = strdup(argv[i + NUMARG]);
256			if (!serverarg[i])
257				exit_stderr("not enough core");
258		}
259		serverarg[i] = NULL;
260		/*FALLTHROUGH*/
261	case 1:	/* no local service */
262		service = argv[NUMPRT];
263		break;
264	}
265
266	start_daemon();
267
268	/*
269	 * Opening wild card socket for this service.
270	 */
271
272	memset(&hints, 0, sizeof(hints));
273	hints.ai_flags = AI_PASSIVE;
274	hints.ai_family = family;
275	hints.ai_socktype = SOCK_STREAM;
276	hints.ai_protocol = IPPROTO_TCP;	/* SCTP? */
277	error = getaddrinfo(NULL, service, &hints, &res);
278	if (error)
279		exit_failure("getaddrinfo: %s", gai_strerror(error));
280
281	s_wld = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
282	if (s_wld == -1)
283		exit_failure("socket: %s", strerror(errno));
284
285#ifdef IPV6_FAITH
286	if (res->ai_family == AF_INET6) {
287		error = setsockopt(s_wld, IPPROTO_IPV6, IPV6_FAITH, &on,
288		    (socklen_t)sizeof(on));
289		if (error == -1)
290			exit_failure("setsockopt(IPV6_FAITH): %s",
291			    strerror(errno));
292	}
293#endif
294
295	error = setsockopt(s_wld, SOL_SOCKET, SO_REUSEADDR, &on,
296	    (socklen_t)sizeof(on));
297	if (error == -1)
298		exit_failure("setsockopt(SO_REUSEADDR): %s", strerror(errno));
299
300	error = setsockopt(s_wld, SOL_SOCKET, SO_OOBINLINE, &on,
301	    (socklen_t)sizeof(on));
302	if (error == -1)
303		exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno));
304
305#ifdef IPV6_V6ONLY
306	error = setsockopt(s_wld, IPPROTO_IPV6, IPV6_V6ONLY, &on,
307	    (socklen_t)sizeof(on));
308	if (error == -1)
309		exit_failure("setsockopt(IPV6_V6ONLY): %s", strerror(errno));
310#endif
311
312	error = bind(s_wld, (struct sockaddr *)res->ai_addr, res->ai_addrlen);
313	if (error == -1)
314		exit_failure("bind: %s", strerror(errno));
315
316	error = listen(s_wld, 5);
317	if (error == -1)
318		exit_failure("listen: %s", strerror(errno));
319
320#ifdef USE_ROUTE
321	sockfd = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC);
322	if (sockfd < 0) {
323		exit_failure("socket(PF_ROUTE): %s", strerror(errno));
324		/*NOTREACHED*/
325	}
326#endif
327
328	/*
329	 * Everything is OK.
330	 */
331
332	(void)snprintf(logname, sizeof(logname), "faithd %s", service);
333	(void)snprintf(procname, sizeof(procname), "accepting port %s", service);
334	openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
335	syslog(LOG_INFO, "Staring faith daemon for %s port", service);
336
337	play_service(s_wld);
338	return 1;
339}
340
341static void
342play_service(int s_wld)
343{
344	struct sockaddr_storage srcaddr;
345	socklen_t len;
346	int s_src;
347	pid_t child_pid;
348	struct pollfd pfd[2];
349	int error;
350
351	/*
352	 * Wait, accept, fork, faith....
353	 */
354again:
355	setproctitle("%s", procname);
356
357	pfd[0].fd = s_wld;
358	pfd[0].events = POLLIN;
359	pfd[1].fd = -1;
360	pfd[1].revents = 0;
361#ifdef USE_ROUTE
362	if (sockfd) {
363		pfd[1].fd = sockfd;
364		pfd[1].events = POLLIN;
365	}
366#endif
367
368	error = poll(pfd, (unsigned int)(sizeof(pfd) / sizeof(pfd[0])), INFTIM);
369	if (error < 0) {
370		if (errno == EINTR)
371			goto again;
372		exit_failure("select: %s", strerror(errno));
373		/*NOTREACHED*/
374	}
375
376#ifdef USE_ROUTE
377	if (pfd[1].revents & POLLIN)
378	{
379		update_myaddrs();
380	}
381#endif
382	if (pfd[0].revents & POLLIN)
383	{
384		len = sizeof(srcaddr);
385		s_src = accept(s_wld, (void *)&srcaddr, &len);
386		if (s_src < 0) {
387			if (errno == ECONNABORTED)
388				goto again;
389			exit_failure("socket: %s", strerror(errno));
390			/*NOTREACHED*/
391		}
392		if (srcaddr.ss_family == AF_INET6 &&
393		    IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)(void *)&srcaddr)->sin6_addr)) {
394			(void)close(s_src);
395			syslog(LOG_ERR, "connection from IPv4 mapped address?");
396			goto again;
397		}
398
399		child_pid = fork();
400
401		if (child_pid == 0) {
402			/* child process */
403			(void)close(s_wld);
404			closelog();
405			openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
406			play_child(s_src, (void *)&srcaddr);
407			exit_failure("should never reach here");
408			/*NOTREACHED*/
409		} else {
410			/* parent process */
411			(void)close(s_src);
412			if (child_pid == -1)
413				syslog(LOG_ERR, "can't fork");
414		}
415	}
416	goto again;
417}
418
419static void
420play_child(int s_src, struct sockaddr *srcaddr)
421{
422	struct sockaddr_storage dstaddr6;
423	struct sockaddr_storage dstaddr4;
424	char src[NI_MAXHOST];
425	char dst6[NI_MAXHOST];
426	char dst4[NI_MAXHOST];
427	socklen_t len = sizeof(dstaddr6);
428	int s_dst, error, hport, nresvport, on = 1;
429	struct timeval tv;
430	struct sockaddr *sa4;
431	const struct config *conf;
432
433	tv.tv_sec = 1;
434	tv.tv_usec = 0;
435
436	(void)getnameinfo(srcaddr, (socklen_t)srcaddr->sa_len,
437	    src, (socklen_t)sizeof(src), NULL, 0, NI_NUMERICHOST);
438	syslog(LOG_INFO, "accepted a client from %s", src);
439
440	error = getsockname(s_src, (void *)&dstaddr6, &len);
441	if (error == -1) {
442		exit_failure("getsockname: %s", strerror(errno));
443		/*NOTREACHED*/
444	}
445
446	(void)getnameinfo((void *)&dstaddr6, len,
447	    dst6, (socklen_t)sizeof(dst6), NULL, 0, NI_NUMERICHOST);
448	syslog(LOG_INFO, "the client is connecting to %s", dst6);
449
450	if (!faith_prefix((void *)&dstaddr6)) {
451		if (serverpath) {
452			/*
453			 * Local service
454			 */
455			syslog(LOG_INFO, "executing local %s", serverpath);
456			if (!inetd) {
457				(void)dup2(s_src, 0);
458				(void)close(s_src);
459				(void)dup2(0, 1);
460				(void)dup2(0, 2);
461			}
462			(void)execv(serverpath, serverarg);
463			syslog(LOG_ERR, "execv %s: %s", serverpath,
464			    strerror(errno));
465			_exit(EXIT_FAILURE);
466		} else {
467			(void)close(s_src);
468			exit_success("no local service for %s", service);
469		}
470	}
471
472	/*
473	 * Act as a translator
474	 */
475
476	switch (((struct sockaddr *)(void *)&dstaddr6)->sa_family) {
477	case AF_INET6:
478		if (!map6to4((struct sockaddr_in6 *)(void *)&dstaddr6,
479		    (struct sockaddr_in *)(void *)&dstaddr4)) {
480			(void)close(s_src);
481			exit_failure("map6to4 failed");
482			/*NOTREACHED*/
483		}
484		syslog(LOG_INFO, "translating from v6 to v4");
485		break;
486	default:
487		(void)close(s_src);
488		exit_failure("family not supported");
489		/*NOTREACHED*/
490	}
491
492	sa4 = (void *)&dstaddr4;
493	(void)getnameinfo(sa4, (socklen_t)sa4->sa_len,
494	    dst4, (socklen_t)sizeof(dst4), NULL, 0, NI_NUMERICHOST);
495
496	conf = config_match(srcaddr, sa4);
497	if (!conf || !conf->permit) {
498		(void)close(s_src);
499		if (conf) {
500			exit_failure("translation to %s not permitted for %s",
501			    dst4, prefix_string(&conf->match));
502			/*NOTREACHED*/
503		} else {
504			exit_failure("translation to %s not permitted", dst4);
505			/*NOTREACHED*/
506		}
507	}
508
509	syslog(LOG_INFO, "the translator is connecting to %s", dst4);
510
511	setproctitle("port %s, %s -> %s", service, src, dst4);
512
513	if (sa4->sa_family == AF_INET6)
514		hport = ntohs(((struct sockaddr_in6 *)(void *)&dstaddr4)->sin6_port);
515	else /* AF_INET */
516		hport = ntohs(((struct sockaddr_in *)(void *)&dstaddr4)->sin_port);
517
518	if (pflag)
519		s_dst = rresvport_af(&nresvport, sa4->sa_family);
520	else
521		s_dst = socket(sa4->sa_family, SOCK_STREAM, 0);
522	if (s_dst < 0) {
523		exit_failure("socket: %s", strerror(errno));
524		/*NOTREACHED*/
525	}
526
527	if (conf->src.a.ss_family) {
528		if (bind(s_dst, (const void*)&conf->src.a,
529		    (socklen_t)conf->src.a.ss_len) < 0) {
530			exit_failure("bind: %s", strerror(errno));
531			/*NOTREACHED*/
532		}
533	}
534
535	error = setsockopt(s_dst, SOL_SOCKET, SO_OOBINLINE, &on,
536	    (socklen_t)sizeof(on));
537	if (error < 0) {
538		exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno));
539		/*NOTREACHED*/
540	}
541
542	error = setsockopt(s_src, SOL_SOCKET, SO_SNDTIMEO, &tv,
543	    (socklen_t)sizeof(tv));
544	if (error < 0) {
545		exit_failure("setsockopt(SO_SNDTIMEO): %s", strerror(errno));
546		/*NOTREACHED*/
547	}
548	error = setsockopt(s_dst, SOL_SOCKET, SO_SNDTIMEO, &tv,
549	    (socklen_t)sizeof(tv));
550	if (error < 0) {
551		exit_failure("setsockopt(SO_SNDTIMEO): %s", strerror(errno));
552		/*NOTREACHED*/
553	}
554
555	error = connect(s_dst, sa4, (socklen_t)sa4->sa_len);
556	if (error < 0) {
557		exit_failure("connect: %s", strerror(errno));
558		/*NOTREACHED*/
559	}
560
561	switch (hport) {
562	case FTP_PORT:
563		ftp_relay(s_src, s_dst);
564		break;
565	default:
566		tcp_relay(s_src, s_dst, service);
567		break;
568	}
569
570	/* NOTREACHED */
571}
572
573/* 0: non faith, 1: faith */
574static int
575faith_prefix(struct sockaddr *dst)
576{
577#ifndef USE_ROUTE
578	int mib[4], size;
579	struct in6_addr faith_prefix;
580	struct sockaddr_in6 *dst6 = (struct sockaddr_in *)dst;
581
582	if (dst->sa_family != AF_INET6)
583		return 0;
584
585	mib[0] = CTL_NET;
586	mib[1] = PF_INET6;
587	mib[2] = IPPROTO_IPV6;
588	mib[3] = IPV6CTL_FAITH_PREFIX;
589	size = sizeof(struct in6_addr);
590	if (sysctl(mib, 4, &faith_prefix, &size, NULL, 0) < 0) {
591		exit_failure("sysctl: %s", strerror(errno));
592		/*NOTREACHED*/
593	}
594
595	return memcmp(dst, &faith_prefix,
596	    sizeof(struct in6_addr) - sizeof(struct in_addr)) == 0;
597#else
598	struct myaddrs *p;
599	struct sockaddr_in6 *sin6;
600	struct sockaddr_in *sin4;
601	struct sockaddr_in6 *dst6;
602	struct sockaddr_in *dst4;
603	struct sockaddr_in dstmap;
604
605	dst6 = (void *)dst;
606	if (dst->sa_family == AF_INET6
607	 && IN6_IS_ADDR_V4MAPPED(&dst6->sin6_addr)) {
608		/* ugly... */
609		memset(&dstmap, 0, sizeof(dstmap));
610		dstmap.sin_family = AF_INET;
611		dstmap.sin_len = sizeof(dstmap);
612		memcpy(&dstmap.sin_addr, &dst6->sin6_addr.s6_addr[12],
613			sizeof(dstmap.sin_addr));
614		dst = (void *)&dstmap;
615	}
616
617	dst6 = (void *)dst;
618	dst4 = (void *)dst;
619
620	for (p = myaddrs; p; p = p->next) {
621		sin6 = (void *)p->addr;
622		sin4 = (void *)p->addr;
623
624		if (p->addr->sa_len != dst->sa_len
625		 || p->addr->sa_family != dst->sa_family)
626			continue;
627
628		switch (dst->sa_family) {
629		case AF_INET6:
630			if (sin6->sin6_scope_id == dst6->sin6_scope_id
631			 && IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &dst6->sin6_addr))
632				return 0;
633			break;
634		case AF_INET:
635			if (sin4->sin_addr.s_addr == dst4->sin_addr.s_addr)
636				return 0;
637			break;
638		}
639	}
640	return 1;
641#endif
642}
643
644/* 0: non faith, 1: faith */
645static int
646map6to4(struct sockaddr_in6 *dst6, struct sockaddr_in *dst4)
647{
648	memset(dst4, 0, sizeof(*dst4));
649	dst4->sin_len = sizeof(*dst4);
650	dst4->sin_family = AF_INET;
651	dst4->sin_port = dst6->sin6_port;
652	memcpy(&dst4->sin_addr, &dst6->sin6_addr.s6_addr[12],
653		sizeof(dst4->sin_addr));
654
655	if (dst4->sin_addr.s_addr == INADDR_ANY
656	 || dst4->sin_addr.s_addr == INADDR_BROADCAST
657	 || IN_MULTICAST(ntohl(dst4->sin_addr.s_addr)))
658		return 0;
659
660	return 1;
661}
662
663
664static void
665/*ARGSUSED*/
666sig_child(int sig)
667{
668	int status;
669	pid_t pid;
670
671	while ((pid = wait3(&status, WNOHANG, (struct rusage *)0)) > 0)
672		if (WEXITSTATUS(status))
673			syslog(LOG_WARNING, "child %ld exit status 0x%x",
674			    (long)pid, status);
675}
676
677static void
678/*ARGSUSED*/
679sig_terminate(int sig)
680{
681	syslog(LOG_INFO, "Terminating faith daemon");
682	exit(EXIT_SUCCESS);
683}
684
685static void
686start_daemon(void)
687{
688#ifdef SA_NOCLDWAIT
689	struct sigaction sa;
690#endif
691
692	if (daemon(0, 0) == -1)
693		exit_stderr("daemon: %s", strerror(errno));
694
695#ifdef SA_NOCLDWAIT
696	(void)memset(&sa, 0, sizeof(sa));
697	sa.sa_handler = sig_child;
698	sa.sa_flags = SA_NOCLDWAIT;
699	(void)sigemptyset(&sa.sa_mask);
700	(void)sigaction(SIGCHLD, &sa, (struct sigaction *)0);
701#else
702	if (signal(SIGCHLD, sig_child) == SIG_ERR) {
703		exit_failure("signal CHLD: %s", strerror(errno));
704		/*NOTREACHED*/
705	}
706#endif
707
708	if (signal(SIGTERM, sig_terminate) == SIG_ERR) {
709		exit_failure("signal TERM: %s", strerror(errno));
710		/*NOTREACHED*/
711	}
712}
713
714static void
715exit_stderr(const char *fmt, ...)
716{
717	va_list ap;
718
719	va_start(ap, fmt);
720	(void)fprintf(stderr, "%s: ", getprogname());
721	(void)vfprintf(stderr, fmt, ap);
722	va_end(ap);
723	exit(EXIT_FAILURE);
724}
725
726void
727exit_failure(const char *fmt, ...)
728{
729	va_list ap;
730
731	va_start(ap, fmt);
732	vsyslog(LOG_ERR, fmt, ap);
733	va_end(ap);
734	exit(EXIT_FAILURE);
735}
736
737void
738exit_success(const char *fmt, ...)
739{
740	va_list ap;
741
742	va_start(ap, fmt);
743	vsyslog(LOG_INFO, fmt, ap);
744	va_end(ap);
745	exit(EXIT_SUCCESS);
746}
747
748#ifdef USE_ROUTE
749static void
750grab_myaddrs(void)
751{
752	struct ifaddrs *ifap, *ifa;
753	struct myaddrs *p;
754
755	if (getifaddrs(&ifap) != 0) {
756		exit_failure("getifaddrs");
757		/*NOTREACHED*/
758	}
759
760	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
761		switch (ifa->ifa_addr->sa_family) {
762		case AF_INET:
763		case AF_INET6:
764			break;
765		default:
766			continue;
767		}
768
769		p = (struct myaddrs *)malloc(sizeof(struct myaddrs) +
770		    ifa->ifa_addr->sa_len);
771		if (!p) {
772			exit_failure("not enough core");
773			/*NOTREACHED*/
774		}
775		memcpy(p + 1, ifa->ifa_addr, ifa->ifa_addr->sa_len);
776		p->next = myaddrs;
777		p->addr = (void *)(p + 1);
778		if (ifa->ifa_addr->sa_family == AF_INET6) {
779			struct sockaddr_in6 *sin6 = (void *)p->addr;
780			inet6_getscopeid(sin6, INET6_IS_ADDR_LINKLOCAL|
781				INET6_IS_ADDR_SITELOCAL);
782		}
783		myaddrs = p;
784		if (dflag) {
785			char hbuf[NI_MAXHOST];
786			(void)getnameinfo(p->addr, (socklen_t)p->addr->sa_len,
787			    hbuf, (socklen_t)sizeof(hbuf), NULL, 0,
788			    NI_NUMERICHOST);
789			syslog(LOG_INFO, "my interface: %s %s", hbuf,
790			    ifa->ifa_name);
791		}
792	}
793
794	freeifaddrs(ifap);
795}
796
797static void
798free_myaddrs(void)
799{
800	struct myaddrs *p, *q;
801
802	p = myaddrs;
803	while (p) {
804		q = p->next;
805		free(p);
806		p = q;
807	}
808	myaddrs = NULL;
809}
810
811static void
812update_myaddrs(void)
813{
814	char msg[BUFSIZ];
815	ssize_t len;
816	struct rt_msghdr *rtm;
817
818	len = read(sockfd, msg, sizeof(msg));
819	if (len < 0) {
820		syslog(LOG_ERR, "read(PF_ROUTE) failed");
821		return;
822	}
823	rtm = (void *)msg;
824	if (len < 4 || len < rtm->rtm_msglen) {
825		syslog(LOG_ERR, "read(PF_ROUTE) short read");
826		return;
827	}
828	if (rtm->rtm_version != RTM_VERSION) {
829		syslog(LOG_ERR, "routing socket version mismatch");
830		(void)close(sockfd);
831		sockfd = 0;
832		return;
833	}
834	switch (rtm->rtm_type) {
835	case RTM_NEWADDR:
836	case RTM_DELADDR:
837	case RTM_IFINFO:
838		break;
839	default:
840		return;
841	}
842	/* XXX more filters here? */
843
844	syslog(LOG_INFO, "update interface address list");
845	free_myaddrs();
846	grab_myaddrs();
847}
848#endif /*USE_ROUTE*/
849
850static void
851usage(void)
852{
853	(void)fprintf(stderr,
854	    "Usage: %s [-dp] [-f conf] service [serverpath [serverargs]]\n",
855	    getprogname());
856	exit(0);
857}
858