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