1 /* $NetBSD: faithd.c,v 1.31 2003/10/16 05:25:51 itojun Exp $ */
2 /* $KAME: faithd.c,v 1.62 2003/08/19 21:20:33 itojun Exp $ */
5 * Copyright (C) 1997 and 1998 WIDE Project.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
34 * User level translator from IPv6 to IPv4.
36 * Usage: faithd [<port> <progpath> <arg1(progname)> <arg2> ...]
37 * e.g. faithd telnet /usr/local/v6/sbin/telnetd telnetd
40 #include <sys/cdefs.h>
41 #include <sys/param.h>
42 #include <sys/types.h>
43 #include <sys/sysctl.h>
44 #include <sys/socket.h>
48 #include <sys/ioctl.h>
62 #include <net/if_types.h>
66 # include <net/route.h>
67 # include <net/if_dl.h>
70 #include <netinet/in.h>
71 #include <arpa/inet.h>
78 char *serverpath
= NULL
;
79 char *serverarg
[MAXARGV
+ 1];
80 static char *faithdname
= NULL
;
82 char procname
[BUFSIZ
];
85 struct sockaddr
*addr
;
87 struct myaddrs
*myaddrs
= NULL
;
88 static const char *service
;
90 static int sockfd
= 0;
95 static char *configfile
= NULL
;
97 int main
__P((int, char **));
98 static int inetd_main
__P((int, char **));
99 static int daemon_main
__P((int, char **));
100 static void play_service
__P((int));
101 static void play_child
__P((int, struct sockaddr
*));
102 static int faith_prefix
__P((struct sockaddr
*));
103 static int map6to4
__P((struct sockaddr_in6
*, struct sockaddr_in
*));
104 static void sig_child
__P((int));
105 static void sig_terminate
__P((int));
106 static void start_daemon
__P((void));
107 static void exit_stderr
__P((const char *, ...))
108 __attribute__((__format__(__printf__
, 1, 2)));
109 static void grab_myaddrs
__P((void));
110 static void free_myaddrs
__P((void));
111 static void update_myaddrs
__P((void));
112 static void usage
__P((void));
115 main(int argc
, char **argv
)
122 faithdname
= strrchr(argv
[0], '/');
126 faithdname
= argv
[0];
128 if (strcmp(faithdname
, "faithd") != 0) {
130 return inetd_main(argc
, argv
);
132 return daemon_main(argc
, argv
);
136 inetd_main(int argc
, char **argv
)
138 char path
[MAXPATHLEN
];
139 struct sockaddr_storage me
;
140 struct sockaddr_storage from
;
141 socklen_t melen
, fromlen
;
145 char sbuf
[NI_MAXSERV
], snum
[NI_MAXSERV
];
147 if (config_load(configfile
) < 0 && configfile
) {
148 exit_failure("could not load config file");
152 if (strrchr(argv
[0], '/') == NULL
)
153 snprintf(path
, sizeof(path
), "%s/%s", DEFAULT_DIR
, argv
[0]);
155 snprintf(path
, sizeof(path
), "%s", argv
[0]);
160 sockfd
= socket(PF_ROUTE
, SOCK_RAW
, PF_UNSPEC
);
162 exit_failure("socket(PF_ROUTE): %s", strerror(errno
));
168 if (getsockname(STDIN_FILENO
, (struct sockaddr
*)&me
, &melen
) < 0) {
169 exit_failure("getsockname: %s", strerror(errno
));
172 fromlen
= sizeof(from
);
173 if (getpeername(STDIN_FILENO
, (struct sockaddr
*)&from
, &fromlen
) < 0) {
174 exit_failure("getpeername: %s", strerror(errno
));
177 if (getnameinfo((struct sockaddr
*)&me
, melen
, NULL
, 0,
178 sbuf
, sizeof(sbuf
), NI_NUMERICHOST
) == 0)
181 service
= DEFAULT_PORT_NAME
;
182 if (getnameinfo((struct sockaddr
*)&me
, melen
, NULL
, 0,
183 snum
, sizeof(snum
), NI_NUMERICHOST
) != 0)
184 snprintf(snum
, sizeof(snum
), "?");
186 snprintf(logname
, sizeof(logname
), "faithd %s", snum
);
187 snprintf(procname
, sizeof(procname
), "accepting port %s", snum
);
188 openlog(logname
, LOG_PID
| LOG_NOWAIT
, LOG_DAEMON
);
190 if (argc
>= MAXARGV
) {
191 exit_failure("too many arguments");
194 serverarg
[0] = serverpath
= path
;
195 for (i
= 1; i
< argc
; i
++)
196 serverarg
[i
] = argv
[i
];
199 error
= setsockopt(STDIN_FILENO
, SOL_SOCKET
, SO_OOBINLINE
, &on
,
202 exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno
));
206 play_child(STDIN_FILENO
, (struct sockaddr
*)&from
);
207 exit_failure("should not reach here");
212 daemon_main(int argc
, char **argv
)
214 struct addrinfo hints
, *res
;
215 int s_wld
, error
, i
, serverargc
, on
= 1;
216 int family
= AF_INET6
;
219 while ((c
= getopt(argc
, argv
, "df:p")) != -1) {
238 if (config_load(configfile
) < 0 && configfile
) {
239 exit_failure("could not load config file");
253 serverargc
= argc
- NUMARG
;
254 if (serverargc
>= MAXARGV
)
255 exit_stderr("too many arguments");
257 serverpath
= strdup(argv
[NUMPRG
]);
259 exit_stderr("not enough core");
260 for (i
= 0; i
< serverargc
; i
++) {
261 serverarg
[i
] = strdup(argv
[i
+ NUMARG
]);
263 exit_stderr("not enough core");
267 case 1: /* no local service */
268 service
= argv
[NUMPRT
];
275 * Opening wild card socket for this service.
278 memset(&hints
, 0, sizeof(hints
));
279 hints
.ai_flags
= AI_PASSIVE
;
280 hints
.ai_family
= family
;
281 hints
.ai_socktype
= SOCK_STREAM
;
282 hints
.ai_protocol
= IPPROTO_TCP
; /* SCTP? */
283 error
= getaddrinfo(NULL
, service
, &hints
, &res
);
285 exit_failure("getaddrinfo: %s", gai_strerror(error
));
287 s_wld
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
289 exit_failure("socket: %s", strerror(errno
));
292 if (res
->ai_family
== AF_INET6
) {
293 error
= setsockopt(s_wld
, IPPROTO_IPV6
, IPV6_FAITH
, &on
, sizeof(on
));
295 exit_failure("setsockopt(IPV6_FAITH): %s",
300 error
= setsockopt(s_wld
, SOL_SOCKET
, SO_REUSEADDR
, &on
, sizeof(on
));
302 exit_failure("setsockopt(SO_REUSEADDR): %s", strerror(errno
));
304 error
= setsockopt(s_wld
, SOL_SOCKET
, SO_OOBINLINE
, &on
, sizeof(on
));
306 exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno
));
309 error
= setsockopt(s_wld
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
));
311 exit_failure("setsockopt(IPV6_V6ONLY): %s", strerror(errno
));
314 error
= bind(s_wld
, (struct sockaddr
*)res
->ai_addr
, res
->ai_addrlen
);
316 exit_failure("bind: %s", strerror(errno
));
318 error
= listen(s_wld
, 5);
320 exit_failure("listen: %s", strerror(errno
));
323 sockfd
= socket(PF_ROUTE
, SOCK_RAW
, PF_UNSPEC
);
325 exit_failure("socket(PF_ROUTE): %s", strerror(errno
));
334 snprintf(logname
, sizeof(logname
), "faithd %s", service
);
335 snprintf(procname
, sizeof(procname
), "accepting port %s", service
);
336 openlog(logname
, LOG_PID
| LOG_NOWAIT
, LOG_DAEMON
);
337 syslog(LOG_INFO
, "Staring faith daemon for %s port", service
);
341 exit(1); /*pacify gcc*/
345 play_service(int s_wld
)
347 struct sockaddr_storage srcaddr
;
351 struct pollfd pfd
[2];
355 * Wait, accept, fork, faith....
358 setproctitle("%s", procname
);
361 pfd
[0].events
= POLLIN
;
367 pfd
[1].events
= POLLIN
;
371 error
= poll(pfd
, sizeof(pfd
)/sizeof(pfd
[0]), INFTIM
);
375 exit_failure("select: %s", strerror(errno
));
380 if (pfd
[1].revents
& POLLIN
)
385 if (pfd
[0].revents
& POLLIN
)
387 len
= sizeof(srcaddr
);
388 s_src
= accept(s_wld
, (struct sockaddr
*)&srcaddr
, &len
);
390 if (errno
== ECONNABORTED
)
392 exit_failure("socket: %s", strerror(errno
));
395 if (srcaddr
.ss_family
== AF_INET6
&&
396 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6
*)&srcaddr
)->sin6_addr
)) {
398 syslog(LOG_ERR
, "connection from IPv4 mapped address?");
404 if (child_pid
== 0) {
408 openlog(logname
, LOG_PID
| LOG_NOWAIT
, LOG_DAEMON
);
409 play_child(s_src
, (struct sockaddr
*)&srcaddr
);
410 exit_failure("should never reach here");
416 syslog(LOG_ERR
, "can't fork");
423 play_child(int s_src
, struct sockaddr
*srcaddr
)
425 struct sockaddr_storage dstaddr6
;
426 struct sockaddr_storage dstaddr4
;
427 char src
[NI_MAXHOST
];
428 char dst6
[NI_MAXHOST
];
429 char dst4
[NI_MAXHOST
];
430 socklen_t len
= sizeof(dstaddr6
);
431 int s_dst
, error
, hport
, nresvport
, on
= 1;
433 struct sockaddr
*sa4
;
434 const struct config
*conf
;
439 getnameinfo(srcaddr
, srcaddr
->sa_len
,
440 src
, sizeof(src
), NULL
, 0, NI_NUMERICHOST
);
441 syslog(LOG_INFO
, "accepted a client from %s", src
);
443 error
= getsockname(s_src
, (struct sockaddr
*)&dstaddr6
, &len
);
445 exit_failure("getsockname: %s", strerror(errno
));
449 getnameinfo((struct sockaddr
*)&dstaddr6
, len
,
450 dst6
, sizeof(dst6
), NULL
, 0, NI_NUMERICHOST
);
451 syslog(LOG_INFO
, "the client is connecting to %s", dst6
);
453 if (!faith_prefix((struct sockaddr
*)&dstaddr6
)) {
458 syslog(LOG_INFO
, "executing local %s", serverpath
);
465 execv(serverpath
, serverarg
);
466 syslog(LOG_ERR
, "execv %s: %s", serverpath
,
471 exit_success("no local service for %s", service
);
476 * Act as a translator
479 switch (((struct sockaddr
*)&dstaddr6
)->sa_family
) {
481 if (!map6to4((struct sockaddr_in6
*)&dstaddr6
,
482 (struct sockaddr_in
*)&dstaddr4
)) {
484 exit_failure("map6to4 failed");
487 syslog(LOG_INFO
, "translating from v6 to v4");
491 exit_failure("family not supported");
495 sa4
= (struct sockaddr
*)&dstaddr4
;
496 getnameinfo(sa4
, sa4
->sa_len
,
497 dst4
, sizeof(dst4
), NULL
, 0, NI_NUMERICHOST
);
499 conf
= config_match(srcaddr
, sa4
);
500 if (!conf
|| !conf
->permit
) {
503 exit_failure("translation to %s not permitted for %s",
504 dst4
, prefix_string(&conf
->match
));
507 exit_failure("translation to %s not permitted", dst4
);
512 syslog(LOG_INFO
, "the translator is connecting to %s", dst4
);
514 setproctitle("port %s, %s -> %s", service
, src
, dst4
);
516 if (sa4
->sa_family
== AF_INET6
)
517 hport
= ntohs(((struct sockaddr_in6
*)&dstaddr4
)->sin6_port
);
519 hport
= ntohs(((struct sockaddr_in
*)&dstaddr4
)->sin_port
);
522 s_dst
= rresvport_af(&nresvport
, sa4
->sa_family
);
524 s_dst
= socket(sa4
->sa_family
, SOCK_STREAM
, 0);
526 exit_failure("socket: %s", strerror(errno
));
530 if (conf
->src
.a
.ss_family
) {
531 if (bind(s_dst
, (const struct sockaddr
*)&conf
->src
.a
,
532 conf
->src
.a
.ss_len
) < 0) {
533 exit_failure("bind: %s", strerror(errno
));
538 error
= setsockopt(s_dst
, SOL_SOCKET
, SO_OOBINLINE
, &on
, sizeof(on
));
540 exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno
));
544 error
= setsockopt(s_src
, SOL_SOCKET
, SO_SNDTIMEO
, &tv
, sizeof(tv
));
546 exit_failure("setsockopt(SO_SNDTIMEO): %s", strerror(errno
));
549 error
= setsockopt(s_dst
, SOL_SOCKET
, SO_SNDTIMEO
, &tv
, sizeof(tv
));
551 exit_failure("setsockopt(SO_SNDTIMEO): %s", strerror(errno
));
555 error
= connect(s_dst
, sa4
, sa4
->sa_len
);
557 exit_failure("connect: %s", strerror(errno
));
563 ftp_relay(s_src
, s_dst
);
566 tcp_relay(s_src
, s_dst
, service
);
573 /* 0: non faith, 1: faith */
575 faith_prefix(struct sockaddr
*dst
)
579 struct in6_addr faith_prefix
;
580 struct sockaddr_in6
*dst6
= (struct sockaddr_in
*)dst
;
582 if (dst
->sa_family
!= AF_INET6
)
587 mib
[2] = IPPROTO_IPV6
;
588 mib
[3] = IPV6CTL_FAITH_PREFIX
;
589 size
= sizeof(struct in6_addr
);
590 if (sysctl(mib
, 4, &faith_prefix
, &size
, NULL
, 0) < 0) {
591 exit_failure("sysctl: %s", strerror(errno
));
595 if (memcmp(dst
, &faith_prefix
,
596 sizeof(struct in6_addr
) - sizeof(struct in_addr
) == 0) {
602 struct sockaddr_in6
*sin6
;
603 struct sockaddr_in
*sin4
;
604 struct sockaddr_in6
*dst6
;
605 struct sockaddr_in
*dst4
;
606 struct sockaddr_in dstmap
;
608 dst6
= (struct sockaddr_in6
*)dst
;
609 if (dst
->sa_family
== AF_INET6
610 && IN6_IS_ADDR_V4MAPPED(&dst6
->sin6_addr
)) {
612 memset(&dstmap
, 0, sizeof(dstmap
));
613 dstmap
.sin_family
= AF_INET
;
614 dstmap
.sin_len
= sizeof(dstmap
);
615 memcpy(&dstmap
.sin_addr
, &dst6
->sin6_addr
.s6_addr
[12],
616 sizeof(dstmap
.sin_addr
));
617 dst
= (struct sockaddr
*)&dstmap
;
620 dst6
= (struct sockaddr_in6
*)dst
;
621 dst4
= (struct sockaddr_in
*)dst
;
623 for (p
= myaddrs
; p
; p
= p
->next
) {
624 sin6
= (struct sockaddr_in6
*)p
->addr
;
625 sin4
= (struct sockaddr_in
*)p
->addr
;
627 if (p
->addr
->sa_len
!= dst
->sa_len
628 || p
->addr
->sa_family
!= dst
->sa_family
)
631 switch (dst
->sa_family
) {
633 if (sin6
->sin6_scope_id
== dst6
->sin6_scope_id
634 && IN6_ARE_ADDR_EQUAL(&sin6
->sin6_addr
, &dst6
->sin6_addr
))
638 if (sin4
->sin_addr
.s_addr
== dst4
->sin_addr
.s_addr
)
647 /* 0: non faith, 1: faith */
649 map6to4(struct sockaddr_in6
*dst6
, struct sockaddr_in
*dst4
)
651 memset(dst4
, 0, sizeof(*dst4
));
652 dst4
->sin_len
= sizeof(*dst4
);
653 dst4
->sin_family
= AF_INET
;
654 dst4
->sin_port
= dst6
->sin6_port
;
655 memcpy(&dst4
->sin_addr
, &dst6
->sin6_addr
.s6_addr
[12],
656 sizeof(dst4
->sin_addr
));
658 if (dst4
->sin_addr
.s_addr
== INADDR_ANY
659 || dst4
->sin_addr
.s_addr
== INADDR_BROADCAST
660 || IN_MULTICAST(ntohl(dst4
->sin_addr
.s_addr
)))
673 while ((pid
= wait3(&status
, WNOHANG
, (struct rusage
*)0)) > 0)
674 if (WEXITSTATUS(status
))
675 syslog(LOG_WARNING
, "child %ld exit status 0x%x",
680 sig_terminate(int sig
)
682 syslog(LOG_INFO
, "Terminating faith daemon");
693 if (daemon(0, 0) == -1)
694 exit_stderr("daemon: %s", strerror(errno
));
697 memset(&sa
, 0, sizeof(sa
));
698 sa
.sa_handler
= sig_child
;
699 sa
.sa_flags
= SA_NOCLDWAIT
;
700 sigemptyset(&sa
.sa_mask
);
701 sigaction(SIGCHLD
, &sa
, (struct sigaction
*)0);
703 if (signal(SIGCHLD
, sig_child
) == SIG_ERR
) {
704 exit_failure("signal CHLD: %s", strerror(errno
));
709 if (signal(SIGTERM
, sig_terminate
) == SIG_ERR
) {
710 exit_failure("signal TERM: %s", strerror(errno
));
716 exit_stderr(const char *fmt
, ...)
722 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
724 fprintf(stderr
, "%s\n", buf
);
729 exit_failure(const char *fmt
, ...)
735 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
737 syslog(LOG_ERR
, "%s", buf
);
742 exit_success(const char *fmt
, ...)
748 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
750 syslog(LOG_INFO
, "%s", buf
);
758 struct ifaddrs
*ifap
, *ifa
;
760 struct sockaddr_in6
*sin6
;
762 if (getifaddrs(&ifap
) != 0) {
763 exit_failure("getifaddrs");
767 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
768 switch (ifa
->ifa_addr
->sa_family
) {
776 p
= (struct myaddrs
*)malloc(sizeof(struct myaddrs
) +
777 ifa
->ifa_addr
->sa_len
);
779 exit_failure("not enough core");
782 memcpy(p
+ 1, ifa
->ifa_addr
, ifa
->ifa_addr
->sa_len
);
784 p
->addr
= (struct sockaddr
*)(p
+ 1);
786 if (ifa
->ifa_addr
->sa_family
== AF_INET6
) {
787 sin6
= (struct sockaddr_in6
*)p
->addr
;
788 if (IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
)
789 || IN6_IS_ADDR_SITELOCAL(&sin6
->sin6_addr
)) {
790 sin6
->sin6_scope_id
=
791 ntohs(*(u_int16_t
*)&sin6
->sin6_addr
.s6_addr
[2]);
792 sin6
->sin6_addr
.s6_addr
[2] = 0;
793 sin6
->sin6_addr
.s6_addr
[3] = 0;
799 char hbuf
[NI_MAXHOST
];
800 getnameinfo(p
->addr
, p
->addr
->sa_len
,
801 hbuf
, sizeof(hbuf
), NULL
, 0,
803 syslog(LOG_INFO
, "my interface: %s %s", hbuf
,
814 struct myaddrs
*p
, *q
;
830 struct rt_msghdr
*rtm
;
832 len
= read(sockfd
, msg
, sizeof(msg
));
834 syslog(LOG_ERR
, "read(PF_ROUTE) failed");
837 rtm
= (struct rt_msghdr
*)msg
;
838 if (len
< 4 || len
< rtm
->rtm_msglen
) {
839 syslog(LOG_ERR
, "read(PF_ROUTE) short read");
842 if (rtm
->rtm_version
!= RTM_VERSION
) {
843 syslog(LOG_ERR
, "routing socket version mismatch");
848 switch (rtm
->rtm_type
) {
856 /* XXX more filters here? */
858 syslog(LOG_INFO
, "update interface address list");
867 fprintf(stderr
, "usage: %s [-dp] [-f conf] service [serverpath [serverargs]]\n",