1 /* $KAME: faithd.c,v 1.46 2002/01/24 16:40:42 sumikawa 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
31 * $FreeBSD: src/usr.sbin/faithd/faithd.c,v 1.2.2.7 2002/04/28 08:01:39 ume Exp $
35 * User level translator from IPv6 to IPv4.
37 * Usage: faithd [<port> <progpath> <arg1(progname)> <arg2> ...]
38 * e.g. faithd telnet /usr/libexec/telnetd telnetd
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>
64 #include <net/if_types.h>
68 # include <net/route.h>
69 # include <net/if_dl.h>
72 #include <netinet/in.h>
73 #include <arpa/inet.h>
79 #include <arpa/nameser.h>
81 #define FAITH_NS "FAITH_NS"
88 char *serverpath
= NULL
;
89 char *serverarg
[MAXARGV
+ 1];
90 static char *faithdname
= NULL
;
92 char procname
[BUFSIZ
];
95 struct sockaddr
*addr
;
97 struct myaddrs
*myaddrs
= NULL
;
98 static const char *service
;
100 static int sockfd
= 0;
103 static int pflag
= 0;
104 static int inetd
= 0;
105 static char *configfile
= NULL
;
107 static int inetd_main(int, char **);
108 static int daemon_main(int, char **);
109 static void play_service(int);
110 static void play_child(int, struct sockaddr
*);
111 static int faith_prefix(struct sockaddr
*);
112 static int map6to4(struct sockaddr_in6
*, struct sockaddr_in
*);
114 static int map4to6(struct sockaddr_in
*, struct sockaddr_in6
*);
116 static void sig_child(int);
117 static void sig_terminate(int);
118 static void start_daemon(void);
119 static void exit_stderr(const char *, ...)
120 __attribute__((__format__(__printf__
, 1, 2)));
121 static void grab_myaddrs(void);
122 static void free_myaddrs(void);
123 static void update_myaddrs(void);
124 static void usage(void);
127 main(int argc
, char **argv
)
134 faithdname
= strrchr(argv
[0], '/');
138 faithdname
= argv
[0];
140 if (strcmp(faithdname
, "faithd") != 0) {
142 return inetd_main(argc
, argv
);
144 return daemon_main(argc
, argv
);
148 inetd_main(int argc
, char **argv
)
150 char path
[MAXPATHLEN
];
151 struct sockaddr_storage me
;
152 struct sockaddr_storage from
;
157 char sbuf
[NI_MAXSERV
], snum
[NI_MAXSERV
];
159 if (config_load(configfile
) < 0 && configfile
) {
160 exit_failure("could not load config file");
164 if (strrchr(argv
[0], '/') == NULL
)
165 snprintf(path
, sizeof(path
), "%s/%s", DEFAULT_DIR
, argv
[0]);
167 snprintf(path
, sizeof(path
), "%s", argv
[0]);
172 sockfd
= socket(PF_ROUTE
, SOCK_RAW
, PF_UNSPEC
);
174 exit_failure("socket(PF_ROUTE): %s", strerror(errno
));
180 if (getsockname(STDIN_FILENO
, (struct sockaddr
*)&me
, &melen
) < 0) {
181 exit_failure("getsockname: %s", strerror(errno
));
184 fromlen
= sizeof(from
);
185 if (getpeername(STDIN_FILENO
, (struct sockaddr
*)&from
, &fromlen
) < 0) {
186 exit_failure("getpeername: %s", strerror(errno
));
189 if (getnameinfo((struct sockaddr
*)&me
, melen
, NULL
, 0,
190 sbuf
, sizeof(sbuf
), NI_NUMERICHOST
) == 0)
193 service
= DEFAULT_PORT_NAME
;
194 if (getnameinfo((struct sockaddr
*)&me
, melen
, NULL
, 0,
195 snum
, sizeof(snum
), NI_NUMERICHOST
) != 0)
196 snprintf(snum
, sizeof(snum
), "?");
198 snprintf(logname
, sizeof(logname
), "faithd %s", snum
);
199 snprintf(procname
, sizeof(procname
), "accepting port %s", snum
);
200 openlog(logname
, LOG_PID
| LOG_NOWAIT
, LOG_DAEMON
);
202 if (argc
>= MAXARGV
) {
203 exit_failure("too many arguments");
206 serverarg
[0] = serverpath
= path
;
207 for (i
= 1; i
< argc
; i
++)
208 serverarg
[i
] = argv
[i
];
211 error
= setsockopt(STDIN_FILENO
, SOL_SOCKET
, SO_OOBINLINE
, &on
,
214 exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno
));
218 play_child(STDIN_FILENO
, (struct sockaddr
*)&from
);
219 exit_failure("should not reach here");
224 daemon_main(int argc
, char **argv
)
226 struct addrinfo hints
, *res
;
227 int s_wld
, error
, i
, serverargc
, on
= 1;
228 int family
= AF_INET6
;
232 #endif /* FAITH_NS */
234 while ((c
= getopt(argc
, argv
, "df:p46")) != -1) {
261 if (config_load(configfile
) < 0 && configfile
) {
262 exit_failure("could not load config file");
267 if ((ns
= getenv(FAITH_NS
)) != NULL
) {
268 struct sockaddr_storage ss
;
269 struct addrinfo hints
, *res
;
270 char serv
[NI_MAXSERV
];
272 memset(&ss
, 0, sizeof(ss
));
273 memset(&hints
, 0, sizeof(hints
));
274 snprintf(serv
, sizeof(serv
), "%u", NAMESERVER_PORT
);
275 hints
.ai_flags
= AI_NUMERICHOST
;
276 if (getaddrinfo(ns
, serv
, &hints
, &res
) == 0) {
278 memcpy(&_res_ext
.nsaddr
, res
->ai_addr
, res
->ai_addrlen
);
282 #endif /* FAITH_NS */
293 serverargc
= argc
- NUMARG
;
294 if (serverargc
>= MAXARGV
)
295 exit_stderr("too many arguments");
297 serverpath
= malloc(strlen(argv
[NUMPRG
]) + 1);
298 strcpy(serverpath
, argv
[NUMPRG
]);
299 for (i
= 0; i
< serverargc
; i
++) {
300 serverarg
[i
] = malloc(strlen(argv
[i
+ NUMARG
]) + 1);
301 strcpy(serverarg
[i
], argv
[i
+ NUMARG
]);
305 case 1: /* no local service */
306 service
= argv
[NUMPRT
];
311 * Opening wild card socket for this service.
314 memset(&hints
, 0, sizeof(hints
));
315 hints
.ai_flags
= AI_PASSIVE
;
316 hints
.ai_family
= family
;
317 hints
.ai_socktype
= SOCK_STREAM
;
318 hints
.ai_protocol
= 0;
319 error
= getaddrinfo(NULL
, service
, &hints
, &res
);
321 exit_failure("getaddrinfo: %s", gai_strerror(error
));
323 s_wld
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
325 exit_failure("socket: %s", strerror(errno
));
328 if (res
->ai_family
== AF_INET6
) {
329 error
= setsockopt(s_wld
, IPPROTO_IPV6
, IPV6_FAITH
, &on
, sizeof(on
));
331 exit_failure("setsockopt(IPV6_FAITH): %s",
337 if (res
->ai_family
== AF_INET
) {
338 error
= setsockopt(s_wld
, IPPROTO_IP
, IP_FAITH
, &on
, sizeof(on
));
340 exit_failure("setsockopt(IP_FAITH): %s",
346 error
= setsockopt(s_wld
, SOL_SOCKET
, SO_REUSEADDR
, &on
, sizeof(on
));
348 exit_failure("setsockopt(SO_REUSEADDR): %s", strerror(errno
));
350 error
= setsockopt(s_wld
, SOL_SOCKET
, SO_OOBINLINE
, &on
, sizeof(on
));
352 exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno
));
354 error
= bind(s_wld
, (struct sockaddr
*)res
->ai_addr
, res
->ai_addrlen
);
356 exit_failure("bind: %s", strerror(errno
));
358 error
= listen(s_wld
, 5);
360 exit_failure("listen: %s", strerror(errno
));
363 sockfd
= socket(PF_ROUTE
, SOCK_RAW
, PF_UNSPEC
);
365 exit_failure("socket(PF_ROUTE): %s", strerror(errno
));
376 snprintf(logname
, sizeof(logname
), "faithd %s", service
);
377 snprintf(procname
, sizeof(procname
), "accepting port %s", service
);
378 openlog(logname
, LOG_PID
| LOG_NOWAIT
, LOG_DAEMON
);
379 syslog(LOG_INFO
, "Staring faith daemon for %s port", service
);
383 exit(1); /*pacify gcc*/
387 play_service(int s_wld
)
389 struct sockaddr_storage srcaddr
;
398 * Wait, accept, fork, faith....
401 setproctitle("%s", procname
);
404 FD_SET(s_wld
, &rfds
);
408 FD_SET(sockfd
, &rfds
);
409 maxfd
= (maxfd
< sockfd
) ? sockfd
: maxfd
;
413 error
= select(maxfd
+ 1, &rfds
, NULL
, NULL
, NULL
);
417 exit_failure("select: %s", strerror(errno
));
422 if (FD_ISSET(sockfd
, &rfds
)) {
426 if (FD_ISSET(s_wld
, &rfds
)) {
427 len
= sizeof(srcaddr
);
428 s_src
= accept(s_wld
, (struct sockaddr
*)&srcaddr
,
431 if (errno
== ECONNABORTED
)
433 exit_failure("socket: %s", strerror(errno
));
439 if (child_pid
== 0) {
443 openlog(logname
, LOG_PID
| LOG_NOWAIT
, LOG_DAEMON
);
444 play_child(s_src
, (struct sockaddr
*)&srcaddr
);
445 exit_failure("should never reach here");
451 syslog(LOG_ERR
, "can't fork");
458 play_child(int s_src
, struct sockaddr
*srcaddr
)
460 struct sockaddr_storage dstaddr6
;
461 struct sockaddr_storage dstaddr4
;
462 char src
[NI_MAXHOST
];
463 char dst6
[NI_MAXHOST
];
464 char dst4
[NI_MAXHOST
];
465 int len
= sizeof(dstaddr6
);
466 int s_dst
, error
, hport
, nresvport
, on
= 1;
468 struct sockaddr
*sa4
;
469 const struct config
*conf
;
474 getnameinfo(srcaddr
, srcaddr
->sa_len
,
475 src
, sizeof(src
), NULL
, 0, NI_NUMERICHOST
);
476 syslog(LOG_INFO
, "accepted a client from %s", src
);
478 error
= getsockname(s_src
, (struct sockaddr
*)&dstaddr6
, &len
);
480 exit_failure("getsockname: %s", strerror(errno
));
484 getnameinfo((struct sockaddr
*)&dstaddr6
, len
,
485 dst6
, sizeof(dst6
), NULL
, 0, NI_NUMERICHOST
);
486 syslog(LOG_INFO
, "the client is connecting to %s", dst6
);
488 if (!faith_prefix((struct sockaddr
*)&dstaddr6
)) {
493 syslog(LOG_INFO
, "executing local %s", serverpath
);
500 execv(serverpath
, serverarg
);
501 syslog(LOG_ERR
, "execv %s: %s", serverpath
,
506 exit_success("no local service for %s", service
);
511 * Act as a translator
514 switch (((struct sockaddr
*)&dstaddr6
)->sa_family
) {
516 if (!map6to4((struct sockaddr_in6
*)&dstaddr6
,
517 (struct sockaddr_in
*)&dstaddr4
)) {
519 exit_failure("map6to4 failed");
522 syslog(LOG_INFO
, "translating from v6 to v4");
526 if (!map4to6((struct sockaddr_in
*)&dstaddr6
,
527 (struct sockaddr_in6
*)&dstaddr4
)) {
529 exit_failure("map4to6 failed");
532 syslog(LOG_INFO
, "translating from v4 to v6");
537 exit_failure("family not supported");
541 sa4
= (struct sockaddr
*)&dstaddr4
;
542 getnameinfo(sa4
, sa4
->sa_len
,
543 dst4
, sizeof(dst4
), NULL
, 0, NI_NUMERICHOST
);
545 conf
= config_match(srcaddr
, sa4
);
546 if (!conf
|| !conf
->permit
) {
549 exit_failure("translation to %s not permitted for %s",
550 dst4
, prefix_string(&conf
->match
));
553 exit_failure("translation to %s not permitted", dst4
);
558 syslog(LOG_INFO
, "the translator is connecting to %s", dst4
);
560 setproctitle("port %s, %s -> %s", service
, src
, dst4
);
562 if (sa4
->sa_family
== AF_INET6
)
563 hport
= ntohs(((struct sockaddr_in6
*)&dstaddr4
)->sin6_port
);
565 hport
= ntohs(((struct sockaddr_in
*)&dstaddr4
)->sin_port
);
570 s_dst
= rresvport_af(&nresvport
, sa4
->sa_family
);
574 s_dst
= rresvport_af(&nresvport
, sa4
->sa_family
);
576 s_dst
= socket(sa4
->sa_family
, SOCK_STREAM
, 0);
580 exit_failure("socket: %s", strerror(errno
));
584 if (conf
->src
.a
.ss_family
) {
585 if (bind(s_dst
, (const struct sockaddr
*)&conf
->src
.a
,
586 conf
->src
.a
.ss_len
) < 0) {
587 exit_failure("bind: %s", strerror(errno
));
592 error
= setsockopt(s_dst
, SOL_SOCKET
, SO_OOBINLINE
, &on
, sizeof(on
));
594 exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno
));
598 error
= setsockopt(s_src
, SOL_SOCKET
, SO_SNDTIMEO
, &tv
, sizeof(tv
));
600 exit_failure("setsockopt(SO_SNDTIMEO): %s", strerror(errno
));
603 error
= setsockopt(s_dst
, SOL_SOCKET
, SO_SNDTIMEO
, &tv
, sizeof(tv
));
605 exit_failure("setsockopt(SO_SNDTIMEO): %s", strerror(errno
));
609 error
= connect(s_dst
, sa4
, sa4
->sa_len
);
611 exit_failure("connect: %s", strerror(errno
));
617 ftp_relay(s_src
, s_dst
);
621 "WARNING: it is insecure to relay rsh port");
622 rsh_relay(s_src
, s_dst
);
626 "WARNING: it is insecure to relay rlogin port");
629 tcp_relay(s_src
, s_dst
, service
);
636 /* 0: non faith, 1: faith */
638 faith_prefix(struct sockaddr
*dst
)
642 struct in6_addr faith_prefix
;
643 struct sockaddr_in6
*dst6
= (struct sockaddr_in
*)dst
;
645 if (dst
->sa_family
!= AF_INET6
)
650 mib
[2] = IPPROTO_IPV6
;
651 mib
[3] = IPV6CTL_FAITH_PREFIX
;
652 size
= sizeof(struct in6_addr
);
653 if (sysctl(mib
, 4, &faith_prefix
, &size
, NULL
, 0) < 0) {
654 exit_failure("sysctl: %s", strerror(errno
));
658 if (memcmp(dst
, &faith_prefix
,
659 sizeof(struct in6_addr
) - sizeof(struct in_addr
) == 0) {
665 struct sockaddr_in6
*sin6
;
666 struct sockaddr_in
*sin4
;
667 struct sockaddr_in6
*dst6
;
668 struct sockaddr_in
*dst4
;
669 struct sockaddr_in dstmap
;
671 dst6
= (struct sockaddr_in6
*)dst
;
672 if (dst
->sa_family
== AF_INET6
673 && IN6_IS_ADDR_V4MAPPED(&dst6
->sin6_addr
)) {
675 memset(&dstmap
, 0, sizeof(dstmap
));
676 dstmap
.sin_family
= AF_INET
;
677 dstmap
.sin_len
= sizeof(dstmap
);
678 memcpy(&dstmap
.sin_addr
, &dst6
->sin6_addr
.s6_addr
[12],
679 sizeof(dstmap
.sin_addr
));
680 dst
= (struct sockaddr
*)&dstmap
;
683 dst6
= (struct sockaddr_in6
*)dst
;
684 dst4
= (struct sockaddr_in
*)dst
;
686 for (p
= myaddrs
; p
; p
= p
->next
) {
687 sin6
= (struct sockaddr_in6
*)p
->addr
;
688 sin4
= (struct sockaddr_in
*)p
->addr
;
690 if (p
->addr
->sa_len
!= dst
->sa_len
691 || p
->addr
->sa_family
!= dst
->sa_family
)
694 switch (dst
->sa_family
) {
696 if (sin6
->sin6_scope_id
== dst6
->sin6_scope_id
697 && IN6_ARE_ADDR_EQUAL(&sin6
->sin6_addr
, &dst6
->sin6_addr
))
701 if (sin4
->sin_addr
.s_addr
== dst4
->sin_addr
.s_addr
)
710 /* 0: non faith, 1: faith */
712 map6to4(struct sockaddr_in6
*dst6
, struct sockaddr_in
*dst4
)
714 memset(dst4
, 0, sizeof(*dst4
));
715 dst4
->sin_len
= sizeof(*dst4
);
716 dst4
->sin_family
= AF_INET
;
717 dst4
->sin_port
= dst6
->sin6_port
;
718 memcpy(&dst4
->sin_addr
, &dst6
->sin6_addr
.s6_addr
[12],
719 sizeof(dst4
->sin_addr
));
721 if (dst4
->sin_addr
.s_addr
== INADDR_ANY
722 || dst4
->sin_addr
.s_addr
== INADDR_BROADCAST
723 || IN_MULTICAST(ntohl(dst4
->sin_addr
.s_addr
)))
730 /* 0: non faith, 1: faith */
732 map4to6(struct sockaddr_in
*dst4
, struct sockaddr_in6
*dst6
)
734 char host
[NI_MAXHOST
];
735 char serv
[NI_MAXSERV
];
736 struct addrinfo hints
, *res
;
739 if (getnameinfo((struct sockaddr
*)dst4
, dst4
->sin_len
, host
, sizeof(host
),
740 serv
, sizeof(serv
), NI_NAMEREQD
|NI_NUMERICSERV
) != 0)
743 memset(&hints
, 0, sizeof(hints
));
745 hints
.ai_family
= AF_INET6
;
746 hints
.ai_socktype
= SOCK_STREAM
;
747 hints
.ai_protocol
= 0;
749 if ((ai_errno
= getaddrinfo(host
, serv
, &hints
, &res
)) != 0) {
750 syslog(LOG_INFO
, "%s %s: %s", host
, serv
,
751 gai_strerror(ai_errno
));
755 memcpy(dst6
, res
->ai_addr
, res
->ai_addrlen
);
769 pid
= wait3(&status
, WNOHANG
, NULL
);
770 if (pid
&& WEXITSTATUS(status
))
771 syslog(LOG_WARNING
, "child %d exit status 0x%x", pid
, status
);
775 sig_terminate(int sig
)
777 syslog(LOG_INFO
, "Terminating faith daemon");
788 if (daemon(0, 0) == -1)
789 exit_stderr("daemon: %s", strerror(errno
));
792 memset(&sa
, 0, sizeof(sa
));
793 sa
.sa_handler
= sig_child
;
794 sa
.sa_flags
= SA_NOCLDWAIT
;
795 sigemptyset(&sa
.sa_mask
);
796 sigaction(SIGCHLD
, &sa
, NULL
);
798 if (signal(SIGCHLD
, sig_child
) == SIG_ERR
) {
799 exit_failure("signal CHLD: %s", strerror(errno
));
804 if (signal(SIGTERM
, sig_terminate
) == SIG_ERR
) {
805 exit_failure("signal TERM: %s", strerror(errno
));
811 exit_stderr(const char *fmt
, ...)
817 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
819 fprintf(stderr
, "%s\n", buf
);
824 exit_failure(const char *fmt
, ...)
830 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
832 syslog(LOG_ERR
, "%s", buf
);
837 exit_success(const char *fmt
, ...)
843 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
845 syslog(LOG_INFO
, "%s", buf
);
853 struct ifaddrs
*ifap
, *ifa
;
855 struct sockaddr_in6
*sin6
;
857 if (getifaddrs(&ifap
) != 0) {
858 exit_failure("getifaddrs");
862 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
863 switch (ifa
->ifa_addr
->sa_family
) {
871 p
= (struct myaddrs
*)malloc(sizeof(struct myaddrs
) +
872 ifa
->ifa_addr
->sa_len
);
874 exit_failure("not enough core");
877 memcpy(p
+ 1, ifa
->ifa_addr
, ifa
->ifa_addr
->sa_len
);
879 p
->addr
= (struct sockaddr
*)(p
+ 1);
881 if (ifa
->ifa_addr
->sa_family
== AF_INET6
) {
882 sin6
= (struct sockaddr_in6
*)p
->addr
;
883 if (IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
)
884 || IN6_IS_ADDR_SITELOCAL(&sin6
->sin6_addr
)) {
885 sin6
->sin6_scope_id
=
886 ntohs(*(u_int16_t
*)&sin6
->sin6_addr
.s6_addr
[2]);
887 sin6
->sin6_addr
.s6_addr
[2] = 0;
888 sin6
->sin6_addr
.s6_addr
[3] = 0;
894 char hbuf
[NI_MAXHOST
];
895 getnameinfo(p
->addr
, p
->addr
->sa_len
,
896 hbuf
, sizeof(hbuf
), NULL
, 0,
898 syslog(LOG_INFO
, "my interface: %s %s", hbuf
,
909 struct myaddrs
*p
, *q
;
925 struct rt_msghdr
*rtm
;
927 len
= read(sockfd
, msg
, sizeof(msg
));
929 syslog(LOG_ERR
, "read(PF_ROUTE) failed");
932 rtm
= (struct rt_msghdr
*)msg
;
933 if (len
< 4 || len
< rtm
->rtm_msglen
) {
934 syslog(LOG_ERR
, "read(PF_ROUTE) short read");
937 if (rtm
->rtm_version
!= RTM_VERSION
) {
938 syslog(LOG_ERR
, "routing socket version mismatch");
943 switch (rtm
->rtm_type
) {
951 /* XXX more filters here? */
953 syslog(LOG_INFO
, "update interface address list");
962 fprintf(stderr
, "usage: %s [-dp] [-f conf] service [serverpath [serverargs]]\n",