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