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