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