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