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