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