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