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