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