1 /* $KAME: faithd.c,v 1.67 2003/10/16 05:26:21 itojun Exp $ */
4 * Copyright (C) 1997 and 1998 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
33 * User level translator from IPv6 to IPv4.
35 * Usage: faithd [<port> <progpath> <arg1(progname)> <arg2> ...]
36 * e.g. faithd telnet /usr/libexec/telnetd telnetd
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
42 #include <sys/param.h>
43 #include <sys/types.h>
44 #include <sys/sysctl.h>
45 #include <sys/socket.h>
49 #include <sys/ioctl.h>
66 #include <net/if_types.h>
70 # include <net/route.h>
71 # include <net/if_dl.h>
74 #include <netinet/in.h>
75 #include <arpa/inet.h>
82 char *serverpath
= NULL
;
83 char *serverarg
[MAXARGV
+ 1];
84 static char *faithdname
= NULL
;
86 char procname
[BUFSIZ
];
90 struct sockaddr
*addr
;
92 struct myaddrs
*myaddrs
= NULL
;
94 static const char *service
;
96 static int sockfd
= 0;
100 static int inetd
= 0;
101 static char *configfile
= NULL
;
103 int main(int, char **);
104 static int inetd_main(int, char **);
105 static int daemon_main(int, char **);
106 static void play_service(int);
107 static void play_child(int, struct sockaddr
*);
108 static int faith_prefix(struct sockaddr
*);
109 static int map6to4(struct sockaddr_in6
*, struct sockaddr_in
*);
110 static void sig_child(int);
111 static void sig_terminate(int);
112 static void start_daemon(void);
113 static void exit_stderr(const char *, ...)
114 __attribute__((__format__(__printf__
, 1, 2)));
115 static void grab_myaddrs(void);
116 static void free_myaddrs(void);
117 static void update_myaddrs(void);
118 static void usage(void);
121 main(int argc
, char **argv
)
128 faithdname
= strrchr(argv
[0], '/');
132 faithdname
= argv
[0];
134 if (strcmp(faithdname
, "faithd") != 0) {
136 return inetd_main(argc
, argv
);
138 return daemon_main(argc
, argv
);
142 inetd_main(int argc
, char **argv
)
144 char path
[MAXPATHLEN
];
145 struct sockaddr_storage me
;
146 struct sockaddr_storage from
;
147 socklen_t melen
, fromlen
;
151 char sbuf
[NI_MAXSERV
], snum
[NI_MAXSERV
];
153 if (config_load(configfile
) < 0 && configfile
) {
154 exit_failure("could not load config file");
158 if (strrchr(argv
[0], '/') == NULL
)
159 snprintf(path
, sizeof(path
), "%s/%s", DEFAULT_DIR
, argv
[0]);
161 snprintf(path
, sizeof(path
), "%s", argv
[0]);
166 sockfd
= socket(PF_ROUTE
, SOCK_RAW
, PF_UNSPEC
);
168 exit_failure("socket(PF_ROUTE): %s", strerror(errno
));
174 if (getsockname(STDIN_FILENO
, (struct sockaddr
*)&me
, &melen
) < 0) {
175 exit_failure("getsockname: %s", strerror(errno
));
178 fromlen
= sizeof(from
);
179 if (getpeername(STDIN_FILENO
, (struct sockaddr
*)&from
, &fromlen
) < 0) {
180 exit_failure("getpeername: %s", strerror(errno
));
183 if (getnameinfo((struct sockaddr
*)&me
, melen
, NULL
, 0,
184 sbuf
, sizeof(sbuf
), NI_NUMERICHOST
) == 0)
187 service
= DEFAULT_PORT_NAME
;
188 if (getnameinfo((struct sockaddr
*)&me
, melen
, NULL
, 0,
189 snum
, sizeof(snum
), NI_NUMERICHOST
) != 0)
190 snprintf(snum
, sizeof(snum
), "?");
192 snprintf(logname
, sizeof(logname
), "faithd %s", snum
);
193 snprintf(procname
, sizeof(procname
), "accepting port %s", snum
);
194 openlog(logname
, LOG_PID
| LOG_NOWAIT
, LOG_DAEMON
);
196 if (argc
>= MAXARGV
) {
197 exit_failure("too many arguments");
200 serverarg
[0] = serverpath
= path
;
201 for (i
= 1; i
< argc
; i
++)
202 serverarg
[i
] = argv
[i
];
205 error
= setsockopt(STDIN_FILENO
, SOL_SOCKET
, SO_OOBINLINE
, &on
,
208 exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno
));
212 play_child(STDIN_FILENO
, (struct sockaddr
*)&from
);
213 exit_failure("should not reach here");
218 daemon_main(int argc
, char **argv
)
220 struct addrinfo hints
, *res
;
221 int s_wld
, error
, i
, serverargc
, on
= 1;
222 int family
= AF_INET6
;
225 while ((c
= getopt(argc
, argv
, "df:p")) != -1) {
244 if (config_load(configfile
) < 0 && configfile
) {
245 exit_failure("could not load config file");
259 serverargc
= argc
- NUMARG
;
260 if (serverargc
>= MAXARGV
)
261 exit_stderr("too many arguments");
263 serverpath
= strdup(argv
[NUMPRG
]);
265 exit_stderr("not enough core");
266 for (i
= 0; i
< serverargc
; i
++) {
267 serverarg
[i
] = strdup(argv
[i
+ NUMARG
]);
269 exit_stderr("not enough core");
273 case 1: /* no local service */
274 service
= argv
[NUMPRT
];
281 * Opening wild card socket for this service.
284 memset(&hints
, 0, sizeof(hints
));
285 hints
.ai_flags
= AI_PASSIVE
;
286 hints
.ai_family
= family
;
287 hints
.ai_socktype
= SOCK_STREAM
;
288 hints
.ai_protocol
= IPPROTO_TCP
; /* SCTP? */
289 error
= getaddrinfo(NULL
, service
, &hints
, &res
);
291 exit_failure("getaddrinfo: %s", gai_strerror(error
));
293 s_wld
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
295 exit_failure("socket: %s", strerror(errno
));
298 if (res
->ai_family
== AF_INET6
) {
299 error
= setsockopt(s_wld
, IPPROTO_IPV6
, IPV6_FAITH
, &on
, sizeof(on
));
301 exit_failure("setsockopt(IPV6_FAITH): %s",
306 error
= setsockopt(s_wld
, SOL_SOCKET
, SO_REUSEADDR
, &on
, sizeof(on
));
308 exit_failure("setsockopt(SO_REUSEADDR): %s", strerror(errno
));
310 error
= setsockopt(s_wld
, SOL_SOCKET
, SO_OOBINLINE
, &on
, sizeof(on
));
312 exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno
));
315 error
= setsockopt(s_wld
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
));
317 exit_failure("setsockopt(IPV6_V6ONLY): %s", strerror(errno
));
320 error
= bind(s_wld
, (struct sockaddr
*)res
->ai_addr
, res
->ai_addrlen
);
322 exit_failure("bind: %s", strerror(errno
));
324 error
= listen(s_wld
, 5);
326 exit_failure("listen: %s", strerror(errno
));
329 sockfd
= socket(PF_ROUTE
, SOCK_RAW
, PF_UNSPEC
);
331 exit_failure("socket(PF_ROUTE): %s", strerror(errno
));
340 snprintf(logname
, sizeof(logname
), "faithd %s", service
);
341 snprintf(procname
, sizeof(procname
), "accepting port %s", service
);
342 openlog(logname
, LOG_PID
| LOG_NOWAIT
, LOG_DAEMON
);
343 syslog(LOG_INFO
, "Staring faith daemon for %s port", service
);
347 exit(1); /*pacify gcc*/
351 play_service(int s_wld
)
353 struct sockaddr_storage srcaddr
;
358 struct pollfd pfd
[2];
366 * Wait, accept, fork, faith....
369 setproctitle("%s", procname
);
373 pfd
[0].events
= POLLIN
;
378 if (s_wld
>= FD_SETSIZE
)
379 exit_failure("descriptor too big");
380 FD_SET(s_wld
, &rfds
);
387 pfd
[1].events
= POLLIN
;
389 if (sockfd
>= FD_SETSIZE
)
390 exit_failure("descriptor too big");
391 FD_SET(sockfd
, &rfds
);
392 maxfd
= (maxfd
< sockfd
) ? sockfd
: maxfd
;
398 error
= poll(pfd
, sizeof(pfd
)/sizeof(pfd
[0]), INFTIM
);
400 error
= select(maxfd
+ 1, &rfds
, NULL
, NULL
, NULL
);
405 exit_failure("select: %s", strerror(errno
));
411 if (pfd
[1].revents
& POLLIN
)
413 if (FD_ISSET(sockfd
, &rfds
))
420 if (pfd
[0].revents
& POLLIN
)
422 if (FD_ISSET(s_wld
, &rfds
))
425 len
= sizeof(srcaddr
);
426 s_src
= accept(s_wld
, (struct sockaddr
*)&srcaddr
, &len
);
428 if (errno
== ECONNABORTED
)
430 exit_failure("socket: %s", strerror(errno
));
433 if (srcaddr
.ss_family
== AF_INET6
&&
434 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6
*)&srcaddr
)->sin6_addr
)) {
436 syslog(LOG_ERR
, "connection from IPv4 mapped address?");
442 if (child_pid
== 0) {
446 openlog(logname
, LOG_PID
| LOG_NOWAIT
, LOG_DAEMON
);
447 play_child(s_src
, (struct sockaddr
*)&srcaddr
);
448 exit_failure("should never reach here");
454 syslog(LOG_ERR
, "can't fork");
461 play_child(int s_src
, struct sockaddr
*srcaddr
)
463 struct sockaddr_storage dstaddr6
;
464 struct sockaddr_storage dstaddr4
;
465 char src
[NI_MAXHOST
];
466 char dst6
[NI_MAXHOST
];
467 char dst4
[NI_MAXHOST
];
468 socklen_t len
= sizeof(dstaddr6
);
469 int s_dst
, error
, hport
, nresvport
, on
= 1;
471 struct sockaddr
*sa4
;
472 const struct config
*conf
;
477 getnameinfo(srcaddr
, srcaddr
->sa_len
,
478 src
, sizeof(src
), NULL
, 0, NI_NUMERICHOST
);
479 syslog(LOG_INFO
, "accepted a client from %s", src
);
481 error
= getsockname(s_src
, (struct sockaddr
*)&dstaddr6
, &len
);
483 exit_failure("getsockname: %s", strerror(errno
));
487 getnameinfo((struct sockaddr
*)&dstaddr6
, len
,
488 dst6
, sizeof(dst6
), NULL
, 0, NI_NUMERICHOST
);
489 syslog(LOG_INFO
, "the client is connecting to %s", dst6
);
491 if (!faith_prefix((struct sockaddr
*)&dstaddr6
)) {
496 syslog(LOG_INFO
, "executing local %s", serverpath
);
503 execv(serverpath
, serverarg
);
504 syslog(LOG_ERR
, "execv %s: %s", serverpath
,
509 exit_success("no local service for %s", service
);
514 * Act as a translator
517 switch (((struct sockaddr
*)&dstaddr6
)->sa_family
) {
519 if (!map6to4((struct sockaddr_in6
*)&dstaddr6
,
520 (struct sockaddr_in
*)&dstaddr4
)) {
522 exit_failure("map6to4 failed");
525 syslog(LOG_INFO
, "translating from v6 to v4");
529 exit_failure("family not supported");
533 sa4
= (struct sockaddr
*)&dstaddr4
;
534 getnameinfo(sa4
, sa4
->sa_len
,
535 dst4
, sizeof(dst4
), NULL
, 0, NI_NUMERICHOST
);
537 conf
= config_match(srcaddr
, sa4
);
538 if (!conf
|| !conf
->permit
) {
541 exit_failure("translation to %s not permitted for %s",
542 dst4
, prefix_string(&conf
->match
));
545 exit_failure("translation to %s not permitted", dst4
);
550 syslog(LOG_INFO
, "the translator is connecting to %s", dst4
);
552 setproctitle("port %s, %s -> %s", service
, src
, dst4
);
554 if (sa4
->sa_family
== AF_INET6
)
555 hport
= ntohs(((struct sockaddr_in6
*)&dstaddr4
)->sin6_port
);
557 hport
= ntohs(((struct sockaddr_in
*)&dstaddr4
)->sin_port
);
560 s_dst
= rresvport_af(&nresvport
, sa4
->sa_family
);
562 s_dst
= socket(sa4
->sa_family
, SOCK_STREAM
, 0);
564 exit_failure("socket: %s", strerror(errno
));
568 if (conf
->src
.a
.ss_family
) {
569 if (bind(s_dst
, (const struct sockaddr
*)&conf
->src
.a
,
570 conf
->src
.a
.ss_len
) < 0) {
571 exit_failure("bind: %s", strerror(errno
));
576 error
= setsockopt(s_dst
, SOL_SOCKET
, SO_OOBINLINE
, &on
, sizeof(on
));
578 exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno
));
582 error
= setsockopt(s_src
, SOL_SOCKET
, SO_SNDTIMEO
, &tv
, sizeof(tv
));
584 exit_failure("setsockopt(SO_SNDTIMEO): %s", strerror(errno
));
587 error
= setsockopt(s_dst
, SOL_SOCKET
, SO_SNDTIMEO
, &tv
, sizeof(tv
));
589 exit_failure("setsockopt(SO_SNDTIMEO): %s", strerror(errno
));
593 error
= connect(s_dst
, sa4
, sa4
->sa_len
);
595 exit_failure("connect: %s", strerror(errno
));
601 ftp_relay(s_src
, s_dst
);
604 tcp_relay(s_src
, s_dst
, service
);
611 /* 0: non faith, 1: faith */
613 faith_prefix(struct sockaddr
*dst
)
617 struct in6_addr faith_prefix
;
618 struct sockaddr_in6
*dst6
= (struct sockaddr_in
*)dst
;
620 if (dst
->sa_family
!= AF_INET6
)
625 mib
[2] = IPPROTO_IPV6
;
626 mib
[3] = IPV6CTL_FAITH_PREFIX
;
627 size
= sizeof(struct in6_addr
);
628 if (sysctl(mib
, 4, &faith_prefix
, &size
, NULL
, 0) < 0) {
629 exit_failure("sysctl: %s", strerror(errno
));
633 if (memcmp(dst
, &faith_prefix
,
634 sizeof(struct in6_addr
) - sizeof(struct in_addr
) == 0) {
640 struct sockaddr_in6
*sin6
;
641 struct sockaddr_in
*sin4
;
642 struct sockaddr_in6
*dst6
;
643 struct sockaddr_in
*dst4
;
644 struct sockaddr_in dstmap
;
646 dst6
= (struct sockaddr_in6
*)dst
;
647 if (dst
->sa_family
== AF_INET6
648 && IN6_IS_ADDR_V4MAPPED(&dst6
->sin6_addr
)) {
650 memset(&dstmap
, 0, sizeof(dstmap
));
651 dstmap
.sin_family
= AF_INET
;
652 dstmap
.sin_len
= sizeof(dstmap
);
653 memcpy(&dstmap
.sin_addr
, &dst6
->sin6_addr
.s6_addr
[12],
654 sizeof(dstmap
.sin_addr
));
655 dst
= (struct sockaddr
*)&dstmap
;
658 dst6
= (struct sockaddr_in6
*)dst
;
659 dst4
= (struct sockaddr_in
*)dst
;
661 for (p
= myaddrs
; p
; p
= p
->next
) {
662 sin6
= (struct sockaddr_in6
*)p
->addr
;
663 sin4
= (struct sockaddr_in
*)p
->addr
;
665 if (p
->addr
->sa_len
!= dst
->sa_len
666 || p
->addr
->sa_family
!= dst
->sa_family
)
669 switch (dst
->sa_family
) {
671 if (sin6
->sin6_scope_id
== dst6
->sin6_scope_id
672 && IN6_ARE_ADDR_EQUAL(&sin6
->sin6_addr
, &dst6
->sin6_addr
))
676 if (sin4
->sin_addr
.s_addr
== dst4
->sin_addr
.s_addr
)
685 /* 0: non faith, 1: faith */
687 map6to4(struct sockaddr_in6
*dst6
, struct sockaddr_in
*dst4
)
689 memset(dst4
, 0, sizeof(*dst4
));
690 dst4
->sin_len
= sizeof(*dst4
);
691 dst4
->sin_family
= AF_INET
;
692 dst4
->sin_port
= dst6
->sin6_port
;
693 memcpy(&dst4
->sin_addr
, &dst6
->sin6_addr
.s6_addr
[12],
694 sizeof(dst4
->sin_addr
));
696 if (dst4
->sin_addr
.s_addr
== INADDR_ANY
697 || dst4
->sin_addr
.s_addr
== INADDR_BROADCAST
698 || IN_MULTICAST(ntohl(dst4
->sin_addr
.s_addr
)))
706 sig_child(int sig __unused
)
711 while ((pid
= wait3(&status
, WNOHANG
, (struct rusage
*)0)) > 0)
712 if (WEXITSTATUS(status
))
713 syslog(LOG_WARNING
, "child %ld exit status 0x%x",
718 sig_terminate(int sig __unused
)
720 syslog(LOG_INFO
, "Terminating faith daemon");
731 if (daemon(0, 0) == -1)
732 exit_stderr("daemon: %s", strerror(errno
));
735 memset(&sa
, 0, sizeof(sa
));
736 sa
.sa_handler
= sig_child
;
737 sa
.sa_flags
= SA_NOCLDWAIT
;
738 sigemptyset(&sa
.sa_mask
);
739 sigaction(SIGCHLD
, &sa
, (struct sigaction
*)0);
741 if (signal(SIGCHLD
, sig_child
) == SIG_ERR
) {
742 exit_failure("signal CHLD: %s", strerror(errno
));
747 if (signal(SIGTERM
, sig_terminate
) == SIG_ERR
) {
748 exit_failure("signal TERM: %s", strerror(errno
));
754 exit_stderr(const char *fmt
, ...)
760 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
762 fprintf(stderr
, "%s\n", buf
);
767 exit_failure(const char *fmt
, ...)
773 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
775 syslog(LOG_ERR
, "%s", buf
);
780 exit_success(const char *fmt
, ...)
786 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
788 syslog(LOG_INFO
, "%s", buf
);
796 struct ifaddrs
*ifap
, *ifa
;
798 struct sockaddr_in6
*sin6
;
800 if (getifaddrs(&ifap
) != 0) {
801 exit_failure("getifaddrs");
805 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
806 switch (ifa
->ifa_addr
->sa_family
) {
814 p
= (struct myaddrs
*)malloc(sizeof(struct myaddrs
) +
815 ifa
->ifa_addr
->sa_len
);
817 exit_failure("not enough core");
820 memcpy(p
+ 1, ifa
->ifa_addr
, ifa
->ifa_addr
->sa_len
);
822 p
->addr
= (struct sockaddr
*)(p
+ 1);
824 if (ifa
->ifa_addr
->sa_family
== AF_INET6
) {
825 sin6
= (struct sockaddr_in6
*)p
->addr
;
826 if (IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
)
827 || IN6_IS_ADDR_SITELOCAL(&sin6
->sin6_addr
)) {
828 sin6
->sin6_scope_id
=
829 ntohs(*(u_int16_t
*)&sin6
->sin6_addr
.s6_addr
[2]);
830 sin6
->sin6_addr
.s6_addr
[2] = 0;
831 sin6
->sin6_addr
.s6_addr
[3] = 0;
837 char hbuf
[NI_MAXHOST
];
838 getnameinfo(p
->addr
, p
->addr
->sa_len
,
839 hbuf
, sizeof(hbuf
), NULL
, 0,
841 syslog(LOG_INFO
, "my interface: %s %s", hbuf
,
852 struct myaddrs
*p
, *q
;
868 struct rt_msghdr
*rtm
;
870 len
= read(sockfd
, msg
, sizeof(msg
));
872 syslog(LOG_ERR
, "read(PF_ROUTE) failed");
875 rtm
= (struct rt_msghdr
*)msg
;
876 if (len
< 4 || len
< rtm
->rtm_msglen
) {
877 syslog(LOG_ERR
, "read(PF_ROUTE) short read");
880 if (rtm
->rtm_version
!= RTM_VERSION
) {
881 syslog(LOG_ERR
, "routing socket version mismatch");
886 switch (rtm
->rtm_type
) {
894 /* XXX more filters here? */
896 syslog(LOG_INFO
, "update interface address list");
905 fprintf(stderr
, "usage: %s [-dp] [-f conf] service [serverpath [serverargs]]\n",