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